spring.jackson.date-format仅对java.util.Date/Calendar生效,对java.time.*无效;需配JavaTimeModule、write-dates-as-timestamps=false,并用@JsonFormat/@DateTimeFormat区分序列化与反序列化。

spring.jackson.date-format 不生效的典型原因
这个配置项只在 Jackson 自动序列化/反序列化 java.util.Date 或 java.util.Calendar 时起作用,对 java.time.* 类型(如 LocalDateTime、ZonedDateTime)完全无效——这是最常踩的坑。
常见错误现象:spring.jackson.date-format=yyyy-MM-dd HH:mm:ss 配了,但返回的 JSON 里时间还是 ISO 8601 格式(如 "2024-05-20T14:30:00.000+0000"),或者直接报错 Cannot deserialize value of type `java.time.LocalDateTime`。
- 确认你用的是
java.time.LocalDateTime还是老式的Date:前者必须配JavaTimeModule,后者才走date-format -
spring.jackson.date-format必须搭配spring.jackson.serialization.write-dates-as-timestamps=false,否则时间会被转成毫秒数 - 如果用了 Lombok 的
@Data,确保没意外触发toString()或日志打印导致格式混淆
正确配置 java.time 类型的全局格式(Spring Boot 2.2+)
从 Spring Boot 2.2 开始,默认已注册 JavaTimeModule,但默认不启用自定义格式。你需要显式配置序列化行为,而不是只靠 date-format。
推荐做法是在 application.yml 中统一控制:
spring:
jackson:
serialization:
write-dates-as-timestamps: false
deserialization:
adjust-dates-to-context-time-zone: false
# 以下两项才是 java.time 的关键
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8注意:date-format 在这里只是给 JavaTimeModule 提供默认模板,实际生效依赖于字段类型和注解。比如 @JsonFormat(pattern = "yyyy-MM-dd") 会覆盖全局配置。
-
write-dates-as-timestamps: false是必须的,否则LocalDateTime会被当成时间戳序列化成数字 -
adjust-dates-to-context-time-zone: false避免 Jackson 把LocalDateTime强行转成系统时区(它本就不含时区) -
time-zone对ZonedDateTime和OffsetDateTime生效,对LocalDateTime无影响
@JsonFormat 和 @DateTimeFormat 的分工别搞混
@JsonFormat 管序列化(Java → JSON),@DateTimeFormat 管反序列化(JSON → Java),两者不互通,也不能互相替代。
典型误用:只在字段上加 @JsonFormat(pattern = "yyyy-MM-dd"),结果前端传过来的 "2024-05-20" 解析失败,报错 Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'。
- 入参解析失败?检查是否漏了
@DateTimeFormat(pattern = "yyyy-MM-dd")(用于@RequestParam或@ModelAttribute) - Controller 方法参数是
@RequestBody?那得靠@JsonFormat(Jackson 解析 JSON body) -
@JsonFormat在LocalDateTime字段上生效,但在String字段上无效——它只作用于 JSR-310 类型
时区处理的真实约束:LocalDateTime 没有时区,硬塞会出事
很多人想让所有 LocalDateTime 默认按东八区解释,于是配 time-zone: GMT+8,结果发现没用——因为 LocalDateTime 本身不带时区信息,Jackson 不会“脑补”时区。
真正需要时区语义的场景,应该用 ZonedDateTime 或 OffsetDateTime,并确保数据库字段类型支持(如 PostgreSQL 的 timestamptz)。
- 存时间点且要跨时区显示?用
ZonedDateTime+ 数据库timestamptz - 只存业务日期(如生日、报表截止日)?用
LocalDate,别强行加时区 - 前端传来带时区的时间字符串(如
"2024-05-20T14:30:00+08:00"),后端用OffsetDateTime接,别用LocalDateTime硬转
复杂点在于:同一个业务模型里混用 LocalDateTime 和 ZonedDateTime 很容易引发隐式转换错误,比如 MyBatis 自动映射时丢掉时区偏移。这种地方不写单元测试,上线后就靠日志猜。










