java - 如何在Java 7中获得国际原子时间

标签 java time java-7 java-time tai-time

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

How to get GPS Time and TAI time in Java?

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

但是,我在努力弄清楚Java 7的使用方法以及从何处获取它。似乎有用于ThreeTen的旧SourceForge和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个以上的链接。

[编辑]
想要TAI的原因是我需要一个单调增加的时间戳,我相信TAI会满足要求(即使在正向和负向leap秒中也是如此,因为它并不关心leap秒将所有秒均等地计入在内,包括leap秒)。

从各种来源了解了POSIX/Unix时间后,我仍然不清楚在Unix Time发生了a秒之后究竟发生了什么。我知道Unix时间在提及UTC时间方面是模棱两可的,但是我不清楚在Time秒发生的瞬间Unix时间会发生什么?例如,Unix时间是“暂停”还是倒退?也许更重要的是,即使不符合Unix Time规范,Unix实现实际上也遵守有关leap秒的规范吗?

最后,我是否正确地说System.currentTimeMillis()将获得POSIX时间的等效值(尽管以毫秒为单位,而不是秒)?

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

[结论]

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

POSIX时间
POSIX时间是用于测量时间的标准(不是实现方式)。它定义的每一天都具有精确的86400秒。因此,POSIX时间不算leap秒(因为一分钟可能会有61秒,导致几天大于86400秒,理论上一分钟可能有59秒,导致几天小于86400秒)。这意味着POSIX中的“秒”具有可变的长度,并且在leap秒之前/期间/之后不久,POSIX时钟可能会跳过秒或重复秒。具体地说,Meno Hochschild在其答案中引用的POSIX规范指出:“未指定一天中的实际时间与自Epoch以来的秒数的当前值之间的关系。”

UTC
UTC是一个时间标准,与地球绕太阳运动的方式有关,旨在维持太阳位置与一天中的时间(在阈值之内)之间的关系。也就是说,在地球的UTC + 0区域中,太阳始终在UTC中午时间处于最高位置。 ap秒(正数或负数)是必需的,因为地球自转的速度不是固定的,并且不会以可预测的方式变化(这意味着我们无法预测何时需要leap秒,或者它们是否将是正leap秒或负leap秒)

表示时间
在我看来,TAI和POSIX都是“秒数”的表示(即,计算机可以轻松存储的某种形式),而UTC是时间的“人为解释”(即,年/月/日小时: Minute:Second.Millisecond),通常不由计算机内部存储。

