【问题标题】:MySQL DATETIME and TIMESTAMP to java.sql.Timestamp to ZonedDateTimeMySQL DATETIME 和 TIMESTAMP 到 java.sql.Timestamp 到 ZonedDateTime
【发布时间】:2016-10-30 01:14:08
【问题描述】:

我想知道转换是如何工作的。 MySQL 服务器(5.6)将 TIMESTAMP 视为区域调整(并在内部存储在/从 UTC 检索)。它还将 DATETIME 视为没有区域。

在 Java 方面,无论哪种情况,我都建议阅读java.sql.Timestamp。是否存在从 MySQL 的 DATETIME 到 java.sql.Timestamp 的区域类型转换(通过 MySQL-connector 5.1.37 时)(例如应用客户端系统区域)?

最后,我的服务器和客户端只有一个区域,因此我维护了一个特定的 ZoneId(在应用程序代码中)以访问ZonedDateTime。但我想使用ZonedDateTime,来回访问存储为 DATETIME 的数据库。一个简单的转换示例将不胜感激!

【问题讨论】:

  • 回答了我自己的问题。您必须使用 Java 8。我的第一条评论一定没有帮助,因为那是对服务器信息的所有客户端解释。我很抱歉。
  • @astrogeek14,我没想到我需要格式化/解析字符串来执行此操作。 ?现在,我有一个来自 MySQL 的 DATETIME 值,我想使用已知的 ZoneId 将它放入 ZonedDateTime(在一个变量中,我们将调用 zid)。
  • 你可能不会;我误解了你的问题。继续:是否可以将ZoneId 放入数据库中(大概是长度为 3 的 varchar)?
  • @astrogeek14,我不知道它是干什么用的。我的代码中有一个ZoneId。我知道要转换到哪个区域(我假设是 java.sql.Timestamp)。

标签: java mysql datetime


【解决方案1】:

让我们解决您遇到的每个问题。第一:

是否发生了从 MySQL 的 DATETIME 到 java.sql.Timestamp 的区域类型转换(通过 MySQL 连接器 5.1.37 时)(例如应用客户端系统区域)?
首先,我假设您正在使用连接器中的 getTimestamp(int) 方法。我找不到向我展示启发性答案的官方消息来源;但是,answer 指出了这个问题:
当您调用 getTimestamp() 时,如果类型为时间戳,MySQL JDBC 驱动程序会将时间从 GMT 转换为默认时区。它不会对其他类型执行此类转换。
但是,在该方法的this 版本中,如果基础数据库不存储时区信息,它使用基础CalendarTimestamp 转换为指定的TimeZone。这可能是您第二个问题的解决方案,只要您知道存储值的时区(您知道)。但如果不是,似乎第一种方法没有发生转换,至少在它检索到DATETIME 时是这样。谈到您的第二个问题:
但我想与ZonedDateTime 合作,来回访问存储为 DATETIME 的数据库。
这让我觉得只要你知道你从哪个时区转换,就有办法做到这一点。正如我们之前所说,您和您的客户只使用一个ZoneId,这完全没问题。但是,提供此答案以适用于更多时区。如果要将连接的ZoneId存储在数据库中,则可以实现多个ZoneId;检索它以及DATETIME,最后将这些值处理成ZonedDateTime。您可以使用ZoneId 类的the ID'sZoneIds 存储到数据库中(如果您愿意的话)。
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZoneId zoneId = ZoneId.of(resultSet.getString(zoneColumnId), ZoneId.SHORT_IDS);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);

或者,您可以将DATETIME 作为TIMESTAMP 存储在数据库中,正如ZZ Coder 在他的上述回答中所建议的那样。但是,您可以只使用硬编码的ZoneId

Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);

编辑
查看source code,在使用getTimestamp(int, Calendar)setTimestamp(int, Timestamp, Calendar) 函数的get 或set 调用中,使用Calendar 的时区。但是,在使用TIMESTAMP 的某些情况下,当不使用Calendar 时,JDBC 会使用服务器的时区。根据原始海报,它起作用了(见下面的comment)。

【讨论】:

  • 你知道,我只是使用测试数据,写入数据库然后读回它,但我不知道你对数据库有什么想法。我这样做了:Timestamp t = rs.getTimestamp(rsCol); ZonedDateTime zdt = t.toInstant().atZone(zoneId);
  • 在写入数据库的情况下,我使用了这个:stmt.setTimestamp( i+1, new Timestamp(( (ZonedDateTime) params.get(i)).toInstant().getEpochSecond() * 1000L));(其中 i 是加载到准备好的语句中的向量参数的索引)
  • 1000L 的乘法是必要的,因为 Java 使用毫秒对吗?而 unix 时间戳以秒为单位?
  • 我应该说我也没想过要检查各种 getTimestamp() 调用。谢谢你,@astrogeek14。
  • 试试吧,如果你没有问题,那我就这么认为。
猜你喜欢
  • 2015-04-20
  • 2018-01-31
  • 2013-10-20
  • 1970-01-01
  • 2021-05-30
  • 2016-02-25
  • 2017-07-08
  • 1970-01-01
  • 2017-01-25
相关资源
最近更新 更多