for e's laboratory
パソコン実習室
パソコンの時計 ハードウェア クロックとシステム クロック
≪ previous next ≫

U.クロックの運用

 パソコンが持っている2つの時計、ハードウェア クロックとシステム クロックは、それぞれが独立した系として動作しています。ハードウェア クロックは文字通りハードウェア(ICチップ)で構成されている実体のあるクロックですが、システム クロックはメモリ上にデータとして存在し、OSによって維持管理されているソフトウェアともいえます。
両者は全く別の代物ですが、互いに補完し合う面もあります。


U.1.システム クロックの設定

 起動されたOSは直ちにハードウェア クロックを読み出して、そのデータを基にシステム クロックの設定を行います。
 ただし、システム クロックはUTCで運用・管理されるため、ハードウェア クロックの設定状況(UTC or ローカルタイム) によってはUTCとの時差の補正が必要になります。

U.1.1.Linux の場合

 Linux はインストール時のオプションによってハードウェア クロックのゾーン属性が変ります。OSは次の手順でシステム クロックの設定を行います。
  1. ハードウェア クロックのゾーン属性(UTC or ローカル タイム)を識別します。
    1. /etc/sysconfig/clock のステートメントを参照します。
      [[ ステートメントの記述例 ]]
      ZONE="Asia/Tokyo"
      UTC=true
    2. UTCステートメントからハードウェア クロックの時刻を次のように認識します。
      UTC=true または yes
      UTC=false または no
       : 
       : 
      UTC
      ローカル タイム
      ※ 記述例では UTC=true なので、ハードウェア クロックをUTCと認識します。
    3. ZONEステートメントはタイムゾーンの表示であると同時に、/etc/localtime のコピー元を示しています。
      ※ /etc/localtime はUTCとの時差を数値(秒数)で保存しています。
      ※ Linux インストール(またはタイムゾーン変更)時に、/usr/share/zoneinfo の下にある地
        域名のディレクトリから、都市名のファイルを /etc/localtime として(別名で)コピーし
        ます。記述例では /usr/share/zoneinfo/Asia/Tokyo が /etc/localtime としてコピーさ
        れています。
      ※ ディストリビューションによっては、コピーではなくシンボリック リンクになっています。

  2. 識別したゾーン属性を元にオプションを決定し、hwclock コマンドを実行します。
    hwclock --hctosys --utc(local)
    hwclock はハードウェア クロックの読み出しと設定を行うコマンドで、オプションには次の意味があります。
    • --hctosys
      ハードウェア クロックの値をシステム クロックに設定します。
      その時、第2オプションの指定に従って補正します。
    • --utc, --local
      ハードウェア クロックのゾーン属性を指定します。
      --utc :ハードウェア クロックをUTCとして処理します。
      --local:ハードウェア クロックをローカル タイムとして処理します。
  3. hwclock コマンドは、読み出したハードウェア クロックの値を次にように処理します。
    1. 基準時刻(1970年01月01日00時00分00秒)からの経過秒数に変換します。
      ※ ハードウェア クロックは秒、分、時、曜日、日、月、年のデータ構成(各1バイト)です。
    2. 第2オプションに従って補正値を次のように設定します。
      • 第2オプションが --utc の場合
        補正値 0 (ゼロ)
      • 第2オプションが --local の場合
        /etc/localtime を参照して補正値を設定します。
         /etc/localtime はバイナリ ファイルですが、その内部にはUTCとの時差が秒数で記述されています。
        例えば Tokyo の場合は 0x7e90(32400秒)と記述されています。
    3. 基準時刻からの経過秒数を補正値で補正します。
      ▼ 記述例では UTC=true なので、"補正なし" になります。
      ▼ UTC=false, ZONE="Asia/Tokyo" の場合は、32400(9時間)がマイナスされます。

  4. hwclock コマンドは、補正の終わった値をシステム クロックとして設定します。

  5. マザーボード上のインターバル タイマーから供給されるパルス(クロック信号)でデータを更新し(時計を進め)ます。

