# hwclock - 显示与设定硬件时钟

hwclock命令 是一个硬件时钟访问工具,它可以显示当前时间、设置硬件时钟的时间和设置硬件时钟为系统时间,也可设置系统时间为硬件时钟的时间。

在Linux中有硬件时钟与系统时钟等两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。当Linux启动时,系统时钟会去读取硬件时钟的设定,之后系统时钟即独立运作。所有Linux相关指令与函数都是读取系统时钟的设定。

hwclock是一种访问硬件时钟的工具,可以显示当前时间,将硬件时钟设置为指定的时间,将硬件时钟设置为系统时间,以及从硬件时钟设置系统时间。您还可以定期运行hwlock以插入或删除硬件时钟中的时间,以补偿系统漂移(如果继续运行,则该时钟始终以一定的速率获得或丢失时间)。

# 适用范围

RedHat
RHEL
Ubuntu
CentOS
Debian
Deepin
SUSE
openSUSE
Fedora
Linux Mint
Alpine Linux
Arch Linux

# 语法

hwclock  [functions]  [options]

# 选项

下面的选项告诉hwclock指令该执行那个函数

-r, --show              # 读取硬件时钟并在标准输出上打印时间。显示的时间总是本地时间,即使您将硬件时钟保持在协调的世界时间。请参见-UTC选项。
--set                   # 将硬件时钟设置为-date选项指定的时间
-s, --hctosys           # 从硬件时钟设置系统时间。
                        # 还将内核的时区值设置为由TZ环境变量和/或/usr/share/zoneinfo指示的本地时区,正如tzset(3)所解释的那样。内核时区值的过时的tz_dsttime字段被设置为DST_NONE。(有关此字段过去的含义的详细信息,请参阅日期的settimeofday(2)。
                        # 这是在系统启动脚本中使用的一个很好的选项
-w, --systohc           # 将硬件时钟设置为当前的系统时间
--systz                 # 根据当前时区设置内核的时区并重置系统时间,系统时间仅在启动后的第一次调用时重置。
                        # 本地时区被认为是TZ环境变量和/或/usr/share/zoneinfo所指示的,tzset(3)将解释它们。内核时区值的过时tz_dsttime字段设置为DST_NONE。(有关此字段过去的含义的详细信息,请参阅日期的settimeofday(2)。
                        # 这是-hctosys的另一个选项,它不读取硬件时钟,并且可以在最近2.6内核的系统启动脚本中使用,因为您知道系统时间包含硬件时钟时间。如果硬件时钟已经在协调时,则不会重置。
--adjust                # 从硬件时钟中增加或减去时间,以说明自上次时钟设置或调整以来的系统漂移。请参阅下面的讨论
--getepoch              # 将内核的硬件时钟时纪元打印到标准输出。这是在AD中引用硬件时钟中的零年值的年份数。正在使用的约定是,硬件时钟中的年份计数器包含1952年以来的完整年份数,然后是内核的硬件计数器时代值必须是1952年。
                        # 每当hwlock读取或设置硬件时钟时,就会使用这个纪元值。epoch只有在Alpha机器上有。
--setepoch              # 将内核的硬件时钟纪元值设置为--epoch选项指定的值。
-v, --version           # 在标准输出上显示hwclock的版本
--date=date_string      # 如果指定-set选项,则需要此选项。否则,将忽略该选项。这将指定设置硬件时钟的时间。选项是date指令的参数。例如:hwclock --set --date="9/22/96 16:45:05"
                        # 参数在本地时间,即使您将硬件时钟保持在协调的世界时间。请参见-UTC选项。
--epoch=year            # 指定硬件时钟时代开始的年份,即在AD中,硬件时钟的年份计数器中的零值所指的进入AD的年份数。它与-setepoch选项一起使用,以设置内核的硬件时钟时代概念,或者指定用于直接ISA访问的时代。例如:hwclock --setepoch --epoch=1952

下面的选项配合函数使用

-u, --utc, --localtime  # 指示硬件时钟分别保持在协调的世界时间或本地时间。您可以选择是否将时钟保持在协调世界协调时或本地时间,但时钟中没有显示任何信息。这是你所选择的,所以这个选项就是你如何将信息提供给时钟。
                        # 如果您指定了这些选项中的一个错误的(或者没有指定,并且选择了错误的默认值),那么硬件时钟的设置和查询都将被搞砸。
                        # 如果您没有指定-utc或-localtime,则默认值以最后一次使用hwlock设置时钟时指定的值为准(即,hwlock成功地使用-set、-system ohc或-调整器选项运行),如adjtime文件中所记录的。如果adjtime文件不存在,则默认值为本地时间。
