英文:
Instant.now(new NanoClock()) returns incorrect time
问题
我们有一段代码,我们正在使用NanoClock来获取精确时间。简而言之,以下是我生成纳秒时间和将其转换为简单日期格式的代码片段。问题是,纳秒时间(在某些情况下)偏差几秒。例如,系统时间是12:23:44.125,纳秒时间将是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);
}
我们正在如下使用NanoClock:
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);
我们在生产环境中运行了这段代码超过5年,一直都没问题。自从过去两个月以来,它开始出现这种不一致性。我们使用的是Java 8更新71(64位),在过去的4-5个月里,系统与Java或我的代码方面都没有发生任何变化。
英文:
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.
答案1
得分: 3
以下是翻译好的内容:
-
The discrepancy is due to system clock drift.
- 差异是由系统时钟漂移引起的。
-
System.currentTimeMillis()
is vulnerable to adjustments in the system clock, for example from the NTP daemon.System.currentTimeMillis()
受系统时钟调整的影响,例如来自NTP守护程序。
-
On the other hand
System.nanoTime()
is a value that increases by 109 every second, irrespective of any adjustments to the system clock.- 另一方面,
System.nanoTime()
是一个值,每秒都会增加109,不受系统时钟调整的影响。
- 另一方面,
-
Whenever there is such an adjustment, you will get a divergence between
NanoClock
, which callsSystem.currentTimeMillis()
once and stores its result, and something which callsSystem.currentTimeMillis()
each time, likenew Date()
.- 每当出现这种调整时,
NanoClock
调用System.currentTimeMillis()
一次并存储其结果,而像new Date()
这样每次都调用System.currentTimeMillis()
的东西之间会出现差异。
- 每当出现这种调整时,
-
NanoClock
is buggy.NanoClock
有缺陷。
-
System.currentTimeMillis()
returnsX
while the current time isX milliseconds + Y microseconds + Z nanoseconds
.System.currentTimeMillis()
返回X
,而当前时间是X 毫秒 + Y 微秒 + Z 纳秒
。
-
So
EPOCH_NANOS
isY microseconds + Z nanoseconds
before the correct epoch.- 因此,
EPOCH_NANOS
在正确的纪元之前是Y 微秒 + Z 纳秒
。
- 因此,
-
Note that
System.nanoTime()
provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes).- 请注意,
System.nanoTime()
提供纳秒精度,但不一定提供纳秒分辨率(即值更改的频率)。
- 请注意,
-
From Java 9 onwards,
Instant.now()
gives you the current system time with nanosecond precision (but not nanosecond resolution).- 从Java 9开始,
Instant.now()
提供具有纳秒精度的当前系统时间(但不提供纳秒分辨率)。
- 从Java 9开始,
英文:
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 10<sup>9</sup> 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).
答案2
得分: 1
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.
英文:
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.
答案3
得分: 0
这可能是一个天真的测试,但在后续调用中所需时间明显低于您的预期精度要求时,您将如何调整以确保准确性?这些值每次运行都会更改。可以考虑忽略启动时间。
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]);
}
打印结果:
200
100
100
0
0
0
0
0
0
100
英文:
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
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论