我想知道这种转换是如何工作的。MySQL服务器(5.6)处理时间戳作为区域调整(和内部存储在/从UTC检索)。它还将DATETIME视为没有区域。
在Java方面,无论哪种情况,我都建议阅读java.sql.Timestamp
。是否有一个区域类型转换发生(当通过MySQL-connector 5.1.37)从MySQL的DATETIME到java.sql.Timestamp
(如应用客户端系统区域)?
最后,我的服务器和客户端只有一个区域,所以我维护一个特定的ZoneId(在应用程序代码中)来获取ZonedDateTime
。但是我想使用ZonedDateTime
,来回到存储为DATETIME的数据库。转换的一个简单的例子将受到赞赏!
让我们来回答您的每个问题。第一:
是否有一个区域类型的转换发生(当通过MySQL-connector 5.1.37)从MySQL的DATETIME到java.sql.Timestamp
(如应用客户端系统区域)?
首先,我假定您正在使用连接器中的getTimestamp(int)方法。我找不到一个能给我一个启发性答案的官方来源;然而,有这样一个问题,其中的答案是:当你调用getTimestamp()时,如果类型是时间戳,MySQL JDBC驱动程序将时间从GMT转换为默认时区。对其他类型不执行这样的转换。但是,在这个版本的方法中,如果底层数据库不存储时区信息,则使用底层
Calendar
将Timestamp
转换为指定的TimeZone
。这可能是第二个问题的解决方案,只要您知道存储该值的时区(您确实知道)。但如果不是,似乎第一个方法没有发生转换,至少在检索DATETIME
时没有。说到你的第二个问题:但是我想和ZonedDateTime
一起工作,来回到数据库存储为DATETIME。
这让我认为有一种方法可以做到这一点,只要你知道哪个时区你从转换。正如我们之前所说,您和您的客户只使用一个ZoneId
,这是完全可以的。但是,提供这个答案是为了使用更多的时区。如果要在数据库中存储连接的ZoneId
,则可以实现多个ZoneId
;检索它和DATETIME
,最后将这些值处理成ZonedDateTime
。您可以使用ZoneId
类的ID将ZoneId
存储到数据库中(如果您愿意的话)。
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZoneId zoneId = ZoneId.of(resultSet.getString(zoneColumnId), ZoneId.SHORT_IDS);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
或者,您可以像ZZ Coder在上面的回答中建议的那样,将DATETIME
作为TIMESTAMP
存储在数据库中。但是,您可以直接使用硬编码的ZoneId
:
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
编辑
查看源代码,在使用getTimestamp(int, Calendar)
或setTimestamp(int, Timestamp, Calendar)
函数的get或set调用中,使用的是Calendar
的时区。但是,在使用TIMESTAMP
的某些情况下,当不使用Calendar
时,JDBC将使用服务器的时区。根据最初的海报,它起作用了(见下面的评论)。