415

Accuracy Vs. Precision

What I would like to know is whether I should use System.currentTimeMillis() or System.nanoTime() when updating my object's positions in my game? Their change in movement is directly proportional to the elapsed time since the last call and I want to be as precise as possible.

I've read that there are some serious time-resolution issues between different operating systems (namely that Mac / Linux have an almost 1 ms resolution while Windows has a 50ms resolution??). I'm primarly running my apps on windows and 50ms resolution seems pretty inaccurate.

Are there better options than the two I listed?

Any suggestions / comments?

mmcdole
  • 91,488
  • 60
  • 186
  • 222
  • 92
    `nanoTime` is significantly usually more accurate than currentTimeMillis but it's a relatively expensive call as well.`currentTimeMillis()` runs in a few (5-6) cpu clocks, nanoTime depends on the underlying architecture and can be 100+ cpu clocks. – bestsss Feb 21 '11 at 01:15
  • 17
    You do all realise that Windows generally has a timeslice granularity of 1000ms / 64, right? Which is 15.625ms, or 15625000nanoseconds! –  Sep 28 '11 at 11:30
  • 8
    I don't think a hundred extra clock cycles are going to impact your game, and the trade off would probably be worth it. You should only be calling the method once per game update then saving the value in mem, so it won't add a lot of overhead. As for the granularity of different platforms, I have no idea. – aglassman Jun 13 '12 at 15:58
  • 14
    Windows has a DEFAULT timeslice granularity of 1000ms/64. You can increase this through the native timeBeginPeriod API. Modern PCs also have high-resolution timers in addition to the basic timer. High-resolution timers are accessible via the QueryPerformanceCounter call. – Robin Davies Jan 16 '13 at 08:11
  • @bestsss how to find out the cpu clocks usage? – Gohan Jul 23 '15 at 02:19
  • 3
    @Gohan - This article goes into detail about the inner workings of `System.currentTimeMillis()`: http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html – Attila Tanyi Aug 13 '17 at 10:33

10 Answers10

345

If you're just looking for extremely precise measurements of elapsed time, use System.nanoTime(). System.currentTimeMillis() will give you the most accurate possible elapsed time in milliseconds since the epoch, but System.nanoTime() gives you a nanosecond-precise time, relative to some arbitrary point.

From the Java Documentation:

public static long nanoTime()

Returns the current value of the most precise available system timer, in nanoseconds.

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292 years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

For example, to measure how long some code takes to execute:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

See also: JavaDoc System.nanoTime() and JavaDoc System.currentTimeMillis() for more info.

1565986223
  • 6,420
  • 2
  • 20
  • 33
dancavallaro
  • 13,109
  • 8
  • 37
  • 33
  • 22
    Are you sure you know the difference between accuracy and precision? There is no way it is accurate to a nanosecond precision. – mmcdole Dec 09 '08 at 02:09
  • 7
    Sorry, I meant precise. I was using the term loosely, but I agree it was confusing (and an improper use of the word). – dancavallaro Dec 09 '08 at 02:10
  • And since you want elapsed time, you don't care about accuracy, you care about precision. System.nanoTime() will give you the most precise time interval possible. – dancavallaro Dec 09 '08 at 02:11
  • 4
    @dancavallaro, thanks for the information. If you don't mind, I edited your answer to include a quote from the docs and fixed up the links – mmcdole Dec 09 '08 at 02:28
  • 2
    successive calls that span greater than approximately 292 years .... my new fav quote! – akuhn Dec 09 '08 at 04:51
  • 152
    This answer is technically correct in choosing nanoTime() but completely glosses over an extremely important point. nanoTime(), as the doc says, is a precision timer. currentTimeMillis() is NOT A TIMER, it is the "wall clock". nanoTime() will always produce positive elapsed time, currentTimeMillis will not (e.g. if you change the date, hit a leap second, etc.) This is an extremely important distinction for some types of systems. – charstar Apr 10 '11 at 10:32
  • 13
    User changing time and NTP sync sure, but why would `currentTimeMillis` change due to DST? DST switch doesn't change the number of seconds past the epoch. It may be a "wall clock" but it is one based on UTC. You must determine based on your timezone and DST settings what that translates to for your local time (or use other Java utilities to do that for you). – Shadow Man Jan 24 '14 at 21:43
  • 1
    System.nanoTime() is not always monotonic http://steveloughran.blogspot.com/2015/09/time-on-multi-core-multi-socket-servers.html – Tarun Chabarwal Nov 02 '19 at 07:25
  • @charstar read the docs again: "The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values *may be negative*)." Also, notice that "This method provides nanosecond precision, but *not necessarily nanosecond resolution* (that is, how frequently the value changes)"; Could someone please point out which platforms this is true for? – Lolechi Aug 19 '21 at 23:41
