Carl

Carl Mastrangelo

A programming and hobby blog.


You Probably Want nanoTime

Quick Quiz: What does the following Java code do?

public class Timer {
  public static void main(String [] args) throws Exception {
    Instant start = Instant.now();
    System.err.println("Starting at " + start);
    Thread.sleep(Duration.ofSeconds(10));
    Instant end = Instant.now();
    System.out.println("Slept for " + Duration.between(start, end));
  }
}

On the surface, it looks correct. The code tries to sleep for 10 seconds, and then prints out how long it actually slept for. However, there is a subtle bug: It’s using calendar time instead of monotonic time


Instant.now() is Calendar Time

Instant.now() seems like a good API to use. It’s typesafe, modern, and has nanosecond resolution! All good right? The problem is that the time comes from computer’s clock, which can move around unpredictably. To show this, I recorded running this program:


As we can see, the program takes a little over 10 seconds to run. However, what would happen if the system clock were to be adjusted? Let’s look:



Time went backwards and our program didn’t measure the duration correctly! This can happen during daylight savings time switches, users changing their system clock manually, and even when returning from sleep or hibernate power states.


Use System.nanoTime to Measure Duration

To avoid clock drift, we can use System.nanoTime(). This API returns a timestamp that is arbitrary, but is consistent during the run of our program. Here’s how to use it:

public class Timer {
  public static void main(String [] args) throws Exception {
    long start = System.nanoTime();
    System.err.println("Starting at " + start);
    Thread.sleep(Duration.ofSeconds(10));
    long end = System.nanoTime();
    System.out.println("Slept for " + Duration.ofNanos(end - start));
  }
}

We don’t get to use the object oriented time APIs, but those weren’t meant for recording duration anyways. It feels a little more raw to use long primitives, but the result is always correct. If you are looking for a typesafe way to do this, consider using Guava’s Stopwatch class.

The nanoTime() call is great in lot’s of situations:


What about System.currentTimeMillis()?

While this function worked well for a long time, it has been superseded by Instant.now(). I usually see other programmers use this function because they only care about millisecond granularity. However, this suffer from the same clock drift problem as Instant.now().


Home

You can find me on Twitter @CarlMastrangelo