javatimenanotime

Does System.nanoTime() pause when the machine sleeps?


I'm tracking a bug in my software that is caused by System.nanoTime() stopping counting time when the machine enters a deep sleep state, whereas System.currentTimeMillis() does not.

Here's a minimal reproducible example. It continuously tracks the difference in milliseconds between System.currentTimeMillis() and System.nanoTime().

public static void main(String[] args) throws Exception {
    while (true) {
        long epoch = System.currentTimeMillis();
        System.out.println(new Date(epoch) + " " + 
                          (epoch - TimeUnit.NANOSECONDS.toMillis(System.nanoTime())));
        Thread.sleep(1000);
    }
}

I'm running it on a MacBook Pro with macOS 15.5 on Java version 21.0.2-amzn downloaded via SdkMan. The reproduction steps are:

In the following example, you can see that after a 15-second sleep, the difference has increased by almost the same amount.

...
Wed Jun 11 00:21:20 BRT 2025 1749394409334
Wed Jun 11 00:21:21 BRT 2025 1749394409334
Wed Jun 11 00:21:36 BRT 2025 1749394423732
Wed Jun 11 00:21:37 BRT 2025 1749394423732
...

The documentation says that:

The value returned represents nanoseconds since some fixed but arbitrary origin time [...]. The same origin is used by all invocations of this method in an instance of a Java virtual machine [...]

However, that does not appear to be the case in this example.

Has anyone seen that before? Am I missing something?


Solution

  • I think that this behavior fits within the bounds of the javadoc.

    In JDK bug report JDK-8307677 on the accuracy of nanotime(), the first response comment is as follows:

    "It is an erroneous assumption to assume that ‘correct’ behaviour would be to continue tracking nanoTime() across sleep/suspend. When you are using relative times and timeouts they are typically relative to the operation of the JVM not the external world, so if the JVM stops then "time" stops. This is the only mode of operation the JVM supports."

    The javadoc includes this sentence:

    This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.

    In practice, nanotime() returns "JVM time" ... which stops when the hardware sleeps. The Java team holds that this behavior is by design, and by implication that it is consistent with the javadoc. The bug has been marked as "won't fix".