You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jackson无法正确序列化/反序列化ZonedDateTime问题

解决ZonedDateTime序列化反序列化时区不一致问题

你的测试用例中,ZonedDateTime序列化后反序列化时丢失了原有时区信息,被转换为UTC时区,导致断言失败。这是因为默认JavaTimeModule处理日期字符串时,未明确保留时区标识的解析规则,且默认会自动调整时区到UTC。

解决方案

关键配置要点

  1. 禁用Jackson自动调整时区的特性
  2. 为ZonedDateTime指定包含时区信息的序列化/反序列化格式

代码实现

方式一:自定义JavaTimeModule并配置格式化器

// 创建JavaTime模块并配置ZonedDateTime的序列化反序列化规则
JavaTimeModule javaTimeModule = new JavaTimeModule();
DateTimeFormatter zonedFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX['['VV']']");
javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(zonedFormatter));
javaTimeModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer(zonedFormatter));

ObjectMapper mapper = new ObjectMapper()
        .enable(MapperFeature.DEFAULT_VIEW_INCLUSION)
        .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
        .registerModule(javaTimeModule)
        // 核心:禁止自动将日期转换为ObjectMapper默认时区
        .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

// 测试代码
ZonedDateTime dateTime = ZonedDateTime.now();
String json = mapper.writeValueAsString(dateTime);
LOGGER.info("ZonedDateTime json: " + json);

ZonedDateTime dateTime2 = mapper.readValue(json, ZonedDateTime.class);
assertEquals(dateTime, dateTime2);

方式二:通过Mixin简化配置

如果不想直接修改模块的序列化器,可以用Mixin类指定规则:

// 定义Mixin类
abstract class ZonedDateTimeMixin {
    @JsonSerialize(using = ZonedDateTimeSerializer.class)
    @JsonDeserialize(using = ZonedDateTimeDeserializer.class)
    private ZonedDateTime zonedDateTime;

    public ZonedDateTimeMixin(
            @JsonProperty("value") String value,
            @JsonProperty("offset") ZoneOffset offset,
            @JsonProperty("zone") ZoneId zone) {}
}

// 配置ObjectMapper
ObjectMapper mapper = new ObjectMapper()
        .enable(MapperFeature.DEFAULT_VIEW_INCLUSION)
        .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
        .registerModule(new JavaTimeModule())
        .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
        .addMixIn(ZonedDateTime.class, ZonedDateTimeMixin.class);

// 测试代码同上

原问题原因

你原代码中调用了findAndRegisterModules(),虽然能注册JavaTimeModule,但默认的ZonedDateTime反序列化逻辑会将带时区的字符串先解析为Instant,再转换为UTC时区的ZonedDateTime,同时Jackson默认开启ADJUST_DATES_TO_CONTEXT_TIME_ZONE,会自动把日期调整为ObjectMapper的默认时区(UTC),最终导致原有时区丢失。

内容的提问来源于stack exchange,提问作者zjffdu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 17:35:13