考虑到新引入的闰秒,1岁的(java)库如何正确执行UTC时间格式

2022-09-04 03:32:56

自 1.1.1970 UTC 以来以毫秒为单位表示的时间戳是存储时间戳的常用方法,例如在 Java 中。

例如:

long timestampUtc = System.currentTimeMillis();

这样的时间戳可以格式化为人类重新读取时间格式,例如使用此代码

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
    df.setTimeZone(TimeZone.getTimeZone("UTC"));
    String humanTimeUtc = df.format(new Date(timestampUtc));
    System.out.println(humanTimeUtc);

它给出输出:2014-02-14 14:58:05

现在想象一下,今天午夜,政府引入了一个新的UTC闰秒。如果我运行tommorow上面的代码,我的系统上的java JRE无法知道闰秒介绍,并且会错误地格式化时间(一秒钟)。

我的推测是否正确?
如何在不能始终使用最新 JRE 的系统中正确格式化时间(例如在日志文件中)。

背景信息:
这用于嵌入式设备,该设备通过GPS同步其系统时钟,使GPS闰秒数偏移到UTC。


答案 1

Java 和 Unix “epoch”(自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数)都完全忽略了闰秒。他们都假设每天(以UTC为单位)都有86400秒。用于验证的简单代码块:

    Calendar c = Calendar.getInstance();
    c.setTimeZone(TimeZone.getTimeZone("UTC"));
    c.set(2014, 0, 1, 0, 0, 0);
    c.set(Calendar.MILLISECOND, 0);
    System.out.println(c.getTimeInMillis());

您将看到从 1/1/1970 到 1/1/2014 的秒数是 86400 的精确倍数(实际上正好是 44 年 * 365.25 天/年 * 86400 秒/天);它不应该是,因为在这个间隔内引入了25个闰秒。

如果你需要考虑闰秒,你需要找到一个可以做到这一点的库,或者提出自己的调整。


答案 2

闰秒处理很难,Java在这方面并不是特别糟糕。

NTP时间尺度和闰秒解释了一些奇怪之处:

在UTC中插入闰秒并随后在NTP和POSIX中插入闰秒会影响系统时钟,从而影响系统时钟时间和传统民用时间之间的转换(以小时,分钟和秒为单位)。但是,由于可用于确定转换的唯一机构存储器是UTC国家广播服务,因此在接收每个广播时间码时,转换实际上重置为UTC。因此,当在UTC中插入闰秒并随后在NTP或POSIX中插入时,所有先前闰秒的知识都将丢失

另一种描述这一点的方法是说,NTP或POSIX的时间尺度与历史闰秒一样多。实际上,在每个新的闰秒之后都会重新建立一个新的时间尺度。因此,所有先前的闰秒,更不用说时间刻度本身的明显起源,随着每个新时间刻度的建立而向后退一秒。例如,如果使用 2005 年与 UTC 同步的时钟来建立 1972 年初发生的事件的 UTC 纪元,则该事件将延迟 22 秒。因此,为了最精确地确定相对于历史公历和UTC时间尺度的纪元,用户必须从明显的NTP或POSIX纪元中减去IERS提供的相关偏移量。这是当今几乎所有时间分配机制的特征。

闰秒几乎从不相关,除非你正在做天文计算或其他取决于地球和太阳位置的东西。

通常,认为自己需要闰秒的人真的需要

  1. 一种稳定的(在可预见的未来)从元组表示(如(年,月,日,...)转换为标量表示(如millis-since-epoch或
  2. 处理一个表示,而不是混合和匹配。

我更喜欢(2)。标量表示更适合科学计算,元组表示更适合商业和休闲应用程序。