Джордан, всъщност имаш правилната идея. Проблемът е, че има грешка в MySQL JDBC драйвер и аргументът Calendar е напълно игнориран по подразбиране. Вижте изходния код за PreparedStatement, за да видите наистина какво се случва.
Забележете, че форматът е Timestamp, използвайки часовата зона на JVM. Това ще работи само ако вашият JVM използва UTC часова зона. Обектът Calendar е напълно игнориран.
this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
timestampString = this.tsdf.format(x);
За да може MySQL да използва аргумента Calendar, трябва да деактивирате наследения код за дата/час със следната опция за връзка:
useLegacyDatetimeCode=false
Така че може да го използвате, когато се свързвате с базата данни по следния начин:
String url = "jdbc:mysql://localhost/tz?useLegacyDatetimeCode=false"
Ако деактивирате наследения код за дата и час с помощта на горния ред, той ЩЕ изобрази вашия Timestamp в часовата зона на целевия календар:
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);
}
Доста лесно е да се види какво се случва тук. Ако предадете обект на Calendar, той ще използва това при форматиране на данните. В противен случай той ще използва часовата зона на базата данни, за да форматира данните. Странно е, че ако прехвърлите календар, той също ще зададе времето на дадената стойност на Timestamp (което изглежда е безсмислено).