108.1 レッスン 1
Certificate: |
LPIC-1 (102) |
---|---|
Version: |
5.0 |
Topic: |
108 基本的なシステムサービス |
Objective: |
108.1 システムの時刻を保守する |
Lesson: |
1 of 2 |
はじめに
現代のコンピューティングでは、正確な時刻管理が必須です。しかし、時刻管理の実装は驚くほど複雑です。エンドユーザーにとっては、正確な時刻の維持は簡単なことのように思えるかもしれませんが、システムは多様なケースや例外をインテリジェントに処理する必要があります。タイムゾーンは、管理の都合や政治上の決定によって変更されることがあるので、静的ではありません。国がサマータイムを止める選択をする可能性もあります。すべてのプログラムは、これらの変更を論理的に処理する必要があります。システム管理者にとって幸いなことに、Linuxオペレーティングシステムにおける時刻管理は成熟していて堅牢であり、通常は保守する必要があまりありません。
Linuxコンピュータが起動するとすぐに、時間のカウントが始まります。オペレーティングシステムがカウントするものを システムクロック と呼びます。また、最近のコンピューターには、ハードウェア または リアルタイムクロック も備えています。ほとんどのマザーボードはハードウェアクロックを備えていて、コンピュータが起動されているかどうかに関わりなく時刻を更新しています。起動の際にはハードウェアクロックからシステムクロックが設定されますが、その他のほとんどの場合は、これら2つのクロックは互いに独立して機能しています。このレッスンでは、システムクロックとハードウェアクロックの両方を操作する方法について説明します。
最近のほとんどのLinuxシステムでは、システムクロックとハードウェアクロックの両方が、Network Time Protocol(NTP)によって ネットワーク時刻 に同期されます。ほとんどの場合、ユーザーはタイムゾーンを設定するだけで、残りはNTPが処理します。ここでは手動で時刻を調整する方法を説明し、次のレッスンでネットワーク時刻の調整について説明します。
ローカルタイムとユニバーサルタイム
システムクロックは、英国グリニッジの現地時刻でもある協定世界時(UTC)に設定されています。ユーザーは自分の ローカルタイム を知りたいことが多いでしょう。UTC時刻を取得し、タイムゾーンとサマータイムに基づく オフセット を適用することで、ローカルタイム(現地時刻)を得ることができます。この方法で、多くの複雑さを回避できます。
システムクロックは、UTC時刻ないし現地時刻のいずれにも設定できますが、UTC時刻に設定することがお勧めです。
dateコマンド
date
コマンドは、デフォルトでは現地時刻を現地言語で出力します。(訳注:例は米国東部標準時EST(UTC-0500)です。)
$ date Sun Nov 17 12:55:06 EST 2019
date
コマンドのオプションを使って、出力を変更できます。
たとえば、date -u
は、現在のUTC時刻を表示します。
$ date -u Sun Nov 17 18:02:51 UTC 2019
オプションを指定することで、さまざまな形式で現在時刻を表示することができます。
-I
-
ISO 8601形式で日付と時刻を返します。
-I
のみ、ないし-Idate
を指定すると、日付のみを表示します。date
の他にhours
、minutes
、seconds
、ns
(ナノ秒)を指定でき、指定した精度までの時刻を表示します。(訳注:ISO 8601は、日付と時刻を表記方法を規定する国際規格です。たとえば日本時間2020年7月15日14時36分15.23秒は、20200715T143615.23+0900
(基本形式)ないし2020-07-15T14:36:15.23+0900
(拡張形式)と表記します。詳しくはWikipediaなどを参照して下さい。) -R
-
RFC 5322形式で日付と時刻を返します。(訳注:RFC 5322は、電子メールにおけるテキストメッセージのフォーマットを規定する規格です。たとえば日本時間2020年7月15日14時36分15.23秒は、
Wed, 15 Jul 2020 14:36:15 +0900
と表示されます。この形式がLinuxのデフォルトです。) --rfc-3339
-
RFC 3339形式で日付と時刻を返します。(訳注:RFC 3339は、インターネット上で日時の表現方法を規定する規格です。ISO 8601とほぼ同じ書式ですが、よりコンピューターで処理しやすい形で定義されています。あまり使用されていません。)
date
の表示形式は、manページに記載されたシーケンス(メタ文字)を使用してカスタマイズできます。たとえば次のようにすると、現在時刻をUnix時刻(後述)で表示します。
$ date +%s 1574014515
date
のマニュアルページを参照すれば、%s
がUnix時刻を表すことがわかります。
Unix時刻とは、ほとんどのUnix系システムが内部的に使用している時刻表現です。UTCの1970年1月1日0時0分0秒を Epoch (訳注: 記念日、起源などの意)と呼び、そこからの秒数で時刻を表します。
Note
|
現時点でUnix時刻を保持するために必要なビット数は32ビットです。将来、2038年1月19日には、32ビットではUnix時刻を保持できなくなるために、32ビットLinuxシステムで深刻な問題が発生することが指摘されています。(訳注:64ビットLinuxシステムでは既に解決されています。) |
これらのシーケンスを使用すれば、さまざまなアプリケーションが期待する形式で日付と時刻をフォーマットできます。もちろん、規格に基づく標準的なフォーマットを使用するに超したことはありません。
また、date --date
を使用すると、現在時刻ではなく指定した時刻を、標準的な形式で表示できます。たとえば、Unix時刻で日時を指定するとこうなります。
$ date --date='@1564013011' Wed Jul 24 20:03:31 EDT 2019
--debug
オプションを使用すると、日時の解析プロセスを確認することができます。有効な日付をコマンドに渡してみましょう。
$ date --debug --date="Fri, 03 Jan 2020 14:00:17 -0500" date: parsed day part: Fri (day ordinal=0 number=5) date: parsed date part: (Y-M-D) 2020-01-03 date: parsed time part: 14:00:17 UTC-05 date: input timezone: parsed date/time string (-05) date: using specified time as starting value: '14:00:17' date: warning: day (Fri) ignored when explicit dates are given date: starting date/time: '(Y-M-D) 2020-01-03 14:00:17 TZ=-05' date: '(Y-M-D) 2020-01-03 14:00:17 TZ=-05' = 1578078017 epoch-seconds date: timezone: system default date: final: 1578078017.000000000 (epoch-seconds) date: final: (Y-M-D) 2020-01-03 19:00:17 (UTC) date: final: (Y-M-D) 2020-01-03 14:00:17 (UTC-05)
このオプションは、日時を生成するアプリケーションのトラブルシューティングを行うときに便利です。
ハードウェアクロック
hwclock
コマンドは、リアルタイムクロックの時刻を表示します。このコマンドの実行にはroot権限が必要なので、sudo
を使用してコマンドを呼び出します。
$ sudo hwclock 2019-11-20 11:31:29.217627-05:00
--verbose
オプションを使用すると、トラブルシューティングに役立つであろうより多くの出力が返されます。
$ sudo hwclock --verbose hwclock from util-linux 2.34 System Time: 1578079387.976029 Trying to open: /dev/rtc0 Using the rtc interface to the clock. Assuming hardware clock is kept in UTC time. Waiting for clock tick... ...got clock tick Time read from Hardware Clock: 2020/01/03 19:23:08 Hw clock time : 2020/01/03 19:23:08 = 1578079388 seconds since 1969 Time since last adjustment is 1578079388 seconds Calculated Hardware Clock drift is 0.000000 seconds 2020-01-03 14:23:07.948436-05:00
Calculated Hardware Clock drift
行に着目しましょう。この行は、システムクロックとハードウェアクロックのズレを示しています。
timedatectlコマンド
timedatectl
コマンドは、日付と時刻の状態を確認するためのコマンドで、ネットワーク時刻との同期状態も表示します。(ネットワークタイムプロトコルについては次のレッスンで取り上げます)。
デフォルトの timedatectl
は、date
と同様の情報を返しますが、RTC(ハードウェア)時刻とNTPサービスの状態が追加されています。
$ timedatectl Local time: Thu 2019-12-05 11:08:05 EST Universal time: Thu 2019-12-05 16:08:05 UTC RTC time: Thu 2019-12-05 16:08:05 Time zone: America/Toronto (EST, -0500) System clock synchronized: yes NTP service: active RTC in local TZ: no
timedatectlを使用した時間の設定
date
や hwclock
で時刻を設定することもできますが、systemd
を採用しているシステムでNTPが使用できない場合は、timedatectl
コマンドで時刻を設定するのがお勧めです。
# timedatectl set-time '2011-11-25 14:00:00'
HH:MM:SS の形式を使用して、時刻のみを設定することもできます。(後述しますが、date
コマンドでも同様です。)
timedatectlを使用したタイムゾーンの設定
systemd
ベースのLinuxシステムにおいて、GUIツールが使えない場合には、timedatectl
を使ってローカルタイムゾーンを設定します。timedatectl
で、まず指定できるタイムゾーンの一覧を表示して、そのいずれかを引数として使用してタイムゾーンを設定します。
まず、指定できるタイムゾーンをリストします。
$ timedatectl list-timezones Africa/Abidjan Africa/Accra Africa/Algiers Africa/Bissau Africa/Cairo ...
タイムゾーンのリストは長いので、grep
コマンドを使うのがお勧めです。(訳注:リストはページャ経由で表示されるので、その検索機能を使うのもよいでしょう。)
次に、返されたリストから1つを選び、タイムゾーンを設定します:
$ timedatectl set-timezone Africa/Cairo $ timedatectl Local time: Thu 2019-12-05 18:18:10 EET Universal time: Thu 2019-12-05 16:18:10 UTC RTC time: Thu 2019-12-05 16:18:10 Time zone: Africa/Cairo (EET, +0200) System clock synchronized: yes NTP service: active RTC in local TZ: no
タイムゾーンの名前を正確に指定することに注意してください。たとえば、タイムゾーンを Africa/Cairo
と指定できますが、cairo
や africa/cairo
と指定することはできません。タイムゾーン名は、ディストリビューションによって異なります。
timedatectlを使用したNTPの無効化
NTPを無効にしたいことがあります。systemctl
を使うこともできますが、ここでは timedatectl
コマンドを使います:
# timedatectl set-ntp no $ timedatectl Local time: Thu 2019-12-05 18:19:04 EET Universal time: Thu 2019-12-05 16:19:04 UTC RTC time: Thu 2019-12-05 16:19:04 Time zone: Africa/Cairo (EET, +0200) NTP enabled: no NTP synchronized: no RTC in local TZ: no DST active: n/a
timedatectlを使わずにタイムゾーンを設定する
タイムゾーンを設定することは、Linuxを新規インストールする場合の標準的な手順のひとつです。グラフィカル画面によるインストールでは、ほとんどの場合、何かを入力する必要もありません。
/usr/share/zoneinfo
ディレクトリには、さまざまなタイムゾーン情報が含まれています。zoneinfo
ディレクトリには、大陸名などのサブディレクトリないしはシンボリックリンクがあります。大陸名から始めて、自分の地域の zoneinfo
を見つけるとよいでしょう。
zoneinfo
ファイルには、UTCに対する現地時間のオフセットを計算するために必要な、サマータイムを含むルールが含まれています。Linuxがローカルタイムゾーンを決定する場合は、/etc/localtime
を読み取ります。GUIを使用せずにタイムゾーンを設定するには、/etc/localtime
を /usr/share/zoneinfo
内の自分の地域のzoneinfoを指すシンボリックリンクとして作成します。例を示します。
$ ln -s /usr/share/zoneinfo/Canada/Eastern /etc/localtime
正しいタイムゾーンを設定したら、以下のコマンドを実行します:
# hwclock --systohc
これにより、システムクロック に ハードウェアクロック をあわせます(つまり、リアルタイムクロックが、date
が表示するのと同じ時刻にセットされます)。このコマンドを実行するには、root権限が必要なことに注意してください。
/etc/timezone
は、/etc/localtime
と似た役割を持っています。ローカルタイムゾーンの名前を保持しているので、cat
で読み取ることができます。
$ cat /etc/timezone America/Toronto
Linuxディストリビューションによっては、このファイルが使われてないこともあります。
timedatectlを使わずに日時を設定する
Note
|
最近のほとんどのLinuxシステムは、構成とサービスに |
dateコマンドを使う
date
コマンドには、システム時刻をセットするオプションがあります。--set
ないし -s
を使用して、日付と時刻をセットします。--debug
オプションを使って、コマンドの解析内容を確認することもできます。
# date --set="11 Nov 2011 11:11:11"
日時をセットするには、root権限が必要であることに注意してください。時間と日付を別々に変更することもできます。
# date +%Y%m%d -s "20111125"
この場合、文字列を適切に解釈するように、形式を示すシーケンスを指定する必要があります。たとえば、%Y
は年を表すので、最初の4桁 2011
は2011年として解釈されます。時刻のシーケンスは %T
ですから、以下に時間をセットする例を示します:
# date +%T -s "13:11:00"
システムクロックを変更した後には、システムクロックとハードウェアクロックを同期するために、ハードウェアクロックも変更するとよいでしょう。
# hwclock --systohc
systohc
は、“システムクロックからハードウェアクロックへ” を意味します。(SYStem to Hardware Clockの略です。)
hwclockを使う
システムクロックをセットしてハードウェアクロックをあわせるのではなく、逆にハードウェアクロックをセットしてシステムクロックをあわせても構いません。
# hwclock --set --date "4/12/2019 11:15:19" # hwclock Fri 12 Apr 2019 6:15:19 AM EST -0.562862 seconds
hwclock
にはUTC時刻をセットするのが普通ですが、返されるのは現地時刻であることに注意してください。
ハードウェアクロックをセットしたら、それにシステムクロックをあわせます。hctosys
は “ハードウェアクロックからシステムクロック” を意味しています。
# hwclock --hctosys
演習
-
表のコマンドが システムクロック と ハードウェアクロック のどちらを表示ないし変更するかを示してください。
コマンド システム ハードウェア 両方 date -u
hwclock --set --date "12:00:00"
timedatectl
timedatectl | grep RTC
hwclock --hctosys
date +%T -s "08:00:00"
timedatectl set-time 1980-01-10
-
以下の出力を見て、正しく解釈されるように引数の書式を修正してください。
$ date --debug --date "20/20/12 0:10 -3" date: warning: value 20 has less than 4 digits. Assuming MM/DD/YY[YY] date: parsed date part: (Y-M-D) 0002-20-20 date: parsed time part: 00:10:00 UTC-03 date: input timezone: parsed date/time string (-03) date: using specified time as starting value: '00:10:00' date: error: invalid date/time value: date: user provided time: '(Y-M-D) 0002-20-20 00:10:00 TZ=-03' date: normalized time: '(Y-M-D) 0003-08-20 00:10:00 TZ=-03' date: ---- -- date: possible reasons: date: numeric values overflow; date: incorrect timezone date: invalid date ‘20/20/2 0:10 -3’
-
date
コマンドのシーケンスを使用して、システムクロックの月を2月にセットしてください。年と日、時刻は変更してはいけません。 -
前問のコマンドが成功したと仮定して、
hwclock
を使ってシステムクロックにハードウェアクロックをあわせてください。 -
Eucla
と呼ばれる地名があります。それはどの大陸にありますか?grep
コマンドを使って調べて下さい。 -
タイムゾーンを
Eucla
のタイムゾーンに設定してください。
発展演習
-
時計を合わせる最適な方法は何ですか? また、その方法が使えない場面はどのようなものでしょう?
-
システム時刻をセットする方法がたくさんあるのはなぜだと思いますか?
-
2038年1月19日以降、システム時刻を保存するには64ビットの数値が必要になります。あるいは、“Epochを変更する” ことでも問題を解決できます。たとえば、2038年1月1日の深夜0時を、新しいEpochの0とすればよいのです。この解決方法を採用しない理由を考察して下さい。
まとめ
このレッスンでは、以下の事柄を学びました:
-
コマンドラインから、日時をさまざまな形式で表示する方法。
-
Linuxのシステムクロックとハードウェアクロックの違い。
-
システムクロックを手動で設定する方法。
-
ハードウェアクロックを手動で設定する方法。
-
システムのタイムゾーンを変更する方法。
このレッスンでは、以下のコマンドを説明しました。
date
-
システムクロックを表示または変更します。主なオプション:
-u
-
UTC時刻を表示します。
+%s
-
Unix時刻を指定するシーケンス。
--date=
-
現在時刻ではなく、指定した時刻を表示します。
--debug
-
指定した日時の文字列を解析するときのデバッグメッセージを表示します。
-s
-
システムクロックを手動設定します。
hwclock
-
ハードウェアクロックを表示または変更します。
--systohc
-
システムクロックにハードウェアクロックをあわせます。
--hctosys
-
ハードウェアクロックにシステムクロックをあわせます。
--set --date
-
ハードウェアクロックを手動で設定します。
timedatectl
-
systemdベースのLinuxシステムにおいて、システムとハードウェアクロックの時刻と、NTPの状態を表示します。
set-time
-
時間を手動で設定します。
list-timezones
-
指定できるタイムゾーンを一覧表示します。
set-timezone
-
timzoneを手動で設定します。
set-ntp
-
NTPの有効/無効を切り替えます。
演習の解答
-
表のコマンドが システムクロック と ハードウェアクロック のどちらを表示ないし変更するかを示してください。
コマンド システム ハードウェア 両方 date -u
✓
hwclock --set --date "12:00:00"
✓
timedatectl
✓
timedatectl | grep RTC
✓
hwclock --hctosys
✓
date +%T -s "08:00:00"
✓
timedatectl set-time 1980-01-10
✓
-
以下の出力を見て、正しく解釈されるように引数の書式を修正してください。
$ date --debug --date "20/20/12 0:10 -3" date: warning: value 20 has less than 4 digits. Assuming MM/DD/YY[YY] date: parsed date part: (Y-M-D) 0002-20-20 date: parsed time part: 00:10:00 UTC-03 date: input timezone: parsed date/time string (-03) date: using specified time as starting value: '00:10:00' date: error: invalid date/time value: date: user provided time: '(Y-M-D) 0002-20-20 00:10:00 TZ=-03' date: normalized time: '(Y-M-D) 0003-08-20 00:10:00 TZ=-03' date: ---- -- date: possible reasons: date: numeric values overflow; date: incorrect timezone date: invalid date ‘20/20/2 0:10 -3’
date --debug --set "12/20/20 0:10 -3"
-
date
コマンドのシーケンスを使用して、システムクロックの月を2月にセットしてください。年と日、時刻は変更してはいけませんdate +%m -s "2"
-
前問のコマンドが成功したと仮定して、
hwclock
を使ってシステムクロックにハードウェアクロックをあわせてください。hwclock -systohc
-
Eucla
と呼ばれる地名があります。それはどの大陸にありますか?grep
コマンドを使って調べて下さい。timedatectl list-timezones | grep -i eucla
または
grep -ri eucla /usr/share/zoneinfo
-
タイムゾーンを
Eucla
のタイムゾーンに設定してください。timedatectl set-timezone 'Australia/Eucla'
または、
ln -s /usr/share/zoneinfo/Australia/Eucla /etc/localtime
発展演習の解答
-
時計を合わせる最適な方法は何ですか? また、その方法が使えない場面はどのようなものでしょう?
ほとんどのLinuxディストリビューションでは、NTPがデフォルトで有効になっているので、干渉しないようにそのままにしておきます。ただし、インターネットに接続されていないLinuxシステムは、NTPにアクセスできません。たとえば、産業用機器で実行されている組み込みLinuxシステムでは、ネットワーク接続がないことがあります。
-
システム時刻をセットする方法がたくさんあるのはなぜだと思いますか?
何十年も前から、すべてのUnix系システムは正確な時刻を必要としていました。そのため、時刻を設定するための多くのレガシーメソッドが残されています。
-
2038年1月19日以降、システム時刻を保存するには64ビットの数値が必要になります。あるいは、“Epochを変更する” ことでも問題を解決できます。たとえば、2038年1月1日の深夜0時を、新しいEpochの0とすればよいのです。この解決方法を採用しない理由を考察して下さい。
2038年までには、大半のコンピュータが64ビットCPUを搭載して、64ビットの数値を使用してもパフォーマンスが大きく低下することはないと予測されます。対して、このような “リセット” する方法のリスクを見積もることは不可能です。影響を受ける可能性があるレガシーソフトウェアがたくさんあります。例えば、銀行や大企業は古いプログラムを大量に抱え、それに依存していることが少なくありません。つまり、この解決方法は、他の多くの解決方法と同様に、トレードオフの問題です。2038年にまだ稼働している32ビットシステムはEpoch時刻のオーバーフローの影響を受けますし、レガシーソフトウェアは変更されたEpochの値の影響を受けることになります。