在 Oracle 时间戳列中以 UTC 保存日期
Posted
技术标签:
【中文标题】在 Oracle 时间戳列中以 UTC 保存日期【英文标题】:Saving date in UTC in Oracle Timestamp column 【发布时间】:2020-01-14 19:50:54 【问题描述】:我需要在 TIMESTAMP WITH TIMEZONE 类型的 Oracle 列中保存当前 UTC 日期和时间。这是来自带有 JPA 和 Hibernate 的 Spring Boot 服务
我在我的应用程序 yml 中启用了以下功能
jpa:
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.Oracle12cDialect
jdbc:
time_zone: UTC
Entity 类字段看起来像
@Column(name = "last_user_edit_date", columnDefinition = "TIMESTAMP WITH TIME ZONE")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime lastUserEditDate;
在设置日期时我正在使用
obj.setLastUserEditDate(ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("UTC")));
以上对于实际日期值来说工作正常。唯一的问题是在数据库中它正在保存 UTC 时间,但提到 MST(我的本地时区)作为时区。例如,保存的值是
12-SEP-19 09.50.53.820000000 PM 美国/丹佛
这里的 9.50 PM 实际上是 UTC 时间,但时区是 AMERICA/DENVER。我想要的是
12-SEP-19 09.50.53.820000000 PM UTC
我怎样才能实现这个 Spring JPA 和 Java 8 类?
谢谢
【问题讨论】:
【参考方案1】:
LocalDateTime
是错误的类
LocalDateTime
类无法及时跟踪。我无法想象调用LocalDateTime.now()
有意义的场景。在使用类之前阅读 Javadoc。
跟踪片刻:Instant
、OffsetDateTime
、ZonedDateTime
要跟踪时刻,请使用 Instant
(始终采用 UTC)、OffsetDateTime
(与 UTC 有偏移的时刻)或 ZonedDateTime
(在特定区域看到的时刻)。
奇怪的是,JDBC 4.2 需要支持 OffsetDateTime
,但保留了最常见的两个类,Instant
和 ZonedDateTime
,可选。
因此,要捕获 UTC 中的当前时刻以进行 JDBC 工作:
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
或者更长的:
Instant instant = instant.now() ; // Capture current moment in UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
发送到数据库:
myPreparedStatement.setObject( … , odt ) ;
从数据库中检索:
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
JPA
我不使用JPA。但看起来这个问题已经涵盖了,JPA Storing OffsetDateTime with ZoneOffset。并看到这篇文章,What’s new in JPA 2.2 – Java 8 Date and Time Types。
其他时区和时差
唯一的问题是在数据库中它正在保存 UTC 时间但提到了 MST
This documentation for Oracle Database 似乎说 TIMESTAMP WITH TIME ZONE
类型确实记录了传入数据的时区或与 UTC 的偏移量。其他一些数据库,如 Postgres 将传入的值调整为 UTC(零时分秒的偏移量)。
要获取 UTC,如上所示检索 OffsetDateTime
,并调用 toInstant
方法以生成始终采用 UTC 的 Instant
对象。或者生成另一个OffsetDateTime
,肯定是UTC:
OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;
【讨论】:
以上是关于在 Oracle 时间戳列中以 UTC 保存日期的主要内容,如果未能解决你的问题,请参考以下文章