ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LocalDateTime 和 MySQL 的时区恩怨:接口返回时间少了 8 小时,我排查了一下午

LocalDateTime 和 MySQL 的时区恩怨:接口返回时间少了 8 小时,我排查了一下午 导读接口返回的发布时间比数据库里少了 8 个小时前端一看2026-10-02 00:00变成了2026-10-01 16:00用户全在评论区问时间是不是错了。查了一下午LocalDateTime JDBC 时区 Jackson 序列化三层都有嫌疑。这篇把时区链路彻底理清楚。LocalDateTime 和 MySQL 的时区恩怨接口返回时间少了 8 小时我排查了一下午先说现象。职位列表接口数据库里create_time 2026-10-02 10:30:00接口返回给前端变成了2026-10-02 02:30:00少了 8 小时。更诡异的是有的环境多 8 小时有的环境正常同一套代码在不同服务器上表现还不一样。时间链路三层都要对齐一条时间从 MySQL 到前端要过四关任何一关的时区不一致就出 8 小时偏差MySQL 存储(无时区) → JDBC 连接(serverTimezone) → Jackson 序列化(时区) → 前端展示(本地时区)MySQL 的 DATETIME 是不带时区的存进去是什么就返回什么。偏差只可能出在 JDBC 和 Jackson 这两层。第一层JDBC url 必须配 serverTimezoneJDBC 连接 MySQL 8 不配serverTimezone直接报错The server time zone value CST is unrecognized or represents more than one time zone.配置正确的写法spring:datasource:url:jdbc:mysql://127.0.0.1:3306/qkl_boot?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseserverTimezoneAsia/Shanghai是关键。坑在这很多教程写serverTimezoneGMT%2B8也能跑但如果服务器系统时区是 UTCJDBC 拿到的时间会先按 UTC 解析再存取出来就偏 8 小时。第二层Jackson 序列化LocalDateTime 不配时区就乱Spring Boot 默认 Jackson 序列化LocalDateTime如果只配了格式没配时区序列化用的是 JVM 默认时区。看两种配置的区别spring:jackson:date-format:yyyy-MM-dd HH:mm:sstime-zone:Asia/Shanghai# 必须显式配时区我遇到的不同环境表现不一致就是因为 A 服务器系统时区是 CST、B 服务器是 UTCJackson 跟着 JVM 走A 正常 B 偏 8 小时。time-zone: Asia/Shanghai显式写死跟服务器系统时区解耦。Java 侧更稳的写法是自定义序列化器全局统一ConfigurationpublicclassJacksonConfig{BeanpublicJackson2ObjectMapperBuilderCustomizercustomizer(){returnbuilder-{DateTimeFormatterfmtDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);builder.serializers(newLocalDateTimeSerializer(fmt));builder.deserializers(newLocalDateTimeDeserializer(fmt));};}}踩坑一数据库时间比接口多 8 小时方向反了现象另一个环境接口返回的时间比数据库多 8 小时。排查过程多 8 小时说明序列化层把时间当 UTC 输出前端按本地时区东八区解析加回了 8 小时。查spring.jackson.time-zone根本没配——上一任开发只配了date-format。定位思路date-format只控制格式时区是独立配置项两个都要配。最终解决配置补上time-zone: Asia/Shanghai同时把项目里散落的SimpleDateFormat全部替换成LocalDateTime 统一序列化器双保险。踩坑二前端正常其实是个坑时间被转成 UTC 字符串现象前端 React 项目用new Date(str)解析接口时间部分浏览器显示正常部分偏 8 小时。排查过程接口返回2026-10-02 10:30:00无时区后缀new Date(2026-10-02 10:30:00)按本地时区解析正常但如果后端序列化输出带Z或TISO 格式new Date()会按 UTC 解析直接偏 8 小时。定位思路前后端时间字符串的语义要约定清楚——接口统一返回无时区的yyyy-MM-dd HH:mm:ss前端一律按本地时区解析别混用 ISO 格式。最终解决后端统一yyyy-MM-dd HH:mm:ss输出不带 Z/T前端解析加时区后缀统一处理。契约定死两端都不许自行发挥。踩坑三MySQL 连接池复用导致首次连接正常、后续偏差现象应用重启后第一次查询时间正常过一会儿全部偏 8 小时。排查过程HikariCP 连接池里老连接是旧的 serverTimezone 建立的新配置只对新连接生效。重启后连接池预热新旧连接混用表现不一致。定位思路时区问题要重启后观察完整周期别只看刚启动的第一次查询。最终解决连接池initializationFailTimeout控制校验配置统一后滚动重启全部实例避免新旧连接混跑。可直接复用的要点MySQL DATETIME 无时区偏差只可能来自 JDBC / Jackson / 前端解析三层。JDBC url 写死serverTimezoneAsia/Shanghai别用GMT%2B8会跟系统时区打架。Jackson 必须同时配date-format和time-zone: Asia/Shanghai只配格式不配时区照样偏。Java 侧统一LocalDateTime 自定义序列化器替换所有SimpleDateFormat。前后端时间契约定死接口返回无时区yyyy-MM-dd HH:mm:ss前端按本地时区解析。排查时区问题要重启后观察完整周期注意连接池新旧连接混用。
返回列表