パソコンが持っている2つの時計、ハードウェア クロックとシステム クロックは、それぞれが独立した系として動作しています。ハードウェア クロックは文字通りハードウェア(ICチップ)で構成されている実体のあるクロックですが、システム クロックはメモリ上にデータとして存在し、OSによって維持管理されているソフトウェアともいえます。
起動されたOSは直ちにハードウェア クロックを読み出して、そのデータを基にシステム クロックの設定を行います。
ただし、システム クロックはUTCで運用・管理されるため、ハードウェア クロックの設定状況(UTC or ローカルタイム) によってはUTCとの時差の補正が必要になります。
Linux は
インストール時のオプションによってハードウェア クロックのゾーン属性が変ります。OSは次の手順でシステム クロックの設定を行います。
- ハードウェア クロックのゾーン属性(UTC or ローカル タイム)を識別します。
- /etc/sysconfig/clock のステートメントを参照します。
[[ ステートメントの記述例 ]]
ZONE="Asia/Tokyo"
UTC=true
- UTCステートメントからハードウェア クロックの時刻を次のように認識します。
UTC=true または yes UTC=false または no
| : : | UTC ローカル タイム |
- ZONEステートメントはタイムゾーンの表示であると同時に、/etc/localtime のコピー元を示しています。
- 識別したゾーン属性を元にオプションを決定し、hwclock コマンドを実行します。
hwclock --hctosys --utc(local)
hwclock はハードウェア クロックの読み出しと設定を行うコマンドで、オプションには次の意味があります。
- --hctosys
ハードウェア クロックの値をシステム クロックに設定します。
その時、第2オプションの指定に従って補正します。
- --utc, --local
ハードウェア クロックのゾーン属性を指定します。
--utc :ハードウェア クロックをUTCとして処理します。
--local:ハードウェア クロックをローカル タイムとして処理します。
- hwclock コマンドは、読み出したハードウェア クロックの値を次にように処理します。
- 基準時刻(1970年01月01日00時00分00秒)からの経過秒数に変換します。
- 第2オプションに従って補正値を次のように設定します。
- 第2オプションが --utc の場合
補正値 0 (ゼロ)
- 第2オプションが --local の場合
/etc/localtime を参照して補正値を設定します。
/etc/localtime はバイナリ ファイルですが、その内部にはUTCとの時差が秒数で記述されています。
例えば Tokyo の場合は 0x7e90(32400秒)と記述されています。
- 基準時刻からの経過秒数を補正値で補正します。
- hwclock コマンドは、補正の終わった値をシステム クロックとして設定します。
- マザーボード上のインターバル タイマーから供給されるパルス(クロック信号)でデータを更新し(時計を進め)ます。
ハードウェア クロックはローカル タイムであると規定されています。読み出しデータからシステム クロックの設定値(UTC)を得るには該当タイム ゾーンに相当する補正が必要になります。
- レジストリ値から補正値を得ます。
- 下記レジストリ キーのレジストリ値を参照します。
HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
- HKLM\・・・\TimeZoneInformation の主なレジストリ値は次の通りです。
- Bias
標準時とUTCとの時差 (分単位)。
- ActiveTimeBias
夏時間とUTCとの時差 (分単位)。
- DaylightBias
夏時間と標準時の差 (分単位)。
- StandardStart
標準時の開始(夏時間の終了)時期。
- DaylightStart
夏時間の開始時期。
- 各レジストリ値間の整合性に異常がなければ、次のレジストリ値を補正値とします。
- 標準時適用期間 : Bias
- 夏時間適用期間 : ActiveTimeBias
- ハードウェア クロックから時刻情報を読み出して、基準時刻(1601年01月01日00時00分00秒)からの経過秒数に変換します。
- 変換済みの経過秒数に、レジストリ値から得た補正値を加えます。
- 補正の終わった値をシステム クロックとして設定します。
- マザーボード上のインターバル タイマーから供給されるパルス(クロック信号)でデータを更新し(時計を進め)ます。
OSが維持・管理しているている時刻情報(システム クロック)はUTCであり、各種リソースの時刻情報もほとんどがUTCで記録されますが、ユーザーが目にする時にはローカル タイムの方が便利です。
デスクトップにある時計や、エクスプローラーでファイル表示をした時のタイム スタンプ、コマンド(date, time等)による時刻表示は、それぞれがライブラリ関数を呼び出して、ローカル タイムに変換して表示しています。
UTCをローカル タイムに変換する際に、Linux では /etc/localtime が参照されますが、Windows は単純にレジストリを参照するのではなく、メモリ上のOS管理領域に保存した補正値を参照しているのかも知れません。この辺りは未確認です。
### タイムゾーンを変更してみました ###
[ Linux の /etc/localtime を他のタイムゾーンのファイルに変更 ]
date コマンドの表示、ファイルのタイム スタンプには即刻反映され、デスクトップ時計の時刻は表示の切り替え時(1〜2分)に反映されます。
[ Windows のレジストリ値(Bias, ActiveTimeBias)を他のタイムゾーンの値に変更 ]
コマンド、タイム スタンプ、時計等の時刻表示に何の変化も見られません。
しかしこの状態で、[日付と時刻の設定] - [タイムゾーンの変更] - [タイムゾーンの設定] で [OK] ボタンをクリックすると、各時刻情報の表示に直ちに反映されます。
【 ご注意 】レジストリを直接変更するのは危険です。止めましょう。
|
ハードウェア クロックが参照されるのはOS起動時の一度だけで、その後はシステム クロックのみが唯一の時刻情報源となります。また両クロック間での同期調整は行われないので、両者の時刻情報には必然的にズレが生じ時間の経過と共にズレは大きくなります。
「ハードウェア クロックはあまり正確ではない」と言われているくらいですから、このままでは再起動やシャットダウンのたびに、時刻合わせに苦労することになります。
ただ、システム クロックについては、人手あるいは自動実行されるNTP(インターネット時刻との同期)によって、その時々に修正が行われるのが普通です。
そこで Linux や Windows では、システム クロックをハードウェア クロックに反映する方法が採られています。
シャットダウンや再起動の時に、システム クロックの値をハードウェア クロックへ書き込み(同期し)ます。システム クロックはUTCなので、状況によって補正が必要になります。
- [ システム クロックの設定 ] と同様に /etc/sysconfig/clock を参照して、ハードウェア クロックのゾーン属性(UTC or ローカル タイム)を識別します。
- 識別したゾーン属性を元にオプションを決定し、hwclock コマンドを実行します。
hwclock --systohc --utc(local)
hwclock はハードウェア クロックの読み出しと設定を行うコマンドで、オプションには次の意味があります。
- --systohc
システム クロックの値をハードウェア クロックに設定します。
その時、第2オプションの指定に従って補正します。
- --utc, --local
ハードウェア クロックのゾーン属性を指定します。
--utc :ハードウェア クロックをUTCとして処理します。
--local:ハードウェア クロックをローカル タイムとして処理します。
- hwclock コマンドは、システム クロックの値を次にように処理します。
- hwclock の第2オプションから補正値を導きます。
- --utc の場合
補正値 0 (ゼロ:補正なし)
- --local の場合
/etc/localtime を参照。
- システム クロックの値を補正値で補正します。
- 1900年を基準年とした、秒、分、時、曜日、日、月、年のデータ形式(各1バイト)に変換します。
- hwclock コマンドは、形式変換の終わったデータをハードウェア クロックに書き込みます。
Windows は時刻情報(システム クロック)が修正されると、直ちにハードウェア クロックに書き込みが行われるようです。
時刻情報の修正は、デスクトップの時計やコマンド(date, time)を使って人為的にもできますが、Windows の場合標準で1週間に1回程度「インターネット時刻との同期」が自動で実施されています。もしこの時、時刻の修正が生じるようであれば、その時点でハードウェア クロックへの書き込みが行われることになります。
- 人為的あるいは定期実行のNTP(インターネット時刻との同期)で、時刻情報の修正が行われます。
- システム クロックのデータ(UTC)に、該当タイム ゾーン分の時差補正を施します。
- 1900年を基準年とした、秒、分、時、曜日、日、月、年のデータ形式(各1バイト)に変換します。
- 形式変換の終わったデータをハードウェア クロックに設定します。
[ インターネット時刻との同期 ]
定期実行される「インターネット時刻との同期」は、レジストリで制御されています。
標準的なキー、値の名前、値のデータの主なものは次の通りです。
キー | 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 を設定すると無条件で修正します。
|