处理闰秒的正确方法

3
在闰秒前和闰秒期间,调用new Date()似乎会返回23:59:59两次(一次在闰秒之前,一次在闰秒期间),而不是23:59:59和23:59:60。
除了在应用程序中实现NTP客户端或检查时钟是否向后或重复自己之外,有没有一种方法可以确定一个给定的秒是闰秒还是非闰秒,以便正确地向用户呈现23:59:60?
同样地,主机操作系统是否有任何钩子来确定其是否为闰秒之前或之后?

Java SE 8在此处清晰地定义了闰秒行为:https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html - le3th4x0rbot
我认为像“闰秒平滑”这样的技术并不符合闰秒的正确表示,但在服务器/数据库环境中,这绝对是处理闰秒的有效方法:https://dev59.com/Z3jZa4cB1Zd3GeqPhLNa#19756183 - Sandman
2个回答

8

让我们来看看java.util.Date的源代码:

public Date() {
    this(System.currentTimeMillis());
}

所以问题可以理解为: System.currentTimeMillis()会产生闰秒值60甚至61吗(如规范所述)?
严格来说,答案取决于底层操作系统。但事实是:所有众所周知的操作系统,如Windows、Linux、Apple、Android都对闰秒不闻不问。相反,这些操作系统在任何时间进行任何时钟操作(回拨等,与NTP服务器同步...)。因此,您将无法使用Date-API观察到闰秒。顺便说一句,值61是不可能的,因为UTC标准规定UTC永远不会比UT1偏差超过0.9秒,导致不会插入双闰秒。
“61”的起源只是早期POSIX规范的一个严重误解(现在已经纠正了这个错误)。不幸的是,旧的Java规范尚未得到修正,直到现在仍然存在误解。 关于Java-8:

是的,所谓的“Java时间刻度”正式指定为UTC-SLS,基于一个已过期的提案,其目的更多是针对NTP服务器的内部实现。在现实世界中不存在任何UTC-SLS的实现。即使Java-8也没有实现UTC-SLS。两个事实证明了这一说法:

  • Java-8不包含闰秒表(这将是任何UTC-SLS实现的基础)。 Threeten项目最初拥有这样一个表,但已被删除(现在也从后备中删除)。

  • java.util.DateInstant的转换只是1:1(请参见源代码-不考虑不同精度的毫秒与纳秒)。请注意,关于所谓的“Java时间刻度”,java.util.Date未在Instant的API中提到。

Java时间刻度用于所有日期时间类。 这包括 Instant,LocalDate,LocalTime,OffsetDateTime,ZonedDateTime和 Duration。

此外: java.util.Date 的起源可以追溯到1995年(Java发明时),但 UTC-SLS 是几年后提出的。
那么在Java-8中剩下什么作为闰秒支持?规范中的空话引起了很多混乱,除此之外没有别的。
你还能做什么?在JDK范围内根本无法做任何事情。您需要一个带有内置闰秒数据的外部第三方库。例如我的库Time4J-请参阅此 article。另一个选择可能是Threeten-Extra库和它的类UTCInstant。但我没有测试它是否能够转换为java.util.Date(似乎有问题?)。

2
根据Java8 Date类的文档,在闰秒期间调用Date将正确返回:60或:61。
所以你不需要做任何事情。
然而,它是如何实现的还是有点神秘的,因为底层的Instant类将闰秒分散在当天的最后1000秒内 - 因此这些最后的秒实际上会变成1.001秒长 - 并且你的应用程序无法知道它是否处于闰秒中。

1
据我所知,java.time.Instant类与java.util.Date没有任何关联。请留意包名。前者是全新的Java 8日期时间API框架中的类。而后者非常古老,来自Java的第一个版本。Date类有一些方便的转换方法可以用来处理Instant实例,但它们的代码基础完全不同。 - Basil Bourque

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