ZonedDateTime 持久化到 SQL 数据库
ZonedDateTime persistance to SQL Database
美好的一天,
我创建了将在全球范围内使用的 Web 应用程序服务。
因此,我需要以 UTC 格式存储日期时间值,并以墙上的时钟向最终用户表示它们。
阅读 Stack overflow 后,我明白了,我应该:
- 在数据库中使用时间戳作为列类型(当前为 MariaDB 10.1.20)
- 在Java中使用ZonedDateTime(我使用java8)
在这些值之间进行转换时出现问题。
当我使用 JDBC 时,我必须进行以下转换:
java.sql.Timestamp <-> java.time.ZonedDateTime
我的代码:
// Get current zonedDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
// Convert zonedDateTime to java.sql.Timestamp before saving to DB
Timestamp = Timestamp.from(zonedDateTime.toInstant());
// Get zonedDateTime from resultSet
Timestamp timestamp = (Timestamp) resultSet.getObject("created");
ZonedDateTime zonedDateTime =
ZonedDateTime.ofInstant(ts.toInstant(), ZoneOffset.UTC))
当我使用:
zonedDateTimeBeforeSave.isEqual(zonedDateTimeAfterSave);
它 returns 我错了(我需要在我的域模型的重写相等方法中比较它们)
下面是两者的打印:
zonedDateTimeBeforeSave: 2017-01-24T20:18:17.720Z
zonedDateTimeAfterSave: 2017-01-24T20:18:17Z
问题:
- 我的选择对吗?也许,我应该使用另一列或 java 类型...
- 我做的转换对吗?也许还有其他更好的方法
谢谢
- 编辑:
在马特约翰逊的帮助下,我明白问题出在事实上,当我将日期时间保存到数据库时,它不会保存分数,尽管它应该。仅供参考列类型是 timestamp(6).
- 编辑:
现在我使用 java.time.Instant 而不是 ZonedDateTime
MySQL 在 5.6.4 版中添加了对小数秒的支持。我猜你 运行 比那年长,因此你的毫秒数被截断了。
来自 MySQL 5.6 文档:
Before MySQL 5.6.4, the instances are limited in which a fractional seconds part is permitted in temporal values. A trailing fractional part is permissible in contexts such as literal values, and in the arguments to or return values from some temporal functions. ... However, when MySQL stores a value into a column of any temporal data type, it discards any fractional part and does not store it.
MySQL 5.6.4 and up expands fractional seconds support for TIME
, DATETIME
, and TIMESTAMP
values, with up to microseconds (6 digits) precision. ...
看完这篇post和评论后,我终于找到了问题所在:
原因是我的 MariaDB JDBC 驱动程序
我有一个旧的 1.1.7 版本,参数 "useFractionalSeconds" 设置为 false。
解决方案是将此参数设置为 true (f.ex by URL)
或更新驱动程序。目前最新版本为 1.5.7 至 25.01.2017
美好的一天,
我创建了将在全球范围内使用的 Web 应用程序服务。
因此,我需要以 UTC 格式存储日期时间值,并以墙上的时钟向最终用户表示它们。
阅读 Stack overflow 后,我明白了,我应该:
- 在数据库中使用时间戳作为列类型(当前为 MariaDB 10.1.20)
- 在Java中使用ZonedDateTime(我使用java8)
在这些值之间进行转换时出现问题。
当我使用 JDBC 时,我必须进行以下转换:
java.sql.Timestamp <-> java.time.ZonedDateTime
我的代码:
// Get current zonedDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
// Convert zonedDateTime to java.sql.Timestamp before saving to DB
Timestamp = Timestamp.from(zonedDateTime.toInstant());
// Get zonedDateTime from resultSet
Timestamp timestamp = (Timestamp) resultSet.getObject("created");
ZonedDateTime zonedDateTime =
ZonedDateTime.ofInstant(ts.toInstant(), ZoneOffset.UTC))
当我使用:
zonedDateTimeBeforeSave.isEqual(zonedDateTimeAfterSave);
它 returns 我错了(我需要在我的域模型的重写相等方法中比较它们)
下面是两者的打印:
zonedDateTimeBeforeSave: 2017-01-24T20:18:17.720Z
zonedDateTimeAfterSave: 2017-01-24T20:18:17Z
问题:
- 我的选择对吗?也许,我应该使用另一列或 java 类型...
- 我做的转换对吗?也许还有其他更好的方法
谢谢
- 编辑: 在马特约翰逊的帮助下,我明白问题出在事实上,当我将日期时间保存到数据库时,它不会保存分数,尽管它应该。仅供参考列类型是 timestamp(6).
- 编辑: 现在我使用 java.time.Instant 而不是 ZonedDateTime
MySQL 在 5.6.4 版中添加了对小数秒的支持。我猜你 运行 比那年长,因此你的毫秒数被截断了。
来自 MySQL 5.6 文档:
Before MySQL 5.6.4, the instances are limited in which a fractional seconds part is permitted in temporal values. A trailing fractional part is permissible in contexts such as literal values, and in the arguments to or return values from some temporal functions. ... However, when MySQL stores a value into a column of any temporal data type, it discards any fractional part and does not store it.
MySQL 5.6.4 and up expands fractional seconds support for
TIME
,DATETIME
, andTIMESTAMP
values, with up to microseconds (6 digits) precision. ...
看完这篇post和评论后,我终于找到了问题所在:
原因是我的 MariaDB JDBC 驱动程序
我有一个旧的 1.1.7 版本,参数 "useFractionalSeconds" 设置为 false。
解决方案是将此参数设置为 true (f.ex by URL)
或更新驱动程序。目前最新版本为 1.5.7 至 25.01.2017