U.1.2.Windows の場合

 ハードウェア クロックはローカル タイムであると規定されています。読み出しデータからシステム クロックの設定値(UTC)を得るには該当タイム ゾーンに相当する補正が必要になります。
  1. レジストリ値から補正値を得ます。
    1. 下記レジストリ キーのレジストリ値を参照します。
      HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
      ※ このキーの基データは下記レジストリにあります。
        HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
        この中にタイム ゾーンごとの値が保管されています。
        タイム ゾーン変更時にはこの値が参照されます。
    2. HKLM\・・・\TimeZoneInformation の主なレジストリ値は次の通りです。
      • Bias
        標準時とUTCとの時差 (分単位)。
      • ActiveTimeBias
        夏時間とUTCとの時差 (分単位)。
        ※ 夏時間適用期間は Bias に DaylightBias を加味した値が設定されますが、
          標準時適用期間は Bias と同じ値です。
      • DaylightBias
        夏時間と標準時の差 (分単位)。
      • StandardStart
        標準時の開始(夏時間の終了)時期。
      • DaylightStart
        夏時間の開始時期。
      ※ 標準時と夏時間は、ローカル タイムを指しています。
    3. 各レジストリ値間の整合性に異常がなければ、次のレジストリ値を補正値とします。
      • 標準時適用期間 : Bias
      • 夏時間適用期間 : ActiveTimeBias
      ※ JST(日本の標準時)に夏時間は無く、両者に 0xfffffde4 が設定されています。
        0xfffffde4 は -540 を表わします。

  2. ハードウェア クロックから時刻情報を読み出して、基準時刻(1601年01月01日00時00分00秒)からの経過秒数に変換します。
    ※ ハードウェア クロックは秒、分、時、曜日、日、月、年のデータ構成(各1バイト)です。

  3. 変換済みの経過秒数に、レジストリ値から得た補正値を加えます。
    ※ JST の場合は、32400秒(540分 × 60秒)がマイナスされます。

  4. 補正の終わった値をシステム クロックとして設定します。

  5. マザーボード上のインターバル タイマーから供給されるパルス(クロック信号)でデータを更新し(時計を進め)ます。

※ メモリ上のシステム クロックに設定されるデータには、開始時刻からの経過秒数の外に秒以下の単位の
  カウンタもあります。



U.2.ローカル タイムの表示

 OSが維持・管理しているている時刻情報(システム クロック)はUTCであり、各種リソースの時刻情報もほとんどがUTCで記録されますが、ユーザーが目にする時にはローカル タイムの方が便利です。
※ ログ等の時刻情報は、ローカル タイムで記録されるようです。

 デスクトップにある時計や、エクスプローラーでファイル表示をした時のタイム スタンプ、コマンド(date, time等)による時刻表示は、それぞれがライブラリ関数を呼び出して、ローカル タイムに変換して表示しています。

 UTCをローカル タイムに変換する際に、Linux では /etc/localtime が参照されますが、Windows は単純にレジストリを参照するのではなく、メモリ上のOS管理領域に保存した補正値を参照しているのかも知れません。この辺りは未確認です。
### タイムゾーンを変更してみました ###

[ Linux の /etc/localtime を他のタイムゾーンのファイルに変更 ]
 date コマンドの表示、ファイルのタイム スタンプには即刻反映され、デスクトップ時計の時刻は表示の切り替え時(1〜2分)に反映されます。

[ Windows のレジストリ値(Bias, ActiveTimeBias)を他のタイムゾーンの値に変更 ]
 コマンド、タイム スタンプ、時計等の時刻表示に何の変化も見られません。
しかしこの状態で、[日付と時刻の設定] - [タイムゾーンの変更] - [タイムゾーンの設定] で [OK] ボタンをクリックすると、各時刻情報の表示に直ちに反映されます。
【 ご注意 】レジストリを直接変更するのは危険です。止めましょう。
※ [OK] ボタンのクリックによって、変更を施したレジストリ値でシステム クロックを調整して
  その値をハードウェア クロックに書き込み、レジストリ(HKLM\...\TimeZoneInformation)と
  システム クロックの再設定をするようです。
  設定したレジストリ値によっては正常起動できなくなる可能性があります。

※ ftp サーバーが返すファイルのタイム スタンプは、UTCかローカル タイムかをサーバー側の設定で変え
  られようになっています。ftp を使ってファイルのアップ(ダウン)ロードをしている場合、使用している
  ftp ソフトの設定をサーバに合わせる必要があります。


U.3.ハードウェア クロックの調整

 ハードウェア クロックが参照されるのはOS起動時の一度だけで、その後はシステム クロックのみが唯一の時刻情報源となります。また両クロック間での同期調整は行われないので、両者の時刻情報には必然的にズレが生じ時間の経過と共にズレは大きくなります。
 「ハードウェア クロックはあまり正確ではない」と言われているくらいですから、このままでは再起動やシャットダウンのたびに、時刻合わせに苦労することになります。

 ただ、システム クロックについては、人手あるいは自動実行されるNTP(インターネット時刻との同期)によって、その時々に修正が行われるのが普通です。
 そこで Linux や Windows では、システム クロックをハードウェア クロックに反映する方法が採られています。

