【问题标题】:Leap seconds and std::chrono闰秒和 std::chrono
【发布时间】:2019-10-30 07:09:04
【问题描述】:

我查看了 cppreference.org(重点是我的):

时钟std::chrono::utc_clock 是表示协调世界时 (UTC) 的时钟。它从 1970 年 1 月 1 日星期四 00:00:00 UTC 开始测量时间,包括闰秒

对比system_clock的定义:

system_clock 测量 Unix 时间(即,自 1970 年 1 月 1 日星期四 00:00:00 协调世界时 (UTC) 以来的时间,不计算闰秒)。

真的有可能在同一个系统中拥有两者吗?例如,如果系统时钟通过 NTP 同步,则服务器决定现在是什么时间,这可以使用闰秒或不使用闰秒,但 C++ 库实现对此一无所知。或者,当引入闰秒时,该标准是否需要数据库?

【问题讨论】:

  • Is it actually possible to have both in the same system? 等等,是否可以不在同一个系统中?那么tai_clockgps_clockfile_clock 呢?为什么utc_clock 如此特别? does the standard require a database over when a leap second was introduced? 嗯,it kind of does
  • Or, does the standard require a database over when a leap second was introduced? 简而言之,是的,除非平台有另一个闰秒信息来源。 IANA 时区数据库包含闰秒插入列表。

标签: c++ chrono c++20 leap-second


【解决方案1】:

NTP 服务器为您提供 UTC(自 1900 年以来的秒数格式)。当前时间,是当前时间。为了到达那里,有多少闰秒并不重要。

当添加闰秒时,事情变得复杂了。 NTP 将在此时宣布这一点,并且各种操作系统在内部做各种事情来记录这一点,因为它们倾向于将时间存储为“自一个纪元以来的秒数”——Linux 和 Windows 不包括闰秒,因为这会使他们的时间戳渲染更加复杂(有多少闰秒?)并且他们无法处理。相反,他们只是在宣布的闰秒前后稍微放慢或加快时钟,因此他们并没有实际记录它,而是调整自己的秒数,以便将该计数作为时间戳呈现在以后会显得准确。

(我不知道操作系统如何在不知道要扣除多少闰秒的情况下从 NTP 事务中重新确定它的非真正但排序的秒数;欢迎编辑。)

system_clock 为您提供秒数,(在主流平台上)直接来自操作系统(例如time())。

utc_clock 为您提供类似的秒数,但它是“真实的”。在这样的主流平台上,这必须是system_clock,事后添加闰秒。这些历史数据也来自系统,确实是some kind of database(尽管确切的来源取决于实现)。

总之,两个时钟的数据源(略有)不同,因此它们是否可以在同一个系统上共存是毫无疑问的。但是,system_clock 可能 直接来自您的操作系统,而utc_clock 可能 没有。

进一步阅读

【讨论】:

  • 示例实现从 IANA 时区数据库获取闰秒插入列表,并在 utc_timesys_time 之间转换时使用该列表。在计算 time_points 在闰秒插入中的差异时,utc_time 对于包含闰秒最有用。
  • @HowardHinnant ? 根据我的阅读,这就是链接的 glibc 存储库的来源。
  • FWIW,那个 repo 已经过时了。这是一个方便更新的列表:en.wikipedia.org/wiki/Leap_second
  • 当前版本的NTP由RFC 5905定义。计算机人写的关于闰秒的散文是不可信的;我更喜欢看数字。在第 14 页,RFC 给出了 1972 年 1 月 1 日 (2,272,060,800) 和 1999 年 12 月 31 日 (3,155,587,200) 的时间戳。如果 NTP 时间戳包含闰秒,则后一个数字将为 3,155,587,222。
【解决方案2】:

我找到了用于 C++ 20 的 this working draft about time,它似乎将于公元 2020 年推出。它有一个 subpage about utc_clock,其中包括以下示例:

clock_­cast<utc_­clock>(sys_­seconds{sys_­days{1970y/January/1}}).time_­since_­epoch() is 0s.
clock_­cast<utc_­clock>(sys_­seconds{sys_­days{2000y/January/1}}).time_­since_­epoch()

并声明最后一个值“是 946'684'822s,即 10'957 * 86'400s + 22s”。请注意,10,957 天大约是 30 年,因此 utc_clock 的值显然表示自 1970 年 1 月 1 日 UTC 以来的秒数,其中每个闰秒都会增加 utc_clock 的值。

由于这表示为转换,因此推断转换将调用闰秒表似乎是合理的,并且即使操作系统不知道 UTC 和 TAI 之间的区别,也没有概念也可以执行一分钟包含 61 秒。

我必须承认我对时间比 C++ 更感兴趣,并且近 20 年没有写过严肃的 C++ 代码了。

【讨论】:

  • 你推断正确。请注意,其中还有一个tai_clock,甚至还有一个gps_clock,以及clock_cast 的能力。
  • 您可以在这里找到所有这些的示例实现:github.com/HowardHinnant/date
猜你喜欢
  • 2015-02-24
  • 2013-07-27
  • 1970-01-01
  • 2011-12-14
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
相关资源
最近更新 更多