hwclock 命令详解与参数实测(Ubuntu 22.04)
以 Ubuntu 22.04 服务器(util-linux 2.37.2,RTC 设备 /dev/rtc0)为实测环境,逐参数验证 hwclock 的读取类功能(-r/--show、--get、-v)、时制声明(-u/-l)、设备与 adjtime 控制(-f、--directisa、--noadjfile、--adjfile)、预测与写入类功能的 --test 干跑(--predict、--set、--systohc、--hctosys、--adjust、--systz)、--delay/--update-drift/--date 以及 /etc/adjtime 三行格式;所有写类操作仅以干跑取证,不实际改写硬件时钟。
hwclock 命令详解与参数实测(Ubuntu 22.04)
实测目标:在带硬件时钟(RTC)的 Ubuntu 22.04 服务器上,逐个验证
hwclock的读类参数与写类参数。读类参数(-r、--get、-v 等)全部真实执行;写类参数(--set、--systohc、--hctosys、--adjust、--systz)会改写硬件时钟、进而影响整机时钟基准,本文一律用--test干跑取证,并在第五章如实说明其在真实服务器上的行为与生产建议。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)
- 命令所属软件包:util-linux 2.37.2-4ubuntu3.6(
hwclock -V实测输出hwclock from util-linux 2.37.2) - 硬件时钟设备:
/dev/rtc0(主 RTC,字符设备 248:0,权限 crw-------,仅 root 可读写;RTC 类型rtc_cmos来自 verbose 实测输出) - 系统时区:UTC(
date -u与 verbose 中Using time zone 'UTC'.相互印证) - adjtime 文件:
/etc/adjtime存在(三行内容见 3.16 节) - 执行身份:root(非 root 行为实测见 3.17 节)
二、命令概览
2.1 语法与测试数据
Usage:
hwclock [function] [option...]
hwclock 管理两套时钟的读、写与换算:
- 系统时钟(System Time):由 Linux 内核维护,开机后所有程序用的是它;
- 硬件时钟(RTC,Real Time Clock):主板上的独立计时芯片,靠主板电池供电,关机断电后仍在走。
开机时内核从 RTC 读一次时间初始化系统时钟,之后两者各自独立走时,会逐渐出现偏差。hwclock 的全部价值就在于读写 RTC、以及用 /etc/adjtime 记录并校正 RTC 的系统性漂移。
测试数据约定:本文所有写类操作都追加 --test。--test 是干跑:完整执行"计算→预演"路径并打印将要写入的内容(含新的 /etc/adjtime 预览),但不真正落钟,verbose 输出末尾明确打印 Test mode: nothing was changed.。
💡 技术拓展:理解 hwclock 的关键是"双时钟 + 漂移账本"模型。RTC 芯片精度有限(每天快/慢若干秒是常态),Linux 不要求 RTC 完全准确,而是在
/etc/adjtime里记录 RTC 的日漂移率,读取时按时间差折算补偿(--get就是补偿后的读数,--predict可以预测未来任意时刻的 RTC 读数)。真正的对时权威应交给 NTP(见第五章 Q2)。
| 角色 | 存在位置 | 断电后 | 谁在改它 |
|---|---|---|---|
| 系统时钟 | 内核内存 | 丢失(每次开机从 RTC/网络重建) | NTP 服务、--hctosys、--systz |
| 硬件时钟 | 主板 RTC 芯片 | 保持走时 | --set、--systohc、--adjust |
| /etc/adjtime | 根文件系统 | 持久 | hwclock 每次写 RTC 时更新 |
2.2 --help 全量输出
hwclock --help
Usage:
hwclock [function] [option...]
Time clocks utility.
Functions:
-r, --show display the RTC time
--get display drift corrected RTC time
--set set the RTC according to --date
-s, --hctosys set the system time from the RTC
-w, --systohc set the RTC from the system time
--systz send timescale configurations to the kernel
-a, --adjust adjust the RTC to account for systematic drift
--predict predict the drifted RTC time according to --date
Options:
-u, --utc the RTC timescale is UTC
-l, --localtime the RTC timescale is Local
-f, --rtc <file> use an alternate file to /dev/rtc0
--directisa use the ISA bus instead of /dev/rtc0 access
--date <time> date/time input for --set and --predict
--delay <sec> delay used when set new RTC time
--update-drift update the RTC drift factor
--noadjfile do not use /etc/adjtime
--adjfile <file> use an alternate file to /etc/adjtime
--test dry run; implies --verbose
-v, --verbose display more details
-h, --help display this help
-V, --version display version
For more details see hwclock(8).
注意 --help 把参数分成 Functions(功能) 与 Options(修饰) 两段:功能段决定"做什么",一次只能选一个;修饰段调整"怎么做",可与任意功能组合。不带任何功能参数执行时,默认行为等价于 --show(3.1 节实测)。
2.3 版本信息
hwclock -V
hwclock --version
hwclock from util-linux 2.37.2
hwclock from util-linux 2.37.2
-V 与 --version 均可用,输出同时指明了所属软件包(util-linux)。
三、参数逐项实测
3.1 -r / --show:读取 RTC 当前时间
ls -l /dev/rtc*
date -u '+%Y-%m-%d %H:%M:%S %Z'
hwclock -r
hwclock --show
hwclock
crw------- 1 root root 248, 0 Oct 15 18:05 /dev/rtc0
2026-10-16 14:27:00 UTC
2026-10-16 14:26:58.998365+00:00
2026-10-16 14:26:59.998969+00:00
2026-10-16 14:27:00.998343+00:00
- 三种写法行为一致:
-r、长选项--show、以及不带任何参数的裸调用,全部返回 RTC 当前时间,退出码 0。 - 现代版 util-linux(2.31 起)输出 ISO 8601 格式,末尾的
+00:00表示按时区 UTC 换算。 - 对照
date -u(14:27:00)与hwclock -r(14:26:58.998,且执行时间晚约 1 秒),可见本机 RTC 读数落后系统时钟约 2 秒——RTC 走时误差是常态,这正是 adjtime 漂移账本与 NTP 存在的理由(第五章 Q1、Q2)。
💡 老脚本里常见的
hwclock -r解析(如hwclock -r | awk '{print $4}'按"Fri 16 Oct 2026 09:46:37"取第 4 列)在新版上会失效,输出已改为 ISO 格式;要拿时间戳可用hwclock --show配合date换算,或直接读date +%s。
3.2 --get:读取漂移校正后的 RTC 时间
hwclock --get
2026-10-16 14:27:01.998521+00:00
--get 与 --show 的区别在于:--show 给出 RTC 的原始读数,--get 给出按 adjtime 漂移率校正后的读数(即"RTC 真正应该等于的时间")。本机 adjtime 漂移因子为 0.000000(见 3.16 节),所以两者读数差异只剩执行间隔。当 RTC 有系统性漂移时,--get 才是"可信时间",--show 只是"钟面上的读数"。
💡 排障口诀:怀疑 RTC 不准时,先看
--show与--get的差值。差值稳定增长说明漂移因子没被记录(adjtime 为 0);差值被消除说明 adjtime 在起作用。
3.3 -v / --verbose:详细诊断输出(附 --debug 已废弃)
hwclock -v --show
hwclock from util-linux 2.37.2
System Time: 1792160824.288748
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2026/10/16 14:27:04
Hw clock time : 2026/10/16 14:27:04 = 1792160824 seconds since 1969
Time since last adjustment is 16806 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2026-10-16 14:27:02.998265+00:00
逐行解读(这是排障最有价值的输出):
System Time:执行瞬间内核系统时钟(epoch 秒,含小数);Trying to open: /dev/rtc0:实际使用的 RTC 设备路径;Using the rtc interface to the clock.:通过内核 RTC 驱动接口读取(未走 ISA 直读路径,对照 3.6 节);Last drift adjustment done at .../Last calibration done at ...:来自/etc/adjtime第一行的后两个数字;Hardware clock is on UTC time:adjtime 第三行声明的时制;Assuming hardware clock is kept in UTC time.:本次调用的时制假定(对照 3.4 节);Waiting for clock tick...:RTC 只能整秒更新,hwclock 等到下一个秒边界再读,保证读数不带毛刺;Time read from Hardware Clock/Hw clock time ... = N seconds since 1969:原始读数与折算后的 epoch 秒;Time since last adjustment is N seconds:距上次对钟的秒数,乘以日漂移率得到下一行;Calculated Hardware Clock drift is N seconds:当前累计漂移量(本机因子为 0,故为 0);- 最后一行:最终打印的 RTC 时间。
老参数 --debug 已废弃,但兼容期行为可用:
hwclock --debug --show
hwclock: use --verbose, --debug has been deprecated.
2026-10-16 14:27:03.998581+00:00
打印废弃提示后照常执行,退出码 0。新脚本一律改用 -v。
💡
--test会隐含打开 verbose(见 --help 中dry run; implies --verbose),所以后文所有干跑输出自带详细诊断,无需再加-v。
3.4 -u / --utc 与 -l / --localtime:声明 RTC 的时制
hwclock -u
hwclock -l
hwclock -u -v --show 2>&1 | grep -E 'Assuming|Hardware clock'
hwclock -l -v --show 2>&1 | grep -E 'Assuming|Hardware clock'
TZ=Asia/Shanghai hwclock -l --show
2026-10-16 14:27:04.998506+00:00
2026-10-16 14:27:05.998932+00:00
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Hardware clock is on UTC time
Assuming hardware clock is kept in local time.
2026-10-16 14:27:08.998648+00:00
-u/-l声明 RTC 钟面上存的到底是 UTC 还是本地时间,只影响换算与显示,不影响读钟本身。- 本机系统时区是 UTC,两种换算结果数值相同,可分辨的只有 verbose 中的假定行(
kept in UTC timevskept in local time);Hardware clock is on UTC time是 adjtime 记录的既有时制,Assuming ...是本次命令采用的时制。 - 实测要点:给
-l设置TZ=Asia/Shanghai环境变量,显示仍是+00:00(UTC)——hwclock 的"本地时区"跟随系统/etc/localtime,不认TZ环境变量。要在单次调用里换算到别的时区,得改系统时区或用date/timedatectl完成。
💡 RTC 该存 UTC 还是本地时间?Linux 世界默认 UTC(服务器跨时区迁移、夏令时切换都不出错)。只有与 Windows 双系统共存的机器才需要 LOCAL,详见第五章 Q6。
3.5 -f / --rtc:指定 RTC 设备文件
hwclock -f /dev/rtc0 --show
2026-10-16 14:27:09.998564+00:00
-f 把默认的 /dev/rtc0 换成指定设备文件。多 RTC 系统(如同时有 /dev/rtc0、/dev/rtc1)里用它点名操作哪块 RTC;也可指向其他兼容设备。指定不存在的设备会报 No such file or directory 并返回非 0。
3.6 --directisa:绕过内核驱动直读 CMOS
hwclock --directisa --show
2026-10-16 14:27:11.001341+00:00
默认路径是 3.3 节 verbose 里的 Using the rtc interface to the clock.(走内核 RTC 驱动);--directisa 改为直接 I/O 访问 CMOS/ISA 端口,用于内核 RTC 驱动不可用的老旧或特殊平台。在标准 x86_64 服务器上两条路径读数一致,日常不需要它。
3.7 --noadjfile:忽略 adjtime 账本
hwclock --noadjfile --show
hwclock --noadjfile -u --show
hwclock: With --noadjfile, you must specify either --utc or --localtime
2026-10-16 14:27:11.998562+00:00
- 单用
--noadjfile直接报错退出码 1:提示信息明确要求必须同时给-u或-l——因为不看账本就无从得知时制,必须显式声明。 - 补上
-u后正常执行,退出码 0;此后 hwclock 不读也不写/etc/adjtime,漂移按 0 处理,时制完全由命令行决定。
💡
--noadjfile的典型用途:只读场景下避免 hwclock 顺手更新 adjtime 文件(对只读根文件系统的机器友好),以及在临时环境中做确定性测试。
3.8 --adjfile:指定替代的 adjtime 文件
为了验证"漂移因子如何进入计算",构造一个替代账本:漂移因子 0.000010 秒/天,时制 LOCAL:
printf '0.000010 1792144000 0.000000\n1792144000\nLOCAL\n' > /etc/adjtime.alt
cat /etc/adjtime.alt
hwclock --adjfile /etc/adjtime.alt -v --show
0.000010 1792144000 0.000000
1792144000
LOCAL
hwclock from util-linux 2.37.2
System Time: 1792160834.314956
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144000 seconds after 1969
Last calibration done at 1792144000 seconds after 1969
Hardware clock is on local time
Assuming hardware clock is kept in local time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2026/10/16 14:27:14
Hw clock time : 2026/10/16 14:27:14 = 1792160834 seconds since 1969
Time since last adjustment is 16834 seconds
Calculated Hardware Clock drift is 0.000001 seconds
2026-10-16 14:27:12.998454+00:00
- verbose 三处随之变化:
Last drift adjustment done at 1792144000(替代文件第一行第二个数字)、Hardware clock is on local time(替代文件第三行 LOCAL)、Calculated Hardware Clock drift按替代文件的漂移率折算出 0.000001 秒。 - 漂移因子单位是每天多少秒:0.000010 秒/天 ×(16834 秒 ÷ 86400 秒/天)≈ 百万分之二秒,verbose 保留 6 位小数显示 0.000001,量级完全一致;对照 3.3 节因子为 0 时恒为 0.000000。
配合 --predict 更直观(3.9 节)。指定不存在的 adjfile 时,hwclock 按默认值(漂移 0、UTC)继续工作,不报错。
💡 想验证"大漂移率"下的行为,把因子改到 3.5 秒/天再预测(
printf '3.500000 1792144018 0.000000\n1792144018\nUTC\n' > /tmp/adjtime-demo2后hwclock --adjfile /tmp/adjtime-demo2 --predict --date '2027-01-01 00:00:00' -v):距上次对钟 6617582 秒(约 76.6 天),Calculated Hardware Clock drift is 268.073344 seconds,Predicted RTC: 1798761331比目标1798761600恰好慢 269 秒(268.07 秒漂移 + 整秒取整),"天数 × 日漂移率"分毫不差。这也解释了 adjtime 因子为什么精确到小数点后 6 位。
3.9 --predict:预测未来某时刻的 RTC 读数
hwclock --predict --date '2027-06-01 12:00:00'
hwclock --adjfile /etc/adjtime.alt --predict --date '2027-10-16 09:46:40' -v
2027-06-01 12:00:00.000000+00:00
hwclock from util-linux 2.37.2
System Time: 1792160835.317661
Last drift adjustment done at 1792144000 seconds after 1969
Last calibration done at 1792144000 seconds after 1969
Hardware clock is on local time
Assuming hardware clock is kept in local time.
Time since last adjustment is 31536000 seconds
Calculated Hardware Clock drift is 0.003650 seconds
Target date: 1823680000
Predicted RTC: 1823679999
2027-10-16 09:46:39.996350+00:00
- 第一条:默认 adjtime(因子 0)下,预测结果就是目标时间本身。
- 第二条用 3.8 节的替代账本:距上次对钟恰好 31536000 秒(整 365 天),日漂移 0.000010 秒 × 365 = 0.003650 秒,verbose 分毫不差;
Predicted RTC(1823679999)比Target date(1823680000)慢了这 0.0036 秒的整数化结果。 --predict只算不写,天然安全,可放心在任何环境执行。
💡
--predict是理解 adjtime 的最好的实验台:改账本里的因子,看预测差值线性变化,比读 man page 直观得多。系统长跑后想知道 RTC 会偏多少,用它即可。
3.10 --set:把 RTC 设置为指定时间(--test 干跑)
hwclock --set --date '2027-01-01 08:00:00' --test
hwclock from util-linux 2.37.2
System Time: 1792160835.319898
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
RTC type: 'rtc_cmos'
Using delay: 0.500000 seconds
1792160835.819898 is close enough to 1792160835.819898 (0.000000 < 0.001000)
Set RTC to 1798790400 (1798790400 + 0; refsystime = 1792160835.319898)
Setting Hardware Clock to 08:00:00 = 1798790400 seconds since 1969
Not adjusting drift factor because the --update-drift option was not used.
New /etc/adjtime data:
0.000000 1798790400 0.000000
1798790400
UTC
Test mode: nothing was changed.
要点:
--set按--date指定的任意时间写 RTC(注意与--systohc的区别:后者取当前系统时间)。Target/Setting Hardware Clock to 08:00:00 = 1798790400:目标时刻的 epoch 秒;Not adjusting drift factor because the --update-drift option was not used.:--set默认重置漂移因子并刷新"上次对钟时间",除非显式--update-drift(见 3.10.3);New /etc/adjtime data:三行预览就是真实执行时将要写入/etc/adjtime的内容;- 末行
Test mode: nothing was changed.确认干跑未落钟。干跑之后复核 RTC(3.10.4)读数未变。
3.10.1 --delay:写钟延迟秒数
hwclock --set --date '2027-01-01 08:00:00' --delay 3 --test
Using delay: 3.000000 seconds
1792160841.508092 is close enough to 1792160839.2508092 (0.000000 < 0.001000)
Set RTC to 1798790400 (1798790400 + 0; refsystime = 1792160838.508092)
Setting Hardware Clock to 08:00:00 = 1798790400 seconds since 1969
...
Test mode: nothing was changed.
--delay 控制"设定时刻相对当前时刻的写入延迟"(默认 0.5 秒,见 3.10 的 Using delay: 0.500000 seconds)。RTC 芯片在秒边界更新,写入要"瞄准"未来的某个秒边界;延迟太短容易踩空(verbose 会打印 missed it ... 再重试下一个边界)。仅当对写入精度有特殊要求时才需要调整。
3.10.2 --update-drift:写钟同时更新漂移因子
hwclock --set --date '2027-01-01 08:00:00' --update-drift --test
Time since last adjustment is 16824 seconds
Calculated Hardware Clock drift is 0.000000 seconds
RTC type: 'rtc_cmos'
Using delay: 0.500000 seconds
...
Set RTC to 1798790401 (1798790400 + 1; refsystime = 1792160841.509382)
Setting Hardware Clock to 08:00:01 = 1798790401 seconds since 1969
Clock drift factor was calculated as 86181.308530 seconds/day.
It is far too much. Resetting to zero.
New /etc/adjtime data:
0.000000 1798790400 0.000000
1798790400
UTC
Test mode: nothing was changed.
加 --update-drift 后,hwclock 会根据"RTC 实际读数与系统时间的偏差"反算新漂移因子。本例反算出 86181.3 秒/天的离谱值(约等于每天偏 1 天),hwclock 自带保护:It is far too much. Resetting to zero.——超过合理阈值直接归零,防止账本被污染。这说明 --update-drift 只适合"RTC 与系统时间只差几十秒以内"的正常校准场景。
3.10.3 --date 非法格式
hwclock --set --date 'not-a-date' --test
hwclock: invalid date 'not-a-date'
--date 只接受可解析的日期时间格式(如 2027-01-01 08:00:00),解析失败报 invalid date 并返回退出码 1,不会继续执行。
3.10.4 干跑后复核
hwclock --show
2026-10-16 14:27:21.998451+00:00
连续多组 --test 干跑后 RTC 读数仍随自然时间走,未被改成 2027 年——验证干跑安全。
💡 真实执行
--set会立即改写 RTC 并重写 adjtime(对钟时刻、漂移因子都更新)。在服务器上手动--set一个过去/未来的时间,会立即反映到下次重启后的系统时钟(开机从 RTC 初始化),务必想清楚再敲。
3.11 -w / --systohc:把系统时间写入 RTC(--test 干跑)
hwclock --systohc --test
hwclock from util-linux 2.37.2
System Time: 1792160835.821033
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
RTC type: 'rtc_cmos'
Using delay: 0.500000 seconds
missed it - 1792160835.821227 is too far past 1792160835.500000 (0.321227 > 0.001000)
1792160836.500000 is close enough to 1792160836.500000 (0.000000 < 0.002000)
Set RTC to 1792160836 (1792160835 + 1; refsystime = 1792160835.000000)
Setting Hardware Clock to 14:27:16 = 1792160836 seconds since 1969
Not adjusting drift factor because the --update-drift option was not used.
New /etc/adjtime data:
0.000000 1792160835 0.000000
1792160835
UTC
Test mode: nothing was changed.
--systohc(hctosys 的反操作:system → hardware clock)把当前系统时间写入 RTC。verbose 完整展示了"瞄秒边界"的过程:missed it - ... is too far past ... 说明第一次没踩准 0.5 秒延迟窗口,自动瞄准下一个秒边界重试,最终 Set RTC to 1792160836。New /etc/adjtime data 预览显示真实执行后"上次对钟时间"会刷新为本次时刻。
💡
--systohc的经典用途:改完系统时区(timedatectl set-timezone)或完成 NTP 对时后,把权威时间落盘到 RTC,保证下次开机就是对的。--set与--systohc的区别:--set配--date写任意时间(常用于修复偏差巨大的 RTC),--systohc只写当前系统时间(常规落盘)。
3.12 -s / --hctosys:把 RTC 时间设为系统时间(--test 干跑)
hwclock --hctosys --test
hwclock from util-linux 2.37.2
System Time: 1792160836.501155
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2026/10/16 14:27:17
Hw clock time : 2026/10/16 14:27:17 = 1792160837 seconds since 1969
Time since last adjustment is 16819 seconds
Calculated Hardware Clock drift is 0.000000 seconds
Calling settimeofday(NULL, 0) to lock the warp_clock function.
Calling settimeofday(1792160837.000000, NULL) to set the System time.
Test mode: nothing was changed.
--hctosys 是开机时序的复刻:读 RTC(经漂移校正)→ 用 settimeofday 系统调用重置内核系统时钟。verbose 最后两行就是真实的动作(warp_clock 锁定 + 设定系统时间)。它要求 root 权限(--help 与 man page 均注明 hctosys requires root privilege),否则 settimeofday 会被拒绝。
3.13 -a / --adjust:按漂移账本微调 RTC(--test 干跑)
hwclock --adjust --test
hwclock from util-linux 2.37.2
System Time: 1792160837.503916
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2026/10/16 14:27:18
Hw clock time : 2026/10/16 14:27:18 = 1792160838 seconds since 1969
Time since last adjustment is 16820 seconds
Calculated Hardware Clock drift is 0.000000 seconds
Needed adjustment is less than one second, so not setting clock.
Test mode: nothing was changed.
--adjust 不以系统时间为准,而是按 adjtime 记录的漂移率把 RTC 微调"回到正确值",然后刷新账本的对钟时刻。本机漂移因子为 0,累计校准量不足 1 秒,verbose 明说 Needed adjustment is less than one second, so not setting clock.——不动钟是正确行为。
💡
--adjust的设计初衷是给长期不联网的服务器定期纠偏(如 cron 里每天凌晨跑一次hwclock --adjust)。联网机器交给 NTP 即可,手动跑它反而可能与 NTP 打架。
3.14 --systz:向内核下发时制配置(--test 干跑)
hwclock --systz --test
hwclock from util-linux 2.37.2
System Time: 1792160838.506937
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Calling settimeofday(NULL, 0) to lock the warp_clock function.
Test mode: nothing was changed.
--systz 不搬时间,只按系统时区配置重置内核对 RTC 的假定(timezone/warp 标志),解决"内核启动时把 RTC 换算错了"的问题。verbose 里只有一行 settimeofday(NULL, 0) 锁定动作。它通常由发行版启动脚本在早期调用,运维手工场景很少。
3.15 --test:干跑的通用规则
从 3.10~3.14 的输出可以归纳 --test 的三条规则,全部来自实测:
- 隐含 verbose:
--test自带详细诊断,无需再加-v; - 完整走计算路径:包括瞄秒边界(可能出现
missed it重试)、漂移折算、adjtime 预览,与真实执行唯一不同的是"不写"; - 明确声明:每次输出末尾打印
Test mode: nothing was changed.,3.10.4 节复核确认 RTC 未变。
3.16 /etc/adjtime:漂移账本的三行格式
cat /etc/adjtime
0.000000 1792144018 0.000000
1792144018
UTC
| 行 | 内容 | 本实测值 | 含义 |
|---|---|---|---|
| 第 1 行 | 漂移因子 + 两个 epoch 时刻 | 0.000000 1792144018 0.000000 | RTC 日漂移率(秒/天);上次漂移调整时刻;上次校准时刻 |
| 第 2 行 | epoch 时刻 | 1792144018 | 上次"设钟"时刻(--systohc/--set 刷新),对应 2026-10-16 09:46:58 UTC |
| 第 3 行 | UTC 或 LOCAL | UTC | RTC 时制声明 |
- 三行格式由新版 hwclock 维护;旧系统可能只有两行(无第 3 行,按 UTC 处理)。
- 账本不需要手工维护,正常使用中由
--systohc、--set、--adjust自动刷新;3.8 节演示了手工构造替代账本的做法,标准账本也可用同样方式重建(内容可先从任意一次--test的New /etc/adjtime data:预览抄录)。 - verbose 中的
Time since last adjustment is N seconds就是"当前时刻 − 第 2 行"。
💡 第 3 行是"RTC 时制"的持久化来源,与 3.4 节的
-u/-l命令行声明、timedatectl的RTC in local TZ字段是同一件事的三张面孔;排查时制问题按这个链路核对即可。
3.17 非 root 执行
setpriv --reuid 65534 --regid 65534 --clear-groups hwclock -r
hwclock: Cannot access the Hardware Clock via any known method.
hwclock: Use the --verbose option to see the details of our search for an access method.
非 root 读 RTC 失败:/dev/rtc0 权限为 crw-------(3.1 节),普通用户两种访问路径(驱动接口与直读端口)都走不通。读类参数同样需要 root,这与很多"读操作不需要特权"的命令不同。
3.18 技术拓展:hwclock 与 date / timedatectl 对比
| 对比项 | hwclock | date | timedatectl |
|---|---|---|---|
| 定位 | 硬件时钟(RTC)读写与漂移管理 | 显示/设置系统时钟 | systemd 的时钟/时区/NTP 总管 |
| 读取对象 | /dev/rtc*(主板芯片) | 内核系统时钟 | 系统时钟 + RTC + NTP 状态 |
| 时区控制 | 只声明 RTC 时制(-u/-l),显示跟随系统时区 | TZ= 环境变量/-u 按任意时区显示 | set-timezone 持久化系统时区 |
| 校时能力 | --set/--systohc/--hctosys/--adjust(写 RTC 或系统时钟) | date -s(仅系统时钟) | set-time、set-ntp true(托管 NTP) |
| 漂移校正 | 有(/etc/adjtime、--get、--predict 独家) | 无 | 无 |
| 依赖 | util-linux(无 systemd 也能用) | coreutils | systemd |
| 典型场景 | 开机初始化、双系统、离线机纠偏 | 脚本取时间戳、临时换算时区 | 日常运维看时钟全景、开 NTP |
三者配合的真实链路:开机时 init 用 hwclock --hctosys 把 RTC 校正后灌入系统时钟 → 运行期 NTP(timedatectl set-ntp true 托管)持续校正系统时钟 → 关机或定期由 systemd 把系统时钟落回 RTC(相当于 --systohc)。timedatectl 的输出字段(Local time、Universal time、RTC time、Time zone、System clock synchronized、NTP service、RTC in local TZ)正好是这套链路的全景面板;无 RTC 的虚拟机/嵌入式环境里其 RTC time 字段会显示 n/a,此时只能依赖 NTP。
四、实战示例
4.1 服务器时钟体检:三分钟搞清双时钟状态
date -u '+%Y-%m-%d %H:%M:%S %Z'
hwclock -r
hwclock --get
cat /etc/adjtime
2026-10-16 14:42:51 UTC
2026-10-16 14:42:50.998529+00:00
2026-10-16 14:42:51.998843+00:00
0.000000 1792144018 0.000000
1792144018
UTC
判断顺序:系统时间与 RTC 读数差值是否在秒级(本例约 1 秒,属正常)→ adjtime 漂移因子是否为 0 → --get 与 --show 的差值是否被账本消除(本例因子 0,两者读数差只剩执行间隔的 1 秒)。任何一项异常都指向第五章对应的 FAQ。
4.2 校时前先干跑预演:把风险挡在执行之前
hwclock --systohc --test | tail -5
New /etc/adjtime data:
0.000000 1792160835 0.000000
1792160835
UTC
Test mode: nothing was changed.
任何写钟动作前先 --test 看两件事:将要写进 RTC 的时间对不对(Setting Hardware Clock to ...)、将要重写的 adjtime 对不对(New /etc/adjtime data:)。确认无误再去掉 --test 真实执行。
4.3 判断 RTC 时制(UTC 还是 LOCAL)
hwclock -v --show 2>&1 | grep -E 'Hardware clock is on|Assuming'
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
两行一致说明命令行假定与账本声明吻合;如果 Hardware clock is on local time 与实际时制不符,开机换算就会错掉一个时区偏移,用 timedatectl set-local-rtc 0(回到 UTC)修正后重跑本命令复核。
4.4 估算 RTC 漂移:用 --predict 做算术
printf '0.050000 1792144018 0.000000\n1792144018\nUTC\n' > /tmp/adjtime-demo
hwclock --adjfile /tmp/adjtime-demo --predict --date '2027-10-16 09:46:58' -v
hwclock from util-linux 2.37.2
System Time: 1792161773.526620
Last drift adjustment done at 1792144018 seconds after 1969
Last calibration done at 1792144018 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time.
Time since last adjustment is 31536000 seconds
Calculated Hardware Clock drift is 18.250000 seconds
Target date: 1823680018
Predicted RTC: 1823679999
2027-10-16 09:46:39.750000+00:00
构造一个 0.05 秒/天(真实 RTC 的典型量级)的账本,目标时刻取距上次对钟整一年:365 天 × 0.05 = 18.25 秒,verbose 的 Calculated Hardware Clock drift is 18.250000 seconds 分毫不差;Predicted RTC(1823679999)正是目标 1823680018 减去 18.25 秒后的取整。同类方法可推算"这台服务器一年会偏多少秒",作为是否需要定期 --systohc 落盘或更换硬件的决策依据。
五、注意事项与常见问题
Q1:date 和 hwclock -r 显示的时间对不上,先修哪个?
先看差值方向与大小。差值固定约等于时区偏移(如 8 小时)→ RTC 时制声明错了(3.4/Q6);差值是秒级 → RTC 走时漂移,联网机器开启 NTP 校正系统时钟、systemd 会自动落盘 RTC,离线机器用 --systohc 对齐后靠 --adjust/adjtime 慢慢纠偏。不要用 date -s 手动硬改系统时钟来"追"RTC,会引入新的不一致。
Q2:真实服务器上执行 --systohc/--hctosys 到底会发生什么?生产上该自己跑吗?
--systohc 真实执行时:把当前系统时钟写入 RTC,并重写 /etc/adjtime(对钟时刻刷新、漂移因子按 3.10.2 的规则处理)——RTC 与系统时钟从此对齐,效果在下一次开机时体现。--hctosys 真实执行时:用 settimeofday 把系统时钟重置为 RTC 校正值——所有运行中的进程立刻感知时间跳变,日志时间戳、cron 计划、TLS 校验都可能受影响,因此它是开机阶段(init/udev)专用的参数。生产建议:保持 NTP 服务常驻(timedatectl set-ntp true,底层 systemd-timesyncd 或 chrony),由它持续校正系统时钟并定期把系统时间落盘 RTC;手工 --systohc 只在修时区、修完 NTP 后落盘一次,--hctosys 基本不应手工执行。
Q3:为什么 --debug 会提示废弃?
util-linux 已用 -v/--verbose 全面替代 --debug(3.3 节实测提示 use --verbose, --debug has been deprecated.)。老脚本里的 --debug 在当前版本仍兼容可用,但新脚本一律写 -v。
Q4:误删 /etc/adjtime 会怎样?
hwclock 不报错,按默认账本工作:漂移因子 0、RTC 时制假定为 UTC。若 RTC 实际是 LOCAL 或有可观漂移,开机时制换算就会出错。重建方法:确认时制后执行一次 hwclock --systohc,账本会按当前状态重新生成;也可以先 --test 看预览再手工落盘(3.16 节)。
Q5:为什么 --noadjfile 必须配 -u 或 -l?
账本被禁用后,hwclock 失去时制信息的来源,必须从命令行获得显式声明,否则直接拒绝执行(3.7 节实测 With --noadjfile, you must specify either --utc or --localtime)。这个强制设计避免了"漂移按 0、时制靠猜"的静默错误。
Q6:RTC 存 UTC 还是本地时间?和 Windows 双系统冲突怎么办?
Linux 惯例是 UTC:不惧夏令时切换与跨时区迁移。Windows 默认把 RTC 当本地时间,双系统下 Linux 若也按 LOCAL 处理才能两全(Ubuntu 上 timedatectl set-local-rtc 1,并接受系统给出的告警)。纯 Linux 服务器一律 UTC(3.16 节第 3 行写 UTC)。注意 3.4 节实测:-l 的"本地时区"只认系统 /etc/localtime,TZ 环境变量不影响。
Q7:普通用户执行报 "Cannot access the Hardware Clock via any known method."?
/dev/rtc* 权限是 crw-------,读写 RTC 一律需要 root(3.17 节实测)。提示语让加 --verbose 看访问方法详情,root 下执行 hwclock -v -r 即可看到它尝试的每条路径(3.3 节)。
Q8:--set、--systohc、--adjust 都会"改 RTC",到底用哪个?
按"以谁为准"选:以指定的目标时间为准用 --set --date(修大偏差);以当前系统时间为准用 --systohc(常规落盘);以 adjtime 账本为准做微调用 --adjust(离线机日常纠偏)。三者都会重写 adjtime;--set 默认把漂移因子清零,想保留就加 --update-drift(3.10.2 的离谱值保护同样适用)。
六、参考链接
man hwclock(本机手册,含 --systohc/--hctosys 的完整行为描述与 adjtime 三行格式)- hwclock(8) 在线手册(Ubuntu 22.04 jammy):https://manpages.ubuntu.com/manpages/jammy/en/man8/hwclock.8.html
- adjtime(5) 在线手册(adjtime 文件格式):https://manpages.ubuntu.com/manpages/jammy/en/man5/adjtime.5.html
- timedatectl(1) 在线手册(系统时钟/NTP/时区托管):https://manpages.ubuntu.com/manpages/jammy/en/man1/timedatectl.1.html
- util-linux 上游源码与发行版:https://github.com/util-linux/util-linux