--noadjfile             # 禁用/etc/adjtime.hwlock提供的工具,不使用此选项读取或写入该文件。在使用此选项时,必须指定-UTC和--localtime
--adjfile=ilename       # 覆盖默认的/etc/adjtime文件
-f, --rtc=filename      # 重写默认/dev文件名,在许多平台上为/dev/rtc,但可能是/dev/rtc0、/dev/rtc1,等等。
--directisa             # 只有在ISA机器或Alpha上才有意义(粗略地说,它实现了足够多的ISA机器来实现hwlock的目的)。对于其他机器,它没有作用。这个选项告诉hwlock使用显式I/O指令来访问硬件时钟。如果没有这个选项,hwlock就会尝试。若要使用/dev/rtc设备(假定它由RTC设备驱动程序驱动),如果它无法打开设备(用于读取),它将使用显式I/O指令。
--badyear               # 表示硬件时钟无法存储超出1994-1999年范围的年份。在一些BIOSes(几乎所有在4/26/94至5/31/95之间制造的BIOSes)中都存在一个问题,在这些BIOSes中,它们无法处理1999年之后的年份。如果试图将世纪价值设置为小于94(或95 in)的值。在某些情况下,实际设置的值为94(或95),因此,如果您有这些机器中的一台,则hwlock不能在1999年之后设置,也不能以正常的方式使用时钟的值作为真正的时间。
                        # 为了弥补这一点(没有BIOS更新,这肯定更好),请始终使用-如果您有这些机器中的一台,就使用-坏年份。在adjtime文件中假设日期是过去一年内的日期。要想让它发挥作用,你最好每年至少运行一次hwclock --set或hwlock –systohc。
                        # 虽然hwlock在读取硬件时钟时忽略了年份值,但当它设置时钟时,它会设置年份值,将其设置为1995、1996、1997或1998,无论哪个年份在闰年周期中所处的位置与真正的年份相同。这样,硬件时钟就会插入。如果你让硬件时钟在没有设置的情况下运行一年以上,这个方案可能会失败,最后你可能会损失一天。
--srm                   # 此选项等价于--epoch=1900,用于使用srm控制台指定alphad上最常见的历元。
--arc                   # 此选项等价于--epoch=1980,用于使用ARC控制台指定ALPHS上最常见的历次(但Ruffans有1900年)。
--jensen, --funky-toy   # 这两个选项指定了您拥有的Alpha机器的类型。如果您没有Alpha,则它们是无效的,如果有,它们通常是不必要的,因为hwlock应该能够自行确定运行在什么上,至少在安装/proc时是这样的。(如果您发现您需要这些选项之一使hwlock工作,请与维护人员联系,看看程序是否可以改进以自动检测您的系统。‘hwlock --debug’和‘cat/proc/cpuinfo’的输出可能会引起人们的兴趣。)
                        # --jensen代表运行在Jensen模式。
                        # --funky-toy意味着在您的机器上,必须使用UF位而不是硬件时钟中的UIP位来检测时间转换。选项名中的“toy”是指机器一年中的时间
--test                  # 测试程序,不改变任何设置
--debug                 # 显示大量关于hwlock内部正在做什么的信息,其中一些功能是复杂的,这个输出可以帮助您理解程序是如何工作的。

# 说明

一般在操作系统中都会有两个时钟,硬件时钟是主板上的定时器时钟,系统时钟是系统的内核时钟,它们相互不影响。

1.硬件时钟

这个时钟,运行独立于任何控制程序运行在CPU中,甚至当机器关闭。在ISA系统中,这个时钟被指定为ISA标准的一部分。控制程序可以读取或设置这个时钟为整秒,但控制程序也可以检测1秒时钟的边缘,因此该时钟实际上具有无限的精度。