123

Since no one else has mentioned this…

It is not safe to compare the results of System.nanoTime() calls between different JVMs, each JVM may have an independent 'origin' time.

System.currentTimeMillis() will return the (approximate) same value between JVMs, because it is tied to the system wall clock time.

If you want to compute the amount of time that has elapsed between two events, like a stopwatch, use nanoTime(); changes in the system wall-clock make currentTimeMillis() incorrect for this use case.

gub
  • 5,079
  • 3
  • 28
  • 33
  • 4
    On Windows that only holds until SP2 according to: http://stackoverflow.com/questions/510462/is-system-nanotime-completely-useless – Peter Schmitz Feb 22 '12 at 11:25
  • 3
    Well, you learn something new every day. I suspect, though, that given it was unsafe in the past (definitely returns nonsense readings across threads), such usage is probably still outside the spec and so should probably be avoided. – gub Mar 04 '12 at 14:55
  • 4
    @jgubby: Very interesting... **any reference to support that _is not safe to compare the results of System.nanoTime() calls between different Threads_?** The following links are worth to see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519418 http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime() – user454322 Oct 09 '12 at 10:45
  • 19
    Looking at the description mentioned here: http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime(), it seems like the difference between the values returned from nanoTime are valid for comparison as long as they were from the same JVM - `The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.` – Tuxdude Jan 20 '16 at 23:01
  • 3
    This is not entirely correct, nanoTime() returns consistently across threads unless your system is buggy, this number will increment between calls as expected. On the other hand System.currentTimeMillis() can jump backwards even on the same thread because it represents wall time, which can be adjusted by outside factors, such as NTP updates. – David Aug 16 '17 at 20:26
  • 3
    I don't see any reason to measure time elapsed between different threads in the first place. But either way, I would like to add a "citation needed" on your statement that `System.nanoTime()` is not thread safe. – Simon Forsberg Oct 20 '17 at 15:15
  • 9
    [The JavaDoc for `nanoTime()`](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#nanoTime--) says: *The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.* which means that it *does* return the same across threads. – Simon Forsberg Feb 01 '18 at 16:02
  • 2
    This answer is wrong. Exactly the opposite is the case: currentTimeMillis() is not thread-safe (in the assumed meaning, i. e. monotonically non-decreasing results), even within a single thread. nanoTime() is thread-safe. – leventov Feb 04 '19 at 03:01
  • @leventov, I don't think the purpose of editing answers includes essentially a full re-write. You're correct in that nanoTime is safe within all threads of any given JVM, but it's probably better to create a different answer and downvote this one. – alife Sep 07 '22 at 19:15
60

Update by Arkadiy: I've observed more correct behavior of System.currentTimeMillis() on Windows 7 in Oracle Java 8. The time was returned with 1 millisecond precision. The source code in OpenJDK has not changed, so I do not know what causes the better behavior.


David Holmes of Sun posted a blog article a couple years ago that has a very detailed look at the Java timing APIs (in particular System.currentTimeMillis() and System.nanoTime()), when you would want to use which, and how they work internally.

Inside the Hotspot VM: Clocks, Timers and Scheduling Events - Part I - Windows

One very interesting aspect of the timer used by Java on Windows for APIs that have a timed wait parameter is that the resolution of the timer can change depending on what other API calls may have been made - system wide (not just in the particular process). He shows an example where using Thread.sleep() will cause this resolution change.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 1
    @Arkadiy: Do you have a source for the statement in the update? – Lii Dec 15 '15 at 17:40
  • @Lii - Unfortunately, no. It comes from me running the code in this question:http://stackoverflow.com/questions/34090914/currenttimemillis-and-waiting-by-spinning-on-nanotime . The code produces 15ms precision with Java 7 and 1 ms precision with Java 8 –  Dec 15 '15 at 18:01
  • 2
    I traced the currentTimeMillis to os::javaTimeMillis in hotspot/src/os/windows/vm/os_windows.cpp in OpenJDK (http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/os/windows/vm/os_windows.cpp#l833). Looks like it's still GetSystemTimeAsFileTime, so I do not know where change comes from. Or if it's even valid. Test before using. –  Dec 16 '15 at 17:44
  • the change in behaviour is the result of changing how `GetSystemTimeAsFileTime` worked in XP vs 7. See [here](http://www.windowstimestamp.com/description) for more details (tl;dr it got more precise since the entire system introduced some more precise timing methods). –  Jul 18 '17 at 22:08
12

As others have said, currentTimeMillis is clock time, which changes due to daylight saving time (not: daylight saving & time zone are unrelated to currentTimeMillis, the rest is true), users changing the time settings, leap seconds, and internet time sync. If your app depends on monotonically increasing elapsed time values, you might prefer nanoTime instead.

You might think that the players won't be fiddling with the time settings during game play, and maybe you'd be right. But don't underestimate the disruption due to internet time sync, or perhaps remote desktop users. The nanoTime API is immune to this kind of disruption.

If you want to use clock time, but avoid discontinuities due to internet time sync, you might consider an NTP client such as Meinberg, which "tunes" the clock rate to zero it in, instead of just resetting the clock periodically.

I speak from personal experience. In a weather application that I developed, I was getting randomly occurring wind speed spikes. It took a while for me to realize that my timebase was being disrupted by the behavior of clock time on a typical PC. All my problems disappeared when I started using nanoTime. Consistency (monotonicity) was more important to my application than raw precision or absolute accuracy.

Peter Kriens
  • 15,196
  • 1
  • 37
  • 55
KarlU
  • 473
  • 6
  • 6
  • 31
    *"currentTimeMillis is clock time, which changes due to daylight saving time"* ... pretty sure that this statement is false. `System.currentTimeMillis()` reports elapsed time (in milliseconds) since the Unix/Posix Epoch which is Midnight, Jan 1, 1970 UTC. Because UTC is never adjusted for daylight savings, this value will not be offset when local time zones add or subject offsets to local times for daylight savings. Moreover, the Java Time Scale smooths out leap seconds so that days continue to appear to have 86,400 seconds. – scottb May 23 '16 at 05:27
11

System.nanoTime() isn't supported in older JVMs. If that is a concern, stick with currentTimeMillis

Regarding accuracy, you are almost correct. On SOME Windows machines, currentTimeMillis() has a resolution of about 10ms (not 50ms). I'm not sure why, but some Windows machines are just as accurate as Linux machines.

I have used GAGETimer in the past with moderate success.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Paul Morel
  • 551
  • 2
  • 13
  • 4
    "older JVMs" as in which ones? Java 1.2 or something? – Simon Forsberg Oct 20 '17 at 15:07
  • 3
    System.nanoTime() was introduced in Java 1.5 in 2004. Java 1.4 extended support in 2013, so it's pretty safe to say System.nanoTime() can now be relied on and this answer is now out of date. – Dave L. Jan 22 '20 at 16:45
5

Yes, if such precision is required use System.nanoTime(), but be aware that you are then requiring a Java 5+ JVM.

On my XP systems, I see system time reported to at least 100 microseconds 278 nanoseconds using the following code:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }
Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
4

For game graphics & smooth position updates, use System.nanoTime() rather than System.currentTimeMillis(). I switched from currentTimeMillis() to nanoTime() in a game and got a major visual improvement in smoothness of motion.

While one millisecond may seem as though it should already be precise, visually it is not. The factors nanoTime() can improve include:

  • accurate pixel positioning below wall-clock resolution
  • ability to anti-alias between pixels, if you want
  • Windows wall-clock inaccuracy
  • clock jitter (inconsistency of when wall-clock actually ticks forward)

As other answers suggest, nanoTime does have a performance cost if called repeatedly -- it would be best to call it just once per frame, and use the same value to calculate the entire frame.

Thomas W
  • 13,940
  • 4
  • 58
  • 76
2

System.currentTimeMillis() is not safe for elapsed time because this method is sensitive to the system realtime clock changes of the system. You should use System.nanoTime. Please refer to Java System help:

About nanoTime method:

.. This method provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes) - no guarantees are made except that the resolution is at least as good as that of currentTimeMillis()..

If you use System.currentTimeMillis() your elapsed time can be negative (Back <-- to the future)

Ricardo Gasca
  • 1,435
  • 1
  • 9
  • 5
1

I've had good experience with nanotime. It provides wall-clock time as two longs (seconds since the epoch and nanoseconds within that second), using a JNI library. It's available with the JNI part precompiled for both Windows and Linux.

Jon Bright
  • 13,388
  • 3
  • 31
  • 46
-3

one thing here is the inconsistency of the nanoTime method.it does not give very consistent values for the same input.currentTimeMillis does much better in terms of performance and consistency,and also ,though not as precise as nanoTime,has a lower margin of error,and therefore more accuracy in its value. i would therefore suggest that you use currentTimeMillis

sarvesh
  • 31
  • 2
  • 6
    As noted in other answers and comments, currentTimeMillis is subject to system clock changes and therefore a poor choice for calculating elapsed time since some earlier event in the JVM. – duelin markers Oct 14 '13 at 19:00