Jordan, thực ra bạn đã có ý tưởng đúng. Vấn đề là có một lỗi trong trình điều khiển MySQL JDBC và đối số Lịch hoàn toàn bị bỏ qua theo mặc định. Xem mã nguồn cho PreparedStatement để thực sự biết điều gì đang xảy ra.
Lưu ý rằng nó định dạng Dấu thời gian bằng cách sử dụng múi giờ của JVM. Điều này sẽ chỉ hoạt động nếu JVM của bạn đang sử dụng múi giờ UTC. Đối tượng Lịch hoàn toàn bị bỏ qua.
this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
timestampString = this.tsdf.format(x);
Để MySQL sử dụng đối số Lịch, bạn phải tắt mã ngày / giờ kế thừa bằng tùy chọn kết nối sau:
useLegacyDatetimeCode=false
Vì vậy, bạn có thể sử dụng nó khi kết nối với cơ sở dữ liệu như thế này:
String url = "jdbc:mysql://localhost/tz?useLegacyDatetimeCode=false"
Nếu bạn tắt mã ngày giờ kế thừa bằng dòng trên, thì mã này SẼ hiển thị Dấu thời gian của bạn trong múi giờ của Lịch mục tiêu:
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);
}
Khá dễ dàng để xem những gì đang xảy ra ở đây. Nếu bạn chuyển đối tượng Lịch vào, đối tượng này sẽ sử dụng đối tượng này khi định dạng dữ liệu. Nếu không, nó sẽ sử dụng múi giờ của cơ sở dữ liệu để định dạng dữ liệu. Thật kỳ lạ, nếu bạn chuyển vào Lịch, nó cũng sẽ đặt thời gian thành giá trị Dấu thời gian đã cho (điều này dường như vô nghĩa).