系统时间

出自 ArchWiki
(重定向自 网络时间协议)

此条目或章节需要扩充。

理由: 本条目主要介绍 systemdtimedatectl;应首先解释诸如 datehwclock 等基本命令 (在 Talk:System time 中讨论)

在操作系统中,时间(时钟)由三个部分决定:时间值、本地时间或 UTC 或其他时间,时区以及夏令时 (DST)(如果适用)。本文解释了它们是什么以及如何读取/设置它们。系统上存在两个时钟:硬件时钟和系统时钟,本文也将详细介绍。

大多数操作系统的标准行为是

  • 在启动时从硬件时钟设置系统时钟。
  • 保持系统时钟的准确时间,请参阅 #时间同步
  • 在关机时从系统时钟设置硬件时钟。

时间标准

有两种时间标准:本地时间协调世界时 (UTC)。本地时间标准取决于当前的时区,而 UTC 是全球时间标准,并且独立于时区值。虽然概念上不同,但 UTC 也被称为 GMT(格林威治标准时间)。

硬件时钟(CMOS 时钟,BIOS 时间)使用的标准由操作系统设置。默认情况下,Windows 使用本地时间,macOS 使用 UTC,其他 UNIX 和类 UNIX 系统各不相同。使用 UTC 标准的操作系统通常会将硬件时钟视为 UTC,并在启动时根据时区对其进行调整以设置操作系统时间。

硬件时钟

硬件时钟(也称为实时时钟 (RTC) 或 CMOS 时钟)存储以下值:年、月、日、小时、分钟和秒。 UEFI 固件还具有存储时区以及是否使用 DST 的额外功能。

读取硬件时钟

# hwclock --show

从系统时钟设置硬件时钟

以下命令从系统时钟设置硬件时钟。此外,它会更新 /etc/adjtime,如果不存在则创建它。有关此文件以及#时间偏差部分的更多信息,请参阅 hwclock(8) § The Adjtime File

# hwclock --systohc

自动同步

默认情况下,Arch Linux 内核启用了一项功能,其中硬件时钟每 11 分钟与系统时钟同步一次。您可以按如下方式查看此功能是否在您的内核上启用

$ zgrep CMOS /proc/config.gz
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_RTC_DRV_CMOS=y

首次同步发生在启动时。这意味着如果您的硬件时钟非常过时(例如,CMOS 电池故障已将时钟重置为 2000 年),那么在启动后的前 11 分钟内,任何需要相当准确时间的操作都会出错 - 包括 SSL,它使用在线证书状态协议 (OCSP)。在您的计算机上运行的 Web 浏览器通常会在其对网站的请求中发送硬件时钟时间,而时间偏差过大会导致浏览器因 OCSP 错误而拒绝连接。

系统时钟

系统时钟(也称为软件时钟)跟踪:时间、时区和 DST(如果适用)。它由 Linux 内核计算为自 1970 年 1 月 1 日午夜 UTC 以来的秒数。系统时钟的初始值是从硬件时钟计算得出的,具体取决于 /etc/adjtime 的内容。启动完成后,系统时钟独立于硬件时钟运行。 Linux 内核通过计算定时器中断来跟踪系统时钟。

读取时钟

要检查当前系统时钟时间(以本地时间和 UTC 时间显示)以及 RTC(硬件时钟)

$ timedatectl

设置系统时钟

要直接设置系统时钟的本地时间

# timedatectl set-time "yyyy-MM-dd hh:mm:ss"

例如

# timedatectl set-time "2014-05-26 11:13:54"

将时间设置为 2014 年 5 月 26 日,11:13 和 54 秒。

多系统

如果一台机器上安装了多个操作系统,它们都将从同一个硬件时钟获取当前时间:建议将其设置为 UTC,以避免跨系统冲突。否则,如果硬件时钟设置为本地时间,则在例如 DST 更改后,多个操作系统可能会对其进行调整,从而导致过度校正;当在不同时区之间旅行并使用其中一个操作系统重置系统/硬件时钟时,也可能会出现问题。

可以使用 timedatectl 命令查询和设置硬件时钟。您可以使用以下命令查看 Arch 系统的当前硬件时钟时间标准

