不要将您的日期时间转换为字符串以存储到 SQL 数据库中。使用日期时间对象。
我假设您将存储到数据类型为 datetime 或 timestamp 的数据库列中,没有时区,并且该列包含 UTC 值(推荐做法)。在这种情况下,进一步假设您至少使用 Java 8 和 JDBC 4.2,请将 UTC 格式的 LocalDateTime 存储到数据库中。
ZonedDateTime dateTime = ZonedDateTime.of(
2018, 7, 1, 9, 0, 0, 0, ZoneId.of("America/Denver"));
LocalDateTime dateTimeInUtc = dateTime.withZoneSameInstant(ZoneOffset.UTC)
.toLocalDateTime();
System.out.println("UTC: " + dateTimeInUtc);
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(date_time) values (?)");
ps.setObject(1, dateTimeInUtc);
ps.executeUpdate();
代码示例在 7 月 1 日上午 9 点在丹佛进行转换并打印:
UTC:2018-07-01T15:00
然后它将打印的 UTC 时间存储到数据库中。注意setObject 方法的使用。
您使用的Calendar 类早已过时,而且设计总是很糟糕。如果您从旧版 API 获得了一个 Calendar 对象,而您现在无法更改或不想更改,请先将其转换为 Instant,然后从那里进行进一步转换:
Calendar localDateTime = // …;
LocalDateTime dateTimeInUtc = localDateTime.toInstant()
.atOffset(ZoneOffset.UTC)
.toLocalDateTime();
我应该在这里使用 LocalDateTime 吗?
编辑:这取决于您在数据库中使用的数据类型和 JDBC 驱动程序的要求。正如我所说,我假设 您 知道数据库中的值是 UTC 并且您使用的数据类型没有时区,所以数据库 不知道。如果是这种情况,则使用带有时区或偏移信息的 Java 类型毫无意义,因为在存储时它们无论如何都会丢失。
有些人会说,在这种情况下,您已经在数据库中使用了错误的类型,并建议您使用timestamp with timezone 列,这样数据库也知道时间是UTC。在这种情况下,您当然应该在存储的值中包含偏移信息。例如,PostgreSQL JDBC 驱动程序在这种情况下需要 OffsetDateTime,这是合乎逻辑的(因为它存储的是 UTC 偏移量,而不是实时时区)。
根据您的 DBMS 的功能,可能还有其他选项。我在底部添加了几个链接,您可以搜索更多。
你的代码出了什么问题?
您对Calendar 的转换工作正常,并且在UTC 中为您提供了相同的时间点。当您尝试将其格式化为String 时,问题才开始出现:当您使用calendar.getTime() 时,您将获得一个包含相同时间点(仍然是正确的时间点)的Date 对象,但是一个Date无法保存时区信息,因此您丢失了有关 UTC 的信息。接下来,您使用SimpleDateFormat 格式化Date。 SimpleDateFormat 有一个时区,如果您不自己设置,它会使用您的 JVM 的时区设置,这可能是 Mountain Time 的某种变体。因此,您的时间以 MT 打印。
链接