【问题标题】:Inconsistent behaviour of Jackson's JsonFormat for Old Date API and ZonedDateTimeJackson 的旧日期 API 和 ZonedDateTime 的 JsonFormat 行为不一致
【发布时间】:2020-07-17 18:42:52
【问题描述】:

我试图在我的 POJO 类中使用 Jackson 的 JsonFormat 注释将 ZonedDateTime 序列化到不同的时区。 (假设 ZonedDateTimeZone 中的时区是 ET,我想用 UTC 序列化它)

我的 POJO:

package com.example.demo;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;

import java.time.ZonedDateTime;

package com.example.demo;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;

import java.time.ZonedDateTime;

public class POJO {


    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", timezone = "UTC")
    private ZonedDateTime zonedDateTimeWithPatternAndTimeZoneInJsonFormat;

    @JsonFormat(timezone = "UTC")
    private ZonedDateTime zonedDateTimeWithTimeZoneInJsonFormat;

    private ZonedDateTime zonedDateTime;


    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", timezone = "UTC")
    private Date oldDateWithTimeZoneAndPatternInJsonFormat;

    @JsonFormat(timezone = "UTC")
    private Date oldDateWithTimeZoneInJsonFormat;

    private Date oldDate;

    //  getters and setters below


}




主要方法

package com.example.demo;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.time.*;
import java.util.TimeZone;

package com.example.demo;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

//@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) throws JsonProcessingException {

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.setTimeZone(TimeZone.getDefault());
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        LocalDateTime ldt = LocalDateTime.of(2020, Month.JUNE.getValue(), 12, 15, 0 , 0);
        ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.of("America/New_York"));
        Date oldDate = Date.from(zdt.toInstant());

        System.out.println("old Date with System's time zone" + oldDate);

        POJO pojo = new POJO();
        pojo.setOldDate(oldDate);
        pojo.setOldDateWithTimeZoneAndPatternInJsonFormat(oldDate);
        pojo.setOldDateWithTimeZoneInJsonFormat(oldDate);

        pojo.setZonedDateTimeWithPatternAndTimeZoneInJsonFormat(zdt);
        pojo.setZonedDateTimeWithTimeZoneInJsonFormat(zdt);
        pojo.setZonedDateTime(zdt);

        System.out.println(objectMapper.writeValueAsString(pojo));

    }


}

输出:

old Date with System's time zoneSat Jun 13 00:30:00 IST 2020

{
    "zonedDateTimeWithPatternAndTimeZoneInJsonFormat": "2020-06-12 19:00:00.000+0000",
    "zonedDateTimeWithTimeZoneInJsonFormat": "2020-06-12T15:00:00-04:00",
    "zonedDateTime": "2020-06-12T15:00:00-04:00",
    "oldDateWithTimeZoneAndPatternInJsonFormat": "2020-06-12 19:00:00.000+0000",
    "oldDateWithTimeZoneInJsonFormat": "2020-06-12T19:00:00.000+00:00",
    "oldDate": "2020-06-13T00:30:00.000+05:30"
}

正如您在输出中看到的那样,如果我只指定时区而不指定模式,则 oldDateWithTimeZone 在 UTC 时区中序列化,但对于 ZonedDateTime,仅指定时区不会在指定时区中序列化它。但如果你也指定模式,它会遵守指定的时区。

【问题讨论】:

  • @Miaden - 编辑了我的代码,由于对不同格式的误解,我尝试使用 pattern 属性使 zonedDateTime 和 oldDate 具有相同的格式。这样做时,我意识到,仅为 oldDate 指定时区会在指定的时区将其序列化,但对于 ZonedDateTime,它需要模式和时区。奇怪!

标签: java datetime serialization jackson zoneddatetime


【解决方案1】:

似乎这是 jackson-databind 中的一个问题。在https://github.com/FasterXML/jackson-databind/issues/2799 上报告了这个问题。

如问题的 cmets 部分所述,指定时区和模式,即 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSZ", timezone = "UTC") 可以按预期工作。我之前只尝试过时区。

【讨论】:

    【解决方案2】:

    @JsonFormat(timezone= "UTC") 在序列化日期时设置您的时区,而不是格式。 如果您想更改格式,我建议使用

    @JsonSerialize(using = CustomDateSerializer.class)
    

    实现CustomDateSerializer

    class CustomDateSerializer extends StdSerializer<ZonedDateTime> {
    
    
    public CustomDateSerializer(Class<ZonedDateTime> t) {
        super(t);
    }
    
    public CustomDateSerializer() {
        this(null);
    }
    
    @Override
    public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        LocalDateTime utc = LocalDateTime.ofInstant(value.toInstant(), ZoneId.of("UTC"));
        gen.writeString("##date format here##");
    }}
    

    【讨论】:

    • 我不好,我不想改变格式,我想在UTC时区序列化日期。
    • 头顶,但您可以先转换为 utc 时间,然后将其序列化。 (编辑实现)
    • @Miaden,是的,我可以这样做,但这里的用例是将实体类转换为不同的 DTO(它们中的大多数希望 Date 在不同的时区。)使用 JsonFormat 可以减少大量样板文件
    • 抱歉在指定用户时出现拼写错误。
    猜你喜欢
    • 2015-10-27
    • 2022-12-19
    • 2017-10-20
    • 2019-08-18
    • 2019-01-26
    • 2021-07-17
    • 2015-03-23
    • 2018-02-01
    • 1970-01-01
    相关资源
    最近更新 更多