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

如何使用Jackson反序列化JSON日期字段为Date或Joda DateTime

问题说明

接口返回的JSON中包含如下格式的Joda Time序列化日期字段:

{
  "modifiedDate": {
    "dayOfWeek": 2,
    "dayOfYear": 172,
    "year": 2022,
    "dayOfMonth": 21,
    "era": 1,
    "monthOfYear": 6,
    "millisOfDay": 12144237,
    "hourOfDay": 3,
    "minuteOfHour": 22,
    "secondOfMinute": 24,
    "millisOfSecond": 237,
    "weekOfWeekyear": 25,
    "weekyear": 2022,
    "yearOfEra": 2022,
    "yearOfCentury": 22,
    "centuryOfEra": 20,
    "secondOfDay": 12144,
    "minuteOfDay": 202,
    "zone": {
      "fixed": true,
      "id": "Etc/UTC"
    },
    "chronology": {
      "zone": {
        "fixed": true,
        "id": "Etc/UTC"
      }
    },
    "millis": 1655781744237,
    "afterNow": false,
    "beforeNow": true,
    "equalNow": false
  }
}

需要将该字段解析为java.util.Date或JodaDateTime类型。自定义反序列化器无法通过Jackson完成映射,相同结构JSON使用Gson可正常解析。

原因说明

  • Gson默认按字段匹配策略做反序列化,只要JSON结构和目标类的可访问字段/构造参数匹配就能完成对象转换,因此可以直接识别该结构生成DateTime实例。
  • Jackson默认的日期反序列化逻辑仅支持时间戳、标准格式日期字符串的转换,不会自动将嵌套的日期属性对象映射为Date/DateTime实例;自定义反序列化器失效通常是因为没有正确读取JSON节点中的核心时间字段。

实现方案

方案1:使用官方适配模块(无自定义代码,推荐)

Joda Time官方提供了Jackson的适配扩展包,可直接识别该序列化结构,无需手写反序列化逻辑:

  1. 引入和项目Jackson版本一致的适配依赖
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>${jackson.version}</version>
</dependency>
  1. 为ObjectMapper注册Joda模块并关闭时间戳序列化配置
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JodaModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  1. 实体类直接声明对应字段类型即可完成解析
public class BizEntity {
    private DateTime modifiedDate;
    // 其余字段、getter/setter省略
}

需要java.util.Date类型时,直接调用解析得到的DateTime实例的toDate()方法即可转换。

方案2:手写自定义反序列化器

如果不希望引入额外依赖,可通过读取日期结构中millis字段存储的UTC毫秒时间戳实现反序列化,不需要解析所有日期属性字段。

  • 解析为java.util.Date的反序列化器实现
public class CustomDateDeserializer extends StdDeserializer<Date> {
    public CustomDateDeserializer() {
        super(Date.class);
    }

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode dateNode = p.getCodec().readTree(p);
        long utcMillis = dateNode.get("millis").asLong();
        return new Date(utcMillis);
    }
}
  • 解析为JodaDateTime的反序列化器实现
public class CustomDateTimeDeserializer extends StdDeserializer<DateTime> {
    public CustomDateTimeDeserializer() {
        super(DateTime.class);
    }

    @Override
    public DateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode dateNode = p.getCodec().readTree(p);
        long utcMillis = dateNode.get("millis").asLong();
        String zoneId = dateNode.get("zone").get("id").asText();
        return new DateTime(utcMillis, DateTimeZone.forID(zoneId));
    }
}

将实现好的反序列化器通过ObjectMapper全局注册,或在对应字段上添加@JsonDeserialize(using = 对应反序列化器类.class)注解即可生效。

注意:直接读取millis字段是最稳定的实现方式,该字段是Joda序列化时存储的核心时间戳,和其余日历字段完全对齐,不会出现时区或日期计算偏差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:09:10