Search code examples
javaprecisionjava-timeplatform

LocalDateTime.now() has different levels of precision on Windows and Mac machine


When creating a new LocalDateTime using LocalDateTime.now() on my Mac and Windows machine i get a nano precision of 6 on my Mac and a nano precision of 3 on my Windows machine. Both are running jdk-1.8.0-172.

  • Is it possible to limit or increase the precision on one of the machines?
  • And why is the precision actually different?

Solution

  • The precision is different because LocalDateTime.now() uses a system default Clock.

    Obtains the current date-time from the system clock in the default time-zone.

    This will query the system clock in the default time-zone to obtain the current date-time.

    ...

    The link in this Javadoc takes you to Clock.systemDefaultZone() which states (emphasis mine):

    Obtains a clock that returns the current instant using the best available system clock, converting to date and time using the default time-zone.

    This clock is based on the best available system clock. This may use System.currentTimeMillis(), or a higher resolution clock if one is available.

    ...

    Which clock Java uses can depend on a lot of things and it looks like your Mac computer has a clock with microsecond precision whereas your Windows computer has a clock with millisecond precision. I'm not aware of any way to increase the precision of a clock but you can definitely decrease the precision so that it matches across platforms.

    One option is to use LocalDateTime.truncatedTo(TemporalUnit):

    import java.time.Instant;
    import java.time.temporal.ChronoUnit;
    
    public class Main {
    
      public static void main(String[] args) {
        Instant original = Instant.now();
        System.out.printf("Original instant  : %s%n", original);
    
        Instant truncated = original.truncatedTo(ChronoUnit.MILLIS);
        System.out.printf("Truncated instant : %s%n", truncated);
      }
    }
    

    -Also see answer by Ole V.V.

    Another option is to plug in your own Clock and use LocalDateTime.now(Clock). If possible, I would use Clock.tickMillis(ZoneId) since this method returns a Clock that truncates to milliseconds.

    Obtains a clock that returns the current instant ticking in whole milliseconds using the best available system clock.

    This clock will always have the nano-of-second field truncated to milliseconds. This ensures that the visible time ticks in whole milliseconds. The underlying clock is the best available system clock, equivalent to using system(ZoneId).

    ...

    Since:
    9

    For example:

    import java.time.Clock;
    // import java.time.Duration;
    import java.time.Instant;
    import java.time.ZoneId;
    
    public class Main {
    
      public static void main(String[] args) {
        // Java 8
        // Clock clock = Clock.tick(Clock.systemDefaultZone(), Duration.ofMillis(1));
    
        // Java 9+
        Clock clock = Clock.tickMillis(ZoneId.systemDefault());
    
        Instant instant = Instant.now(clock);
        System.out.printf("Instant : %s%n", instant);
      }
    }