我尝试插入一条记录。当服务器的时区大于数据库设置的时区时,我发现了一个问题。时间戳将自动转换该字段中的数据。如图所示,我在11-10 00:51 As插入此记录,服务器时区为+8
但反过来,当服务器的时区小于数据库设置的时区时,它不会进行转换
我在11-09 21:56 is插入此记录,服务器时区为+5
我使用java进行测试,orm框架是jpa,我使用jdbc连接mysql。
有人能告诉我为什么吗?
发布于 2021-11-09 21:33:29
tl;dr
myPreparedStatement.setObject(
… ,
ZonedDateTime
.of(
LocalDate.of( 2021 , Month.NOVEMBER , 10 ) ,
LocalTime.of( 0 , 51 ) ,
ZoneId.of( "Australia/Perth" )
) // Returns a `ZonedDateTime` object.
.toOffsetDateTime() // Returns a `OffsetDateTime` object.
)
…和…
myResultSet.getObject(
… ,
OffsetDateTime.class
) // Returns a `OffsetDateTime` object.
.atZoneSameInstant(
ZoneId.of( "Australia/Perth" )
) // Returns a `ZonedDateTime` object.
详细信息
不要相信您的工具会报告检索到的真值。某些工具具有在从数据库检索日期-时间值后应用时区的反功能。用意是好的,但却非常令人困惑。
MySQL 8中的TIMESTAMP
列始终存储调整为协调世界时的值。这意味着在UTC子午线之前或之后零小时-分钟-秒的偏移量。每个the docs
MySQL将时间戳值从当前时区转换为协调时区进行存储,并从协调时区转换回当前时区以进行检索。
Always 指定所需的 或offset-from-UTC。不要在Java、数据库连接或数据库服务器中隐式依赖默认时区。
ZoneId z = ZoneId.of( "Asia/Hong_Kong" ) ;
始终使用java.time类。切勿使用旧的Date
**,Calendar
,** SimpleDateFormat
类。
LocalDate ld = LocalDate.of( 2021 , Month.NOVEMBER , 10 ) ;
LocalTime lt = LocalTime.of( 0 , 51 ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
要发送到数据库,请通过OffsetDateTime
类将时区转换为纯粹的偏移量,以与SQL兼容。
OffsetDateTime odt = zdt.toOffsetDateTime() ;
如果要查看最终将存储在数据库中的值,请将偏移量调整为零。
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ;
发送到数据库。
myPreparedStatement.setObject( … , odt ) ;
从数据库中检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
调整为时区。
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ; // Same moment but viewed through the wall-clock time of a particular time zone.
您提到使用JPA (现在称为)。JPA的最新版本完全支持java.time类。提示:要试验和了解这一切是如何工作的,请跳过JPA并进行一些直接的JDBC调用作为练习。
所有这些都已经在Stack Overflow上被多次介绍过了。搜索以了解更多信息。
发布于 2021-11-09 17:04:42
您的MySQL服务器上的time_zone参数如何?您可以使用以下查询进行检查:
SELECT @@time_zone
https://stackoverflow.com/questions/69902146
复制相似问题