Ranjit Meher
Ranjit Meher

Reputation: 41

Ending 0's are getting truncated from millisecond part of ZonedDateTime object in Java11

I am upgrading my spring boot application to spring boot 2.7.8 and Java 11. I getting different rest response of ZonedDateTime object after upgrade.

My request contain "2023-06-23T18:13:06.630Z[UTC]", and I am returning same request object as a Map key in response. But in response ending 0's from millisecond part getting trimmed "2023-06-23T18:13:06.63Z[UTC]".

Request:
{
    "dateList": [
       "2023-06-23T18:13:06.630Z[UTC]"
    ]
}

Response:
{
    "dateList": {
        "2023-06-23T18:13:06.63Z[UTC]": "2023-06-23T11:13:06.630-07:00"
    }
}

Did someone faced earlier this issue?

Any solution to this issue, As I am using as Map key of ZonedDateTime, I need to keep it consistent.

Upvotes: 1

Views: 869

Answers (1)

Soheil Babadi
Soheil Babadi

Reputation: 669

This is a known issue with Jackson that affects the serialization of ZonedDateTime objects.

This issue is caused by the fact that Jackson by default uses Java's built-in DateTimeFormatter to serialize and deserialize dates and times, so this format does not preserve trailing zeros in milliseconds.

To fix this issue, you can configure Jackson to use a custom date/time format that preserves trailing zeros in milliseconds

I tried this and by creating a custome config for jackson:

@Configuration
public class JacksonConfig {

    @Value("${spring.jackson.date-format}")
    private String dateFormat;

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
        return builder -> {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
            builder.simpleDateFormat(dateFormat).serializers(new ZonedDateTimeSerializer(formatter));
            builder.deserializers(new ZonedDateTimeDeserializer(formatter));
        };
    }

    public static class ZonedDateTimeSerializer extends StdSerializer<ZonedDateTime> {

        private final DateTimeFormatter formatter;

        public ZonedDateTimeSerializer(DateTimeFormatter formatter) {
            super(ZonedDateTime.class);
            this.formatter = formatter;
        }

        @Override
        public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(formatter.format(value));
        }
    }

    public static class ZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {

        private final DateTimeFormatter formatter;

        public ZonedDateTimeDeserializer(DateTimeFormatter formatter) {
            super(ZonedDateTime.class);
            this.formatter = formatter;
        }

        @Override
        public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String value = p.getValueAsString();
            return ZonedDateTime.parse(value, formatter);
        }
    }
}

P.S :Also you can use this formatter to format your ZonedDateTime objects before adding them to the map:

ZonedDateTime zdt = ZonedDateTime.parse("2023-06-23T18:13:06.630Z[UTC]");
String formatted = zdt.format(formatter);

Map<String, String> response = new HashMap<>();
response.put(formatted, zdt.toString());

Upvotes: 1

Related Questions