Why should I use t1 - t0 < 0, not t1 < t0, when using System.nanoTime() in Java

t0 - t1 < 0 is better then t0 < t1 when we are sure that real difference of values (before overflow) is not grater than half or size of set that contains all possible values.
For nanoseconds it will be approximately 292 years (nanoseconds are stored in long and half of long size is 2^64/2 = 2^63 nanoseconds ~= 292 years).

So for time samples separated with less then 292 years we should use t0 - t1 < 0 to get correct results.


To better visualize it lets say that cycle contains 8 possible values which are -4, -3, -2, -1 ,0, 1, 2, 3.

So timeline can look like

real time values:  .., -6, -5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5,  6,  7, ..
overflowed values: ..,  2,  3, -4, -3, -2, -1,  0,  1,  2,  3, -4, -3, -2, -1, ..

Lets take a look how t0 - t1 < 0 and t0 < t1 will behave for values where difference will be and wont be greater than 4 (half of cycle size, and -4 is minimal value which means it can be minimal result for calculating delta). Notice that only t0 - t1 < 0 will give correct results when t1 overflows

  1. delta = 1 with overflow of bigger value (notice: we don't make lesser value overflow because it would mean that both values are in the same cycle so calculations would be same as if there wouldn't be any overflow)

    • real values: t0 = 3 t1 = 4
    • overflowed: t0 = 3 t1 = -4
    • t0 < t1 ==> 3 < -4 -> false
    • t0 - t1 < 0 ==> 3 - (-4) < 0 ==> -1 < 0 (7 overflows to -1) true

    so only for t0 - t1 < 0 we got correct result despite or maybe thanks to overflow.

  2. delta = 1 but this time no overflow

    a) positive values

    • t0 = 2, t1 = 3
    • 2 < 3 true
    • 2 - 3 < 0 ==> -1 < 0 true

    b) negative values

    • t0 = -4, t1 = -3
    • -4 < -3 true
    • -4 - (-3) < 0 ==> -1 < 0 true

    for rest of cases where real delta = 1 we will also get correct results for both t0 < t1 and t0 - t1 < 0 tests (t0 - t1 will be always -1)

  3. delta = 3 (almost half of cycle)

    a1) with overflow of bigger value

    • real values: t0 = 3 t1 = 6
    • overflowed: t0 = 3 t1 = -2
    • t0 < t1 ==> 3 < -2 -> false
    • t0 - t1 < 0 ==> 3 - (-2) < 0 ==> -3 < 0 (5 overflows to -3) true

    a2) another case with overflow

    • real values: t0 = 2 t1 = 5
    • overflowed: t0 = 2 t1 = -3
    • t0 < t1 ==> 2 < -3 -> false
    • t0 - t1 < 0 ==> 2 - (-3) < 0 ==> -3 < 0 (again 5 overflows to -3) true


    So again only t0 - t1 < 0 gave correct result.

    b) without overflow t0 - t1 will always be equal to -3 (-delta) so this will always be giving correct result. t0 < t1 will also give correct resilt

    • real values: t0 = -1 t1 = 2
    • t0 < t1 ==> -1 < 2 -> true
    • t0 - t1 < 0 ==> -1 - 2 < 0 ==> -3 < 0 true
  4. delta = 4 result of t0 - t1 will always be equal to -4 so it will also be <0.

    examples with overflow
    a1)

    • real values: t0 = 0 t1 = 4
    • overflowed: t0 = 0 t1 = -4
    • t0 < t1 ==> 0 < -4 -> false
    • t0 - t1 < 0 ==> 0 - (-4) < 0 ==> -4 < 0 (4 overflows to -4) true

    a2)

    • real values: t0 = 1 t1 = 5
    • overflowed: t0 = 1 t1 = -3
    • t0 < t1 ==> 1 < -4 -> false
    • t0 - t1 < 0 ==> 1 - (-3) < 0 ==> -4 < 0 (4 overflows to -4) true

    So again only t0 - t1 < 0 give correct results.

    Examples without overflow obviously will be correct for both tests.

  5. delta = 5 (and more)

    a1) with overflow
    (minimal value tor t0 is -1 so lets start with it)

    • real values: t0 = -1 t1 = 4
    • overflowed: t0 = -1 t1 = -4
    • t0 < t1 ==> -1 < -4 -> false
    • t0 - t1 < 0 ==> -1 - (-4) < 0 ==> 3 < 0 false

    a2) with overflow

    • real values: t0 = 1 t1 = 6
    • overflowed: t0 = 1 t1 = -2
    • t0 < t1 ==> 1 < -2 -> false
    • t0 - t1 < 0 ==> 1 - (-2) < 0 ==> 3 < 0 false both tests failed

    b1) without overflow

    • t0 = -4, t1 = 1
    • -4 < 1 true
    • -4 - 1 < 0 ==> 3 < 0 (-5 overflows to 3) false

+-------------+-----------------------------+----------------------------+
|  tests if   | delta <= size of half cycle | delta > size of half cycle |
| t0 is less  |-----------------------------|----------------------------|
|  than t1    |  overflow  |  no overflow   | overflow  |  no overflow   |
|-------------|------------|----------------|-----------|----------------|
|   t0 < t1   |      -     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 < 0 |      +     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 > 0 |      -     |       -        |     +     |       -        |
+-------------+------------+----------------+-----------+----------------+

The quote from the API is actually:

Differences in successive calls that span greater than approximately 292 years (2^63 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

If t0 and t1 are measured 292 years apart you will experience numerical overflow. Otherwise either the comparison or the subtraction will work just fine.


The Nano time is not a 'real' time, it is just a counter that increments starting from some unspecified number when some unspecified event occurs (maybe the computer is booted up).

It will overflow, and become negative at some point. If your t0 is just before it overflows (i.e. very large positive), and your t1 is just after (very large negative number), then t1 < t0 (i.e. your conditions are wrong because t1 happened after t0).....

But, if you say t1 - t0 < 0, well, the magic is that a for the same overflow (undeflow) reasons (very large negative subtract a very large positive will underflow), the result will be the number of nanoseconds that t1 was after t0..... and will be right.

In this case, two wrongs really do make a right!