Jackson用ISO.DATE_TIME序列化OffsetDateTime时零毫秒丢失问题
原因说明
该现象的核心来自两个认知偏差:
- 注解作用域匹配错误:
@org.springframework.format.annotation.DateTimeFormat是Spring框架用于Web请求参数绑定(处理@RequestParam、@PathVariable、表单提交参数转换)的注解,Jackson做JSON序列化时完全不会读取这个注解的配置。你看到的Javadoc里标注的yyyy-MM-dd'T'HH:mm:ss.SSSXXX格式和示例,只对Spring的参数绑定逻辑生效,和JSON序列化流程无关。 - Jackson默认序列化规则本身就会省略零值小数秒:Spring Boot默认引入的
jackson-datatype-jsr310模块提供的OffsetDateTime序列化器,默认采用「按需输出小数秒」的逻辑:- 时间的纳秒值非0时,自动输出对应精度的小数秒,自动截断尾部连续的0,比如1毫秒对应输出
.001,230毫秒对应输出.23 - 时间的纳秒值为0时,直接省略整个小数秒段,因此你传入0毫秒的时间会被序列化为
2000-10-10T10:10:10Z。
- 时间的纳秒值非0时,自动输出对应精度的小数秒,自动截断尾部连续的0,比如1毫秒对应输出
这个默认输出本身是符合ISO-8601规范的——ISO-8601允许省略尾部全为0的小数秒部分,只是和你预期的固定保留3位毫秒的输出格式不一致。
修复方法
根据你需要生效的范围二选一即可:
- 全局生效:调整Spring Boot中Jackson的序列化配置,强制所有
OffsetDateTime序列化时固定输出3位毫秒。
如果用配置文件方式,直接在application.yml添加如下配置:
如果需要更精准的控制,也可以通过配置类注册自定义的序列化器:spring: jackson: date-format: yyyy-MM-dd'T'HH:mm:ss.SSSXXX serialization: write-dates-as-timestamps: false@Bean public Jackson2ObjectMapperBuilderCustomizer jacksonOffsetDateTimeCustomizer() { DateTimeFormatter offsetFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); return builder -> { builder.serializers(new OffsetDateTimeSerializer(OffsetDateTimeSerializer.INSTANCE, false, offsetFormatter)); builder.deserializers(new OffsetDateTimeDeserializer(offsetFormatter)); }; } - 单字段生效:如果只需要调整
validTo字段的序列化格式,直接在字段上加Jackson识别的@JsonFormat注解即可,原来的@DateTimeFormat如果需要做参数绑定可以保留,两者互不冲突:@JsonProperty("validTo") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") @org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME) private OffsetDateTime validTo;
配置完成后,0毫秒的时间值就会按照预期序列化为2000-10-10T10:10:10.000Z,非零毫秒值也会正常保留3位精度。
内容的提问来源于stack exchange,提问作者warozell
相关产品推荐
相关产品推荐

