システム時刻

提供: ArchWiki
/etc/adjtimeから転送)
ナビゲーションに移動 検索に移動

関連記事

オペレーティング システムでは、時間 (クロック) は 3 つの部分によって決定されます: 時間の値、現地時間か UTC かそれ以外か、タイム ゾーン、および該当する場合は夏時間 (DST) です。この記事では、それらが何であるか、およびそれらの読み取り/設定方法について説明します。システムには、ハードウェア クロックとシステム クロックの 2 つのクロックが存在します。これについても、この記事で詳しく説明します。

ほとんどのオペレーティング システムの標準的な動作は次のとおりです。

  • 起動時にハードウェア クロックからシステム クロックを設定します。
  • システムクロックの正確な時刻を維持します。#時刻同期 を参照してください。
  • シャットダウン時にシステム クロックからハードウェア クロックを設定します。

ハードウェアクロック

ハードウェアクロック (又の名をリアルタイムクロック (Real Time Clock, RTC) もしくは CMOS クロック) は次の値を保存しています: 年・月・日・時・分・秒。2016 年以降のUEFI ファームウェアには、タイムゾーンとサマータイムを保存する機能を備えられています。

ハードウェアクロックの読み込み

# hwclock --show

システムクロックからハードウェアクロックを設定する

以下は、システムクロックからハードウェアクロックを設定するものです。さらに、/etc/adjtime を更新するか、存在しない場合は作成します。このファイルに関するより詳しい情報は #タイムスキュー の項と同様に hwclock(8) § The Adjtime File を参照してください。

# hwclock --systohc

システムクロック

システムクロック (又の名をソフトウェアクロック) は次の情報を記録しています: 時刻、タイムゾーン、そして DST が適用されるかどうか。Linux カーネルは1970年1月1日の午前0時からの秒数でシステムクロックをはじき出します。システムクロックの初期値は /etc/adjtime を使ってハードウェアクロックから算定されます。起動が完了した後は、システムクロックはハードウェアクロックとは独立して動作します。Linux カーネルはタイマー割り込みを数えることによりシステムクロックを記録します。

時刻を表示する

現在のシステム時刻を確認するには (UTC と現地時間のどちらも表示されます):

$ timedatectl status

root で同じコマンドを実行すればハードウェアクロックの時間も表示します。

時刻を設定する

直接システムクロックを設定するには:

# timedatectl set-time "yyyy-MM-dd hh:mm:ss"

例:

# timedatectl set-time "2014-05-26 11:13:54"

2014年5月26日、11時13分54秒に設定されます。

RTC

ほとんどのオペレーティングシステムは:

  • 起動時にハードウェアクロックからシステムクロックを設定します
  • NTP デーモンを使ってシステムクロックの時間を正確に保ちます
  • シャットダウン時にシステムクロックからハードウェアクロックを設定します

時刻系

2つの時刻系が存在します: 地方時 (localtime) と 協定世界時 (Coordinated Universal Time, UTC) です。地方時系は現在のタイムゾーンによって決まりますが、UTC は世界時であり、タイムゾーンの値は関係ありません。概念的には異なっていますが、UTC は GMT (グリニッジ標準時, Greenwich Mean Time) とも言われます。

ハードウェアクロック (CMOS クロック, BIOS で表示される時間) で使われる時刻系はオペレーティングシステムによって定義されます。デフォルトでは、Windows は localtime を使いますが、Mac OS は UTC を使っていて、UNIX ライクなオペレーティングシステムでは決まっていません。一般的に、UTC を使う OS は起動時に CMOS (ハードウェアクロック) の時間を UTC 時間 (GMT, Greenwich time) だと認識して、あなたのタイムゾーンによってその時間を調整してシステム時刻を設定します。

複数のオペレーティングシステムがマシンにインストールされている場合、それらはすべて同じハードウェアクロックから現在の時刻を取得します。システム間の競合を避けるために、UTC に設定することをお勧めします。それ以外の場合、ハードウェアクロックが「現地時間」に設定されている場合、たとえば DST の変更後に複数のオペレーティングシステムがそれを調整する可能性があり、その結果、過剰な修正が行われます。異なるタイムゾーン間を移動し、オペレーティング システムの 1 つを使用してシステム/ハードウェア クロックをリセットするときにも、問題が発生する可能性があります。

ハードウェアクロックは、timedatectl コマンドで照会および設定ができます。 以下を使用して、Arch システムの現在のハードウェアクロック時間標準を確認できます。

$ timedatectl | grep local
RTC in local TZ: no


