系統時間

出自 Arch Linux 中文维基

系統中通常存在兩種時間:軟件時間和硬件時間。一個操作系統通過如下內容確定時間:時間數值、時間標準、時區和夏令時調節(中國已經廢止)。本文分別介紹各個部分的定義及如何設置他們.

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

  • 啟動時根據硬件時鐘設置系統時間
  • 運行時通過時間同步聯網校正時間
  • 關機時根據系統時間設置硬件時間

時間標準[編輯 | 編輯原始碼]

時間表示有兩個標準:localtimeUTC(Coordinated Universal Time) 。localtime 標準則依賴於當前時區。UTC 是與時區無關的全球時間標準。儘管概念上有差別,UTC 和 GMT (格林威治時間) 是一樣的。

硬件所使用的時間標準由操作系統設定,Windows 默認使用 localtime,Mac OS 默認使用 UTC ,而其他的 UNIX-like 操作系統各不相同。使用 Linux 時,最好將硬件時鐘設置為 UTC 標準,並在所有操作系統中使用。這樣 Linux 系統就可以自動調整夏令時設置,而如果使用 localtime 標準那麼系統時間不會根據夏令時自動調整。

硬件時鐘[編輯 | 編輯原始碼]

硬件時鐘(即實時時鐘 RTC 或 CMOS 時鐘)僅能保存:年、月、日、時、分、秒這些時間數值,無法保存時間標準(UTC 或 localtime)。在2016年及以後的 UEFI 固件上支持保存是否使用夏令時。

讀取硬件時鐘[編輯 | 編輯原始碼]

# hwclock --show

將系統時鐘設置到硬件時鐘[編輯 | 編輯原始碼]

下面命令將系統時鐘設置到硬件時鐘,同時會創建或更新 /etc/adjtime。詳情請參考 hwclock(8) § The Adjtime File 和後面的 #Time skew 段落。

# hwclock --systohc

系統時鐘[編輯 | 編輯原始碼]

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

讀取系統時間[編輯 | 編輯原始碼]

下面命令可以獲得系統時間(同時以 localtime 和 UTC 顯示:

$ timedatectl

設置系統時鐘[編輯 | 編輯原始碼]

設置系統時間的本地時間:

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

例如:

# timedatectl set-time "1999-01-08 11:45:14"

設置時間為1999年,1月8日,11時45分14秒。

多系統[編輯 | 編輯原始碼]

如果機器上安裝多個操作系統,硬件使用的是本地時間,可能多個操作系統都進行 夏令時調整,導致時間錯亂。計算機在多個時區切換時,也會出現問題。 所以建議多系統用戶統一使用 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 驅動時可能會根據系統時鐘設置硬件時鐘。是否設置依賴於平台、內核版本和內核編譯選項。如果進行了設置,此時會假定硬件時鐘為 UTC 標準,/sys/class/rtc/rtcN/hctosys(N=0,1,2,..) 會設置成 1。

後面 systemd 會根據/etc/adjtime重新設置。所以使用當地時間作為硬件時鐘時,可能在啟動過程中導致系統時間反覆變更(there is a lot more to it). 所以從 systemd 216 版本開始,如果 RTC 設置為本地時間, systemd 不會將時間回寫,因為這樣會引起 windows 時間錯亂。systemd 也不會將當前時區信息傳遞給內核,這意味着 FAT 時間戳將統一按 UTC 時間處理u[1].

注意:
  • 使用 timedatectl 需要一個啟動的 D-Bus.因此,在chroot (比如在安裝系統時) 下可能無法運行 timedatectl.在這些情況下, 你可以回去使用hwclock命令或使用 systemd-nspawn 代替chroot.
  • If /etc/adjtime不存在, systemd 會假設硬件時鐘設為 UTC.

Windows 系統使用 UTC[編輯 | 編輯原始碼]

如果要支持Windows 雙系統啟動默認使用地方時),那麼一般 RTC 會被設置為地方時。Windows 其實也能處理 UTC,需要修改註冊表。建議讓 Windows 使用 UTC,而非讓 Linux 使用地方時。Windows 使用 UTC 後,請記得禁用 Windows 的時間同步功能,以防 Windows 錯誤設置硬件時間。如上文所說,Linux 可以使用NTP服務來在線同步硬件時鐘。

使用 regedit,新建如下 DWORD 值,並將其值設為十六進制的 1

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal

也可以用管理員權限啟動命令行來完成:

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,僅是顯示時間會改變。

設置時間標準後需要重新設置硬件時間和系統時間。 updated

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

# timedatectl set-timezone America/Los_Angeles

Historical notes[編輯 | 編輯原始碼]

For really old Windows, the above method fails, due to Windows bugs. More precisely,

  • For 64-bit versions of Windows 7 and older builds of Windows 10, there was a bug that made it necessary to have a QWORD value with hexadecimal value of 1 instead of a DWORD value. This bug has been fixed in newer builds and now only DWORD works.
  • Before Vista SP2, there is a bug that resets the clock to localtime after resuming from the suspend/hibernation state.
  • For XP and older, there is a bug related to the daylight saving time. See [2] for details.
  • For even older versions of Windows, you might want to read https://www.cl.cam.ac.uk/~mgk25/mswish/ut-rtc.html - the functionality was not even documented nor officially supported then.

For these operating systems, it is recommended to use localtime.

