使用Jackson将Java8 LocalDateTime序列化为UTC时间戳

使用Jackson将Java8 LocalDateTime序列化为UTC时间戳,java,datetime,java-8,jackson,java-time,Java,Datetime,Java 8,Jackson,Java Time,我刚刚根据新的(ish)Java8时间包将我的许多日期转换为LocalDateTime。到目前为止,我一直很喜欢这种转换,直到我开始尝试序列化和反序列化 我如何配置Jackson以支持它们 LocalDateTime--序列化-->UTC时间戳--反序列化-->LocalDateTime 这里有大量关于转换为格式化字符串的资料,但我似乎找不到utc时间戳的现成解决方案。您可以为LocalDateTime自定义序列化程序和反序列化程序,用于exmaple: CustomLocalDateTimeS

我刚刚根据新的(ish)Java8时间包将我的许多日期转换为LocalDateTime。到目前为止,我一直很喜欢这种转换,直到我开始尝试序列化和反序列化

我如何配置Jackson以支持它们

LocalDateTime--序列化-->UTC时间戳--反序列化-->LocalDateTime


这里有大量关于转换为格式化字符串的资料,但我似乎找不到utc时间戳的现成解决方案。

您可以为
LocalDateTime
自定义序列化程序和反序列化程序,用于exmaple:

CustomLocalDateTimeSerializer

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;

public class CustomLocalDateTimeSerializer extends StdSerializer<LocalDateTime> {

    protected CustomLocalDateTimeSerializer(Class<LocalDateTime> t) {
        super(t);
    }

    protected CustomLocalDateTimeSerializer() {
        this(null);
    }

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider sp)
            throws IOException {
        Long epoch = value.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
        gen.writeString(epoch.toString());
    }
}

不必手动重写所有内容,您可以利用:


以下是如何简单有效地完成这项工作:

@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="EEE MMM dd HH:mm:ss Z yyyy")
@JsonProperty("created_at") 
ZonedDateTime created_at;

这是一个问题的引语:,因此这可能是一个重复的问题

以下解决方案解决了将
LocalDateTime
序列化/反序列化为时间戳的任务,并且至少与spring boot v1.5相关,还包括@xingbin未考虑的下一点:

  • 如果需要与java.util.Date具有相同的行为,则必须使用
    toInstant().toEpochMilli()
    而不是
    toInstant().getEpochSecond()
  • 检查要反序列化的值
    null
  • 和可选点:为Jackson
    ObjectMapper
时间戳序列化程序类:

public class LocalDateTimeSerializer extends StdSerializer<LocalDateTime> {
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");

    public LocalDateTimeSerializer() {
        super(LocalDateTime.class);

    }

    @Override
    public void serialize(final LocalDateTime value,
                          final JsonGenerator generator,
                          final SerializerProvider provider) throws IOException {
        if (value != null) {
            final long mills = value.atZone(DEFAULT_ZONE_ID).toInstant().toEpochMilli();
            generator.writeNumber(mills);
        } else {
            generator.writeNull();
        }
    }
}
public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");

    public LocalDateTimeDeserializer() {
        super(LocalDateTime.class);
    }

    @Override
    public LocalDateTime deserialize(final JsonParser parser,
                                     final DeserializationContext context) throws IOException {
        final long value = parser.getValueAsLong();
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(value), DEFAULT_ZONE_ID);
    }
}

这应该会有帮助:如果是UTC时间戳,为什么不使用
Instant
而不是
LocalDateTime
?@assylias,信不信由你,这是行不通的:写日期,因为时间戳适用于日期。当为LocalDateTimes启用时,Jackson将其序列化为一个值数组。@ernest_k,我想使用LocalDateTime还有其他原因。但是,第三方API希望将其格式化为时间戳整数,因此我需要将其转换为与他们的系统交互。@DanielPatrick如果您注册一个
新的JavaTimeModule()
,它应该可以工作-请看这里:这可以工作。。。非常感谢。不敢相信Jackson没有允许LocalDateTime序列化与旧日期序列化兼容的配置。@DanielPatrick我不确定这是否是最合适的方法,这只是一种可行的方法。链接中有一个解释。根据我对这个问题的理解,链接中的解释似乎解释了为什么这不适用于
LocalDateTime
,因此针对这个问题
@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="EEE MMM dd HH:mm:ss Z yyyy")
@JsonProperty("created_at") 
ZonedDateTime created_at;
public class LocalDateTimeSerializer extends StdSerializer<LocalDateTime> {
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");

    public LocalDateTimeSerializer() {
        super(LocalDateTime.class);

    }

    @Override
    public void serialize(final LocalDateTime value,
                          final JsonGenerator generator,
                          final SerializerProvider provider) throws IOException {
        if (value != null) {
            final long mills = value.atZone(DEFAULT_ZONE_ID).toInstant().toEpochMilli();
            generator.writeNumber(mills);
        } else {
            generator.writeNull();
        }
    }
}
public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");

    public LocalDateTimeDeserializer() {
        super(LocalDateTime.class);
    }

    @Override
    public LocalDateTime deserialize(final JsonParser parser,
                                     final DeserializationContext context) throws IOException {
        final long value = parser.getValueAsLong();
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(value), DEFAULT_ZONE_ID);
    }
}
@Configuration
public class ObjectMapperConfiguration {
    @Bean
    public ObjectMapper objectMapper() {
        final ObjectMapper objectMapper = new ObjectMapper();
        final SimpleModule module = new SimpleModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        objectMapper.registerModule(module);
        return objectMapper;
    }
}