将毫秒时间戳反序列化为 java.time.Instant

Posted

技术标签:

【中文标题】将毫秒时间戳反序列化为 java.time.Instant【英文标题】:Deserialize millisecond timestamp to java.time.Instant 【发布时间】:2018-01-27 12:09:39 【问题描述】:

我正在尝试使用 Jackson 读取 JSON 文件并将其中一个字段存储为一个纪元毫秒作为 Java Instant,但是反序列化的行为不符合预期。

这是我在尝试读取时间戳时看到的:

1503115200000

Jackson 将 Instant 字段设置为 +49601-10-28T16:00:00Z

这似乎是因为 Jackson 的默认设置是使用 Instant.ofEpochSecond(Long l) 而不是 Instant.ofEpochMilli(Long l) 读取时间戳。

有没有办法将 Jackson ObjectMapper 设置为使用 ofEpochMilli 方法?这就是我目前的ObjectMapper

ObjectMapper om = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setSerializationInclusion(Include.NON_NULL);

注意

如果我将输入 JSON 更改为 ISO 日期,例如 2017-08-19T04:00:00Z 或纪元秒,例如 1503115200Instant 字段能够正确设置。

不幸的是,JSON 输入必须是纪元毫秒,例如1503115200000

【问题讨论】:

【参考方案1】:

如果您不想编辑或创建对象映射器,更灵活的解决方案可能是编写自己的转换器类。

public class LongToInstantConverter extends StdConverter<Long, Instant> 
    public Instant convert(final Long value) 
        return Instant.ofEpochMilli(value);
    

你只需要在你的类中添加注解

@JsonDeserialize(converter = LongToInstantConverter.class)
private Instant sentDate;

【讨论】:

【参考方案2】:

对于那些使用 Spring Boot 并在 rest 请求反序列化期间遇到此问题的用户 - 在 application.properties 中提供此问题:

spring.jackson.deserialization.read-date-timestamps-as-nanoseconds=false

@JB Nizet 的答案是正确的,但由于 Spring Boot 内部有自己的 ObjectMapper - 您需要在属性中配置此值。

【讨论】:

【参考方案3】:

来自https://github.com/FasterXML/jackson-modules-java8/blob/master/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.java:

如果启用了 @code READ_DATE_TIMESTAMPS_AS_NANOSECONDS(默认情况下),则比较模糊的整数类型会读取为不带小数点的小数秒,否则读取为毫秒。

因此您需要禁用 READ_DATE_TIMESTAMPS_AS_NANOSECONDS。

【讨论】:

【参考方案4】:

解决方案是将.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false) 添加到 ObjectMapper。完整的 ObjectMapper 看起来像:

ObjectMapper om = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .setSerializationInclusion(Include.NON_NULL);

【讨论】:

以上是关于将毫秒时间戳反序列化为 java.time.Instant的主要内容,如果未能解决你的问题,请参考以下文章

将时间序列的时间精度降低到毫秒

将 Python namedtuple 序列化为 json

如何将对象序列化为字符串

将枚举成员序列化为 JSON

将 Python 字典序列化为 XML [关闭]

Symfony 序列化器:将 Json 反序列化为实体