sql >> Database teknologi >  >> RDS >> Mysql

Hvad er JDBC-mysql-driverindstillingerne for fornuftig håndtering af DATETIME og TIMESTAMP i UTC?

Løsningen er at indstille JDBC-forbindelsesparameteren noDatetimeStringSync=true med useLegacyDatetimeCode=false . Som en bonus fandt jeg også sessionVariables=time_zone='-00:00' afhjælper behovet for at set time_zone eksplicit på hver ny forbindelse.

Der er en "intelligent" tidszonekonverteringskode, der bliver aktiveret dybt inde i ResultSet.getString() metode, når den registrerer, at kolonnen er en TIMESTAMP kolonne.

Ak, denne intelligente kode har en fejl:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) returnerer et Timestamp forkert tagget til JVM'ens standardtidszone, selv når tz parameter er sat til noget andet:

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

Returneringen ts ville være helt gyldig, undtagen når længere oppe i opkaldskæden, den konverteres tilbage til en streng ved hjælp af den blottede toString() metode, som gengiver ts som en streng, der repræsenterer, hvad et ur ville vise i JVM-standardtidszonen, i stedet for en strengrepræsentation af tiden i UTC. I 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();

Indstilling af noDatetimeStringSync=true deaktiverer hele parse/unparse messen og returnerer bare strengværdien, som den modtages fra databasen.

Test output:

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 er stadig vigtigt, fordi det ændrer adfærden for getDefaultTimeZone() for at bruge databaseserverens TZ.

Mens jeg jagtede dette, fandt jeg også dokumentationen for useJDBCCompliantTimezoneShift er forkert, selvom det ikke gør nogen forskel:dokumentationen siger [Dette er en del af den gamle dato-tidskode, og ejendommen har således kun en effekt, når "useLegacyDatetimeCode=true." ], men det er forkert, se ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean) .




  1. A.* er ikke i GROUP BY med venstre join på laravel query Builder

  2. Node.js og Microsoft SQL Server

  3. PHP/MySQL:Lagring og hentning af UUIDS

  4. Indsættelse af mm/dd/åååå formatdatoer i MySQL