ハードウェアクロックは timedatectl コマンドで尋ねたり設定できます。ハードウェアクロックの時刻系を localtime に変更するには次を実行してください:

# timedatectl set-local-rtc true

ハードウェアクロックの時刻系を localtime に変更するには、次を実行してください:

# timedatectl set-local-rtc 1

逆にハードウェアクロックの時刻系を UTC に戻すには次を実行してください:

# timedatectl set-local-rtc 0

これらは /etc/adjtime を自動的に生成し、それに応じて RTC を更新します。これ以上の設定は必要ありません。

カーネルの起動中、RTC ドライバーがロードされた時点で、ハードウェアクロックからシステムクロックを設定することができます。設定するかどうかはハードウェアプラットフォーム、カーネルのバージョン・ビルドオプション次第です。設定される場合、ブートシーケンスで既に、ハードウェアクロックは UTC と認識され /sys/class/rtc/rtcN/hctosys (N=0,1,2,..) の値は 1 に設定されます。その後、/etc/adjtime の値を使って、再度 systemd によってハードウェアクロックからシステムクロックが設定されます。そのため、ハードウェアクロックで localtime を使っているとブートシーケンス中に予期しない動作が発生するかもしれません。例えば、システム時刻が後戻りするなど。従ってこの設定は良いアイデアとは言えません。

その後、/etc/adjtime の値に応じて、systemd によってハードウェアクロックからシステムクロックが再度設定されます。したがって、ハードウェアクロックで localtime を使用すると、ブートシーケンス中に予期しない動作が発生する可能性があります。たとえば、システム時間が逆行することは、常に悪い考えです (他にもたくさんあります)。ハードウェアクロックが UTC に設定されていてローカルタイムゾーンについてカーネルに通知しないでください。その結果、Linux システムが使用する FAT ファイルシステムのタイムスタンプは UTC になります。

ノート:
  • timedatectl を使うには D-Bus が有効になっている必要があります。そのため、(インストール中など) chroot 下でこのコマンドが使えないかもしれません。そのような場合には、hwclock コマンドを使って下さい。
  • /etc/adjtime が存在しない場合、systemd はハードウェアクロックが UTC に設定されていると認識しています。

Windows で UTC を使う

RTC を localtime に設定する理由に Windows とのデュアルブートをするためということがあります (Windows は localtime を使っています)。しかしながら、Windows ではレジストリを編集することで RTC で UTC を使っていても対応できるようにすることができます。従って、Linux に localtime を使わせるよりも Windows に UTC を使わせるようにすることが推奨されます。Windows に UTC を使わせる場合、Windows のインターネット時刻機能をオフにするようにしてください。オフにすると Windows はハードウェアクロックにメスを入れなくなるので、代わりに NTP デーモンを使って RTC を同期させる必要があります。

regedit を使って、レジストリに十六進数で 1DWORD 値を追加してください:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation\RealTimeIsUniversal

管理者権限で開いたコマンドプロンプトで以下のコマンドを実行することでも設定できます:

reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f

もしくは、以下の内容で *.reg ファイルを (デスクトップに) 作成しそれをダブルクリックしてレジストリにインポートしてください:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation]
     "RealTimeIsUniversal"=dword:00000001
ノート: 64ビット版の Windows を使っている場合で、上記の設定を行っても効果がないときは DWORD の代わりに QWORD を使うことで問題が解決することがあります。

DST が変わったことで Windows が時計を更新すると行ってきた場合は、それに従って下さい。Windows は時計を UTC のままにしておき、表示する時間だけ修正します。

値を設定した後にハードウェアクロックとシステムクロックの時刻を更新する必要があるかもしれません。

時計がずれる問題が発生している場合、tzdata を再インストールしてタイムゾーンをもう一度設定してみてください:

# pacman -S tzdata
# timedatectl set-timezone Asia/Tokyo

Ubuntu で UTC を使う

Ubuntu とその派生ディストリはインストール時に Windows が認識されたときにハードウェアクロックを "localtime" と認識されるように設定します。Linux 初心者が Windows コンピュータで Ubuntu を試したときにレジストリを編集しなくてもよいように故意にこのような挙動となっています。

タイムゾーン

現在のゾーンを確認するには:

$ timedatectl status

利用可能なゾーンを一覧するには:

$ timedatectl list-timezones

タイムゾーンを変更するには:

# timedatectl set-timezone <Zone>/<SubZone>

例:

# timedatectl set-timezone Asia/Tokyo

