【问题标题】:Why does the new Java 8 Date Time API not have nanosecond precision? [duplicate]为什么新的 Java 8 日期时间 API 没有纳秒精度? [复制]
【发布时间】:2016-02-02 08:10:52
【问题描述】:

Java 8 中新的日期时间 API 的特性之一应该是纳秒精度。但是,当我像这样将当前日期时间打印到控制台时

DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("yyyy-MM-dd'T'HH:mm:ss,nnnnnnnnnZ");
System.out.println(OffsetDateTime.now().format(formatter)); 

我只看到毫秒精度:2015-11-02T12:33:26,746000000+0100

操作系统似乎确实支持纳秒精度。当我通过终端打印当前日期时间时

date -Ins

我看到 2015-11-02T12:33:26,746134417+0100

如何在 Java 中获得纳秒精度?我在 Ubuntu 14.04 64 位上运行 Oracle Java 1.8.0_66

【问题讨论】:

  • 在 Java 9 中修复。Clock 中的A fresh implementation 以高达纳秒的分辨率捕获当前时刻(取决于主机硬件时钟的能力)。

标签: java java-8 java-time


【解决方案1】:

java.time API 通常确实具有纳秒精度。例如:

DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("yyyy-MM-dd'T'HH:mm:ss,nnnnnnnnnZ");
OffsetDateTime odt = OffsetDateTime.of(2015, 11, 2, 12, 38, 0, 123456789, ZoneOffset.UTC);
System.out.println(odt.format(formatter));

输出:

2015-11-02T12:38:00,123456789+0000

但是,OffsetDateTime.now() 返回的时钟值是一个只有毫秒的值。

来自 Java 8 中的 Clock 实现:

这里提供的时钟实现基于System.currentTimeMillis()。该方法几乎不能保证时钟的准确性。需要更精确时钟的应用程序必须使用不同的外部时钟(例如 NTP 服务器)自己实现这个抽象类。

所以这里没有什么不精确的地方——只是使用System.currentTimeMillis()Clock 的默认实现。您可能会创建自己的更精确的子类。但是,您应该注意,在不增加 accuracy 的情况下增加更多的精度可能并不是非常有用。 (诚​​然,有时可能会......)

【讨论】:

  • 最后一点尤其重要。 nanosleep(2) 在标准的消费级硬件上也有类似的问题,因为睡眠精确的纳秒数会导致约 1 个 CPU 周期的误差线,这在抢占式多任务环境中实际上无法完成。尽管如此,如果您只需要对相对于彼此的各种事件进行排序并且不关心它们之间的精确间隔,那么高精度可能会很有用。我假设时钟是单调递增的,我希望是真的。
【解决方案2】:

为了对 Jon Skeet 的回答做出重要补充,Java 9 应该提供更高精确度的时钟 - 请参阅 the bug log。背景:在许多操作系统(尤其是 Linux)上,都有更好的时钟可用。

java.time.Clock 的 Java SE 8 规范声明“The 系统工厂方法提供基于最佳可用的时钟
系统时钟。这可能使用 System.currentTimeMillis() 或更高版本 分辨率时钟(如果可用)。”。在 JDK 8 中实现
返回的时钟基于 System.currentTimeMillis(),并且 因此只有毫秒的分辨率。在 JDK 9 中,实现
是基于底层的本机时钟 System.currentTimeMillis() 正在使用,提供最大分辨率 从那个时钟可用。在大多数系统上,这可能是微秒, 有时甚至是十分之一微秒。

一个应用程序假设时钟由这些返回 系统工厂方法将始终具有毫秒精度,并且 积极依赖它,因此可能需要更新以 考虑到更大分辨率的可能性,就像以前一样
在 API 文档中说明。

还应该注意一个(奇异的)事实,即在闰秒附近不存在秒精度 - 即使在 Java 9 中也不存在。

【讨论】:

  • 是否有更多关于为什么在闰秒附近不存在秒精度的信息?那是因为有multiple ways to implement them(例如闰涂片)吗?
  • @Thunderforge 像ChronoUnit.SECONDS.between(instant1, instant2) 这样的表达式永远无法计算闰秒。 java.time-designers 决定隐藏闰秒并假装每分钟包含 60 秒。他们的规范正式规定了 UTC-SLS,而 JDK 中的真正实现实际上类似于 POSIX 而不是 UTC-SLS——只是忽略了闰秒。所有已知的操作系统时钟(作为Clock.systemUTC() 的基础,其行为方式相同或应用某种时钟重置或闰秒涂抹。SI 秒未建模。如果您认真寻找真正的闰秒支持,请考虑我的 lib Time4J。
猜你喜欢
  • 2015-07-20
  • 2015-02-27
  • 2021-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-13
  • 2013-07-05
  • 1970-01-01
相关资源
最近更新 更多