U.3.1.Linux の場合

 シャットダウンや再起動の時に、システム クロックの値をハードウェア クロックへ書き込み(同期し)ます。システム クロックはUTCなので、状況によって補正が必要になります。
  1. [ システム クロックの設定 ] と同様に /etc/sysconfig/clock を参照して、ハードウェア クロックのゾーン属性(UTC or ローカル タイム)を識別します。

  2. 識別したゾーン属性を元にオプションを決定し、hwclock コマンドを実行します。
    hwclock --systohc --utc(local)
    hwclock はハードウェア クロックの読み出しと設定を行うコマンドで、オプションには次の意味があります。
    • --systohc
      システム クロックの値をハードウェア クロックに設定します。
      その時、第2オプションの指定に従って補正します。
    • --utc, --local
      ハードウェア クロックのゾーン属性を指定します。
      --utc :ハードウェア クロックをUTCとして処理します。
      --local:ハードウェア クロックをローカル タイムとして処理します。
  3. hwclock コマンドは、システム クロックの値を次にように処理します。
    1. hwclock の第2オプションから補正値を導きます。
      • --utc の場合
        補正値 0 (ゼロ:補正なし)
      • --local の場合
        /etc/localtime を参照。
        ※ Asia/Tokyo (JST) の場合は、32400(9時間)が設定されます。
    2. システム クロックの値を補正値で補正します。
      ※ --local で Asia/Tokyo (JST) の場合、32400を加算します。
    3. 1900年を基準年とした、秒、分、時、曜日、日、月、年のデータ形式(各1バイト)に変換します。
  4. hwclock コマンドは、形式変換の終わったデータをハードウェア クロックに書き込みます。
※ crontab を利用して hwclock --systohc --utc(local) を定期実行する方法もあります。
※ カーネルのバージョンや設定によっては、11分ごとにシステム クロックの値をハードウェア クロック
  に書き込むものもあります。


U.3.2.Windows の場合

 Windows は時刻情報(システム クロック)が修正されると、直ちにハードウェア クロックに書き込みが行われるようです。

 時刻情報の修正は、デスクトップの時計やコマンド(date, time)を使って人為的にもできますが、Windows の場合標準で1週間に1回程度「インターネット時刻との同期」が自動で実施されています。もしこの時、時刻の修正が生じるようであれば、その時点でハードウェア クロックへの書き込みが行われることになります。
※ ハードウェア クロックはローカル タイムなので、ほとんどの地域では書き込み前にUTCとの時差補正が
  必須です。
  1. 人為的あるいは定期実行のNTP(インターネット時刻との同期)で、時刻情報の修正が行われます。
  2. システム クロックのデータ(UTC)に、該当タイム ゾーン分の時差補正を施します。
  3. 1900年を基準年とした、秒、分、時、曜日、日、月、年のデータ形式(各1バイト)に変換します。
  4. 形式変換の終わったデータをハードウェア クロックに設定します。
※ タイム ゾーンを変更した場合も、ハードウェア クロックへの書き込みが発生します。


[ インターネット時刻との同期 ]
 定期実行される「インターネット時刻との同期」は、レジストリで制御されています。
標準的なキー、値の名前、値のデータの主なものは次の通りです。
※ 下記「値のデータ」の設定値は、標準で設定されている初期値です。

キーHKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters
値の名称NtpServer値のデータtime.windows.com,0x1
同期を行う NTP サーバを、ホスト名または IP アドレスで指定します。
末尾の 0x1 は同期方法を指示するパラメータで次の意味になります。
  • 0x1 : 定間隔 (次項の SpecialPollInterval を参照する) での同期を行います。
  • 0x2 : ドメイン、外部の両方の NTP サーバを利用します。
  • 0x4 : 指定ホストの時刻情報が信頼できない場合、他の NTP サーバをチェックします。
  • 0x8 : 指定したホストとのみ同期を行います。
※ このパラメータはビットフラグなので、0x9 は 0x1 と 0x8 を組み合わせたものになります。
※ パラメータの値に 0x1 が含まれない場合、同期間隔は HKLM\....\W32Time\Config キーの
  下記レジストリ値に制御されます。
    MinPollInterval, MaxPollInterval

キーHKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient
値の名称SpecialPollInterval値のデータdword:00093a80 (604800 秒 : 7 日)
前回同期後、次回同期までの間隔。
このレジストリ値は、上記 NtpServer レジストリ値の末尾パラメータが 0x1 の場合 (通常 0x1 です) に有効となります。

キーHKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config
値の名称MaxPosPhaseCorrection値のデータ0x0000d2f0 (54000秒 : 15 時間)
値の名称MaxNegPhaseCorrection値のデータ0x0000d2f0 (54000秒 : 15 時間)
NTP サーバとの同期によって修正が必要となった時に、許容可能な修正幅 (最大秒数) を設定します。
設定値以上の誤差がある場合は、修正を行わずイベントが記録されます。
MaxPosPhaseCorrection : クロックを進める方向の最大秒数
MaxNegPhaseCorrection : クロックを遅らせる方向の最大秒数
0xffffffff を設定すると無条件で修正します。




≪ previous [[ パソコンの時計 ]] next ≫