java - 在sql server中用UTC时间保存当前日期的问题
问题描述
我想在 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
在数据库中创建此列时使用了数据类型。
解决方案
类型错误
您为列使用了错误的数据类型。
类型datetime2
不能代表片刻。该类型仅存储日期和时间,但缺少时区或从 UTC 偏移的上下文。因此,如果您存储“2020 年 1 月 23 日中午”,我们无法知道您是指日本东京的中午、突尼斯突尼斯的中午,还是美国俄亥俄州托莱多的中午,三个不同的时刻相隔几个小时。这种错误类型类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE
。Java 中的等价类是LocalDateTime
.
如果您已经存储了数据,则需要重构您的数据库。基本上,添加一个正确类型的新列,为每一行复制数据,随时转换。当然,这仅在您知道每个保存的值中缺少的预期时区时才有效。
正确的类型
虽然我不使用 Microsoft SQL Server,但根据文档,您应该使用类型列datetimeoffset
来记录 moment。此类型将任何提交的值调整为 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类中的任何一个:Instant
和ZonedDateTime
. 该规范确实需要支持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 ) ;
推荐阅读
- java - 使用 privateKey 签署消息(椭圆 p256)
- azure-active-directory - .net core 2.0 Azure AD 登录失败:AADSTS70001:在目录“xxxx ....”中找不到标识符为“xxx ....”的应用程序
- linux - 在 shell 脚本中解析命令的输出
- regex - 正好匹配两个反斜杠
- c# - 如何对 .Include 进行单元测试以进行 Entity Framework 预加载
- html - 具有动态高度的垂直可滚动 div
- java - 如果 prod 配置文件不存在,Spring Boot 2 使用 dev 配置文件
- file - PowerShell移动具有文件夹结构的旧文件
- json - 通过json中的数组元素名称获取值
- teradata - Teradata.Net.Data.Provider 在 Pivotal Cloud Foundry (PCF) 环境中不支持