Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jakie są ustawienia sterownika JDBC-mysql dla rozsądnej obsługi DATETIME i TIMESTAMP w UTC?

Rozwiązaniem jest ustawienie parametru połączenia JDBC noDatetimeStringSync=true z useLegacyDatetimeCode=false . Jako bonus znalazłem również sessionVariables=time_zone='-00:00' łagodzi potrzebę set time_zone wyraźnie przy każdym nowym połączeniu.

Istnieje pewien "inteligentny" kod konwersji strefy czasowej, który jest aktywowany głęboko w ResultSet.getString() metoda, gdy wykryje, że kolumna jest TIMESTAMP kolumna.

Niestety, ten inteligentny kod ma błąd:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) zwraca Timestamp błędnie otagowane do domyślnej strefy czasowej JVM, nawet jeśli tz parametr jest ustawiony na coś innego:

final static Timestamp fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) {
    Calendar cal = (tz == null) ? new GregorianCalendar() : new GregorianCalendar(tz);
    cal.clear();

    // why-oh-why is this different than java.util.date, in the year part, but it still keeps the silly '0' for the start month????
    cal.set(year, month - 1, day, hour, minute, seconds);

    long tsAsMillis = cal.getTimeInMillis();

    Timestamp ts = new Timestamp(tsAsMillis);
    ts.setNanos(secondsPart);

    return ts;
}

Zwracany ts byłby całkowicie prawidłowy, z wyjątkiem sytuacji, gdy dalej w łańcuchu wywołań jest konwertowany z powrotem na ciąg znaków za pomocą samego toString() metoda, która renderuje ts jako ciąg reprezentujący to, co zegar wyświetliłby w domyślnej strefie czasowej JVM, zamiast ciągu reprezentującego czas w UTC. W ResultSetImpl.getStringInternal(int columnIndex, boolean checkDateTypes) :

                case Types.TIMESTAMP:
                    Timestamp ts = getTimestampFromString(columnIndex, null, stringVal, this.getDefaultTimeZone(), false);

                    if (ts == null) {
                        this.wasNullFlag = true;

                        return null;
                    }

                    this.wasNullFlag = false;

                    return ts.toString();

Ustawienie noDatetimeStringSync=true wyłącza cały bałagan parsowania/odtwarzania i po prostu zwraca wartość ciągu w postaci otrzymanej z bazy danych.

Wyjście testowe:

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

useLegacyDatetimeCode=false jest nadal ważne, ponieważ zmienia zachowanie getDefaultTimeZone() aby użyć TZ serwera bazy danych.

Szukając tego, znalazłem również dokumentację dla useJDBCCompliantTimezoneShift jest niepoprawne, chociaż nie ma znaczenia:dokumentacja mówi [Jest to część starszego kodu daty i godziny, dlatego właściwość ma wpływ tylko wtedy, gdy „useLegacyDatetimeCode=true”. ], ale to źle, zobacz ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean) .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. jak wybrać licznik z głównego zapytania do podzapytania

  2. mysqli::mysqli():(HY000/2002):Nie można połączyć się z lokalnym serwerem MySQL przez gniazdo 'MySQL' (2)

  3. Unicode w MySQL Regex?

  4. Kłopotliwe zachowanie arytmetyczne php/Mysql w czasie

  5. pip install mysqlclient na amazon linux