このコマンドによって /usr/share/zoneinfo/ 下の zoneinfo ファイルを指し示したシンボリックリンク /etc/localtime が作られます。リンクを手動で作成する場合 (chroot の中で timedatectl が使用できない場合など)、archlinux(7) に書かれているように、ハードリンクではなくシンボリックリンクを使ってください:

# ln -sf /usr/share/zoneinfo/Zone/SubZone /etc/localtime

詳細は timedatectl(1), localtime(5), archlinux(7) を見てください。

ノート: systemd 以前の設定ファイル /etc/timezone がシステムにまだ存在している場合、もう使われていないので削除しても問題ありません。
ヒント: tzselect を使ってインタラクティブにタイムゾーンを選択することもできます。

地理情報を元に設定

IP アドレスの位置情報を元に自動的にタイムゾーンを設定したい場合、$ curl https://ipapi.co/timezone などで geolocation API を使ってタイムゾーンを取得して timedatectl set-timezone に出力を渡すことで自動設定できます。以下のサービスが無料あるいは一部無料で geo-IP API を提供しています:

また、tzupdateAUR ツールは IP アドレスの位置情報を元にタイムゾーンを自動設定します。

NetworkManager がネットワークに接続するたびにタイムゾーンを更新する

NetworkManager dispatcher スクリプト を作成します:

/etc/NetworkManager/dispatcher.d/09-timezone
#!/bin/sh
case "$2" in
    up)
        timedatectl set-timezone "$(curl --fail https://ipapi.co/timezone)"
    ;;
esac
ヒント: up の代わりに connectivity-change を使用すると、OpenConnect などのクライアントで VPN に接続するときにタイムゾーンの変更を防ぐことができます。

あるいは、ツール tzupdateAUR が IP アドレスのジオロケーションに基づいてタイムゾーンを自動的に設定します。この 最も人気のある IP 地理位置情報 API の比較 は、プロダクションでどの API を使うか決める際に役に立つかもしれません。

クロックスキュー

全ての時計は本当の時間 (一番正確なのは国際原子時) とは違う値を示しています、どの時計も完全ではありません。クォーツを使っている電子時計は(不完全な)時間を刻んでいますが、規則的なズレを生じさせています。この本質的な'ズレ'は'クロックスキュー'や'クロックドリフト'として知られています。

ハードウェアクロックが hwclock で設定された時、新しいドリフト値(一日に何秒ズレるか)が算定されます。このドリフト値は新しく設定された値と以前に設定されていたハードウェアクロックの値の差から計算され、以前のドリフト値とハードウェアクロックが最後に設定された時間を考慮しています。新しいドリフト値と時計が設定された時刻は /etc/adjtime ファイルに書き込まれ以前の値を上書きします。これにより hwclock --adjust を実行することでハードウェアクロックのずれを調整できるようになっています。また、hwclock デーモンが有効になっている場合シャットダウン時にも実行されます (よって systemd を使っているシステムでは実行されません)。

ノート: 以前に設定した時から24時間以内に再度 hwlock が設定された場合、hwclock は経過時間が短すぎて正確にドリフトを計算できないとしてドリフトは再計算されません。

ハードウェアクロックが時間の消失と取得を何度も繰り返している場合、不正なドリフトが保存されている可能性があります (ただし hwclock デーモンが実行中の場合に限ります)。これはハードウェアクロックの時間を間違って設定したり時刻系を Windows や Mac OS と合わせていないときに起こります。/etc/adjtime を削除してドリフト値を削除してから、正しいハードウェアとシステムクロックの時間を設定して、時刻系が直ったか確認してください。

ノート: systemd を使用しているのに /etc/adjtime に保存されているドリフト値を使いたい (つまり NTP を使えない・使いたくない) 場合、定期的に hwclock --adjust を実行するか、それを代わりにする cron ジョブを作って下さい。

ソフトウェアクロックはかなり正確ですが、他の時計と同じく完全に正しいわけではありませんし同じようにズレが起こります。稀に、カーネルが割り込みを飛ばしたときにシステム時刻が正確さを失うことがあります。ソフトウェアクロックの正確性を改善するツールが複数存在します。#時刻同期を見てください。

時刻同期

Network Time Protocol (NTP) はパケット交換でデータの遅延時間が不確定なネットワークを介してコンピュータシステムの時刻を同期するためのプロトコルです。NTP の実装は以下が存在します:

  • Chrony — ローミングフレンドリーで、常時オンラインではないシステムのために特別に設計されたクライアントとサーバーです。ほとんどの場合、ntpd よりも速く、より参照に近い形で収束します。
