Jordan, właściwie miałeś dobry pomysł. Problem polega na tym, że istnieje błąd w sterowniku MySQL JDBC, a argument Kalendarz jest domyślnie całkowicie ignorowany. Spójrz na kod źródłowy dla PreparedStatement, aby naprawdę zobaczyć, co się dzieje.
Zwróć uwagę, że formatuje znacznik czasu przy użyciu strefy czasowej JVM. Będzie to działać tylko wtedy, gdy JVM używa strefy czasowej UTC. Obiekt Calendar jest całkowicie ignorowany.
this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
timestampString = this.tsdf.format(x);
Aby MySQL mógł używać argumentu Kalendarz, musisz wyłączyć starszy kod daty/czasu za pomocą następującej opcji połączenia:
useLegacyDatetimeCode=false
Możesz go więc użyć podczas łączenia się z bazą danych w ten sposób:
String url = "jdbc:mysql://localhost/tz?useLegacyDatetimeCode=false"
Jeśli wyłączysz starszy kod daty i godziny za pomocą powyższego wiersza, wyrenderuje on Twoją sygnaturę czasową w docelowej strefie czasowej Kalendarza:
if (targetCalendar != null) {
targetCalendar.setTime(x);
this.tsdf.setTimeZone(targetCalendar.getTimeZone());
timestampString = this.tsdf.format(x);
} else {
this.tsdf.setTimeZone(this.connection.getServerTimezoneTZ());
timestampString = this.tsdf.format(x);
}
Całkiem łatwo zobaczyć, co się tutaj dzieje. Jeśli przekażesz obiekt Calendar, użyje go podczas formatowania danych. W przeciwnym razie do sformatowania danych użyje strefy czasowej bazy danych. O dziwo, jeśli przekażesz Kalendarz, ustawi on również czas na podaną wartość Timestamp (co wydaje się bezcelowe).