如何设定与维持准确的电脑时钟 <author> 作者: Ron Bean, <tt><htmlurl url="mailto:rbean@execpc.com" name="rbean@execpc.com"></tt><newline> 译者: Da-Wei Chiang, <tt><htmlurl url="mailto:dawei@sinica.edu.tw" name="dawei@sinica.edu.tw"></tt> <date> v, December 1996 翻译日期: 2-16 July 1998 <!-- Converted from ASCII to SGML Aug. 1997, no changes to text --> <!-- Thanks to qinglong@yggdrasil.com for the SGML conversion --> <abstract> 如何设定与维持准确的电脑时钟. </abstract> <!-- Table of contents --> <toc> <sect>介绍 <p> 个人电脑(甚至於昂贵的工作站)主机板上所使用的 real-time-clock 晶片不够准确是众所皆知的事情. 然而 Linux 作业系统提供了一个简单的方法来校正这个不准确的电脑时钟, 使得电脑时钟就算是不倚赖外面的校时源也可以达到 *<em>相当</em>* 准确的地步. 但是似乎大多数人都还不知道有这个方法, 其原因如下: <enum> <item> 在一般 ``如何设定 linux 作业系统'' 的文件中并未述及这个方法, 而且在安装作业系统时很难自动地完成设定 (但是理论上并不是不可能的, 如果你有一台数据机的话). <item> 若你使用``<tt>man clock</tt>''来查看设定时钟的说明时, 你可能会取得非预期的 <tt>clock(3)</tt> 说明内容. (试著使用``<tt>man 8 clock</tt>''). <item> 似乎大多数人并不在意现在的正确时刻是多少. <item> 那些少数在意的人往往会采用 <tt>louie.udel.edu</tt> 所提供的 <tt>xntpd</tt> 程式集以便与外面的校时源, 例如网路校时伺服器或无线电时钟信号, 取得同步. </enum> </p> <p> 如果各位对本文所讲述的低阶的时钟设定方法有著极高度的兴趣, 我强烈建议各位花些时间来浏览网页<url url="http://www.eecis.udel.edu/˜ntp/"> , 这个网页有著各类你所感兴趣的内容,例如有关於 <tt>xntpd</tt> 的完整资讯以及 NIST 与 USNO 等站台的超连结. (我在本文後面也对 <tt>xntpd</tt> 作了些许的简介.) </p> <p> <descrip> <tag/注意/ 如果你在同一台机器上跑多个作业系统, 你应该只让其中一个来重新设定 CMOS 时钟, 如此它们□不会相互影响而导致混乱. 假使你平常在同一台机器上跑 Linux 和 Windows 二种作业系统, 而当你要寻找一些共享的校时程式便时可以忽略 Windows 作业系统的部分 (参考前面所说网页的超连结). </descrip> </p> <sect>使用``<tt>clock</tt>''程式 <p> 所有你须要知道的内容都在 <tt>clock(8)</tt> 的说明中, 而本文将带领各位完成整个设定程序. </p> <p> <descrip> <tag/注意/ 要执行``<tt>clock</tt>''或是其它会影响到系统时间和 CMOS 时钟的程式, 你必须拥有 <bf>root</bf> 的权限. </descrip> </p> <sect1>检查你的作业系统 <p> 检查你作业系统的开机执行档中是否有类似``<tt>clock -a</tt>''或 ``<tt>clock -ua</tt>''的命令. 这个命令可能放在 <tt>/etc/rc.local</tt> ,或 <tt>/etc/rc.d/rc.sysinit</tt> , 或其它类似的地方, 这要看你安装的是那一套 Linux 作业系统. </p> <p> 如果找到的命令是 ``<tt>clock -s</tt>'' 或 ``<tt>clock -us</tt>'' , 请将 ``<tt>s</tt>'' 更改成 ``<tt>a</tt>'' , 接著检查看看是否有 <tt>/etc/adjtime</tt> 这个档案, 该档案的内容只有一行看起来像是这样: <tscreen> <verb> 0.000000 842214901 0.000000 </verb> </tscreen> </p> <p> 这些数字依序是校正因子 (每天偏差的秒数), 上一次校正时钟的时间 (由 Jan 1, 1970 开始起算的秒数), 上一次校正所扣除的秒数. 如果你找不到这个档案, 请以 <bf>root</bf> 的身份产生此档案, 其内容只有一行看起来像是这样 (全部是零): <tscreen> <verb> 0.0 0 0.0 </verb> </tscreen> </p> <p> 然後透过 shell 手动执行 ``<tt>clock -a</tt>'' 或 ``<tt>clock -ua</tt>'' 以便更新第二个数字 (如果你的时钟被设定成协调国际时间而不是本地时间 你得使用 ``<tt>u</tt>''这个参数). </p> <sect1>量测时钟的偏差率 <p> 首先你得知道现在到底是几点钟 <tt>:-)</tt>. 你机器的本地时间可能是不准确的. 我最喜欢的方法是拨电话到 WWV 的 (303)499-7111 电话报时台 (这是个付费电话). 如果你能够与网路校时伺服器连上线, 你也可以使用 <tt>xntpd</tt> 程式集所提供的 <tt>ntpdate</tt> 程式来校时 (使用 <tt>-b</tt> 选项以避免系统弄乱 CMOS 时钟). 或者使用 ``<tt>date -s hh:mm:ss</tt>'' 以手动方式设定系统时钟, 不论那一种方法最後都得使用 ``<tt>clock -w</tt>'' 将系统时间写入 CMOS 时钟. 你必须记得最後一次设定时钟的日期, 所以你得将该日期写下来放在不会遗失的地方. 如果你使用的是 <tt>ntpdate</tt> 程式, 执行 ``<tt>date +%s</tt>'' 然後写下自从 Jan 1,1970 算起到该程式执行的秒数. </p> <p> 然後等待几天或几个星期後之後再回来看看时钟到底偏差了多少时间. 如果你以手动的方式设定时钟, 建议至少得等待二个星期之後, 再来计算时钟偏差率将可得到趋近 .1 sec/day 的结果. 几个月之後偏差率应该会趋近 .01 sec/day (有些人宣称应该更准确, 但是我个人持保留的态度). 如果你使用 <tt>ntpdate</tt> 程式来设定时钟你可能不必等待太久的时间, 然而不论使用那种方式之後都得做些微调的工作. </p> <p> 你可以使用 cron 在一定的时间周期内执行 ``<tt>clock -a</tt>'' 以便系统时间能够与 (校正过的) CMOS时间维持一致性. 其实在你每次开机的时候都会从开机执行档来执行这个命令, 然而只要常常做上面这个动作就可以达到你准确机器时间的目的. </p> <p> 注意如果系统时间的修正一次超过一秒或是时间往回修正, 有些系统的 clock 程式可能会无法执行. 如果你有这方面的问题, 则可以使用 <tt>xntpd</tt> 或 <tt>ntpdate</tt> 程式 来逐步地修正时间. </p> <sect1>实例 <sect2>设定时间 <p> 签入系统并成为 <bf>root</bf>. 拨电话至 (303)499-7111 (语音), 来聆听报时的内容. 然後使用键盘打出下面几个字: <tscreen> <verb> date -s hh:mm:ss </verb> </tscreen> 一直等到哔的一声□按下 enter 键. (如果在此处使用 ``<tt>ntpdate</tt>'' 程式, 则你可以省略拨电话的动作) 这个步骤在设定 ``系统时间''. 接著执行: <tscreen> <verb> clock -w </verb> </tscreen> 这个步骤将系统时间写回 CMOS 时钟让二者时间一致. 接著执行: <tscreen> <verb> date +%j </verb> </tscreen> (如果在前面使用 ``<tt>ntpdate</tt>'' 程式你得执行 ``<tt>date +%s</tt>'') 将其执行的结果记录下来. </p> <sect2>重新设定时间与检查偏差率 <p> 找出你上次写下来日期. 签入系统并成为 <bf>root</bf>. 然後执行: <tscreen> <verb> clock -a </verb> </tscreen> 这个步骤将 CMOS 时间写入系统时钟让二者时间一致. 拨电话至 (303)499-7111 (语音), 来聆听报时的内容. 接著使用键盘打出下面几个字: <tscreen> <verb> date </verb> </tscreen> 一直等到哔的一声□按下 enter 键, 但是当你等待的时候, 写下报时的内容, 并且还不要挂上电话. 这个动作是让你知道目前真正的时间是几点, 而此时相对你的机器上的时间是几点. 现在使用键盘打出下面几个字: <tscreen> <verb> date -s hh:mm:00 </verb> </tscreen> 其中分针部分所设定的数字就是目前报时内容 *<bf>之後的</bf>* 下一分钟, 一直等到哔的一声□按下 enter 键 (现在可以挂上电话了). 而 <tt>hh</tt> 的部分则使用机器本地的时针数字即可. 这个步骤在设定 ``系统时间''. 然後执行: <tscreen> <verb> clock -w </verb> </tscreen> 将新的 (校正过的) 系统时间写回 CMOS 时钟. 然後执行: <tscreen> <verb> date +%j </verb> </tscreen> (或是执行 ``<tt>date +%s</tt>'' ) </p> <p> 你现在手上有三个数字 (二个校正日期及一个正确时间) 於是你可以开始计算偏差率了. </p> <sect2>计算校正因子 <p> 当你在某一分钟执行 ``<tt>date</tt>'' 程式时, 你机器的本地时间是慢还是快呢? 如果是快了, 你必须将之减去一些秒数以符合正确时间, 所以你应该写下一个负的偏差数值. 如果是慢了,你必须将之加上一些秒数以符合正确时间, 所以你应该写下一个正的偏差数值. </p> <p> 现在将二个校正日期相减. 如果之前你使用的是 ``<tt>date +%j</tt>'', 则数值所代表意义为一年的第几天 (1-365, 或 1-366 如果是闰年). 如果自从你上一次设定时钟到现在经过1 月1 日你还须要将第二个校正日期加 365 (或 366) 如果之前你使用的是 ``<tt>date +%s</tt>'' 则数值的单位为秒数, 你必须将之除以 86400 以便取得日数. </p> <p> 如果你的档案 <tt>/etc/adjtime</tt> 中已经有校正因子, 你必须将先前已校正过的秒数考虑进来, 如果你校正过度, 这个校正因子的正负号将与你量测到偏差数值相反; 如果你校正不足则二者正负号相同. 将旧的校正因子乘以日数, 然後加上新获得的偏差秒数 (附注-- 如果二者正负号相同, 你将取得一个较大的偏差数值, 如果二者正负号相反, 你将取得一个较小的偏差数值). </p> <p> 接著将这个总偏差秒数除以日数以便取得新的校正因子, 然後将档案 <tt>/etc/adjtime</tt> 中旧的校正因子代换成新的. 最後写下新的校正日期 (以秒数或日数为单位) 以便下次使用. </p> <p> 这里是我的 <tt>/etc/adjtime</tt> 档案内容: <tscreen> <verb> -9.600000 845082716 -0.250655 </verb> </tscreen> (注意每天 9.6 秒则一个月将近有 5 分钟的偏差!) <sect> xntpd 简介 <p> 你的系统实际上有二个时钟-- 一个是当系统关机继续使用电池电力维持计时功能的 ``real time clock'' (也就是所谓的 ``CMOS 时钟'', ``硬体时钟'', 或 ``RTC'') 而另一个是 ``kernel clock'' (有时称为 ``软体时钟'' 或 ``系统时钟'') 系统时钟的跳动是以计时器的中断信号为基准并在开机时从CMOS 时钟处载入初始值. 这二个时钟有不同的时间偏差率, 所以二个时钟上的时间会逐渐地产生偏差, 而且也会与 ``真正的''时间产生偏差. </p> <p> 在 <tt>xntpd</tt> 文件中所述及的 ``the clock'' 就是指 ``kernel clock''. 当你执行 <tt>xntpd</tt> 或 <tt>timed</tt> 程式时 (或是其他使用到 <tt>adjtimex</tt> 系统呼叫的程式) linux 作业系统会假定系统时钟比 CMOS 时钟准确, 而且会在开机後每隔 11 分钟重新设定一次 CMOS 时间 (一直到重开机为止). 这意味著 ``<tt>clock</tt>'' 程式不再知道上一次重新设定 CMOS 时钟的正确时间, 所以你不可以使用档案 <tt>/etc/adjtime</tt> 中的校正因子. 你可以在开机执行档上使用 <tt>ntpdate</tt> 程式 以便在初次执行 <tt>xntpd</tt> 程式之前与校时伺服器对时. 如果你在开机的时候一直无法连上准确的校时源, 这可能会让你面临到一些困境-- 实际上 <tt>xntpd</tt> 不是被设计来在那种情况之下使用的. </p> <p> <tt>Xntpd</tt> 包含了许多无线电时钟的驱动程式, 并且也可以被设定在一定的周期内拨电话至 NIST 的电话拨接电脑校时服务 (当你设定好电话拨接的周期之後最好先计算一下电话帐单的花费). 在与其他的校时源失去联络一段时间之後这个方式也能提供系统时钟一个校正因子. </p> <p> 大部分的无线电时钟大约要花费 $3-4K, 不过你可以采用较便宜的 ``<tt>gadget box</tt>'' 方案 (实际上是一个 300 baud 的数据机) 他被放在你的电脑与一台短波无线电接收器之间 频道调至 Canada 的 CHU 校时无线电台 (参见网址 <url url="ftp://ftp.udel.edu/pub/ntp/gadget.tar.Z">). 而Heathkit WWV 接收器 (``最准确的时钟'') 仍然买的到 (但不是一组套件), 大约要花费 $4-500. 目前GPS 的讯号里仍然包含有校时的资讯, 而且部分的 GPS 接收器可以接上电脑的串列埠. 在最近的未来这可能会成为低价位的解决方案. </p> <p> 理论上, 一般人可以自己写程式来使用 NIST 的电话拨接电脑校时服务以便自动 计算 CMOS 时钟与系统时钟的偏差率. 虽然我不知道是否有单独的程式能够达到这个目的, 但是大部分的程式码应该可以借用自 <tt>xntpd</tt> 程式集. </p> </article>