这种时钟通常被称为硬件时钟、实时时钟、RTC、BIOS时钟和CMOS时钟。硬件时钟以其大写的形式被hwlock所发明,因为其他所有的名称都不适合误导。例如,一些非ISA系统有几个实时时钟。一个非常低功耗的I2C或SPI时钟芯片可以与备用电池一起作为硬件时钟,以初始化一个功能更好的集成实时时钟,用于大多数其他用途。

2.系统时钟

这是由Linux内核内的时钟保持的时间,由计时器中断驱动。(在ISA机器上,计时器中断是ISA标准的一部分)。它只有在linux在机器上运行时才有意义。系统时间是从1970年世界协调时(UTC)1月1日00:00开始的秒数(或者更简洁地说,是1969年以来的秒数)。不过,系统时间不是整数,它实际上是无限的。系统时间是重要的时间。Linux系统中硬件时钟的基本目的是在Linux不运行时保持时间。在Linux启动时,将系统时间从硬件时钟初始化,然后不再使用硬件时钟。请注意,在设计ISA的DOS中,硬件时钟是唯一的实时时钟。

重要的是,当系统运行时,系统时间不存在任何不连续性,比如使用date命令来设置它。但是,在系统运行时,您可以对硬件时钟做任何您想做的事情,而下一次Linux启动时,它将使用硬件时钟的调整时间进行设置。

Linux内核维护系统的本地时区的概念。但是不要被误导-几乎没有人关心内核认为它在哪个时区。相反,关心时区的程序(可能因为他们想为您显示本地时间)几乎总是使用更传统的方法。确定时区:它们使用“tz”环境变量或“/usr/share/zoneinfo”目录,如tzset(3)的手册页所解释的那样。时区值是错误的,vFAT文件系统会在文件上报告并设置错误的时间戳。

当您使用”--hctosys”选项设置系统时间时,hwlock将内核时区设置为“tz”或“/usr/share/zoneinfo”所指示的值。

时区值实际上由两部分组成:1)字段“tz_minutesWest”表示本地时间(未根据DST进行调整)滞后于UTC;2)字段“tz_dsttime”,指示当前在本地有效的夏令时(DST)约定的类型。第二个字段不在Linux下使用,始终为零。

3.hwclock如何访问硬件时钟

hwlock使用多种不同的方法来获取和设置硬件时钟值,最常见的方法是对设备特殊文件“/dev/rtc”执行I/O操作,假定该文件是由rtc设备驱动程序驱动的。然而,这种方法并不总是可用的。首先,rtc驱动程序是linux中比较新的一种。此外,虽然有一些版本的rtc驱动程序可以在decalpha上工作,但似乎有大量的alpha无法工作(常见的症状是时钟挂起)。此外,最近的linux系统对rtc有更多的通用支持,甚至支持不止一个的系统,所以您可能需要通过指定/dev/rtc 0或/dev/rtc 1来覆盖默认值。

在旧系统中,访问硬件时钟的方法取决于系统硬件。

在ISA系统中,hwlock通过对端口0x70和0x71进行I/O操作,可以直接访问构成时钟的“CMOS存储器”寄存器。它使用实际的I/O指令,因此只有在超级用户有效用户ID的情况下才能这样做。(对于jensen Alpha,hwlock无法执行这些I/O指令,因此它使用设备文件“/dev/port”,它提供了与I/O子系统几乎一样低的接口)。这是一种非常糟糕的访问时钟的方法,因为用户空间程序通常不应该进行直接I/O和禁用中断。但是在ISA和Alpha系统中,这是唯一的方式。

在m68k系统上,hwlock可以通过控制台驱动程序访问时钟,通过设备文件“/dev/tty1”访问时钟。

hwlock尝试使用文件“/dev/rtc”。如果内核没有编译“/dev/rtc”,或者它无法打开“/dev/rtc”,那么hwlock将返回到另一种方法(如果可用的话)。在ISA或Alpha计算机上,您可以强制hwclock使用CMOS寄存器的直接操作,而无需通过指定“--directisa”选项。

4.校准功能adjust

硬件时钟通常不是很精确,但是它的许多不准确是完全可以预测的,它每天得到或失去相同的时间。这被称为系统漂移。hwlock的“调整”功能允许您进行系统校正以纠正系统漂移。它的工作方式如下:hwlock保存了一个文件“/etc/adjtime”,它保存了一些历史信息。

