Die Lösung besteht darin, den JDBC-Verbindungsparameter noDatetimeStringSync=true
zu setzen mit useLegacyDatetimeCode=false
. Als Bonus habe ich auch sessionVariables=time_zone='-00:00'
gefunden verringert die Notwendigkeit, set time_zone
explizit bei jeder neuen Verbindung.
Es gibt einen "intelligenten" Zeitzonen-Umwandlungscode, der tief in ResultSet.getString()
aktiviert wird -Methode, wenn erkannt wird, dass die Spalte ein TIMESTAMP
ist Spalte.
Leider hat dieser intelligente Code einen Fehler:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart)
gibt einen Timestamp
zurück falsch in die Standardzeitzone der JVM getaggt, selbst wenn der tz
Parameter auf etwas anderes gesetzt ist:
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;
}
Die Rückgabe ts
wäre vollkommen gültig, außer wenn es weiter oben in der Aufrufkette mit dem bloßen toString()
zurück in einen String konvertiert wird -Methode, die das ts
rendert als String, der darstellt, was eine Uhr in der JVM-Standardzeitzone anzeigen würde, anstelle einer String-Darstellung der Zeit 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();
Setzen von noDatetimeStringSync=true
deaktiviert das gesamte Parsing/Unparse-Durcheinander und gibt nur den String-Wert zurück, wie er von der Datenbank empfangen wird.
Testausgabe:
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Der useLegacyDatetimeCode=false
ist immer noch wichtig, da es das Verhalten von getDefaultTimeZone()
ändert um die TZ des Datenbankservers zu verwenden.
Während ich dem nachjagte, fand ich auch die Dokumentation für useJDBCCompliantTimezoneShift
ist falsch, obwohl es keinen Unterschied macht:Dokumentation sagt [Dies ist Teil des veralteten Datums-Uhrzeit-Codes, daher hat die Eigenschaft nur eine Auswirkung, wenn "useLegacyDatetimeCode=true." ], aber das ist falsch, siehe ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean)
.