Search code examples
javadatetimeserializationjacksonzoneddatetime

Inconsistent behaviour of Jackson's JsonFormat for Old Date API and ZonedDateTime


I was trying to use Jackson's JsonFormat annotation in my POJO class to serialize the ZonedDateTime into a different timezone. (Say the timezone in ZonedDateTimeZone is ET, I want to serialize it in UTC)

My 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


}




Main Method

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));

    }


}

Output:

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"
}

As you can see in output, if i only specify timezone and not pattern, the oldDateWithTimeZone is serialized in UTC timezone but for ZonedDateTime only specifying timezone doesn't serialize it in specified timezone. But if you specify pattern as well, It respects the specified timezone.


Solution

  • Seems like it's an issue in jackson-databind. Reported the issue on https://github.com/FasterXML/jackson-databind/issues/2799 .

    As mentioned in question's comments section, Specifying timezone along with pattern, i.e. @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSZ", timezone = "UTC") works as expected. I earlier tried just with timezone.