Spring JPA REST接口返回MariaDB DATETIME列时间偏移7小时问题
这个时间差问题核心是时区处理不一致,拆解来看:
数据库侧特性
MariaDB的DATETIME类型是无时区存储的,它只保存插入时的「本地时间字符串」(比如数据库服务器时区为西七区时,插入的12:34:56就是西七区的时间)。MySQL Workbench连接数据库时,会用数据库服务器的时区显示这个值,所以你看到的是2022-07-17 12:34:56。JPA与Java类型转换
你用的java.util.Date本质是UTC时间戳(记录从1970-01-01 UTC开始的毫秒数)。Hibernate读取DATETIME列时,会默认把数据库里的时间当作JVM所在时区的时间,转换成对应的UTC时间戳。如果你的JVM时区是UTC,那西七区的12:34:56转成UTC就是19:34:56,这就是时间戳的实际值。JSON序列化时区输出
Spring默认用Jackson序列化java.util.Date时,会把这个UTC时间戳转换成UTC时区的ISO格式字符串,也就是你看到的"2022-07-17T19:34:56.000+00:00"。
解决办法
1. 统一全链路时区(推荐)
让数据库服务器、JVM、Jackson序列化都使用同一个时区,比如和数据库服务器一致的时区:
- 在Spring Boot的
application.properties中添加:# 让Hibernate用指定时区解析数据库时间 hibernate.jdbc.time_zone=America/Los_Angeles # 让Jackson序列化时用指定时区输出 spring.jackson.time-zone=America/Los_Angeles - 同时确保JVM启动时区一致(可加启动参数
-Duser.timezone=America/Los_Angeles)
2. 改用Java 8+时间API(更规范)
抛弃容易混淆的java.util.Date,用LocalDateTime对应数据库的DATETIME(无时区匹配),实体类修改后不需要@Temporal注解:
@Entity() @Table(name="Thing") @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Thing { ... @Column(name="my_date", nullable = false) private LocalDateTime myDate; ... }
LocalDateTime直接对应数据库的无时区时间,序列化后会输出和数据库一致的时间字符串(配合Jackson时区配置可控制输出格式)。
3. 仅调整JSON输出时区
如果只想让接口返回的时间和数据库显示一致,只需要配置Jackson的序列化时区:
spring.jackson.time-zone=America/Los_Angeles
这样Jackson会把UTC时间戳转换成指定时区的时间输出,和数据库显示的12:34:56对应。
内容的提问来源于stack exchange,提问作者Woodchuck