假设您从没有adjtime文件开始,发出hwlock-set命令将硬件时钟设置为真实的当前时间。hwlock创建adjtime文件,并在其中记录当前时间,作为最后一次校准时钟。5天后,时钟增加了10秒,因此您可以发出另一个“hwlock --set”命令来设置它。返回10秒。hwlock更新adjtime文件,显示当前时间作为最后一次校准时钟,并以系统漂移速率记录每天2秒。24小时过去,然后发出“hwlock --adjust”命令。hwlock查阅adjtime文件,看到时钟离开时每天增加2秒。一个人呆了整整一天。所以它从硬件时钟中减去2秒。然后,它记录当前时间作为最后一次调整时钟的时间。又过了24小时,你又发出了另一个“hwclock --adjust”指令。hwclock做了同样的事情:减去2秒,用当前时间更新adjtime文件,这是最后一次调整时钟。

每次您校准时钟(使用--set或—systohc)时,hwlock根据上次校准的时间、上次调整后的时间、在任何中间的调整中假定的漂移率以及时钟当前的关闭量,重新计算系统漂移率。在hwclock使用的任何时候,都会出现少量的误差,因此它不会进行小于1秒的调整。稍后,当您再次请求调整时,累积漂移将超过1秒钟,而hwlock则会进行调整。

在系统启动时,在“hwlock --hctosys”之前进行hwlock的调整是很好的,并且在系统通过cron运行时也可以定期进行调整。

虽然adjtime文件的命名仅仅是为了控制时间调整的历史记录,但它实际上包含了hwlock在从一个调用到下一个调用时记忆信息时使用的其他信息。adjtime文件的格式是ASCII:

第1行的3个数字数字,用空格隔开,分别代表:a)系统漂移率,每天以秒为单位,浮点小数点;b)自1969年世界协调时以来最近调整或校准的秒数,小数整数;c)零(与时钟(8)兼容)为十进制整数。

第2行一个数字,代表自1969年世界协调时以来最近一次校准产生的秒数。如果还没有校准,或者已知任何先前的校准都是没有意义的,那么值就是0(例如,因为在校准之后,硬件时钟已经被找到,不包含有效时间)。这是一个十进制整数。

第3行是“utc”或“local”。指示硬件时钟是设置为协调世界时间还是设置为本地时间。

5.内核如何自动同步硬件时钟

在某些系统中,您应该注意到硬件时钟保持同步的另一种方式。Linux内核有一种模式,它每11分钟将系统时间复制一次到硬件时钟。这是一个很好的模式,当您使用一些复杂的东西,比如NTP来保持系统时间同步时。(NTP是一种保持系统时间同步的方法,它可以与网络上的某个时间服务器或连接到您的系统的无线电时钟保持同步。参见RFC 1305)。

这个模式(我们称之为“11分钟模式”)是关闭的,直到有东西打开它。ntp守护进程xntpd就可以打开它。您可以通过运行任何东西来关闭它,包括“hwlock --hctosys”,它以老式的方式设置系统时间。

如果你的系统以11分钟的模式运行,不要使用“hwlock --adjust”或“hwlock-hctosys”。在启动时使用“hwlock --hctosys”来获得一个合理的系统时间是可以接受的,直到您的系统能够运行为止。从外部源设置系统时间并启动11分钟模式

# 举例

不适用任何参数,直接查看硬件时钟

[root@localhost ntop-4.0.1]$ hwclock
2018年08月23日 星期四 15时01分28秒  -0.577410 seconds

设置硬件时钟

[root@localhost ntop-4.0.1]$ hwclock --set --date="0904" # 设置硬件时钟,需要date参数来配合使用
[root@localhost ntop-4.0.1]$ hwclock
2018年09月04日 星期二 09时04分09秒  -0.479386 seconds

将硬件时钟设置成本地时间格式

[root@localhost ntop-4.0.1]$ hwclock --localtime
2018年09月04日 星期二 01时05分46秒  -0.462990 seconds

将硬件时钟设置成系统时间

[root@localhost ntop-4.0.1]$ date  #查看当前系统时间
2018年 09月 04日 星期二 12:25:15 CST
[root@localhost ntop-4.0.1]$ hwclock –w #将硬件时钟设置为系统时间
[root@localhost ntop-4.0.1]$ hwclock   #查看硬件时钟
2018年09月04日 星期二 12时25分48秒  -0.263687 seconds