在服务过程中,在我的情况下,在使用Java 8的Spring Boot API中,在将LocaDateTime写入数据库的过程中,在数据库侧保存配置为TIMESTAMP的属性,在API中保存配置为LocaDateTime的属性时,该日期是保存时间比当前操作系统日期晚3个小时。
假设我尝试在上午10点准确地执行此操作,保存到数据库的日期应该是11个小时,但就我而言,它不能以这种方式工作...
private LocalDateTime dataLimite;
@PrePersist
public void prepareToSave() {
String str = "1986-04-08 10:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
this.dataLimite = dateTime.plusHours(1);
}
显然应该指出,这是Mysql配置方面的问题,但是当我测试...
SELECT NOW();
结果恰好是操作系统的日期和时间,那么到底发生了什么真正的问题?如何解决此问题?
答案 0 :(得分:1)
LocalDateTime
仔细阅读文档。
此类不存储也不表示时区。相反,它是对用于生日的日期的描述,以及在墙上时钟上看到的本地时间。如果没有其他信息(例如偏移量或时区),则无法在时间轴上表示时刻。
Java中的LocalDateTime
类不能用于表示时刻。它代表了大约26-27小时(全球时区范围)内的潜在时刻。
此类包含日期和时间,但故意缺少时区或UTC偏移量的任何概念。因此,例如,如果您存储例如今年1月23日中午,那么我们就不知道您是否要在东京,加尔各答,巴黎或蒙特利尔中午……所有不同的时刻,相隔数小时,发生在东部的较早时间,以及稍后发生的西方。
所以您使用的是错误的类。请暂时使用Instant
,OffsetDateTime
或ZonedDateTime
。
TIMESTAMP
更仔细地阅读文档。
MySQL 8中的TIMESTAMP
类型类似于SQL标准类型TIMESTAMP WITH TIME ZONE
。此类型表示时刻,即时间轴上的特定点。
将提交到数据库的时刻调整为UTC的文档explains已存储。
MySQL将
TIMESTAMP
值从当前时区转换为UTC进行存储,然后从UTC返回当前时区进行检索。
这说明了您的问题。您隐式依赖当前的默认时区来分配给Java中缺少任何时区的错误类型的对象。 切勿编写依赖于服务器当前默认时区(或语言环境)的代码,因为这超出了程序员的控制范围。相反,请始终明确指定所需/期望的时区。或者更好,只要有可能就在UTC中工作。
为获得最佳结果,与数据库交换值时请坚持使用UTC。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
要查看特定地区人民使用的挂钟时间的那一刻,请应用ZoneId
以获得ZonedDateTime
。
ZoneId z = ZoneId.of( "Australia/Sydney" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;