如何解决ZonedDateTime 到 MySql -- 错误的偏移量?
设置:Spring Boot '2.4.1' 应用程序,(休眠 5.4.25),Java 11
问题 如何使用 java.time* 保存日期(德国时间),以便运行时 = db
问题:
调试期间: zoneddatetime = 2021-05-03 16:11:42.021236
在数据库中: 日期时间(6) 2021-05-03 14:11:42.021236
@Entity
public class User {
private zoneddatetime createdAt;
//getter&setter
//calling the setter like like:
user.setCreatedAt(zoneddatetime.Now(ZoneId.of("Europe/Berlin")))
//saving via JPARepo...
Repository.save(user);
application.properties:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MysqL57Dialect
#tried but no effect
hibernate.jdbc.time_zone=CET
#tried but no effect
hibernate.jdbc.time_zone=UTC
毕业
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'MysqL:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
解决方法
我既不使用 Spring 也不使用 Hibernate,所以我无法专门提供帮助。并且您省略了关键细节,例如数据库列的确切数据类型,因此无法提供具体答案。但我可以给你一些一般性的建议。
使用 OffsetDateTime
和 ZoneOffset.UTC
在 JDBC 中交流时刻
关于 ZonedDateTime
,要知道 JDBC 4.2 spec 需要支持 OffsetDateTime
。奇怪的是,规范省略了对更常用的 Instant
和 ZonedDateTime
类的支持。 Java 团队的这种设计选择让我感到困惑,尤其是在 Instant
方面,它来回转换非常简单。
➥ 无论如何,请专注于使用 OffsetDateTime
进行 JDBC 工作。
通常最好在 UTC 中完成所有业务逻辑、数据交换、数据存储、日志记录和调试。也就是说,与 UTC 的零时分秒偏移量,并且没有时区。仅在业务规则要求或用户对演示文稿的期望时使用时区。
在UTC 中看到的时刻的基本类是Instant
。通常,这应该是您的班级成员字段的类型,用于跟踪某个时刻、时间轴上的特定点。
使用 Instant.now
捕捉当前时刻。记录何时创建“用户”对象:
Instant userCreated = Instant.now() ;
要在数据库中记录片刻,您的列的类型必须类似于 SQL 标准 TIMESTAMP WITH TIME ZONE
。在 MySQL 8 中,这意味着 TIMESTAMP
,not DATETIME
。见the documentation。
要将 Instant
对象的值写入数据库,您的 JDBC 驱动程序可能能够处理 Instant
对象,尽管在 JDBC 规范中是可选的。如果没有,或者如果您想编写更可移植的代码,convert to OffsetDateTime
。指定 ZoneOffset.UTC
的常量以获取零时-分-秒的偏移量。
OffsetDateTime odt = userCreated.atOffset( ZoneOffset.UTC ) ;
将该对象传递给准备好的语句。
myPreparedStatement.setObject( …,odt ) ;
检索。
OffsetDateTime odt = myResultSet.getObject( …,OffsetDateTime.class ) ;
轻松转换回简单的 Instant
。
Instant instant = odt.toInstant() ;
要适应德国时间,请应用 ZoneId
以获得 ZonedDateTime
。
ZoneId z = ZoneId.of( "Europe/Berlin" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
了解 MySQL 以 UTC 存储所有 TIMESTAMP
值,只有 UTC。不幸的是,一些中间件和工具可能会选择对您从数据库中检索到的值进行时区调整。使用上面的代码,相信你不会有这个问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。