尽管存在缺陷,但 CLOCK_REALTIME 应该是系统对当前 UTC 或民用时间的最佳估计。它是系统能够显示与您查看手表、墙上的时钟、手机或收听广播电台的时间广播等时相同的时间的基础。( display 确实涉及从 UTC 到本地时间的转换;稍后会详细介绍。)
但如果 CLOCK_REALTIME 与现实世界中的 UTC 时间相匹配,那么至少有两个非常重要的问题:
- 如果有人不小心将您计算机上的时钟设置错了怎么办?他们将不得不修复它,而修复可能涉及时间跳跃。几乎没有办法解决这个问题,特别是如果错误很大(例如,几小时或几天)。
- 不幸的是,大多数计算机无法表示leap seconds。因此,当现实世界中出现闰秒时,大多数计算机时钟都必须跳动一点。
所以当你读到 CLOCK_REALTIME 可能有不连续性,可能向前和向后跳跃时,这不是一个错误,而是一个特性:CLOCK_REALTIME 必须有这些可能性,如果它是为了应对真实的世界上有闰秒和偶尔出错的时钟。
因此,如果您编写的代码应该与现实世界中的时间相匹配,那么 CLOCK_REALTIME 就是您想要的,这是您想要的。不过,理想情况下,您编写代码的方式应使其行为合理(不会崩溃或做一些奇怪的事情),如果偶尔由于某种原因时钟向前或向后跳动。
您可能从您引用的另一个问题中知道,CLOCK_MONOTONIC 保证始终以每秒一秒的速度前进,没有跳跃或不连续性,但是时钟的绝对值不会'意义不大。如果 CLOCK_MONOTONIC 的值为 13:05,这并不意味着它只是在下午 1 点之后,它通常意味着计算机已经启动并运行了 13 小时 5 分钟。
因此,如果您只对相对时间感兴趣,那么 CLOCK_MONOTONIC 就可以了。特别是,如果您想计算某件事花费了多长时间,最好取两个 CLOCK_MONOTONIC 值并减去它们,因为如果在之间。
或者,总而言之,正如人们在 cmets 线程中所说,CLOCK_REALTIME 是您需要的绝对时间,而 CLOCK_MONOTONIC 则更适合相对时间。
现在,还有几点。
如前所述,CLOCK_REALTIME 并不完全是“墙上时间”,因为它实际上以 UTC 交易。它使用自 1970 年以来著名(臭名昭著?)的 Unix/Posix 表示 UTC 秒。例如,CLOCK_REALTIME 值 1457852399 转换为 2016 年 3 月 13 日 06:59:59 UTC。我住的地方,格林威治以西 5 小时,对应于当地时间 01:59:59。但是一秒钟后不是 2:00!事实上,1457852400 对应于当地时间 03:00:00,因为此时夏令时开始生效。
我建议如果你的时钟有误,时间跳跃几乎是修复它的唯一方法,但事实并非如此。如果您的时钟只是略微偏离,可以通过逐渐“调整”时间(通过稍微改变时钟频率)来纠正它,以便在几分钟或几小时后它会漂移到正确的时间而不会跳跃。这就是 NTP 试图做的事情,尽管根据其配置,它可能只愿意为非常小的错误这样做。
我说过 CLOCK_MONOTONIC 通常是计算机启动并运行的时间。标准不能保证这一点;所有标准都说 CLOCK_MONOTONIC 从某个任意时间点开始计算时间。在确实将 CLOCK_MONOTONIC 实现为系统启动时间的系统上,可以有两种解释:是自启动以来的时间,还是系统启动和运行的时间(即减去它休眠或挂起的任何时间) ?在许多系统上,还有另一个时钟 CLOCK_BOOTTIME 计算自启动以来的时间(无论是启动还是暂停),而 CLOCK_MONOTONIC 仅计算系统启动和运行的时间。
我说过,“CLOCK_MONOTONIC 保证始终以每秒一秒的速度前进”,但这也可能不完全正确。如果您的计算机处于时间转换操作的中间,为了尝试逐渐纠正绝对时间错误,实际上可能是 CLOCK_MONOTONIC 暂时以每秒 1.001 秒或每秒 0.999 秒或类似的速度步进那。误差通常很小,但如果它很重要,一些系统还有其他时钟类型,例如CLOCK_MONOTONIC_RAW,应该没有这种扰动。
最后,如果你想跟踪正确的时间,并且你想避免闰秒的跳跃或不连续,你就会遇到问题,因为在传统的 Unix 中对闰秒的处理很差/Linux(以及 Windows 和所有其他)计算机系统。在最近的(4.x?)Linux 内核下,有一个 CLOCK_TAI 可能会有所帮助。一些实验系统可能会实现另一个时钟CLOCK_UTC,它可以正确处理闰秒。这两者都有一些其他成本,你必须真正知道你在做什么才能有效地使用它们,至少在今天的支持水平下。请参阅LEAPSECS mailing list 了解更多信息。