Instant.now(new NanoClock()) 返回不正确的时间。

huangapple go评论62阅读模式
英文:

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

以下是翻译好的内容:

  1. The discrepancy is due to system clock drift.

    • 差异是由系统时钟漂移引起的。
  2. System.currentTimeMillis() is vulnerable to adjustments in the system clock, for example from the NTP daemon.

    • System.currentTimeMillis() 受系统时钟调整的影响,例如来自NTP守护程序。
  3. 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,不受系统时钟调整的影响。
  4. 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 调用 System.currentTimeMillis() 一次并存储其结果,而像 new Date() 这样每次都调用 System.currentTimeMillis() 的东西之间会出现差异。
  5. NanoClock is buggy.

    • NanoClock 有缺陷。
  6. System.currentTimeMillis() returns X while the current time is X milliseconds + Y microseconds + Z nanoseconds.

    • System.currentTimeMillis() 返回 X,而当前时间是 X 毫秒 + Y 微秒 + Z 纳秒
  7. So EPOCH_NANOS is Y microseconds + Z nanoseconds before the correct epoch.

    • 因此,EPOCH_NANOS 在正确的纪元之前是 Y 微秒 + Z 纳秒
  8. Note that System.nanoTime() provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes).

    • 请注意,System.nanoTime() 提供纳秒精度,但不一定提供纳秒分辨率(即值更改的频率)。
  9. From Java 9 onwards, Instant.now() gives you the current system time with nanosecond precision (but not nanosecond resolution).

    • 从Java 9开始,Instant.now() 提供具有纳秒精度的当前系统时间(但不提供纳秒分辨率)。
英文:

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 &lt; times.length; i+=2) {
    System.out.println(times[i+1] - times[i]);
}                                  

prints

200
100
100
0
0
0
0
0
0
100

</details>



huangapple
  • 本文由 发表于 2023年7月4日 21:31:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76613168.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定