系統時間 - Arch Linux 中文维基

跳至內容

# 系統時間

出自 Arch Linux 中文维基

相關文章

- 網絡時間協議
- OpenNTPD
- Chrony
- systemd-timesyncd

翻譯狀態：

- 本文（或部分內容）譯自 System time，最近一次同步於 2025-07-26，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

這篇文章的某些內容需要擴充。

原因：文章內容基本上與 systemd timedatectl 關聯；需要先解釋如 date 和 hwclock 等基礎命令的作用 (在 Talk:系統時間 中討論)

在作業系統中，時間（時鐘）取決於三個部分：時間值（本地時間或 UTC 等）、時區及夏令時（DST，需要時應用，在中國已廢止）。本文將分別介紹各個部分的定義及如何設置和讀取它們。系統中也存在兩種時鐘：硬體時鐘和系統時鐘，下文也將進行詳細描述。

大部分作業系統的時間管理包括如下方面：

- 啟動時根據硬體時鐘設置系統時間
- 保持系統時鐘準確，細節請參考#時鐘同步
- 關機時根據系統時鐘設置硬體時鐘

## 時間標準

時間表示有兩個標準：localtime 和 UTC（Coordinated Universal Time）。localtime 標準依賴於當前時區，而 UTC 是與時區無關的全球時間標準。儘管概念上有差別，UTC 和 GMT（格林威治時間）是一樣的。

硬體（CMOS 時鐘，即 BIOS 時鐘）所使用的時間標準由作業系統設定，Windows 默認使用 localtime，macOS 默認使用 UTC ,而其他的 UNIX 和類 UNIX 作業系統各不相同。使用 UTC 標準的作業系統通常會認為硬體時鐘也是 UTC，並在啟動時根據時區調整到對應時間。

在 tzdata 中，時區的名字由該地區的最大城市代表。目前中國大陸全境官方使用 Asia/Shanghai 時區，它在2000年之後等於 UTC+8，而在歷史上則根據當時的時區政策可能有夏令時等變化。

## 硬體時鐘

硬體時鐘（即實時時鐘 RTC 或 CMOS 時鐘）僅能保存：年、月、日、時、分、秒這些時間數值。UEFI 固件可以額外存儲時區以及是否使用夏令時的信息。

### 讀取硬體時鐘

    # 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 年），那任何需要準確時間的操作都將報錯（包括 SSL 和在線證書狀態協議（OCSP））。瀏覽器通常會將硬體時鐘附在發往網站的請求中，因此如果時鐘誤差過大，就會因 OCSP 錯誤導致瀏覽器拒絕進行連接。

## 系統時鐘

系統時鐘（即軟體時間）保存了：時間、時區和夏令時設置。Linux 內核將其計算為自 UTC 時間 1970 年 1 月 1 日經過的秒數。初始系統時鐘是從硬體時間計算得來，計算時會考慮 `/etc/adjtime` 的設置。系統啟動之後，系統時鐘與硬體時鐘獨立運行，Linux 內核通過時鐘中斷計數維護系統時鐘。

### 讀取系統時間

下面命令可以獲得系統時間（同時以 localtime 和 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，以避免各作業系統之間的衝突。如果硬體時鐘使用的是本地時間，那可能會有多個作業系統同時修改硬體時鐘（如進行夏令時調整），導致修正過度；另外，在跨多個時區出行的場景下，使用其中一個作業系統重置系統/硬體時鐘也可能會產生問題。

通過 `timedatectl` 命令可以查看並設置硬體時間。通過下面命令查看 Arch 系統當前硬體時鐘的時間標準：

    $ timedatectl | grep local

    RTC in local TZ: no

將硬體時間設置為 localtime：

    # 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（比如在安裝系統時）下可能無法運行 timedatectl。在這些情況下, 你可以使用 hwclock 命令或使用 systemd-nspawn 代替 chroot。
- 如果 `/etc/adjtime` 不存在，systemd 會假設硬體時鐘設為 UTC。

### Windows 系統使用 UTC

在 Arch + Windows 雙系統時，建議配置 Windows 使用 UTC 時間，而不是讓 Linux 使用 localtime。（Windows 默認使用 localtime [2]）

這一步可以通過修改註冊表值達成：打開 `regedit`，然後新建一個 `DWORD` 類型的值，位置為 `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal`，值為十六進制的 `1`。

也可以用管理員權限啟動命令行，然後執行以下命令來完成：

    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 要求根據夏令時更新時鐘，可以允許。時鐘仍然是 UTC，僅是顯示時間會改變。

在設置該值後，可以會需要更新#硬體時鐘和#系統時鐘值。

如果你有時間偏移問題，重新安裝 tzdata包 並再次設置你的時區：

    # timedatectl set-timezone Asia/Shanghai

### UTC 在 Ubuntu/Fedora 下的設置

很多 Linux 發行版會在安裝時檢測計算機上是否存在 Windows，若存在則會默認使用localtime。這一操作似乎是為了讓新用戶在不修改註冊表的前提下，在 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 Asia/Shanghai

此命令會創建一個 `/etc/localtime` 軟連結，指向 `/usr/share/zoneinfo/` 中的時區文件，如果你要手動創建連結（如在 chroot 中無法使用 `timedatectl` 的情況下），請確保創建的是軟連結（參閱 localtime(5) § DESCRIPTION）：