$ timedatectl | grep local
RTC in local TZ: no

要将硬件时钟时间标准更改为本地时间,请使用

# timedatectl set-local-rtc 1

要恢复为硬件时钟使用 UTC,请输入

# timedatectl set-local-rtc 0

这些命令会自动生成 /etc/adjtime 并相应地更新 RTC;无需进一步配置。

在内核启动期间,当 RTC 驱动程序加载时,可能会从硬件时钟设置系统时钟。这是否发生取决于硬件平台、内核版本和内核构建选项。如果确实发生这种情况,则在启动序列中的此时,硬件时钟时间被假定为 UTC,并且 /sys/class/rtc/rtcN/hctosys (N=0,1,2,..) 的值将被设置为 1。

稍后,系统时钟会由 systemd 再次从硬件时钟设置,具体取决于 /etc/adjtime 中的值。因此,硬件时钟使用本地时间可能会在启动序列期间导致一些意外行为;例如,系统时间倒退,这始终是一个坏主意(还有很多原因)。自 systemd 版本 216 起,当 RTC 配置为本地时间(而不是 UTC)时,systemd 将永远不会同步回它,因为这可能会在稍后的启动时使 Windows 感到困惑。并且 systemd 将不再告知内核当前时区。因此,这意味着 FAT 时间戳将始终被视为 UTC[1]

注意
  • 使用 timedatectl 需要活动的 D-Bus。因此,在 chroot 下(例如在安装期间)可能无法使用此命令。在这些情况下,您可以恢复为 hwclock 命令,或使用 systemd-nspawn 而不是 chroot。
  • 如果 /etc/adjtime 不存在,systemd 假定硬件时钟设置为 UTC。

Microsoft Windows 中的 UTC

与 Windows 双启动,建议将 Windows 配置为使用 UTC,而不是将 Linux 配置为使用本地时间。(Windows 默认使用本地时间 [2]。)

可以通过简单的注册表修复来完成:打开 regedit 并向注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal 添加一个十六进制值为 1DWORD

您可以从运行的管理员命令提示符中执行此操作

C:\>reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f

或者,创建一个包含以下内容的 *.reg 文件(在桌面上)并双击它以将其导入注册表

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation]
"RealTimeIsUniversal"=dword:00000001

如果 Windows 要求由于 DST 更改而更新时钟,请允许它。它会将时钟保持在预期的 UTC 时间,仅校正显示的时间。

设置此值后,可能需要更新#硬件时钟#系统时钟时间。

如果您在时间偏移方面遇到问题,请尝试重新安装 tzdata,然后再次设置您的时区

# timedatectl set-timezone America/Los_Angeles

Ubuntu/Fedora 中的 UTC

许多 Linux 发行版在安装过程中检测到任何磁盘上的 Windows 时,都将硬件时钟设置为解释为“本地时间”。显然,这样做是故意的,目的是允许新用户在他们的 Windows 计算机上试用 Linux,而无需编辑注册表。

要更改此行为,请参见上文。

多 NTP 交互