UTC 在Ubuntu的設置[編輯 | 編輯原始碼]

Ubuntu及其衍生發行版會在安裝時檢測計算機上是否存在Windows,若存在則會默認使用localtime。這是為了讓Windows用戶能夠在不修改註冊表的情況下,在Ubuntu內看到正確的時間。可以通過上面的方法統一設置為 UTC 時間。

時區[編輯 | 編輯原始碼]

檢查當前時區:

$ 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

詳情請參考 timedatectl(1), localtime(5)

Setting based on geolocation[編輯 | 編輯原始碼]

注意: Some desktop environments have support for automatic time zone selection (e.g. see GNOME#Date & time).

To set the timezone automatically based on the IP address location, one can use a geolocation API to retrieve the timezone, for example curl https://ipapi.co/timezone, and pass the output to timedatectl set-timezone for automatic setting. Some geo-IP APIs that provide free or partly free services are listed below:

Update timezone every time NetworkManager connects to a network[編輯 | 編輯原始碼]

Create a NetworkManager dispatcher script:

/etc/NetworkManager/dispatcher.d/09-timezone
#!/bin/sh
case "$2" in
    up)
        timedatectl set-timezone "$(curl --fail https://ipapi.co/timezone)"
    ;;
esac
提示:Using connectivity-change instead of up can prevent timezone changes when connecting to VPNs with clients such as OpenConnect.

Alternatively, the tool tzupdateAUR automatically sets the timezone based on the geolocation of the IP address. This comparison of the most popular IP geolocation apis may be helpful in deciding which API to use in production.

時鐘偏移[編輯 | 編輯原始碼]

最能代表「真實時間」的是國際原子時鐘),所有的時鐘都是有誤差的。電子時鐘的時間是不準的,但是一般有固定的偏移。這種於基值的差稱為「time skew」或「時間偏移」。用 hwclock 設置硬件時間時,會計算每天偏移的秒數。偏移值是原硬件時間與新設置硬件時間的差,並且考慮上次硬件時間設置時的偏移。新的偏移值會在設置時鐘時寫到文件 /etc/adjtime

注意: 如果硬件時間值與原值的差小於 24 小時,偏移量不會重新計算,因為時間過短,無法精確設置偏移。

如果硬件時鐘總是過快或過慢,可能是計算了錯誤的偏移值。硬件時鐘設置錯誤或者時間標準與其他操作系統不一致導致。刪除文件 /etc/adjtime 可以刪除偏移值,然後設置正確的硬件時鐘和系統時鐘,並檢查時間標準是不是設置正確。

注意: 使用 Systemd 時,要使用 /etc/adjtime中的 drift 值(即無法或不想使用 NTP 時); 需要每次調用 hwclock --adjust命令,可以通過 cron 任務實現。

提高系統時間精度的方法有:

  • NTP 可以通過網絡時間協議同步 Linux 系統的時間。NTP 也會修正中斷頻率和每秒滴答數以減少時間偏移。並且每隔 11 分鐘同步一次硬件時鐘。

時鐘同步[編輯 | 編輯原始碼]

網絡時間協議 (NTP) 是一個通過包交換和可變延遲網絡來同步計算機系統時間的協議。下列為這個協議的實現:

  • Chrony — 是一個客戶端和服務器,更適合漫遊,是為不能始終保持在線的系統而特別設計。
https://chrony.tuxfamily.org/ || chrony
  • ConnMan — A lightweight network manager with NTP support.
https://01.org/connman (waybackmachine) || connman
  • Network Time Protocol daemon — 是這個協議的參考實現,推薦用於時間服務器。它也可以調節中斷頻率和每秒滴答次數以減少系統時鐘誤差,使得硬件時鐘每隔11秒重新同步一次。
https://www.ntp.org/ || ntp
  • ntpclient — 是簡單的命令行 NTP 客戶端。
http://doolittle.icarus.com/ntpclient/ || ntpclientAUR
  • NTPsec — A fork of NTPd, focused on security.
https://ntpsec.org/ || ntpsecAUR
  • OpenNTPD — 是 OpenBSD 項目的一部分,同時實現了客戶端和服務器。
https://www.openntpd.org/ || openntpd
  • sntpntp 包裡附帶的一個 SNTP 客戶端。它取代了 ntpdate ,並被推薦用於非服務器環境。
https://www.ntp.org/ || ntp
  • systemd-timesyncd — 是一個簡單的 SNTP 守護進程。它只實現了客戶端,專用於從遠程服務器查詢時間,更適用於絕大部分安裝的情形。
https://www.freedesktop.org/wiki/Software/systemd/ || systemd

Per-user/會話或臨時設置[編輯 | 編輯原始碼]

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 and enable the service fake-hwclock.service.

故障排除[編輯 | 編輯原始碼]

時間顯示的既不是UTC也不是本地時間[編輯 | 編輯原始碼]

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

要強制校準你的時鐘,並且讓系統寫入正確的硬件時間,遵循下面幾步:

  • 設置好ntpd(不需要將其作為一個服務來運行);
  • 正確設置你的時區
  • 運行ntpd -qg,此時在系統和網絡進行時間校正時,會忽略本地UTC時間與網絡UTC時間之間過大的差異;
  • 運行hwclock --systohc,將當前的正確UTC時間寫入硬件時間。

外部資源[編輯 | 編輯原始碼]