3

I have the need for extremely precise and accurate time with as few garbage collections (GCs) as possible, ideally 1 per day. System.currentTimeMillis() is not precise enough, System.nanoTime() isn't an accurate source of time. The only thing that will give me what I want is java.util.Date.getTime() but it's not a static method so I have to create a new Date object every time I need precise and accurate time which causes GC to be triggered more often.

Does anyone know how the Date class gets accurate and precise time? I'm hoping to take Date's method and tailor it to minimize object creation. To summarize my problem, see the following:

long nanosSinceEpoch;
nanosSinceEpoch = System.currentTimeMillis(); // Not precise
nanosSinceEpoch = System.nanoTime();          // Not accurate
nanosSinceEpoch = new Date().getTime();       // Too many objects

EDIT:

I'm not sure why I thought System.currentTimeMillis() and new Date().getTime() were different but it turns out they are the same. But that didn't fix my problem sadly.

Also, getNano() from java.time.Instant appears to only have millisecond resolution.

SomeGuy
  • 478
  • 4
  • 8
  • 2
    I didnt find any difference between the time returned by 1st and 3rd option. For instance, I tried to execute both the statements and got below value: 1522333417157 . Am I missing anything? – Aman Chhabra Mar 29 '18 at 14:24
  • 1
    Well, the constructor of `Date` uses `System#currentTimeMillis`. – Jacob G. Mar 29 '18 at 14:25
  • 2
    1) Nowadays, you should use [`Instant.now()`](https://docs.oracle.com/javase/10/docs/api/java/time/Instant.html#now()) instead of `new Date()` (although there are more object creations involved). 2) "I have to create a new [...] object [...] which causes GC to be triggered more often." => Any proof of that? If you simply create a new object, and its reference does not _escape_ the method, the object is most likely created on the stack and not on the heap. See the article on [escape analysis](https://en.wikipedia.org/wiki/Escape_analysis). The GC then has no work to do! – Seelenvirtuose Mar 29 '18 at 14:29
  • @Seelenvirtuose - You have just change my life. Thank you! – SomeGuy Mar 29 '18 at 15:10
  • After doing some testing. I've found that `Instant.now().getNano()` isn't any more precise than `(System.currentTimeMillis() % 1_000) * 1_000_000` i.e. it zero-pads the micro and nano seond digits. I'm using openJDK8 on Ubuntu 16.04. – SomeGuy Mar 29 '18 at 15:37
  • @SomeGuy You assume conventional computer hardware clocks can track time to nanosecond precision. Your assumption is incorrect, as of 2018. Perhaps in future hardware, but not today’s hardware. – Basil Bourque Mar 29 '18 at 18:42
  • @BasilBourque RDTSC gets you within a precision of a few dozen nanoseconds. – the8472 Apr 02 '18 at 08:10
  • @the8472 The [Wikipedia article on Time Stamp Counter (TSC) and RDTSC](https://en.m.wikipedia.org/wiki/Time_Stamp_Counter) makes it sound like that feature is *not* practical/reliable for time-keeping on modern hardware. – Basil Bourque Apr 02 '18 at 15:51
  • @BasilBourque it is practical and reliable on many but not all *modern* systems. The "but not all" part mostly means it requires some probing by the OS at boot time. It is used under the hood by various time sources if possible. – the8472 Apr 02 '18 at 17:37
  • @the8472 Unless I have misunderstood, according to the Wikipedia article that facility is not to be relied upon for accurate time-keeping on (a) any machine with multiple CPUs, (b) any multi-core machine, (c) any hyper-threaded machine, (d) any machine with out-of-order execution, nor (e) any machine running MS Windows OS. What modern system does that leave remaining? – Basil Bourque Apr 02 '18 at 19:34
  • You have indeed misunderstood, *modern* processors have fixed most of the issues that were present on *older* processors. But elaborating would not be appropriate for comments. – the8472 Apr 03 '18 at 05:59
  • @Seelenvirtuose “*the object is most likely created on the stack*”—that’s a tenacious wrong explanation of what will happen. A JVM like HotSpot *never* allocates objects on the stack. What will happen, is dissolving the object’s fields into variables, most likely getting replaced by whatever data source actually determined their value (though mutable variables may even spawn new variables), just like the optimizer treats local variables. Or, in other words, the object will not get allocated at all. – Holger Apr 03 '18 at 12:29

2 Answers2

5

Instant.now

Java 9 brought a fresh implementation of Clock able to capture the current moment in a precision finer than the milliseconds capability of Java 8’s Clock.

Instant instant = Instant.now() ;

Let me be clear: The Instant class in all versions of Java is able to hold a value in nanoseconds. But capturing the current moment is limited to milliseconds in Version 8 specifically.

You should research the capabilities of the hardware clock of your current computer equipment. I believe you will find that current conventional hardware is not capable of accuracy in tracking time to the nanosecond.

In using Oracle JDK 9.0.4 on macOS Sierra, I am seeing current moment captured in microseconds, six digits of decimal fractional second.

System.nanoTime() isn't an accurate source of time

No, accuracy is not the issue. The issue there is that System.nanoTime() is designed to track elapsed time, not the current date-time. This feature simply tracks a count of nanoseconds since an arbitrary undocumented starting point.

And again, as noted above, we are not talking about incrementing by single nanoseconds as current conventional computer hardware is not capable.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

System.nanoTime() isn't an accurate source of time

This is not quite true. Its accuracy is highly system-dependent. If you have control over your hardware and OS you can in principle construct a high precision clock from it even on older java versions.

Since JDK-8068730 has been implemented the newer time APIs shield you from those complexities by deferring to the most accurate OS clock available which in turn will do the necessary hardware feature detection to figure out whether the TSCs are reliable enough to be used as a time source.

the8472
  • 40,999
  • 5
  • 70
  • 122