翻译时间
鉴于以上所述,从POSIX(不计算任何leap秒)到TAI(已计算leap秒)存在许多问题:
  • 它需要维护一个表/of秒数,才能将任何POSIX时间转换为TAI时间
  • 即使解决了第1点问题,上述POSIX规范也无法保证a秒内会发生什么,因此在这种情况下,我们无法准确表示明确的时间
  • 如果许多系统必须进行通信,并在它们之间传递时间戳,则必须保证leap秒表/计数保持一致

  • 另一方面,很容易将POSIX转换为UTC的“人工解释”。它不需要knowledge秒的知识,因为它只是假设每一天都有相同的秒数(尽管其中某些“秒”实际上有不同的时间长度)。实际上,您只需要使用POSIX规范中公式的逆函数即可获得各种UTC时间分量(同样,请参见Meno Hochschild引用的POSIX规范)。

    最佳答案

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

    我自己在自己的图书馆Time4J上工作,该图书馆除了POSIX还支持TAI,GPS和UTC。

    [,自2014年7月起更新:Time4J现在可作为稳定版本time4j-v1.0提供。已经考虑了该辩论-例如参见Moment.toString(TimeScale) 。]

    对新发布的OP问题的更正和详细说明:

    a)是的,即使在leap秒内,TAI也以SI秒为单位单调增加。如果仅是您想要的,则可以选择TAI,但有一个陷阱。如果要描述民用时间戳记,那么TAI会给您错误的时间戳记(只需比较Wikipedia diagram的第一列和第二列)。原因很简单,公民生活是由UTC而不是TAI统治的。

    b)关于我对Wikipedia图是错误的评论,我再次仔细查看了一下,改变了主意。 POSIX和TAI之间的关系不是固定的(仅在1972年偏移了10s),所以请原谅我的错误。到现在为止,我对TAI的了解还不够,而对POSIX和UTC的了解却不多。但是,感谢您提出的问题和富有启发性的辩论,所以您值得我的支持。整个过程很棘手。当我们讨论以不同时标表示的时间戳时,我们需要在ymdhms形式和epochsecs形式之间进行区别。让我们详细考虑一下时间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不算leap秒的说法呢?它不会以ymdhms形式计算leap秒,但当然会以纪元秒级别计算它们(单调性要求!)。和POSIX?它根本不计算leap秒,以ymdhms形式或以epoch-secs级别为单位。因此,最后我们在TAI和POSIX之间没有固定的关系。转换需要。秒表。

    c)POSIX规范对leap秒性能有何启示?参见here。尤其要注意以下语句:“未指定自大纪元以来,一天中的实际时间与秒数的当前值之间的关系。”因此,这也涉及the秒。如果它们在the秒之前跳转,在after秒之后跳转或卡住一秒钟,则由时钟实现决定。

    d)是,System.currentTimeMillis()将获得POSIX Time的等效值(尽管以毫秒为单位,而不是秒)。

    e)请注意,TAI标签在1971年之前没有定义,国际原子时间在1958年之前也没有定义,因此,三十父类(super class)TAIInstant的多用表在某种程度上是胡说八道。因此,在1972年之前我不会申请TAI。在这里,我与时标专家Steve Allen一起去。

    f)如果您需要一个“可在JVM和机器之间移植的”时间对象,则UTC本身需要在各处分发/存在相同的leap秒表。如果选择TAI,则仍需要此leap秒表,以使应用程序能够将TAI时间戳转换为UTC或POSIX时间戳。因此,我怀疑您是否可以单调增加时间戳,而同时忽略leap秒。 TAI没有提供解决此难题的方法。

    2013年12月31日以来OP的问题/摘要的答案:

    您有关TAI和POSIX的摘要是正确的。

    关于UTC,您首先应该了解UTC是一种妥协。一方面,它设计为跟随太阳,另一方面,UTC尺度上的第二个与TAI尺度上的完全相同,即SI秒(原子定义)。您说对了,地球转速出乎意料地减速,这是对的,因此插入了leap秒几秒钟。 UT1(平均太阳时间)与UTC之间的时差应始终小于0.9 SI秒。因此,这与SI秒相等是UTC的核心思想。顺便说一句,JSR-310对UTC-SLS量表的适应性与UTC的这些核心思想不兼容。关于leap秒的可预测性,巴黎BIPM每半年会发布一次,如果6个月后是否有必要形成leap秒,那么您将提前6个月来确定此可预测性框架。

    您写道:关于UTC的部分,也许是脚的修正:“太阳总是在UTC的正午时分处于最高点。”在类java.time.Instant的javadoc中也给出了类似的声明,即所谓的java time-scale。抛开事实,您肯定不想说太阳的位置与您的本地位置无关,甚至在正午的正确经度也不正确。为什么?从天文/科学的角度来看,您首先应该不要忘记,平均太阳日照时间与您观看的实际本地太阳时数不一样(只是给出关键字“时间等式”)。此外,由于UTC仍基于原子时间并且使用原子时间进行同步,因此UT1和UTC之间存在所谓的delta-T关系。此增量在0.9sec的范围内,并且由IERS/BIPM定期在公告B中发布。要获取太阳的真实位置以及何时太阳最高,您需要知道此增量。

    我认为“代表时代”这一部分太简单了。好的,我们可以说TAI和POSIX数秒,而UTC则以年/月/日/...-形式表示。但是我们确实可以将这两种表示形式应用于所有比例。但是,我们需要仔细区分这些表示形式,并仔细考虑如何进行转换。请注意,维基百科甚至在图中选择了TAI的ymdhms形式。好吧,计算机可以最好地存储简单的整数。 POSIX或TAI可以很容易地以这种格式存储。但是,正如我之前所说,对这些整数的解释并不总是那么简单。如果使用的是TAI,您甚至需要使用a秒表来转换为可读的民谣形式(UTC或POSIX)。

    关于下一节“翻译时间”,我同意第1-3点。

    您的最终声明“另一方面,很容易将POSIX转换为UTC的“人类解释”。是正确的,但leap秒除外。好吧,我要使用即将到来的库在不同比例之间进行合适的翻译。它具有一个内置但可配置的leap秒表,将来我还计划使用IANA-TZDB数据作为此类表的源。

    总而言之,大多数企业开发人员并不需要如此高的准确性。大多数人会简单地使POSIX和UTC相等,并且可能会对Linux OS或Google NTP服务器上的任何平滑硬件解决方案感到满意。真正的UTC和TAI(考虑了leap秒)需要付出更多的努力。因此,您必须确定您的软件体系结构是否需要科学的准确性。

    需要注意的是,JSR-310正式上根本没有解决扩展范围很广的POSIX,相反,他们说,他们的Instant类在定义上应该是UTC-SLS(另请参见此有趣的debate)。

    最后,我很高兴进行这次讨论。它也帮助我阐明了我对图书馆中TAI的看法。谢谢。

    关于java - 如何在Java 7中获得国际原子时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20746740/

    相关文章:

    ruby-on-rails - 比较两次而不考虑相关日期 - Ruby

    matlab - UTC 时间到字符串的转换

    java - 为什么 2020 年 3 月 30 日和 2020 年 3 月 1 日之间的差值错误地给出了 28 天而不是 29 天?

    java - 为什么 Jsoup 无法连接某些 URL?

    JavaFX - 如何从主方法创建多个窗口?

    java - 在ant中自定义AnsiColorLogger的颜色?

    java - switch 语句不兼容类型

    java - 自定义和不同的 json 日期格式

    Python 时间(以毫秒为单位)

    java - 使用 Java 8 5 天编译用 Java 编写的旧程序