为什么新的Java 8日期时间API没有纳秒精度?

76

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月2日12:33:26.746134417+0100

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


2
Java 9中已经修复。Clock的全新实现可以以纳秒分辨率(取决于您主机硬件时钟的能力)捕获当前时刻。 - Basil Bourque
2个回答

106
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()。您可以潜在地创建自己的更准确的子类。但是,您应该注意,如果不增加更多的准确性,增加更多的精度可能并不是非常有用。(当然,有时候可能会有用...)

8
最后一部分尤为重要。nanosleep(2)在标准消费级硬件上存在类似问题,因为精确休眠一定纳秒数会产生约1个 CPU 周期的误差,这在抢占式多任务环境下无法实现。但是,如果您只需要按照相对顺序安排各种事件并不关心它们之间的精确间隔,则高水平的精度可能很有用。我假设时钟单调递增,希望这是正确的。 - Kevin

60
为了补充Jon Skeet的答案,Java 9应该提供一个精度更高的时钟 - 请参见bug日志。 背景:在许多操作系统(特别是Linux)上,有更好的时钟可用。

Java SE 8规范的java.time.Clock指出:“系统工厂方法提供基于最佳可用系统时钟的时钟。这可能使用System.currentTimeMillis(),或者如果有更高分辨率时钟,则使用更高分辨率时钟。” 在JDK 8中,返回的时钟实现基于System.currentTimeMillis(),因此仅具有毫秒级分辨率。在JDK 9中,实现基于System.currentTimeMillis()使用的底层本机时钟,提供该时钟可用的最大分辨率。在大多数系统上,这可以是微秒,甚至是十分之一微秒。

因此,假设这些系统工厂方法返回的时钟始终具有毫秒级精度并且积极依赖它的应用程序可能需要进行更新,以考虑更高分辨率的可能性,如API文档中所述。

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


第二精度在闰秒附近不存在的更多信息是什么?那是因为有多种实现方法(例如跃迁涂抹)吗? - Thunderforge
7
ChronoUnit.SECONDS.between(instant1, instant2)这样的表达式永远无法计算闰秒。 java.time 的设计者们决定隐藏闰秒,并假装每分钟都由60秒组成。他们的规范正式规定了UTC-SLS,并且JDK中的实际实现类似于POSIX而不是UTC-SLS——简单地忽略闰秒。所有已知的操作系统时钟(作为Clock.systemUTC()的基础)行为相同或应用某种形式的时钟重置或闰秒涂抹。SI秒并未建模。如果您真正寻求真正的闰秒支持,请考虑我的库Time4J。 - Meno Hochschild

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接