如果您使用 NTP 客户端(请参阅下面的#时间同步)来跟踪任何系统上的 RTC 漂移,则应禁用除一个系统之外的所有系统上的时间同步。否则,NTP 客户端将不会意识到彼此的调整,并对 RTC 漂移做出非常不正确的估计。

对于 Windows,转到日期和时间设置并取消选中时间同步选项。您还可以以管理员身份运行 w32tm /unregister 以取消注册时间同步服务:已知 Active Directory 计算机会忽略同步设置,并且仍然会执行同步以防止重放攻击。 Windows 时钟同步例程一开始就非常不准确,甚至需要额外的工作才能达到一秒的精度,因此禁用它应该不会有太大损失。

时区

要检查为系统定义的当前时区

$ timedatectl status

要列出可用的时区

$ timedatectl list-timezones

要设置您的时区

# timedatectl set-timezone Zone/SubZone

示例

# timedatectl set-timezone Canada/Eastern

这将创建一个指向 /usr/share/zoneinfo/ 下的 zoneinfo 文件的 /etc/localtime 符号链接。如果您选择手动创建链接(例如在 chroot 期间,timedatectl 将不起作用),请记住它必须是符号链接,如 localtime(5) § DESCRIPTION 中指定的那样

# ln -sf /usr/share/zoneinfo/Zone/SubZone /etc/localtime
提示: 时区也可以使用 tzselect 以交互方式选择。

有关详细信息,请参阅 timedatectl(1)localtime(5)

基于地理位置设置

注意: 某些桌面环境支持自动时区选择(例如,请参阅 GNOME#日期和时间)。

要根据 IP 地址位置自动设置时区,可以使用地理位置 API 来检索时区,例如 curl https://ipapi.co/timezone,并将输出传递给 timedatectl set-timezone 以进行自动设置。下面列出了一些提供免费或部分免费服务的 geo-IP API

每次 NetworkManager 连接到网络时更新时区

此条目或章节是与 NetworkManager#自动设置时区 合并的候选对象。

注意: (在 Talk:System time 中讨论)

创建一个 NetworkManager 调度器脚本 并使其可执行

/etc/NetworkManager/dispatcher.d/09-timezone
#!/bin/sh
case "$2" in
    up)
        timedatectl set-timezone "$(curl --fail https://ipapi.co/timezone)"
    ;;
esac
提示: 使用 connectivity-change 而不是 up 可以防止在使用 OpenConnect 等客户端连接到 VPN 时更改时区。

或者,工具 tzupdateAUR 根据 IP 地址的地理位置自动设置时区。 最流行的 IP 地理位置 api 的比较 可能有助于决定在生产中使用哪个 API。

时间偏差

每个时钟都有一个与真实时间不同的值(其中最好的表示是国际原子时);没有完美的时钟。基于石英的电子时钟保持的时间不完美,但保持一致的不准确性。这种基本“不准确性”被称为“时间偏差”或“时间漂移”。

当使用 hwclock 设置硬件时钟时,会计算一个新的每日漂移值(以秒为单位)。漂移值是通过使用设置的新值与设置之前硬件时钟的值之间的差异来计算的,同时考虑了先前漂移值的值和上次设置硬件时钟的时间。新的漂移值和设置时钟的时间被写入文件 /etc/adjtime,覆盖先前的值。因此,当运行命令 hwclock --adjust 时,可以调整硬件时钟以补偿漂移;这也发生在关机时,但仅当启用了 hwclock 守护进程时才会发生,因此对于使用 systemd 的 Arch 系统,这不会发生。

注意: 如果在上次设置后不到 24 小时再次设置 hwclock,则不会重新计算漂移,因为 hwclock 认为经过的时间段太短,无法准确计算漂移。

如果硬件时钟持续以大幅度增量丢失或获得时间,则可能是记录了无效的漂移(但这仅在 hwclock 守护进程运行时适用)。如果您错误地设置了硬件时钟时间或者您的时间标准未与 Windows 或 macOS 安装同步,则可能会发生这种情况。可以通过首先删除文件 /etc/adjtime,然后设置正确的硬件时钟和系统时钟时间来删除漂移值。然后,您应该检查您的时间标准是否正确。

注意: 如果您希望即使在使用 systemd 时也使用存储在 /etc/adjtime 中的漂移值(例如,您不能或不想使用 NTP),则必须定期调用 hwclock --adjust,也许可以通过创建 cron 作业来实现。

软件时钟非常准确,但像大多数时钟一样,它并非完全准确,也会漂移。虽然很少见,但如果内核跳过中断,系统时钟可能会失去准确性。有一些工具可以提高软件时钟的准确性

时间同步

网络时间协议 (NTP) 是一种用于通过分组交换、可变延迟数据网络同步计算机系统时钟的协议。

网络时间协议 (NTP)

为了获得 RFC 定义的正确 NTP 支持,客户端必须能够合并来自多个服务器的时间、补偿延迟并跟踪系统(软件)时钟的漂移。以下是 Arch Linux 可用的 NTP 实现

  • Chrony — 一个客户端和服务器,它对漫游友好,专为不一直在线的系统而设计。在大多数情况下,比 ntpd 更快且更接近参考。还可以跟踪硬件时钟 (RTC) 漂移。
https://chrony-project.org/ || chrony
https://www.ntp.org/ || ntp
  • NTPsec — NTPd 的一个分支,专注于安全性。工作方式类似,只是抛弃了很多旧代码。
https://ntpsec.org/ || ntpsecAUR

简单网络时间协议 (SNTP)

任何功能低于适当 NTP 节点的东西都被认为是简单网络时间协议 (SNTP)。基本的 SNTP 客户端可能只是从单个服务器获取时间并立即设置,而无需跟踪长期漂移。 SNTP 提供较低的精度,但占用较少的资源。对于桌面用户和嵌入式工作负载来说,精度通常足够好,但对于 NTP 服务器来说是不可接受的。以下实现了 SNTP

  • ConnMan — 一个带有 SNTP 支持的轻量级网络管理器。
https://01.org/connman (waybackmachine) || connman
  • ntpclient — 一个简单的命令行 SNTP 客户端。
http://doolittle.icarus.com/ntpclient/ || ntpclientAUR
  • OpenNTPD — OpenBSD 项目的一部分,实现了 SNTP 客户端和服务器。不支持闰秒。
https://www.openntpd.org/ || openntpd
  • sntp — 一个随 NTPd 提供的 SNTP 客户端。它取代了 ntpdate,建议在非服务器环境中使用。
https://www.ntp.org/ || ntp
  • systemd-timesyncd — 一个简单的 SNTP 守护进程,仅实现客户端,仅专注于从一个远程服务器查询时间。对于大多数安装来说,它应该绰绰有余。
https://systemd.io/ || systemd

每用户/会话或临时设置

对于某些用例,更改时间设置而不影响全局系统值可能很有用。例如,在开发期间测试依赖于时间的应用程序,或者在从另一个区域远程登录到服务器时调整系统时区。

要使应用程序“看到”与系统不同的日期/时间,您可以使用 faketime(1) 实用程序(来自 libfaketime)。

相反,如果您希望应用程序“看到”与系统不同的时区,请设置 TZ 环境变量,例如

$ date && export TZ=":/usr/share/zoneinfo/Pacific/Fiji" && date
Tue Nov  1 14:34:51 CET 2016
Wed Nov  2 01:34:51 FJT 2016

这与仅设置时间不同,例如,它允许测试程序在具有正或负 UTC 偏移值时的行为,或者在非 DST 时区中的系统上开发时 DST 更改的效果。

另一个用例是为同一系统的不同用户设置不同的时区:这可以通过在 shell 的配置文件中设置 TZ 变量来实现,请参阅 环境变量#定义变量

技巧与提示

fake-hwclock

alarm-fake-hwclock 专为没有电池备份 RTC 的系统设计,它包含一个 systemd 服务,该服务在关机时保存当前时间,并在启动时恢复保存的时间,从而避免奇怪的时间旅行错误。

安装 fake-hwclock-gitAUR, 启动/启用 服务 fake-hwclock.service

虚拟 PTP

虚拟机访客可以使用 PTP(精确时间协议)/dev/ptp0 接口从主机获取时间。与在主机和访客之间使用基于 IP 的 NTP 相比,该接口更准确。

chronyntpd 都可以使用虚拟 PTP 设备来同步访客和主机之间的时间,方法是将设备配置为好像它是真正的 PTP 参考时钟。

故障排除

时钟显示的值既不是 UTC 也不是本地时间

这可能是由多种原因引起的。例如,如果您的硬件时钟在本地时间上运行,但 timedatectl 设置为假定它在 UTC 中,则结果是您的时区到 UTC 的偏移量实际上被应用了两次,从而导致您的本地时间和 UTC 值错误。

要强制您的时钟设置为正确的时间,并将正确的 UTC 写入您的硬件时钟,请按照以下步骤操作

  • 设置 ntpd (无需将其作为服务启用)。
  • 正确设置您的时区
  • 运行 ntpd -qg 以手动将您的时钟与网络同步,忽略本地 UTC 和网络 UTC 之间的较大偏差。
  • 运行 hwclock --systohc 以将当前软件 UTC 时间写入硬件时钟。

参见