如何在Java 7中获取国际原子时



我正在做一个Java7项目,我们需要一个国际原子时间的时间戳。我发现了一些与此相关的其他问题,这些问题指向JSR-310和ThreeTen项目(正在实现JSR-310):

如何在Java中获取GPS时间和TAI时间?

http://www.coderanch.com/t/549178/java/java/TAI-Atomic-Time-International

然而,我正在努力弄清楚Java 7到底该用什么以及从哪里获得它。似乎有旧的SourceForge&ThreeTen的GitHub页面,以及一个OpenJDK页面。

我已经找到了Java 7后台端口,但从Maven下载后,它不包括TAIInstant类,这正是我真正需要的(TIAInstant类列在ThreeTen SourceForge JavaDoc上的javax.time.TAIInstant下)

为了完整起见,这是我的pom.xml的摘录:

<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
<version>0.8.1</version>
</dependency>

我应该使用其他东西吗?我应该从哪里得到它?

注意:很抱歉,我无法提供我所指的所有页面的链接,StackOverflow不会让我在没有更高代表的情况下每篇文章有2个以上的链接。

[EDIT]想要TAI的原因是我需要一个单调递增的时间戳,我相信TAI可以实现这一点(即使在正闰秒和负闰秒期间,因为它不在乎闰秒平等地计算所有秒,包括闰秒)。

在从各种来源阅读了POSIX/Unix时间之后,我仍然不清楚Unix时间在闰秒内到底发生了什么。我知道Unix时间在指UTC时间方面是模糊的,但我不清楚在闰秒发生的那一刻,Unix时间会发生什么?例如,Unix时间是"暂停"还是倒退?也许更重要的是,即使它不应该符合Unix时间规范,Unix实现真的遵守关于闰秒的规范吗。。。?

最后,我说System.currentTimeMillis()将获得相当于POSIX时间的值(尽管单位是毫秒而不是秒),这是正确的吗?

注意,我需要一个可在JVM和机器之间移植的对象(排除System.nanoTime()或类似的对象)。

[结论]

TAI
TAI是一种测量时间的系统,其中每一秒都被计算在内,并且"所有秒都相等",即每一秒由相同的时间段组成,所有秒(包括闰秒)都被计算在总数中。这意味着TAI中的秒数(从某个任意起点开始计数,例如Unix Epoch)是一个单调递增的整数。

POSIX时间
POSIX时间是测量时间的标准(而非实现)。它将每天定义为正好有86400秒。因此,POSIX时间不计算闰秒(因为偶尔一分钟可能有61秒,导致天数>86400秒,理论上一分钟可能会有59秒,导致日期<86400秒)。这意味着POSIX中的"秒"长度可变,在闰秒之前/期间/之后不久,POSIX时钟可能会跳过秒或重复秒。具体来说,Meno Hochschild在回答中提到的POSIX规范指出,"自大纪元以来,一天中的实际时间和当前秒数之间的关系是未指明的。">

UTC
UTC是一种与地球绕太阳运行方式有关的时间标准,旨在保持太阳位置与一天中时间之间的关系(在阈值内)。即在地球的UTC+0区域,太阳总是在UTC时间中午处于最高点。闰秒(正闰秒或负闰秒)是必要的,因为地球自转的速度不是固定的,也不会以可预测的方式变化(这意味着我们无法预测何时需要闰秒,或者闰秒是正闰秒还是负闰秒。)

表示时间
在我看来,TAI和POSIX都是"秒数"的表示(即计算机易于实际存储的东西),而UTC是时间的"人工解释"(即年/月/日小时:分钟:秒.毫秒),通常不由计算机内部存储。

翻译时间
鉴于上述情况,从POSIX(不计算任何闰秒)翻译到TAI(计算闰秒)存在许多问题:

  1. 它需要维护一个表/闰秒计数来将任何POSIX时间转换为TAI时间
  2. 即使第1点得到了解决,上述POSIX规范也不能保证在闰秒期间会发生什么,因此在这种情况下,我们无法准确表示明确的时间
  3. 如果许多系统必须进行通信,并在它们之间传递时间戳,我们必须保证闰秒表/计数保持一致

