java.time.Instant.now has more precision in java 11 compared to java 8 and how to get backward compatible

436 Views Asked by At

I've below code in java

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.Instant;

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        Instant instant = Instant.now();
        System.out.println("java version " + System.getProperty("java.version"));
        System.out.println("java vendor " + System.getProperty("java.vendor"));
//        System.out.println(instant.truncatedTo(ChronoUnit.MILLIS));
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JodaModule());
        mapper.registerModule(new JavaTimeModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        System.out.println(mapper.writeValueAsString(instant));
    }

}

when I run with java 8 I get below output -

java version 1.8.0_352
java vendor Azul Systems, Inc.
2023-07-15T07:27:49.588Z

when I run with java 11 I get below output -

java version 11.0.17
java vendor Azul Systems, Inc.
2023-07-15T07:08:15.457153Z

It is clearly java 11 has more precision than java 8 and it is causing schema change in the middleware downstream.

Is there any way to make this api call backward compatible?

1

There are 1 best solutions below

0
Sweeper On

If you just want a String with 3 digits of fractional seconds, you can make your own DateTimeFormatter and format the Instant with that:

// note that there are only 3 "S"
var formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS'Z'")
    .withZone(ZoneOffset.UTC);
System.out.println(formatter.format(Instant.now()));

This will always produce 3 digits after the decimal dot, even if they are all 0.

If you actually want an Instant that is rounded to the nearest millisecond, use truncatedTo:

System.out.println(Instant.now().truncatedTo(ChronoUnit.MILLIS));

Instant.toString will use at most 3 decimal places for such Instants. Instant.toString uses the ISO_INSTANT formatter.