Reputation: 247
we are having a piece of code where we are using NanoClock to get the exact time. In a nut shell below is the code snippet of how i am generating the nano time and how we are converting to simple date format. the problem is, nono time (in some cases) is off by few seconds. so for eg, the system time is 12:23:44.125 the nano time will be 12:23:56.1234567.
public static Date getTimeStamp() {
final Clock clock = new NanoClock();
Instant instant = Instant.now(clock);
return Timestamp.from(instant);
}
public static Date getTimeInMilis(Timestamp timestamp) throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String miliDate = dateFormat.format(timestamp);
return dateFormat.parse(miliDate);
}
we are using NanoClock as follows
public static final long NANOS_PER_SECOND = 1000000000;
private static final long EPOCH_NANOS = System.currentTimeMillis() * 1000000;
private static final long NANO_START = System.nanoTime();
final long now = System.nanoTime() - NANO_START + EPOCH_NANOS;
return Instant.ofEpochSecond(now / NANOS_PER_SECOND, now % NANOS_PER_SECOND);
we were running this code in production for over 5 years and it was always fine. it started giving this discrepancy since past 2 months. we are using JAVA 8 update 71 (64 bits) and nothing has changed on the system with respect to JAVA or my code in past 4-5 months.
Upvotes: 0
Views: 694
Reputation:
The discrepancy is due to system clock drift.
System.currentTimeMillis()
is vulnerable to adjustments in the system clock, for example from the NTP daemon.
On the other hand System.nanoTime()
is a value that increases by 109 every second, irrespective of any adjustments to the system clock.
Whenever there is such an adjustment, you will get a divergence between NanoClock
, which calls System.currentTimeMillis()
once and stores its result, and something which calls System.currentTimeMillis()
each time, like new Date()
.
NanoClock
is buggy.
System.currentTimeMillis()
returns X
while the current time is X milliseconds + Y microseconds + Z nanoseconds
.
So EPOCH_NANOS
is Y microseconds + Z nanoseconds
before the correct epoch.
Note that System.nanoTime()
provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes).
From Java 9 onwards, Instant.now()
gives you the current system time with nanosecond precision (but not nanosecond resolution).
Upvotes: 3
Reputation: 40057
This may be a naive test, but how are you going to adjust for accuracy when subsequent calls take inconsistent times well below your expected precision requirements. The values change per run. The first can probably be ignored for startup time.
long[] times = new long[20];
times[0] = System.nanoTime();
times[1] = System.nanoTime();
times[2] = System.nanoTime();
times[3] = System.nanoTime();
times[4] = System.nanoTime();
times[5] = System.nanoTime();
times[6] = System.nanoTime();
times[7] = System.nanoTime();
times[8] = System.nanoTime();
times[9] = System.nanoTime();
times[10] = System.nanoTime();
times[11] = System.nanoTime();
times[12] = System.nanoTime();
times[13] = System.nanoTime();
times[14] = System.nanoTime();
times[15] = System.nanoTime();
times[16] = System.nanoTime();
times[17] = System.nanoTime();
times[18] = System.nanoTime();
times[19] = System.nanoTime();
for (int i = 0; i < times.length; i+=2) {
System.out.println(times[i+1] - times[i]);
}
prints
200
100
100
0
0
0
0
0
0
100
Upvotes: 0
Reputation: 28099
I don't think you fully understand how milliseconds / nanoseconds work in the jvm.
You can only compare two System.nanoTime()
values to see how many nanoseconds have elapsed. You can't use them to construct Date
or Instant
instances.
The following is not valid
private static final long EPOCH_NANOS = System.currentTimeMillis()*1000000;
The result of this multiplication might exceed Long.MAX_VALUE
Please explain what you are trying to achieve as I feel this might be an X/Y problem. For instance you might be able to create a StopWatch
class based on System.nanoTime()
to achieve your goal.
Upvotes: 1