另一方面,从POSIX转换为UTC"人类解释"很容易。它不需要闰秒的知识,因为它只是假设每天都有相同的秒数(尽管这些"秒"中的一些在现实中有不同的时间长度)。在实践中,您只需使用POSIX规范中公式的倒数来获得时间的各种UTC分量(再次参见Meno Hochschild引用的POSIX规范)。

TAIInstant和其他类似UTCInstant的类在JSR-310过程中被删除。该小组得出的结论是,这些都是专业项目,不需要在核心JDK中。我仍然相信这是一个正确的决定。

这样做的结果是JSR-310中对时间尺度的支持非常少。然而,有一种正式定义的方法可以将JSR-310连接到时间刻度,允许在给定准确源的情况下创建准确的时钟。虽然不是每个人都喜欢这个解决方案,但它对主流来说是实用的。

总之,UTC和TAI的单独类的原始设计是合理的(并且对于处理过去和将来的事件是必要的)。然而,对于JDK来说,它太专业了。

额外的threeten项目现在可以作为JDK8的jar使用,这些类在.中

JSR-310-backport只支持Java 8中包含的功能。TAI(和真正的UTC)将不受支持,因此它不能在后台端口中。唯一的选择是尝试包含TAIInstant类的threeten额外项目,但整个额外项目可能不是最新的(非常旧的代码)。

我自己正在开发我的图书馆Time4J,除了POSIX之外,它还支持TAI、GPS和UTC。

[2014年7月更新:Time4J现在可以作为稳定版本的Time4J-v1.0使用。这个争论已经被考虑在内了——例如Moment.toString(TimeScale).]


对新发布的OP问题的更正和详细备注:

a) 是的,即使在闰秒期间,TAI也以SI秒为单位单调增加。如果只是你想要的,你可以选择TAI,但这是一个陷阱。如果你想描述民用时间戳,那么TAI会给你错误的时间戳(只需比较维基百科图表的第一列和第二列)。原因很简单,公民生活是由UTC而不是TAI统治的。

b) 关于我对维基百科图表错误的评论,我再次仔细地看了一遍,并改变了主意。POSIX和TAI之间的关系不是固定的(1972年才偏移10秒),所以请原谅我的错误。到目前为止,我还没有考虑太多关于TAI,而是关于POSIX和UTC。但谢谢你的提问和这场富有启发性的辩论,所以你值得我投赞成票。整件事很棘手。当我们谈论以不同时间尺度表示的时间戳时,我们需要区分ymdhms形式和划时代形式。让我们详细考虑一下时间1999-01-01T00:00:00Z(UTC刻度):

i) TAI = (29 * 365 + 7) days * 86400 + 22 leap seconds + 10s (offset at 1972) = 915148832
ii) UTC = TAI - 10 = 915148822 (fixed relation between UTC and TAI on epoch-second-level)
iii) POSIX = UTC - 22 leap seconds = 915148800
=> (ymdhms-form);
i) TAI (915148800 + 32) = 1999-01-01T00:00:32 (based on TAI-"day" = 86400 SI-secs)
ii) UTC = 1999-01-01T00:00:00 (stripped off former 22 leap secs in conversion to ymdhms)
iii) POSIX = 1999-01-01T00:00:00 (fixed relation between UTC and POSIX with exception of leapsecs)

那么,为什么TAI不计算闰秒呢?它不计算ymdhms形式的leapsecs,但当然它在epoch第二级计算它们(单调性要求!)。POSIX呢?它根本不计算闰秒,无论是ymdhms形式还是epoch-secs级别的neiter。所以最后我们在TAI和POSIX之间没有固定的关系。转换需要闰秒表。

c) POSIX规范对闰秒行为有何说明?请参见此处。特别要注意的是:"一天中的实际时间和大纪元以来的当前秒数之间的关系是未指明的。"因此,这也涉及闰秒。如果它们在闰秒之前跳转、在闰秒之后跳转或冻结一秒,则取决于时钟实现。

d) 是的,System.currentTimeMillis()将获得相当于POSIX时间的值(尽管单位是毫秒而不是秒)。