https://chrony.tuxfamily.org/ || chrony
  • Network Time Protocol daemon — プロトコルのリファレンス実装であり、特に時刻サーバーでの使用が推奨されます。NTPd は割り込みの周期や1秒辺りのティックの数を調整してシステムクロックのずれを減らすことも可能です。NTPd の実行中は11分ごとにハードウェアクロックの再同期も行われます。
http://www.ntp.org/ || ntp
  • NTPsec — NTPd のフォークで、セキュリティに重点を置いています。多くの古いコードが捨てられる以外は、同じように動作します。
https://ntpsec.org/ || ntpsecAUR

適切な NTP ノード以下の機能を持つものは、SNTP("Sinplified" の意)とみなされます。基本的な SNTP クライアントは、長期的なドリフトを追跡することなく、単に 1 つのサーバーから時刻を取得し、すぐに設定することができます。SNTP は精度が低いですが、より少ないリソースで動作します。この精度は通常、デスクトップユーザーや組み込みワークロードには十分ですが、NTP サーバーには受け入れられません。以下は、SNTP を実装しています:

  • ConnMan — A lightweight network manager with SNTP support.
https://01.org/connman (waybackmachine) || connman
  • ntpclient — シンプルなコマンドライン NTP クライアント。
http://doolittle.icarus.com/ntpclient/ || ntpclientAUR
  • OpenNTPD — クライアントとサーバーの両方を実装する OpenBSD プロジェクト。
http://www.openntpd.org/ || openntpd
  • sntp — NTPd に付属している SNTP クライアント。ntpdate を置き換えることができ、サーバー以外の環境での使用が推奨されます。
http://www.ntp.org/ || ntp
  • systemd-timesyncd — クライアント側だけを実装したシンプルな SNTP デーモン。リモートサーバーに時刻を問い合わせることだけを行います。大抵の環境ではクライアントだけで十分です。
https://www.freedesktop.org/wiki/Software/systemd/ || systemd

ユーザー別あるいは一時的に時刻を設定

ときとしてシステムの時刻は変えずに一時的に設定を変えたいということがあるでしょう。例えば、時間を使用するアプリケーションを開発していて実際に動きをテストしたい場合やタイムゾーンが異なる場所からサーバーにログインしている場合などです。

アプリケーションにシステム時刻以外の時刻を使わせたいときは (libfaketime に含まれている) faketime(1) ユーティリティが使えます。

アプリケーションにシステム設定のタイムゾーン以外のタイムゾーンを使わせたいときは、以下のように TZ 環境変数を設定してください:

$ date && export TZ="/usr/share/zoneinfo/Pacific/Fiji" && date
Tue Nov  1 14:34:51 CET 2016
Wed Nov  2 01:34:51 FJT 2016

環境変数によってシステムの時刻が変わるわけではないため、プログラムの開発時に UTC からの時差を変えたり DST をテストすることが可能です。

タイムゾーンを別々に設定するケースとして同一システム上にユーザーが複数存在する場合も考えられます。シェルの設定ファイルで TZ 変数を設定することでユーザーごとにタイムゾーンを設定できます。環境変数#変数の定義自動起動#シェルを参照してください。

ヒントとテクニック

fake-hwclock

alarm-fake-hwclock は RTC をバックアップするバッテリーが搭載されていないシステム用のスクリプトで、シャットダウン時に現在時刻を保存して、起動時に保存した時刻を復元する systemd サービスが付属しています。これによって時刻が飛んでしまうエラーを防ぐことができます。

fake-hwclock-gitAURインストールして fake-hwclock.service起動・有効化してください。

トラブルシューティング

時計が示している値が UTC でも localtime でもない

さまざまな理由が考えられます。例えば、ハードウェアクロックが localtime で動いているのに、timedatectl が UTC に設定されていると、タイムゾーンのオフセットが UTC に二重に適用されることで、localtime でも UTC でもない間違った値になってしまいます。

時計を正しい時刻に直して、ハードウェアクロックに正しい UTC を書き込むには、以下の手順に従って下さい:

  • NTP を設定してください (サービスとして有効にする必要はありません)。
  • タイムゾーンを適切に設定してください。
  • ntpd -qg を実行して手動で時計をネットワークと同期してください、ローカル UTC とネットワーク UTC の時差は無視します。
  • hwclock --systohc を実行して現在のソフトウェア UTC 時刻をハードウェアクロックに書き込んで下さい。

資料