【问题标题】:How to get current time in nano seconds in java?如何在java中以纳秒为单位获取当前时间?
【发布时间】:2019-02-04 05:20:03
【问题描述】:

我做了很多研究,但没有找到任何好的答案。 我想在一纳秒内获得当前的日期和时间。 我发现System.nanoTime() 将提供纳秒,但那是系统经过的时间。意味着它将提供系统启动的时间。我需要以纳秒为单位使用当前日期和时间。

我需要这个来避免 InfluxDB 中的点重复,请参阅How does InfluxDB handle duplicate points? 所以当我使用毫秒时,我面临数据联合的问题。所以需要决定使用纳秒,但问题是使用System.nanoTime() 生成的纳秒不包含当前日期和时间数据。它给了我 JVM 正常运行时间,这对我来说毫无用处。

【问题讨论】:

  • 您真的认为您计算机的系统时钟是纳米级精度的吗?
  • @JackFlamp 可能是当前时间,精确到纳秒。
  • @Jack Flamp 意思是说你的 JVM 已经运行了 1 天。当您使用此方法获得纳秒级时,这将为您提供仅纳秒级的 JVM 正常运行时间。
  • @Pavel 是的,我很好奇,我真的很想知道。

标签: java datetime influxdb


【解决方案1】:

理论上,可以将当前时间精确到纳秒,如下:

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

问题:

  1. systemDefaultZone() 调用为平台提供“最佳可用时钟”。 JVM 规范说这可能具有优于毫秒的精度,但这并不能保证。所以nano 值的精度可能不超过毫秒。

  2. seconds 和 nano 的值取决于本地硬件时钟的精度。在许多系统上,保持本地时钟与“实时”时间同步是很困难的。通常,亚毫秒级的精度具有挑战性,而表面上的纳秒精度是一种错觉。

  3. 即使您已设法将硬件时钟以“实时”时间同步到纳秒精度,在进行上述调用以获取纪元纳秒时间时的开销和可变性也会破坏纳秒精度。 (例如内存缓存的可变性、主内存总线的繁忙程度等。以及自上次同步以来本地硬件时钟的漂移。)

实际上,在大多数系统上,纳秒级精度是无法实现的,因此您需要避免依赖于此的设计/算法。

【讨论】:

  • 除非我遗漏了什么,否则这不能提供比毫秒精度更好的东西,因为Clock.systemDefaultZone() 返回一个java.time.Clock.SystemClock,而SytemClock.instant() 实现为return Instant.ofEpochMilli(millis())。您确实会得到一个编码微秒和纳秒的值,但它们始终为零。
  • 我正在查看 OpenJDK 11 源代码,但它没有这样做。它实际上正在从操作系统获得纳秒级的调整。显然,Clock.systemDefaultZone() 返回的时钟行为取决于平台。 javadocs 不做任何承诺。
  • 我想知道 Ole V.V.下面可以得到微秒级的精度,不同的 JDK 会解释它。我正在使用 Oracle JDK 1.8.0_181,并且只能获得毫秒精度。有趣,感谢您的检查。
【解决方案2】:

最后,感谢 Franz Wilhelmstötter 先生

我找到了一种解决方案。使用http://jenetics.io/ 和 班级电话NanoClock.java 正在转换并执行Stephen C 建议的相同技巧。我想分享这个,因为它对其他人也有用。我无法确认给出了精确的纳米时间,但这个技巧对我有用。 @Ole V.V.再次感谢您的帮助。

【讨论】:

  • NanoClock 中的想法是记录一次真实世界时间和System.nanos() 之间的偏移量,然后使用System.nanos() 和偏移量生成当前时间,单位为纳秒。好想,我希望它能给你一个很好的准确性。在我的电脑上,它的精度似乎在 100 纳秒左右,而且我不可能两次获得相同的时间。不过,这并不能保证。感谢您报告您的发现。
【解决方案3】:

您可以从Instant.now() 获得 Java 可以为您提供的最佳准确度和精度。这是否足以解决你的问题,我不敢说。当然在普通计算机上是无法达到纳秒级精度的。

如果Instant.now() 两次返回相同的值,您可能需要通过添加人工纳秒来玩一些技巧。

或者简单的使用your link中提到的技巧:

引入任意新标签以强制唯一性。

对于添加人工纳秒的技巧,您可以使用以下内容:

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;
    }
}

当我在计算机上从这门课中快速连续绘制时间时,我得到如下结果。从输出来看(我解释它的方式):

  • 我的 JVM 无法从系统时钟获得比微秒(秒为 6 位小数)更高的精度。
  • 不时添加人工纳秒以保持瞬间的独特性。

.

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

【讨论】:

  • “您可能需要通过添加人工纳秒来玩一些技巧”,这听起来很有趣。我会尝试更新你。
猜你喜欢
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 2017-11-29
  • 1970-01-01
  • 2016-07-04
  • 2017-04-25
  • 1970-01-01
相关资源
最近更新 更多