e) 需要注意的是,TAI这个标签在1971年之前没有定义,国际原子时在1958年之前也没有定义,所以"三个十级额外的TAIInstant"这个令人怀疑的尺度在某种程度上是无稽之谈。所以我不会在1972年之前申请TAI。在这里,我和史蒂夫·艾伦,时间尺度的专家。

f) 如果您需要一个"可在JVM和机器之间移植"的时间对象,那么UTC本身就需要到处分布/存在相同的闰秒表。如果您选择TAI,您仍然需要这个闰秒表,以便应用程序能够将TAI时间戳转换为UTC或POSIX时间戳。所以我怀疑你是否可以有一个单调增加的时间戳,同时忽略闰秒。TAI并没有为这一困境提供解决方案。

2013-12-31年度OP问题/总结答案:

您对TAI和POSIX的总结是正确的。

关于UTC,您首先应该明白UTC是一种妥协。一方面,它被设计为跟随太阳,另一方面,UTC刻度的秒与TAI刻度的秒完全相同,即SI秒(原子定义)。当你说地球自转速度正在不可控制地减慢时,你是对的,所以闰秒被插入了几次。UT1(平均太阳时)和UTC之间的差值应始终小于0.9 SI秒。因此,这一点和SI秒相等的事实是UTC的核心思想。顺便说一句,JSR-310中对奇异的UTC-SLS规模的改编与UTC的这些核心思想不兼容。关于闰秒的可预测性,巴黎的BIPM每半年宣布一次,6个月后是否需要闰秒,所以你提前6个月就有了这个可预测性框架。

关于UTC部分的一个可能是迂腐的更正,你写道:"太阳总是在UTC时间中午时处于最高点。"关于所谓的java时间尺度,java.time.Instant类的javadoc中也给出了类似的语句。抛开事实不谈,你肯定不想说太阳的位置独立于你当地的位置,它甚至在中午的正确经度上都不正确。为什么?从天文学/科学的角度来看,你首先不应该忘记,平均太阳太阳时间与你观看的真实当地太阳时间不同(只需给出关键词"时间方程")。此外,由于UTC仍然以原子时间为基础,并使用原子时间进行同步,因此UT1和UTC之间存在所谓的delta-T-relation。这个德尔塔在0.9秒的范围内,由IERS/BIPM定期在公告B中发布。当你想获得太阳的真实位置和太阳最高的时候,你需要知道这个德尔塔。

"代表时代"一节在我看来有点过于简单。好吧,我们可以说TAI和POSIX以秒为单位,而UTC则以年/月/日/…表示-形式。但我们确实可以将这两种表示应用于所有尺度。但我们需要仔细区分这些表示,并彻底思考如何转换。请注意,维基百科甚至在图表中为TAI选择了ymdhms形式。计算机可以最好地存储简单的整数。POSIX或TAI可以很容易地以这种格式存储。但正如我之前所说,对这些整数的解释并不总是简单的。在TAI的情况下,您甚至需要一个闰秒表来转换为可读的民用ymdhms形式(UTC或POSIX)。

关于下一节"翻译时代",我同意第1-3点。

你的最后一句话"另一方面,从POSIX转换为UTC‘人类解释’很容易"是正确的,闰秒除外。好吧,随着我即将到来的图书馆,我可以在不同的尺度之间进行适当的翻译。它有一个内置但可配置的闰秒表,将来我还计划使用IANATZDB数据作为这样一个表的源。

总而言之,请注意,大多数业务开发人员不需要那么多准确性。大多数人会简单地均衡POSIX和UTC,并可能对Linux操作系统或谷歌NTP服务器上的任何平滑硬件解决方案感到满意。真正的UTC和TAI(考虑闰秒)需要付出更多的努力。所以你必须决定你的软件架构是否需要科学的准确性。

需要注意的是,JSR-310官方根本没有解决非常广泛的POSIX,相反,他们说,根据定义,他们的类Instant应该是UTC-SLS(另请参阅这场有趣的辩论)。

最后,我很荣幸参加这次讨论。这也帮助我在图书馆里澄清了我对TAI的看法。谢谢

相关内容

  • 没有找到相关文章

最新更新