5

I do lots of research but did not find any good answer. I wanted to get the current date and time in a nanosecond. I found that System.nanoTime() will provide nanoseconds, but that is and system elapsed time. means it will provide a time when system up. I need to use the current date and time in a nanosecond.

I need this for avoiding duplicate of points in InfluxDB, see How does InfluxDB handle duplicate points? So when I use millisecond I am facing issues of data union. So need deciding to go with nanosecond but the problem is while generated nano the second using System.nanoTime() did not contain current date and time data. and it give me JVM uptime which is useless for me.

Himeshgiri gosvami
  • 2,559
  • 4
  • 16
  • 28
  • 5
    Do you really think your computer's system clock is nano-precise? – Pavel Aug 29 '18 at 12:12
  • Maybe related: [Current time in microseconds in java](https://stackoverflow.com/questions/1712205/current-time-in-microseconds-in-java) – LuCio Aug 29 '18 at 12:13
  • 1
    @JackFlamp probably current time, down to nano-second precision. – Eugene Aug 29 '18 at 12:13
  • @ Jack Flamp Means lets say your JVM is up for 1 day. when you get nanosecond using this method, that will give you nanosecond only of JVM uptime. – Himeshgiri gosvami Aug 29 '18 at 12:13
  • @Pavel Yes, I am curious and I really wants to know that. – Himeshgiri gosvami Aug 29 '18 at 12:15
  • The solution proposed is not to get the time in nanoseconds but to increment by 1 the time to prevent the duplicate. "_Increment the timestamp by a nanosecond._" I guess you could simple add any value you want, using a incremente value from 0 to x. This would prevent the duplicate to the millisecond problem – AxelH Aug 29 '18 at 12:29
  • @Axel with your approach, I am a compromise with time series database, I need time to make time-based queries. – Himeshgiri gosvami Aug 29 '18 at 12:34

3 Answers3

14

In theory, it is possible to get the current time to "better than microsecond" accuracy as follows:

Clock clock = Clock.systemDefaultZone();
Instant instant = clock.instant();   // or Instant.now();
long seconds = instant.getEpochSecond();
long nano = instant.getNano();
// epoch nanoseconds = seconds * 10E9 + nano

The problems:

  1. The systemDefaultZone() call gives the "best available clock" for the platform. The JVM spec says that this may have better than millisecond precision, but this is not guaranteed. So the nano value may have no better than millisecond precision.

  2. The values of seconds and nano depend on the accuracy of the local hardware clock. On many systems, keeping the local clock synced to a "real" time is difficult. Often, sub-millisecond accuracy is challenging, and apparent nanosecond accuracy is an illusion.

  3. Even you have previously managed to sync the hardware clock with a "real" time source to nanosecond accuracy, the overheads and variability in the making the above calls to acquire the epoch nanosecond time would swamp the hardware clock's nanosecond accuracy. Things like memory cache variability, how busy the main memory bus is, etc. And of course the hardware clock may have drifted since it was last synced externally.

In practice, on most systems, nano-second accuracy is unachievable, so you need avoid designs / algorithms that depend on this.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Unless I'm missing something, this cannot ever give anything better than millisecond accuracy because `Clock.systemDefaultZone()` returns a `java.time.Clock.SystemClock` and the `SytemClock.instant()` is implemented as `return Instant.ofEpochMilli(millis())`. You do get a value that encodes micro- and nanoseconds, but those will always be zero. – G. Bach Oct 08 '19 at 11:14
  • 1
    I am looking at the OpenJDK 11 source code and it doesn't do that. It is actually getting a nano-second adjustment from the OS. Clearly, the behavior the clock returned by `Clock.systemDefaultZone()` is platform dependent. The javadocs don't make any promises. – Stephen C Oct 08 '19 at 11:26
  • I wondered how Ole V.V. below could get microsecond accuracy, and a different JDK would explain it. I'm using the Oracle JDK 1.8.0_181, and only get millisecond accuracy with this. Interesting, thanks for checking. – G. Bach Oct 08 '19 at 11:37
  • @G.Bach - Bear in mind, that the behavior is OS dependent. Java can only deliver high precision time if the OS allows user-space code to access to high precision clocks. – Stephen C Feb 08 '22 at 05:21
3

Finally, Thanks for Mr. Franz Wilhelmstötter

I found one solution. using http://jenetics.io/ and Class call NanoClock.java is converting and doing the same trick that Stephen C suggested. I want to share this because it will useful for others as well. I am not able to confirm that is given precise nano time, but this trick works for me. @Ole V.V. Thanks again for your help.

Himeshgiri gosvami
  • 2,559
  • 4
  • 16
  • 28
  • 1
    The idea in `NanoClock` is to record the offset between real-world time and `System.nanos()` once and then use `System.nanos()` and the offset to generate current time in nanos. Well thought, and I would expect it to give you a pretty good accuracy. On my computer it seems to have a precision around 100 nanos, and there was no way I could get the same time twice. This is no guarantee, though. Thanks for reporting back what you had found. – Ole V.V. Aug 29 '18 at 15:40
1

You get the best accuracy and precision Java can give you from Instant.now(). Whether this is enough to solve your problem, I dare not tell. Certainly on a normal computer there is no way to get nanosecond accuracy.

You may need to play some tricks with adding an artificial nanosecond in case Instant.now() returns the same value twice.

Or simple use the trick mentioned in your link:

Introduce an arbitrary new tag to enforce uniqueness.

For the trick of adding an artificial nanosecond you may for example use something like the following:

public class TimeProvider {

    Instant last = Instant.now().minusSeconds(1);

    Instant getUniqueInstant() {
        Instant result = Instant.now();
        if (! result.isAfter(last)) {
            result = last.plusNanos(1);
        }
        last = result;
        return result;
    }
}

When I draw times in rapid succession from this class on my computer, I get results like below. It would seem from the output (the way I interpret it):

  • My JVM cannot get higher precision than microseconds (6 decimals on the seconds) from the system clock.
  • An artificial nanosecond is added now and then to keep the instants unique.

.

2018-08-29T15:18:35.617616001Z
2018-08-29T15:18:35.617617Z
2018-08-29T15:18:35.617618Z
2018-08-29T15:18:35.617618001Z
2018-08-29T15:18:35.617619Z
2018-08-29T15:18:35.617619001Z
2018-08-29T15:18:35.617620Z
2018-08-29T15:18:35.617620001Z
2018-08-29T15:18:35.617621Z
2018-08-29T15:18:35.617621001Z
2018-08-29T15:18:35.617622Z
2018-08-29T15:18:35.617623Z
2018-08-29T15:18:35.617623001Z
2018-08-29T15:18:35.617624Z
2018-08-29T15:18:35.617624001Z
2018-08-29T15:18:35.617625Z
2018-08-29T15:18:35.617625001Z
2018-08-29T15:18:35.617626Z
2018-08-29T15:18:35.617626001Z
2018-08-29T15:18:35.617627Z
2018-08-29T15:18:35.617627001Z
2018-08-29T15:18:35.617628Z
2018-08-29T15:18:35.617631Z
2018-08-29T15:18:35.617634Z
2018-08-29T15:18:35.617635Z
2018-08-29T15:18:35.617636Z
2018-08-29T15:18:35.617636001Z
2018-08-29T15:18:35.617637Z
2018-08-29T15:18:35.617637001Z
2018-08-29T15:18:35.617638Z
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161