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

4

31

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?
Threefold answered 26/8, 2018 at 20:15 Comment(9)
LocalDateTime.now() uses the system Clock which means whatever precision the system clock has that's how much precision LocalDateTime.now() will have.Gnathion
"milliseconds precision of 6" is that the same as microsecond precision? (Perhaps better phrased as "subsecond precision").Camp
Sorry! It´s actually called "nano".Threefold
@Gnathion Running System.currentTimeMillis() provides the same level of precision on both machines.Threefold
@TobiasMarschall because that's the time with millisecond precision.Camp
The system Clock may use System.currentTimeMillis() or a higher resolution clock if available. It looks like your Mac has a clock with microsecond precision.Gnathion
Is there some kind of "default clock" that can provide the same level of presicion on both machines?Threefold
By the way, LocalDateTime is the wrong class when your intention is to track moments. Use Instant, OffsetDateTime, or ZonedDateTime instead. Lacking any concept of time zone or offset-from-UTC, the LocalDateTime cannot track moments.Epidermis
Whose implementation of Java 8 are you using on macOS? I do not know of any that can capture current moment in microseconds. See OpenJDK issue ticket JDK-8068730, Increase the precision of the implementation of java.time.Clock.systemUTC() Discussed here.Epidermis
G
37

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);
  }
}
Gnathion answered 26/8, 2018 at 20:49 Comment(1)
In other words, resolution of current moment is an implementation detail.Epidermis
O
13

I don’t think you can get any better precision than the one you are already getting. If you want to reduce the precision to match that of the other system, it’s straightforward (when you know how):

LocalDateTime.now(ZoneId.of("Europe/Berlin")).truncatedTo(ChronoUnit.MILLIS);

The precision you get depends on the hardware, the settings, the OS and the integration of the JVM with all of those. It’s well known that Mac generally offers better precision than Windows (though I was under the impression that this was only the case from Java 9, per OpenJDK issue # JDK‑8068730).

Osage answered 26/8, 2018 at 20:30 Comment(3)
is ZoneID needed? maybe a bit confusing, at least it is kind of hiding the important part (laptop)Maxima
A good habit if you want to control what you get, @CarlosHeuberger. If you want the JVM’s default time zone in that moment, I still prefer ZoneId.systemDefault() over leaving it out. It reads the intention more clearly, though the result is the same. You are correct that this discussion is not relevant to the question asked.Osage
sure, there are a lot of 'good habits'... like having a constant for such? like avoiding too long lines?Maxima
S
11

If anyone had the same issue with Instant precision on mac or ubuntu on Java 15 that I want to show the difference:

mac Instant precision: 2021-03-10T12:28:19.228816Z

ubuntu Instant precision: 2021-03-10T12:28:19.228816800Z

Solution: please add .truncatedTo(ChronoUnit.MILLIS) to Instant variable if You want to have the same precision on this OS

Sadyesaechao answered 11/3, 2021 at 10:22 Comment(0)
B
0

You can set the precision using a formatter, without resorting to truncatedTo or Clock.tickMillis:

jshell> OffsetDateTime.now().format(ISO_DATE_TIME)
$5 ==> "2020-10-21T10:13:48.57776451+02:00"

jshell> OffsetDateTime.now().format(ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSZ"))
$8 ==> "2020-10-21T10:15:31.27+0200"

I realized this after discovering that JDK 15 has different precision on macOS and Linux.

Boorish answered 21/10, 2020 at 8:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.