Solusinya adalah dengan mengatur parameter koneksi JDBC noDatetimeStringSync=true
dengan useLegacyDatetimeCode=false
. Sebagai bonus, saya juga menemukan sessionVariables=time_zone='-00:00'
mengurangi kebutuhan untuk set time_zone
secara eksplisit pada setiap koneksi baru.
Ada beberapa kode konversi zona waktu "cerdas" yang diaktifkan jauh di dalam ResultSet.getString()
metode ketika mendeteksi bahwa kolom adalah TIMESTAMP
kolom.
Sayangnya, kode cerdas ini memiliki bug:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart)
mengembalikan Timestamp
salah menandai zona waktu default JVM, bahkan ketika tz
parameter diatur ke sesuatu yang lain:
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;
}
Kembalinya ts
akan benar-benar valid kecuali ketika lebih jauh dalam rantai panggilan, itu diubah kembali menjadi string menggunakan toString()
telanjang metode, yang merender ts
sebagai String yang mewakili apa yang akan ditampilkan jam di zona waktu default-JVM, alih-alih representasi String dari waktu dalam UTC. Di 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();
Menyetel noDatetimeStringSync=true
menonaktifkan seluruh kekacauan parse/unparse dan hanya mengembalikan nilai string seperti yang diterima dari database.
Hasil pengujian:
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
masih penting karena mengubah perilaku getDefaultTimeZone()
untuk menggunakan TZ server database.
Saat mengejar ini, saya juga menemukan dokumentasi untuk useJDBCCompliantTimezoneShift
tidak benar, meskipun tidak ada bedanya:dokumentasi mengatakan [Ini adalah bagian dari kode tanggal-waktu lama, sehingga properti hanya memiliki efek ketika "useLegacyDatetimeCode=true." ], tapi itu salah, lihat ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean)
.