【问题标题】:Issue in saving current date with UTC time in sql server在sql server中用UTC时间保存当前日期的问题
【发布时间】:2019-09-25 13:25:31
【问题描述】:

我想在 sql server 2014 中使用 UTC 时区保存日期。我使用 ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC")) 获取当前日期时间并使用 Hibernate 会话对象将其保存到 db。在调试时,我可以看到在 Java 程序中日期很好,就像 2019-09-25T13:22:29.573Z[UTC],但是在保存到数据库列之后,它就像这样 2019-09-25 18:53:23.3630000。它会根据系统时间自动转换时间部分。任何人都可以请建议是什么问题?我在数据库中创建此列时使用了datetime2 数据类型。

【问题讨论】:

  • Sql server 没有将时区存储为日期的一部分,那么如果不在系统时间的时区中,您希望如何存储它?如果您需要完全相同的时间,请修改服务器以使用 UTC 时间,或者记住在将日期读回 java 时将其转换回 UTC
  • 如果使用 hibernate/java 检索日期并通过 java(或在调试器中)打印它会得到什么?

标签: java hibernate sql-server-2014


【解决方案1】:

类型错误

您的列使用了错误的数据类型。

datetime2 类型不能表示时刻。该类型仅存储日期和时间,但缺少时区或与 UTC 的偏移量的上下文。因此,如果您存储“2020 年 1 月 23 日中午”,我们无法知道您是指日本东京的中午、突尼斯突尼斯的中午,还是美国俄亥俄州托莱多的中午,三个不同的时刻相隔几个小时。此错误类型类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE。 Java 中的等价类是LocalDateTime

如果您已经存储了数据,则需要refactor your database。基本上,添加一个正确类型的新列,为每一行复制数据,随时转换。当然,这仅在您知道每个保存的值中缺少的预期时区时才有效。

正确的类型

虽然我不使用 Microsoft SQL Server,但根据文档,您应该使用 datetimeoffset 类型的列来记录时刻。此类型将任何提交的值调整为 UTC 以进行查询和排序,同时还记录偏移量。此类型类似于 SQL 标准类型TIMESTAMP WITH TIME ZONE

通常最好以 UTC 格式存储您的时刻,偏移量为零时分秒。

Instant 类代表 UTC 中的一个时刻。

Instant instant = Instant.now() ;

如果您有ZonedDateTime,则可以提取Instant

Instant instant = zdt.toInstant() ;

我们希望将 Instant 直接保存到数据库中。不幸的是,JDBC 4.2 soec 不需要支持两个最常用的java.time 类:InstantZonedDateTime。该规范确实需要支持OffsetDateTime。所以我们转换。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

提交到数据库。

myPreparedStatement.setObject( … , odt ) ; 

检索。

OffsetDateTime odt = MyResultSet.getObject( … , OffsetDateTime.class ) ;

提取 Instant 以在您的代码中明确您需要 UTC。

Instant instant = odt.toInstant() ;

通过特定地区(时区)的人们使用的挂钟时间查看这一刻。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

【讨论】:

  • 嗨,Basil,谢谢您的回复,实际上我正在使用 Hibernate 来持久化和检索关于这种情况的数据,我可以在 pojo 类中为这个日期时间字段使用哪个类?
猜你喜欢
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 2014-08-09
  • 1970-01-01
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多