sql >> Database >  >> RDS >> Mysql

Wat zijn JDBC-mysql-stuurprogramma-instellingen voor een gezonde omgang met DATETIME en TIMESTAMP in UTC?

De oplossing is om de JDBC-verbindingsparameter noDatetimeStringSync=true in te stellen met useLegacyDatetimeCode=false . Als bonus vond ik ook sessionVariables=time_zone='-00:00' verlicht de noodzaak om set time_zone expliciet bij elke nieuwe verbinding.

Er is een "intelligente" tijdzone-conversiecode die diep in de ResultSet.getString() wordt geactiveerd methode wanneer het detecteert dat de kolom een ​​TIMESTAMP . is kolom.

Helaas, deze intelligente code heeft een fout:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) retourneert een Timestamp verkeerd getagd naar de standaard tijdzone van de JVM, zelfs wanneer de tz parameter is ingesteld op iets anders:

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;
}

De terugkeer ts zou perfect geldig zijn, behalve wanneer hoger in de oproepketen, het terug wordt geconverteerd naar een string met behulp van de kale toString() methode, die de ts . weergeeft als een tekenreeks die aangeeft wat een klok zou weergeven in de JVM-standaardtijdzone, in plaats van een tekenreeksrepresentatie van de tijd in UTC. In 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();

noDatetimeStringSync=true instellen schakelt de gehele ontleden/ontleden puinhoop uit en retourneert gewoon de tekenreekswaarde zoals deze is ontvangen van de database.

Testuitgang:

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

De useLegacyDatetimeCode=false is nog steeds belangrijk omdat het het gedrag van getDefaultTimeZone() . verandert om de TZ van de databaseserver te gebruiken.

Terwijl ik dit najaagde, vond ik ook de documentatie voor useJDBCCompliantTimezoneShift is onjuist, hoewel het geen verschil maakt:documentatie zegt [Dit maakt deel uit van de oude datum-tijdcode, dus de eigenschap heeft alleen effect als "useLegacyDatetimeCode=true." ], maar dat is fout, zie ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean) .




  1. Hoe de LOAD_FILE()-functie werkt in MySQL

  2. SQLite hebben

  3. Kan een tabel meerdere primaire sleutels hebben?

  4. Hoe ROWNUM werkt in een paginatiequery?