手動創建(例如 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` 進行自動設置。有些 IP 位置 API 提供免費服務或免費額度，可參考以下清單：

- Abstract IP geolocation API
- FreegeoIP
- IP-api
- IPAPI
- Ipdata
- Ipstack
- TimezoneApi

#### 在每次 NetworkManager 連接到網絡時更新時區

請參考 NetworkManager#自動設置時區。

## 時鐘偏移

所有的時鐘都距「真實時間」（代表為國際原子時鐘）有一定偏差，世界上沒有完美的時鐘。石英電子鐘的時間是不準確的，但會有固定的誤差，這裡的「誤差」即「時鐘偏移」。

用 `hwclock` 設置硬體時間時，會計算每天偏移的秒數。偏移值是原硬體時間與新設置硬體時間的差，並且考慮上次硬體時間設置時的偏移與上次設置值時的時間。新的偏移值及設置值的時間會寫入到 `/etc/adjtime`，並覆寫掉上次的值。因此，在運行 `hwclock --adjust` 命令時，可以根據偏移修正硬體時鐘。如果啟用了 `hwclock` 守護進程，那該步驟在關機時也會進行，但對於使用 systemd 的 Arch 類型系統而言不會出現該情況。

注意：如果硬體時間值與原值的差小於 24 小時，偏移量不會重新計算，因為時間過短，無法精確設置偏移。
注意：如果在 24 小時內再次設置了硬體時鐘，由於 `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包

- Network Time Protocol daemon — 是這個協議的參考實現。

  https://www.ntp.org/ || ntp包

- ntpd-rs — 帶 NTS 支持的全功能 NTP 實現。

  https://docs.ntpd-rs.pendulum-project.org/ || ntpd-rs包

- NTPsec — 專注於安全的 NTPd 分支。移除了大量舊代碼，但在使用上區別不大。

  https://ntpsec.org/ || ntpsecAUR

### 簡單網絡時間協議（SNTP）

功能上比標準 NTP 節點少的都被認為是簡單網絡時間協議（SNTP）。最簡單的 SNTP 客戶端會從單台伺服器獲取時間，不跟蹤時鐘偏移並直接將其設置到系統上。SNTP 的準確度相對較低，但消耗的系統資源更少。其提供的準確度適用於桌面和嵌入式環境，但不適合用於 NTP 伺服器上。以下為 SNTP 的實現：

- ConnMan — 帶 SNTP 支持的輕量網絡管理器。

  https://01.org/connman (waybackmachine) || connman包

- ntpclient — 是簡單的命令行 NTP 客戶端。

  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包

## 單用戶/會話或臨時設置

For some use cases it may be useful to change the time settings without touching the global system values. For example to test applications relying on the time during development or adjusting the system time zone when logging into a server remotely from another zone.

To make an application "see" a different date/time than the system one, you can use the faketime(1) utility (from libfaketime包).

If instead you want an application to "see" a different time zone than the system one, set the `TZ` environment variable, for example:

    $ 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

This is different than just setting the time, as for example it allows to test the behavior of a program with positive or negative UTC offset values, or the effects of DST changes when developing on systems in a non-DST time zone.

Another use case is having different time zones set for different users of the same system: this can be accomplished by setting the `TZ` variable in the shell's configuration file, see Environment variables#Defining variables.

## 提示和技巧

### fake-hwclock

alarm-fake-hwclock designed especially for system without battery backed up RTC, it includes a systemd service which on shutdown saves the current time and on startup restores the saved time, thus avoiding strange time travel errors.

Install fake-hwclock-gitAUR, start/enable the service `fake-hwclock.service`.

### 虛擬 PTP

Virtual machine guests may obtain time from the host machine using the PTP (Precision Time Protocol) `/dev/ptp0` interface. The interface is more accurate compared to using NTP over IP between the host and guest.

- On KVM machines, the `ptp_kvm` kernel module needs to be loaded to provide a virtual PTP device. See VM timekeeping: Using the PTP Hardware Clock on KVM.
- On Hyper-V machines, the guest integration should spawn a `/dev/ptp0` without additional configuration.

chrony and ntpd can each use the virtual-PTP device to sync the time between guest and host, by configuring the device as if it is a real PTP reference clock.

## 故障排除

### 時間顯示的既不是 UTC 也不是本地時間

這可能是由多種原因造成的。假如說你的硬體時間使用的是 localtime，但 `timedatectl`被設為將其用作 UTC 時間，結果是你的時區偏移設置被應用了兩次，導致系統顯示的既不是UTC也不是本地時間。

要強制校準你的時鐘，並且讓系統寫入正確 UTC 時間到硬體時鐘，遵循下面幾步：

- 設置好 ntpd（不需要將其作為服務來運行）；
- 正確設置你的時區；
- 運行 `ntpd -qg` 以手動從網絡同步時鐘，此時在進行時間校正時，會忽略本地 UTC 時間與網絡 UTC 時間之間過大的差異；
- 運行 `hwclock --systohc`，將當前軟體 UTC 時間寫入硬體時間。

## 外部資源

- Linux Tips - Linux, Clocks, and Time
- An introduction to timekeeping in Linux VMs
- Sources for Time Zone and Daylight Saving Time Data for tzdata包
- Time Scales
- Gentoo: System time
- Wikipedia:Time

分類：​

- 主板和 BIOS
- 系統管理

系統時間
新增話題