Spring接口如何将JSON中yyyyMMdd日期字符串转为OffsetDateTime
问题原因
- 默认反序列化得到1970年错误时间:未匹配到对应字符串解析规则时,Jackson会将纯数字格式的日期字符串尝试转换为时间戳数值,
20200716被当作自1970-01-01起的时间量计算,最终得到不符合预期的时间结果。 - 直接添加
@JsonFormat("yyyyMMdd")报错:OffsetDateTime类型解析必须包含时间、时区偏移字段信息,仅指定日期格式yyyyMMdd时,解析器缺失必要字段的赋值规则,无法完成转换。
解决方案
根据业务影响范围选择对应方案即可:
方案1:单字段自定义解析(推荐,无全局侵入)
仅对birthDate字段生效,不影响项目中其他OffsetDateTime字段的解析逻辑,最适配单字段特殊格式的场景。
- 修正字段注解,指定JSON字段名与自定义反序列化器:
public class UserRequest { // 其他字段... @JsonProperty("birth-date") @JsonDeserialize(using = YyyyMMddOffsetDateTimeDeserializer.class) private OffsetDateTime birthDate; // getter/setter... }
- 实现自定义反序列化器,解析时自动补全0点时间与UTC+0偏移量:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; public class YyyyMMddOffsetDateTimeDeserializer extends JsonDeserializer<OffsetDateTime> { private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd"); @Override public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { String dateValue = parser.getText().trim(); LocalDate parseDate = LocalDate.parse(dateValue, DATE_FORMAT); // 时间置为00:00:00,时区偏移置为UTC+0,符合预期格式 return parseDate.atStartOfDay().atOffset(ZoneOffset.UTC); } }
方案2:全局统一配置(适用于全项目统一格式场景)
如果项目中所有OffsetDateTime类型的入参都需要兼容yyyyMMdd格式的纯日期字符串,可直接配置Jackson全局规则,无需在每个字段上加注解。
import com.fasterxml.jackson.datatype.jsr310.deser.OffsetDateTimeDeserializer; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; @Configuration public class JacksonDateConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer offsetDateTimeCustomizer() { // 为缺失的时间、时区字段配置默认值 DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("yyyyMMdd") .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) .parseDefaulting(ChronoField.NANO_OF_SECOND, 0) .parseDefaulting(ChronoField.OFFSET_SECONDS, ZoneOffset.UTC.getTotalSeconds()) .toFormatter(); return builder -> builder.deserializerByType(OffsetDateTime.class, new OffsetDateTimeDeserializer(formatter)); } }
注意:Spring Boot 2.x及以上版本默认已集成
jackson-datatype-jsr310依赖,无需额外引入;如果是1.x版本需手动引入该依赖,并确保spring.jackson.serialization.write-dates-as-timestamps配置为false,避免日期被序列化为时间戳格式。
内容的提问来源于stack exchange,提问作者pixel
相关产品推荐
相关产品推荐

