我将系统时间和 RTC 设置为以下值。
date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null //set system time
hwclock -w //sync RTC to system time
另外,/etc/TZ(与 中的 /etc/localtime 相同的文件busybox
)保存为
LMT0:00LMT-1:00,M5.5.1/10,M8.5.1/10
其中表示夏令时将于 5 月最后一周星期一上午 10:00 生效;并将于 8 月最后一周星期一上午 10:00 停用。
我特意将系统时间和RTC设置为比DST结束日期早30秒,以便观察系统行为。
当 DST 结束后,系统时间(也许还有 RTC?)应该向后减去一小时。
结果如下,很明显,只是系统时间减了一小时,而不是系统时间和RTC都减了。
~ # cat /etc/TZ
LMT0:00LMT-1:00,M5.5.1/10,M8.5.1/10
~ # date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null
~ # hwclock -w
~ #
~ # date
Mon Aug 30 09:59:36 LMT 2021
~ # hwclock
Mon Aug 30 09:59:42 2021 0.000000 seconds
~ #
~ #
~ # date
Mon Aug 30 09:59:49 LMT 2021
~ # hwclock
Mon Aug 30 09:59:53 2021 0.000000 seconds
~ # date
Mon Aug 30 09:00:00 LMT 2021
~ # hwclock
Mon Aug 30 10:00:03 2021 0.000000 seconds
~ # date
Mon Aug 30 09:00:05 LMT 2021
~ # hwclock
Mon Aug 30 10:00:06 2021 0.000000 seconds
然而,另一方面,它的行为却有所不同!这次我想观察进入夏令时时的系统行为。
/etc/TZ 被另存为
LMT0:00LMT-1:00,M8.5.1/10,M12.5.1/10
其中表示夏令时将于 8 月最后一周星期一上午 10:00 生效;并将于 12 月最后一周星期一上午 10:00 停用。
另外,我将系统时间和 RTC 设置为以下值。
date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null //set system time
hwclock -w //sync RTC to system time
当 DST 生效时,系统时间(也许还有 RTC?)应提前一小时添加。
结果如下,很明显系统时间和RTC都增加了1个小时。
~ # cat /etc/TZ
LMT0:00LMT-1:00,M8.5.1/10,M12.5.1/10
~ # date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null
~ # hwclock -w
~ #
~ # date
Mon Aug 30 09:59:35 LMT 2021
~ # hwclock
Mon Aug 30 09:59:37 2021 0.000000 seconds
~ # date
Mon Aug 30 09:59:48 LMT 2021
~ # hwclock
Mon Aug 30 09:59:51 2021 0.000000 seconds
~ # date
Mon Aug 30 11:00:04 LMT 2021
~ # hwclock
Mon Aug 30 11:00:06 2021 0.000000 seconds
我想知道为什么会出现这种矛盾的行为。
答案1
您认为hwclock
显示硬件时钟在其寄存器中的确切值。
它不会那样做。
证明:
# date; hwclock; TZ=UTC hwclock; grep rtc_time /proc/driver/rtc
Wed 1 Sep 18:33:18 EEST 2021
2021-09-01 18:33:18.870798+03:00
2021-09-01 15:33:18.981738+00:00
rtc_time : 15:33:20
hwclock
请注意和的输出有何TZ=UTC hwclock
不同?
hwclock
显示硬件时钟的值根据需要转换为当前时区(包括 DST 偏移量和时区)。如果您想查看原始值,则必须使用cat /proc/driver/rtc
:取决于您的系统是否使用经典的 PC CMOS 时钟驱动程序、UEFI 时钟接口或其他一些实时时钟驱动程序,可能会也可能不会转换为time_t
(或time64_t
)并返回时钟设置过程。
获取/设置硬件时钟时也不使用--utc
nor选项,因此硬件时钟的本地/UTC状态由文件的第三行(如果存在)--local
确定。/etc/adjtime
在第一个测试中,您在 DST 生效时设置硬件时钟,因此 UTC 偏移量为 -1(UTC=本地 - 1 小时)。如果硬件时钟设置为使用本地时间,它将按预期设置为 09:59:30。
但如果硬件时钟设置为使用 UTC,则设置到时钟寄存器的实际值将为08:59:30。当您在 DST 转换之前查看时钟时,此偏移量会自动由 取回hwclock
,因此您将看到预期的 09:59:**。
当 DST 发生转换时,如果硬件时钟设置为本地时间,时钟寄存器将递增到 10:00:00 的值。由于现在已经是当地时间并且 DST 偏移量现在为 0,因此hwclock
会将其显示为 10:00:00。
但如果硬件时钟设置为 UTC 时间,时钟寄存器中的值现在将为 09:00:00。由于 DST 转换后 UTC 偏移量现在为 0,hwclock
因此也将其显示为 09:00:00。
操作系统时钟始终以 UTC 内部运行,并根据时区+DST 规则转换为本地时间,因此它将按预期显示 09:00:00(非 DST)。
由于您hwclock
在这里得到的结果是 10:00:00,因此文件的第三行似乎/etc/adjtime
必须显示LOCAL
。
在第二个测试中,您在 DST 无效时设置时钟,因此总 UTC 偏移量为 0。现在,无论设置为使用 UTC 还是本地时间,时钟寄存器都将设置为 09:59:30 。从之前的测试中,我们知道您已将其设置为当地时间。
当 DST 转换时间到达时,硬件时钟寄存器将读取 10:00:00...并且由于寄存器值是根据当前时区格式化显示的,因此存在一个问题:根据有效的时区规则,当地时间今天 10:00:00 不存在!
由于 DST 转换,在这个特殊的日子里,没有可能的 UTC 时间戳值可以代表当地时间 10:00:00 的值: 09:59:59 UTC 是当地时间 09:59:59,但是 10:00 :00 UTC 是当地时间 11:00:00。当时间值经过 的glibc
时区转换和格式化例程时,不存在的 10:00:00 被推送到 11:00:00。
因此,如果您在 DST 到标准时间转换后的第一个小时内查询硬件时钟,hwclock
可能会告诉您错误的时间因为时钟寄存器中的实际值无法表示为有效的本地时间值。这只是一个显示工件:/proc/driver/rtc
即使在这个神奇的时刻,仍然应该显示正确的值。
这是一个很好的例子,说明了将硬件时钟设置为本地时间可能会引起各种意外的麻烦。
我将以一个链接结束Tom Scott 制作的这段关于计算机计时的 10 分钟 YouTube 视频非常适用。我相信你会欣赏这个结论。