若您在操作过程中涉及配置更改、数据写入、重启服务等操作,需核实操作前是否已经进行快照备份,以免对您的系统造成直接影响。
问题背景
Linux主机设置了系统时间为UTC(设置方法是ln -s /usr/share/zoneinfo/UTC /etc/localtime),但是重启后时间会比实际时间快8小时。
原理
Linux系统用两个时钟保存时间:硬件时钟和系统时钟。
硬件时钟(即实时时钟 RTC 或 CMOS 时钟)仅能保存:年、月、日、时、分、秒这些时间数值,无法保存时间标准(UTC 或 localtime)和是否使用夏令时调节。
系统时钟(即软件时间)与硬件时间分别维护,保存了:时间、时区和夏令时设置。Linux 内核保存为自 UTC 时间 1970 年1月1日经过的秒数。初始系统时钟是从硬件时间计算得来,计算时会考虑
/etc/adjtime
的设置。系统启动之后,系统时钟与硬件时钟独立运行,Linux 通过时钟中断计数维护系统时钟。因为系统时间是按 32 为整数保存的,最大只能记到 2038 年,所以 32 位 Linux 系统将在 2038 年停止工作。
大部分操作系统的时间管理包括如下方面:
启动时根据硬件时钟设置系统时间
运行时通过时间同步联网校正时间
关机时根据系统时间设置硬件时间
用户的设置系统时间为UTC方法仅能让系统时间读取UTC的数据,若关机重启,由于RTC in local TZ: yes,系统会把当前+8时区的时间设置给硬件时间。RTC时间由于没有时区信息,启动的时候,根据之前保存RTC时间设置系统时间,就会错把+8时区的时间作为+0区的UTC时间设置给系统时间,所以系统时间的UTC时间设定会比真实的UTC时间快8小时。
通过NTP等方式可以同步时间。通过timedatectl status可以看到系统的提示中说明,系统设置从本地时区设置RTC时间,这种模式没有被完全支持,会造成很多麻烦,如果可以的话,可以通过timedatectl set-local-rtc 0来设置RTC使用UTC时间。
# timedatectl status Local time: Thu 2019-12-05 13:25:28 CST Universal time: Thu 2019-12-05 05:25:28 UTC RTC time: Thu 2019-12-05 13:25:29 Time zone: Asia/Shanghai (CST, +0800) NTP enabled: no NTP synchronized: yes RTC in local TZ: yes DST active: n/a Warning: The system is configured to read the RTC time in the local time zone. This mode can not be fully supported. It will create various problems with time zone changes and daylight saving time adjustments. The RTC time is never updated, it relies on external facilities to maintain it. If at all possible, use RTC in UTC by calling 'timedatectl set-local-rtc 0'.
解决方法
通过timedatectl set-local-rtc 0
设置RTC in local TZ: no,使得RTC时间存储为UTC时间了。
# timedatectl status Local time: Thu 2019-12-05 05:41:16 UTC Universal time: Thu 2019-12-05 05:41:16 UTC RTC time: Thu 2019-12-05 05:41:16 Time zone: UTC (UTC, +0000) NTP enabled: no NTP synchronized: yes RTC in local TZ: no DST active: n/a
总结
正确的设置系统时间为UTC的方式是timedatectl set-timezone UTC,此外使用timedatectl可以进行如下常见操作
查看当前时间/日期/时区:timedatectl或者timedatectl status
查看所有可用时区:timedatectl list-timezones
设置时区:timedatectl set-timezone “Asia/Shanghai” 或者 timedatectl set-timezone PRC
设置时间:timedatectl set-time HH:MM:SS
设置日期:timedatectl set-time YYYY-MM-DD
设置日期时间:timedatectl set-time “YYYY-MM-DD HH:MM:SS”
设置硬件时钟为本地时间:timedatectl set-local-rtc 1
设置硬件时钟为UTC时间:timedatectl set-local-rtc 0
启动NTP时间同步(启用NTP服务或者Chrony服务):timedatectl set-ntp true
禁用NTP时间同步:timedatectl set-ntp false