はじめに
東京オリンピックの暑さ対策としてサマータイム導入の検討が騒がれている。システム屋としては日本に夏時間の導入は全力で反対するが、キーワードで「夏時間で2時間早くする」というものがあった。2時間のサマータイムは聞いたことないわけで気になって試してみた。
Time Zone Database
ご存知の通りUNIX系のOS(LinuxとかBSD, etc..)では、時差つまりタイムゾーンをTime Zone Database (tz database, aka. zoneinfo)を使って管理している。Time Zone Database は、/usr/share/zoneinfo にある。
なお以下の記事の例ではFreeBSDを利用して試しているが、Linuxや Macでもまったく同様である。
$ ls /usr/share/zoneinfo
Africa Australia Etc MST WET
America CET Europe MST7MDT posixrules
Antarctica CST6CDT Factory PST8PDT zone.tab
Arctic EET HST Pacific
Asia EST Indian SystemV
Atlantic EST5EDT MET UTC
$
Time Zone Database には、過去を含めて時差と夏時間の情報があるわけだが、はたして2時間のサマータイムは導入できる構造なのか。
ウィキペディアの「夏時間」を見てみる
実際に Time Zone Database をいじる前に、改めてウィキペディアの「夏時間」を読むと、こんな記述があった。
ただし、オーストラリアのロード・ハウ島では夏時間と通常の時間の差が1時間でなく30分である。
おお!30分!! なので zoneinfo では 1時間でないサマータイムをサポートしていることは容易に推測できる。
Time Zone Database の入手
元々Time Zone Database (以下 zoneinfo)はアーサー・デイヴィッド・オルソン(Arthur David Olson)さんが個人的に管理していたが、今はIANAが情報をまとめてデータベースを更新している。このあたりはウィキペディアのtz databaseにまとめられている。
ということで最新の Time Zone Database は IANA の Time Zone Database のページからダウンロードできるので拾ってきて展開してみる。
$ tar xf tzdb-2018e.tar.lz
$ ls
tzdb-2018e
$ ls tzdb-2018e | wc
67 67 742
$
思っていたよりたくさんのファイルがあり、zic(zoneinfoコンパイラ)等の関連ユーティリティのソースや、BSDのstrftimeのソース、それらのman等も含まれていた。Time Zone Database そのものはテキストファイルであり、zic コマンドで変換して zoneinfo として利用する。
ちなみにデータベースの情報など大部分はパブリックドメインである。一部のソースやmanはBSDからそのまま持ってきているので、それらについてはBSDライセンスとなる。
ロード・ハウ島の例
ウィキペディアに記載のあるロード・ハウ島の情報は、australasia のファイルにあるが、該当部分は次のように定義されている。
# Lord Howe Island
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule LH 1981 1984 - Oct lastSun 2:00 1:00 -
Rule LH 1982 1985 - Mar Sun>=1 2:00 0 -
=============== 中略 ===============
Rule LH 2008 max - Apr Sun>=1 2:00 0 -
Rule LH 2008 max - Oct Sun>=1 2:00 0:30 -
Zone Australia/Lord_Howe 10:36:20 - LMT 1895 Feb
10:00 - AEST 1981 Mar
10:30 LH +1030/+1130 1985 Jul
10:30 LH +1030/+11
過去には1時間のサマータイムが実施されたことがあるが、2008年以降10月の第1日曜日から4月の第1日曜日の午前2時を切り替え時間として 30分の夏時間で運用されていることがわかる。
日本のzoneinfoを変更してみる
日本時間の情報は asia というファイルの中に以下のように定義されており、戦後に実施された夏時間の情報もちゃんと含まれている(コメント部を削って引用)。
# Japan
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Japan 1948 only - May Sat>=1 24:00 1:00 D
Rule Japan 1948 1951 - Sep Sun>=9 0:00 0 S
Rule Japan 1949 only - Apr Sat>=1 24:00 1:00 D
Rule Japan 1950 1951 - May Sat>=1 24:00 1:00 D
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u
9:00 Japan J%sT
明治時代の情報まで記録されているのには驚いた。
これを書き換えて、次の2行を # Zone の行の前に追加してみた。2018年以降、6月1日の午前2時 から 10月1日の午前2時までが夏時間という設定である。
Rule Japan 2018 max - Jun 1 2:00 2:00 D
Rule Japan 2018 max - Oct 1 2:00 0 S
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u
9:00 Japan J%sT
あとは zic でファイルをコンパイルすれば、日本夏時間を含む zoneinfo の出来上がり。システム標準のものを書き換えるわけにもいかないので、/tmp に出力した。asia に含まれている、一部のヨーロッパやインドエリアの zoneinfo も一緒に生成されているのがわかる。
$ /usr/sbin/zic -d /tmp asia
$ ls /tmp
Asia Europe Indian
$ ls -l /tmp/Asia/Tokyo
-rw-r--r-- 1 minmin wheel 884 Aug 8 12:44 /tmp/Asia/Tokyo
$
生成結果を手っ取り早く確認するには、TZ環境変数を利用すればよい。
$ date ; TZ=:/tmp/Asia/Tokyo date
Wed Aug 8 12:45:11 JST 2018
Wed Aug 8 14:45:11 JDT 2018
$
この通り、修正した日本用のzoneinfoを利用すると、2時間進んだ夏時間に変更できることが分かった。
出来た Tokyo を /etc/localtime にコピーするか、/etc/localtime のシンボリックリンクを書き換えてこのファイルを参照するようにすれば、2時間進んだサマータイムを導入したシステムとなる(実際に実行したわけでは無い)。
$ sudo cp /tmp/Asia/Tokyo /etc/localtime
Password:
$
切りの良い時間ばかりでは面白くないので、SAVEのフィールドを 1:37 として試したのが、次の例である。
$ date ; TZ=:/tmp/Asia/Tokyo date
Wed Aug 8 12:47:35 JST 2018
Wed Aug 8 14:24:35 JDT 2018
また -1:00 を設定し夏に1時間遅れるようにしてみると、正しく1時間遅れる結果となった。
$ date ; TZ=:/tmp/Asia/Tokyo date
Wed Aug 8 12:48:24 JST 2018
Wed Aug 8 11:48:24 JDT 2018
$
結果は省略するが、1:00:05 のように秒まで設定すれば、秒単位の変更も問題なくできる。
まとめ
Time Zone Databaseは、柔軟な時差、サマータイムに対応できる構造であり、サマータイムとして2時間進める設定も簡単に導入できることがわかった。実際の多くのシステムでは、zoneinfo の更新は OS のアップデートに頼ることになるはずである。しかしながら自分で書き換えることは簡単であり、任意の時刻に任意の時差を設定することで、夏時間との切り替え時点でのアプリケーションの挙動確認にも応用できることがわかった。
追記: システムのサマータイムへの対応
zoneinfoで対応できるシステムの時刻変更は、サマータイムの対応に必要なシステム全体の変更項目の極一部でしかない。サマータイムの対応では、アプリケーションの時刻の扱い、zoneinfoなんてものを知らない制御系システム、通信で利用される時刻などをどうするかの問題の方が遥かに大きい。
追記 その2: TZ環境変数
TZ で zoneinfo のファイルを指定する場合は、: (コロン)で始めるのが正式のようなので修正した。実際は多くの実装でコロンが無くても動作し、事実マニュアルにもコロンが無い場合の挙動について記載されている。
追記 その3: 2時間のサマータイム
一連の話題の中で2時間のサマータイムを実施した国があるというのを見かけたので、調べてみた。といってもやってることは簡単でzoneinfoのデータベースからSAVEが2時間になっている部分をgrepで拾い出すだけである。なお次の例の、egrep での検索文字列の空白部分は TAB である。
$ egrep '^Rule.* 2:00 .$' *
europe:Rule France 1942 only - Mar 9 0:00 2:00 M
europe:Rule France 1943 only - Mar 29 2:00 2:00 M
europe:Rule France 1944 only - Apr 3 2:00 2:00 M
europe:Rule France 1945 only - Apr 2 2:00 2:00 M
europe:Rule Germany 1947 only - May 11 2:00s 2:00 M
europe:Rule Port 1943 only - Apr 17 22:00s 2:00 M
europe:Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M
europe:Rule Spain 1938 only - Apr 30 23:00 2:00 M
$
この通りヨーロッパの 4つの国で見つかったが、時代的にはコンピュータが利用されるより前の話だ。ざっくりeurope のファイルを見た感じだと、1時間ずらした上でさらに1時間ずらして結果的に2時間進んだ運用を行ったように見える(勘違いしてるかも)。