“DST: Mar-Oct” を真実として static なページに情報として埋め込んで意味がないかもしれない話 (本編)

やっぱりね、っと。

静的な情報ページに Daylight Saving Time の開始終了「月」だけ記載することのナンセンスさに関する考察なのよ

発端

wikipedia の空港コード一覧の By IATA code のうち「A」~「L」までのフォーマット:

「M」~「Z」には Timezone/DST のカラムがない。そもそもこの「不統一」が情報リソースとしての価値を激減させている。

ひとまずはこの“DST: Mar-Oct”という記載方式自体に初見から違和感があったことは脇に置いて、「自力でこの情報を埋めれるだろうか?」と考えたのが最初。違和感の意味はこの記事全体読めばわかる。

最初に考えたこと: 緯度経度から Timezone/DST を割り出せるか?

元はと言えば空港一覧からの話なので、取れてれば位置情報が取れてる。ここから Timezone/DST を割り出すリーズナブルな方法は、あれば、あるか?

先に「なんにも知らない」という人向けに軽く説明しとく。

  1. タイム「ゾーン」がないがローカルタイムがある世界が仮にあるならば、人は時計を経度方向への移動のたびに調整しなければならないだろう。
  2. UTC からの、経度から直接計算されるオフセットは単純な算数で、シンプルには「今いる経度/180*12」である。日本の場合、+135/180.*12 == +9。
  3. この算数が通用しないことは小学校地理で習う「日付変更線がうねってる」ことだけでも理解出来るだろう。
  4. そもそも「時計を経度方向への移動のたびに調整」は不便過ぎるだろう。
  5. だからタイム「ゾーン」がある。日常生活で時計調整を頻繁には必要としない「範囲」を決めるのだ。
  6. だからタイム「ゾーン」は国ごとに決める。
  7. だからといって「ユーラシア大陸共通」なんて、「5時は朝なのか深夜なのか」の概念の統一が崩れて、きっと不便だろう、5時は世界共通で「朝ですよー」と言いたい、それが「時計」ってもんだろう。
  8. だからタイム「ゾーン」は、広い国では複数あるのである。
  9. に加えて「夏時間」。この話は今は放置。

今上の列挙で言いたいのはひとまず、「緯度と経度」という情報だけでは、ソフトウェアはなんにも出来ない、ということ。「タイムゾーン境界を決定するポリゴン(的な何か)(とそれに紐付く UTC オフセットの情報)」が必要だ、ということ。だから「リーズナブル度」に差はあれど、どんなアプローチであれ必ず「ばかでかいデータベース的なもの」が必要。セットアップしてしまえば簡単、かどうかは別として、データのセットアップ等々をゼロコストには出来ない。

この手のもんは StackOverflow で百発百中で見つかる。結構あるね。プログラム的に、しかも Python でやるなら timezonefinder あたりが良さげか。動かしてみもいないしなんならインストールさえしてないが、こう使うんですと:

想像図
1 >>> from timezonefinder import TimezoneFinder
2 >>> tf = TimezoneFinder()
3 >>> longitude = 13.358
4 >>> latitude = 52.5061
5 >>> tf.timezone_at(lng=longitude, lat=latitude)
6 'Europe/Berlin'

timezonefinder はある一群のファミリに属してて、Eric Muller が作成した ShepeFile の情報を使う。なので当然これをダウンロードし、timezonefinder が扱える形式に変換するプロセスが必要で、このために GDAL が必要。GDAL ねぇ…。GDAL/OGR って依存物多くてなぁ、Windows なんか地獄だぞ、確か。(unix でもかなり面倒。) まぁこれはこれで興味深いからあとでやってみるかぁ、と思い、これはこれで手を止める。

その前に、timezonefinder が「Europe/Berlin」名を取れるのはわかったが、じゃぁここからどうやって UTC オフセットと DST を引っ張ってこれるのかな、ってのが次の話。

次に考えたこと: Timezone 名がわかっているとして、UTC オフセットと DST を知りたい

これをやり始めてすぐに、「発端」で書いた違和感の意味がすぐに(おぼろげだが)見えてきた。

なお、予告編で書いた通り、あたしはそもそも「DST (Daylight Saving Time/夏時間)」についてこれまで真剣に取り組んだことはなく、ほぼ初めて取り組んでるので、読んでるあなたは一緒に驚いたり喜んだりしてみて欲しい。

元はといえば動機は「自力で wikipedia に欠けてる情報を埋めれるか」なので同じく Python の pytz を使って考える。

まずはシンプルに全てのタイムゾーンの DST (の transition) を表示してみようとしたのである:

プライベートなメソッド使っちゃってやぁねぇ、とは口が裂けても言わない
 1 from pytz import timezone, all_timezones
 2 
 3 for tzname in all_timezones:
 4     tz = timezone(tzname)
 5     print(tzname, [dt for dt in tz._utc_transition_times if dt.year == 2016])
 6     # tz._dst
 7     # tz._transition_info
 8     # tz._tzinfos
 9     # tz._tzname
10     # tz._utc_transition_times
11     # tz._utcoffset
12     # tz.dst
13     # tz.fromutc
14     # tz.localize
15     # tz.normalize
16     # tz.tzname
17     # tz.utcoffset
18     # tz.zone

結果は…:

 1 ('Africa/Abidjan', [])
 2 ('Africa/Accra', [])
 3 ('Africa/Addis_Ababa', [])
 4 ('Africa/Algiers', [])
 5 ('Africa/Asmara', [])
 6 ('Africa/Asmera', [])
 7 ('Africa/Bamako', [])
 8 ('Africa/Bangui', [])
 9 ('Africa/Banjul', [])
10 ('Africa/Bissau', [])
11 ('Africa/Blantyre', [])
12 ('Africa/Brazzaville', [])
13 ('Africa/Bujumbura', [])
14 ('Africa/Cairo', [])
15 ('Africa/Casablanca', [datetime.datetime(2016, 3, 27, 2, 0), datetime.datetime(2016, 6, 5, 2, 0), datetime.datetime(2016, 7, 10, 2, 0), datetime.datetime(2016, 10, 30, 2, 0)])
16 ('Africa/Ceuta', [datetime.datetime(2016, 3, 27, 1, 0), datetime.datetime(2016, 10, 30, 1, 0)])
17 ('Africa/Conakry', [])
18 ('Africa/Dakar', [])
19 ('Africa/Dar_es_Salaam', [])
20 ('Africa/Djibouti', [])
21 ('Africa/Douala', [])
22 ('Africa/El_Aaiun', [datetime.datetime(2016, 3, 27, 2, 0), datetime.datetime(2016, 6, 5, 2, 0), datetime.datetime(2016, 7, 10, 2, 0), datetime.datetime(2016, 10, 30, 2, 0)])
23 #...
24 ('America/New_York', [datetime.datetime(2016, 3, 13, 7, 0), datetime.datetime(2016, 11, 6, 6, 0)])
25 ('America/Nipigon', [datetime.datetime(2016, 3, 13, 7, 0), datetime.datetime(2016, 11, 6, 6, 0)])
26 ('America/Nome', [datetime.datetime(2016, 3, 13, 11, 0), datetime.datetime(2016, 11, 6, 10, 0)])
27 ('America/Noronha', [])
28 ('America/North_Dakota/Beulah', [datetime.datetime(2016, 3, 13, 8, 0), datetime.datetime(2016, 11, 6, 7, 0)])
29 ('America/North_Dakota/Center', [datetime.datetime(2016, 3, 13, 8, 0), datetime.datetime(2016, 11, 6, 7, 0)])
30 ('America/North_Dakota/New_Salem', [datetime.datetime(2016, 3, 13, 8, 0), datetime.datetime(2016, 11, 6, 7, 0)])
31 #...

んんん…、なんだ、なんだ? 「夏時間」と「以外」の「二分法」なんじゃないの? なんで ‘Africa/Casablanca’ と ‘Africa/El_Aaiun’ はこんなに分かれてるんだ??

どうも特殊なのはこの2つだけらしいな、と、この Casablanca El_Aaiun の DST の意味を調べようと「Casablanca El_Aaiun d」と検索窓に打ち込んだだけで Google さんは「dst」を即座に推測。うむ…、誰もが疑問に思うことらしいな…。

と結構長い時間探すも、どこにも答えが書いてない。なんなんだ、これは? うーむ、一旦置いておくか。

その前に「_utc_transition_times」で拾った情報が合ってるのかどうか、ほかのリソースに頼って答え合わせしてみる:

良いと思いますぅ。

実際にはこの時点でもう「違和感」の正体が理解できていたりしてな

だってさぁ、さっきのプログラムの結果でもう、たった一つだけ確実に言えることがあるのさね。

wikipedia の空港コード一覧のフォーマットは、「Mar~Oct」のように、月だけ書いている。そしてそこに書いてある説明をさらっと読むに、「この DST の情報を使えば時計合わせ出来るんだぜっ」って書いてあるが、…、出来るかぁ!!

01 Mar~31 Oct、じゃないのだ。だから3月1日に夏時間に切り替えたらあなたはバカを見る。

実際 Google 検索窓に「Daylight Saving」まで打ち込んでみて欲しい。「Time 2016」が補完されるはずだ。つまり夏時間を使う国の人にとっては夏時間の開始終了が年によって違うことも、月の切れ目じゃない日に発生することも「常識」なのであり、しかも「その人たちも結構自分の地域の夏時間がいつからいつまでかを記憶してないのかもしれない」ということがわかる。

なんにしてもだ、「DST として月だけ情報として載せても誰の役にも立たないのだ」ということは、既にはっきり言えるのであった。むしろ「迷惑」とすら言える。

いったん基礎に立ち返る。そもそも「夏時間」ってなんだ

もとはといえばエコノミックな理由で、とかなんとかってのはそれこそ Wikipedia とかみて欲しい。

最も雑だがわかりやすい「夏時間の扱い方」の説明は、「夏時間切り替え時刻になったら時計を1時間進める、夏時間終了切り替え時刻になったら時計を1時間戻す」である。

この雑な説明だけで終えてるサイトも結構あるみたいだし、Wikipedia も肝心なことは書いてなかった。少なくともコンパクトにまとめると、多くのサイトで得られる情報は以下:

  • 夏時間の採用可否も切り替え時期も行政によって決まる
  • 夏時間を採用する国内でも採用しない地域も混在している
  • 夏時間切り替えは結構ラフなルールで決められている(3月第一日曜日、など)
  • 夏時間切り替えは深夜0時とは限らない
  • 夏時間で調整する時間が1時間とは限らない

あらゆるサイトをくまなくみたわけではないけれど、南半球での扱いについてちゃんと書いてるとこは見つけられなかった。同じと言えば同じなんだけれど、確実に逆に見えるのね。当たり前だけど夏冬が逆なので、北半球の国では1~12月で「通常~夏時間開始~夏時間終了~通常」と辿るところが南半球だと「夏時間~夏時間終了~通常~夏時間開始~夏時間」となるのね。どっちが「非夏時間」なのか、確実に混乱する。というか混乱した、わたしは。(transition の切れ目で UTC オフセットが北半球では「開始」タイミングで増えるが南半球の同じ時期「終了」となるので UTC オフセットが小さくなる。)

「行政で決める」「ラフな決め方」に反応しろや、てのと、コンピュータソフトウェアでの処理、に話は戻る

ひょっとしたら「タイムゾーン・DST は IANA が管理している」という情報を耳にしたことがあるかもしれない。が、当たり前だが IANA がタイムゾーン・DST を決めているのではない。そりゃそーだ。IANA は「各地域におけるタイムゾーン・DST の扱い方をデータベース化して管理している」だけ。

先の pytz は実はこのデータベースを丸抱えしている。Unix 系 OS だとこのデータベースがインストールされてるはずだし、おそらく Windows も近いものを持ってるんじゃないかと思うが、当然「政治的な事情」によって刻々と変わるものなので、結構この本家データベースも pytz も頻繁に更新される。

pytz のものや Unix 系 OS にバンドルされるそれはデータがバイナリファイルになっているが、元はルールを記述したソースファイルからコンパイルされたものである。バイナリファイルとしては transition が発生する日付時刻とオフセットに関する情報が取りだせるものとなっているが、もともとのソースは「3月の最終日曜」のような人間可読なフォーマットで記述されている。

これまではコンパイル済みバイナリファイルと pytz ソースばかり見て済んでいたけど、今回 本家データ を久しぶりにお取り寄せしてみた。きっとこのソースに色々ヒントがあるに違いない、と思ったからさ。

…っと…。その前にひとこと。この作業を始める前からワタシの頭の中にはすでに、今回の本題の「意味ないじゃん」に向けての証拠探しモードに入っている。つまり、「Mar~Oct」って言ってるけど、これがばかにならない頻度で「Marじゃない~Octじゃない」にならんのけ? ってことな。つまりはこれこそが「違和感」。そんなに枯れてるもんなん?

てわけでまずは。たとえば夏時間採用の歴史が長くて安定してる国の例:

tzdata2016fのなかのnorthamerica、内の Canada ルール
 1 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 2 Rule	Canada	1918	only	-	Apr	14	2:00	1:00	D
 3 Rule	Canada	1918	only	-	Oct	27	2:00	0	S
 4 Rule	Canada	1942	only	-	Feb	 9	2:00	1:00	W # War
 5 Rule	Canada	1945	only	-	Aug	14	23:00u	1:00	P # Peace
 6 Rule	Canada	1945	only	-	Sep	30	2:00	0	S
 7 Rule	Canada	1974	1986	-	Apr	lastSun	2:00	1:00	D
 8 Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
 9 Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
10 Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
11 Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S

なんとなくはわかると思う。2016年の場合は、2007年からのルールだけが有効になっていて、3月と11月に切り替わる、というルールなんだろう、と想像出来る。これが「夏時間が常識の国」の場合。

けれども「2007年てめちゃくちゃ最近じゃないの?」と思う感覚って大事。つまり wikipedia に「カナダの DST は4月~10月である!」と2006年に事実として記述すれば、2016年の今では大嘘である、てことだ。(ちなみにあたしだって「sun>=1」とかの意味はわかんないよ。けど記事の本題とは関係ないので気にしない。)

なお、みてたらさっきの Casablanca と El_Aaiun について謎が解けた。ソースに書かれていた。長い議論がコメントとしてくっついてるので全部読むのはヘビィなんだけれど、どうやらモロッコでは「ラマダン」の月に夏時間から通常時間に戻すらしい。なぜか Emacs Lisp のプログラムを乗っけてる以下が面白い:

 1 # From Paul Eggert (2015-06-08):
 2 # For now, guess that later spring and fall transitions will use 2015's rules,
 3 # and guess that Morocco will switch to standard time at 03:00 the last
 4 # Sunday before Ramadan, and back to DST at 02:00 the first Sunday after
 5 # Ramadan.  To implement this, transition dates for 2016 through 2037 were
 6 # determined by running the following program under GNU Emacs 24.3, with the
 7 # results integrated by hand into the table below.
 8 # (let ((islamic-year 1437))
 9 #   (require 'cal-islam)
10 #   (while (< islamic-year 1460)
11 #     (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year)))
12 #           (b (calendar-islamic-to-absolute (list 10 1 islamic-year)))
13 #           (sunday 0))
14 #       (while (/= sunday (mod (setq a (1- a)) 7)))
15 #       (while (/= sunday (mod b 7))
16 #         (setq b (1+ b)))
17 #       (setq a (calendar-gregorian-from-absolute a))
18 #       (setq b (calendar-gregorian-from-absolute b))
19 #       (insert
20 #        (format
21 #         (concat "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 3:00\t0\t-\n"
22 #                 "Rule\tMorocco\t%d\tonly\t-\t%s\t%2d\t 2:00\t1:00\tS\n")
23 #         (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a))
24 #         (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b)))))
25 #     (setq islamic-year (+ 1 islamic-year))))

モロッコルールは結果こんな:

 1 # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 2 
 3 Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
 4 Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
 5 Rule	Morocco	1940	only	-	Feb	25	 0:00	1:00	S
 6 Rule	Morocco	1945	only	-	Nov	18	 0:00	0	-
 7 Rule	Morocco	1950	only	-	Jun	11	 0:00	1:00	S
 8 Rule	Morocco	1950	only	-	Oct	29	 0:00	0	-
 9 Rule	Morocco	1967	only	-	Jun	 3	12:00	1:00	S
10 Rule	Morocco	1967	only	-	Oct	 1	 0:00	0	-
11 Rule	Morocco	1974	only	-	Jun	24	 0:00	1:00	S
12 Rule	Morocco	1974	only	-	Sep	 1	 0:00	0	-
13 Rule	Morocco	1976	1977	-	May	 1	 0:00	1:00	S
14 Rule	Morocco	1976	only	-	Aug	 1	 0:00	0	-
15 Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
16 Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
17 Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
18 Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
19 Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
20 Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
21 Rule	Morocco	2009	only	-	Aug	21	 0:00	0	-
22 Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
23 Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
24 Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
25 Rule	Morocco	2011	only	-	Jul	31	 0:00	0	-
26 Rule	Morocco	2012	2013	-	Apr	lastSun	 2:00	1:00	S
27 Rule	Morocco	2012	only	-	Jul	20	 3:00	0	-
28 Rule	Morocco	2012	only	-	Aug	20	 2:00	1:00	S
29 Rule	Morocco	2012	only	-	Sep	30	 3:00	0	-
30 Rule	Morocco	2013	only	-	Jul	 7	 3:00	0	-
31 Rule	Morocco	2013	only	-	Aug	10	 2:00	1:00	S
32 Rule	Morocco	2013	max	-	Oct	lastSun	 3:00	0	-
33 Rule	Morocco	2014	2021	-	Mar	lastSun	 2:00	1:00	S
34 Rule	Morocco	2014	only	-	Jun	28	 3:00	0	-
35 Rule	Morocco	2014	only	-	Aug	 2	 2:00	1:00	S
36 Rule	Morocco	2015	only	-	Jun	14	 3:00	0	-
37 Rule	Morocco	2015	only	-	Jul	19	 2:00	1:00	S
38 Rule	Morocco	2016	only	-	Jun	 5	 3:00	0	-
39 Rule	Morocco	2016	only	-	Jul	10	 2:00	1:00	S
40 Rule	Morocco	2017	only	-	May	21	 3:00	0	-
41 Rule	Morocco	2017	only	-	Jul	 2	 2:00	1:00	S
42 Rule	Morocco	2018	only	-	May	13	 3:00	0	-
43 Rule	Morocco	2018	only	-	Jun	17	 2:00	1:00	S
44 Rule	Morocco	2019	only	-	May	 5	 3:00	0	-
45 Rule	Morocco	2019	only	-	Jun	 9	 2:00	1:00	S
46 Rule	Morocco	2020	only	-	Apr	19	 3:00	0	-
47 Rule	Morocco	2020	only	-	May	24	 2:00	1:00	S
48 Rule	Morocco	2021	only	-	Apr	11	 3:00	0	-
49 Rule	Morocco	2021	only	-	May	16	 2:00	1:00	S
50 Rule	Morocco	2022	only	-	May	 8	 2:00	1:00	S
51 Rule	Morocco	2023	only	-	Apr	23	 2:00	1:00	S
52 Rule	Morocco	2024	only	-	Apr	14	 2:00	1:00	S
53 Rule	Morocco	2025	only	-	Apr	 6	 2:00	1:00	S
54 Rule	Morocco	2026	max	-	Mar	lastSun	 2:00	1:00	S
55 Rule	Morocco	2036	only	-	Oct	19	 3:00	0	-
56 Rule	Morocco	2037	only	-	Oct	 4	 3:00	0	-
57 
58 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
59 Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
60 			 0:00	Morocco	WE%sT	1984 Mar 16
61 			 1:00	-	CET	1986
62 			 0:00	Morocco	WE%sT
63 
64 # Western Sahara
65 #
66 # From Gwillim Law (2013-10-22):
67 # A correspondent who is usually well informed about time zone matters
68 # ... says that Western Sahara observes daylight saving time, just as
69 # Morocco does.
70 #
71 # From Paul Eggert (2013-10-23):
72 # Assume that this has been true since Western Sahara switched to GMT,
73 # since most of it was then controlled by Morocco.
74 
75 Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan # El Aaiテコn
76 			-1:00	-	WAT	1976 Apr 14
77 			 0:00	Morocco	WE%sT

これの場合「only」行がその年のラマダンに関係する transition が発生する時刻。なるほどなぁ。

ちなみにさっき「答え合わせ」に使った worldclock など、このラマダン transition を考慮したものはあんましなさそう。

さて。「そんなに枯れてるもんなん?」の決定打は、さらっと眺めただけですぐに見つかった。エジプト。

 1 # From Steffen Thorsen (2016-04-29):
 2 # Egypt will have DST from July 7 until the end of October....
 3 # http://english.ahram.org.eg/NewsContentP/1/204655/Egypt/Daylight-savings-time-returning-to-Egypt-on--July.aspx
 4 # From Mina Samuel (2016-07-04):
 5 # Egyptian government took the decision to cancel the DST,
 6 
 7 Rule	Egypt	2008	only	-	Aug	lastThu	24:00	0	-
 8 Rule	Egypt	2009	only	-	Aug	20	24:00	0	-
 9 Rule	Egypt	2010	only	-	Aug	10	24:00	0	-
10 Rule	Egypt	2010	only	-	Sep	 9	24:00	1:00	S
11 Rule	Egypt	2010	only	-	Sep	lastThu	24:00	0	-
12 Rule	Egypt	2014	only	-	May	15	24:00	1:00	S
13 Rule	Egypt	2014	only	-	Jun	26	24:00	0	-
14 Rule	Egypt	2014	only	-	Jul	31	24:00	1:00	S
15 Rule	Egypt	2014	only	-	Sep	lastThu	24:00	0	-
16 
17 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
18 Zone	Africa/Cairo	2:05:09 -	LMT	1900 Oct
19 			2:00	Egypt	EE%sT

2008年に夏時間を採用するも、2014年にはもうやめている、かつ、「2014年ってさぁ、たった2年前なんすけど」。オマイガッ。な? もう2014年に「エジプトの夏時間は~月から~月までなんだぜっ」と書いちゃったら、今ではもうウソなのだ。

もう結論出たでしょう、ダメじゃね、それ?

wikipedia の空港コード一覧 に DST の情報を埋め込もうとした誰かが何を思ったのかはわからない。そして未遂に終わっている理由も。

けれども、まず第一に、「DST の切り替えを月だけで示しても情報として無意味」。そしてなぜ月だけを書いたのか、書こうと決めた誰かの頭の中は理解出来る。「3月第一日曜日、とかって年によって変わるんじゃ静的情報として価値がないから月だけ載せとけやぁ」てことだろ?

けど、それすらアウトだ、てのが今回言いたかったこと。エジプトのように、採用したはいいがすぐにやめてしまう国はどうやら結構多そうだ。歴史の長い北米などと違ってその他の国は、結構国民感情の反感などもすぐに起こるんだろう、採用してはやめ、採用してはやめ、を繰り返す国もあるようだし、北米でさえ切り替え時期は結構頻繁に変わってきているようだ。

DST の情報を「価値のあるもの」として掲載するためには静的ページじゃダメだと思うぞ。ダイナミックなページでフレッシュな、かつ「日付までわかる」ものでねーと。ある国のエラい人の気紛れのたんびに更新しなければならないコストなんぞバカになりませんて。そんなもんは IANA にまかせとけばいい。

オマケ: Daylight Saving Time 2016 を pytz で

さわりだけだけど、上のほうで使ったプログラムをちょっと書き換えて:

 1 from datetime import timedelta
 2 from pytz import timezone, all_timezones
 3 
 4 for tzname in all_timezones:
 5     tz = timezone(tzname)
 6     print(tzname, [
 7             (
 8                 tz.localize(dt - timedelta(1), is_dst=True).strftime("%d %b %z"),
 9                 tz.localize(dt, is_dst=True).strftime("%d %b %z"),
10                 tz.localize(dt + timedelta(1), is_dst=True).strftime("%d %b %z"),
11                 )
12             for dt in tz._utc_transition_times if dt.year == 2016])

なんてのでそれらしいものを作れる。これの出力はこんな:

 1 ('Africa/Abidjan', [])
 2 ('Africa/Accra', [])
 3 ('Africa/Addis_Ababa', [])
 4 ('Africa/Algiers', [])
 5 ('Africa/Asmara', [])
 6 ('Africa/Asmera', [])
 7 ('Africa/Bamako', [])
 8 ('Africa/Bangui', [])
 9 ('Africa/Banjul', [])
10 ('Africa/Bissau', [])
11 ('Africa/Blantyre', [])
12 ('Africa/Brazzaville', [])
13 ('Africa/Bujumbura', [])
14 ('Africa/Cairo', [])
15 ('Africa/Casablanca', [('26 Mar +0000', '27 Mar +0100', '28 Mar +0100'), ('04 Jun +0100', '05 Jun +0100', '06 Jun +0000'), ('09 Jul +0000', '10 Jul +0100', '11 Jul +0100'), ('29 Oct +0100', '30 Oct +0100', '31 Oct +0000')])
16 ('Africa/Ceuta', [('26 Mar +0100', '27 Mar +0100', '28 Mar +0200'), ('29 Oct +0200', '30 Oct +0200', '31 Oct +0100')])
17 ('Africa/Conakry', [])
18 ('Africa/Dakar', [])
19 ('Africa/Dar_es_Salaam', [])
20 ('Africa/Djibouti', [])
21 ('Africa/Douala', [])
22 ('Africa/El_Aaiun', [('26 Mar +0000', '27 Mar +0100', '28 Mar +0100'), ('04 Jun +0100', '05 Jun +0100', '06 Jun +0000'), ('09 Jul +0000', '10 Jul +0100', '11 Jul +0100'), ('29 Oct +0100', '30 Oct +0100', '31 Oct +0000')])
23 ('Africa/Freetown', [])
24 ('Africa/Gaborone', [])
25 #...
26 ('America/Nassau', [('12 Mar -0500', '13 Mar -0400', '14 Mar -0400'), ('05 Nov -0400', '06 Nov -0500', '07 Nov -0500')])
27 ('America/New_York', [('12 Mar -0500', '13 Mar -0400', '14 Mar -0400'), ('05 Nov -0400', '06 Nov -0500', '07 Nov -0500')])
28 ('America/Nipigon', [('12 Mar -0500', '13 Mar -0400', '14 Mar -0400'), ('05 Nov -0400', '06 Nov -0500', '07 Nov -0500')])
29 ('America/Nome', [('12 Mar -0900', '13 Mar -0800', '14 Mar -0800'), ('05 Nov -0800', '06 Nov -0900', '07 Nov -0900')])
30 ('America/Noronha', [])
31 ('America/North_Dakota/Beulah', [('12 Mar -0600', '13 Mar -0500', '14 Mar -0500'), ('05 Nov -0500', '06 Nov -0600', '07 Nov -0600')])
32 ('America/North_Dakota/Center', [('12 Mar -0600', '13 Mar -0500', '14 Mar -0500'), ('05 Nov -0500', '06 Nov -0600', '07 Nov -0600')])
33 ('America/North_Dakota/New_Salem', [('12 Mar -0600', '13 Mar -0500', '14 Mar -0500'), ('05 Nov -0500', '06 Nov -0600', '07 Nov -0600')])
34 ('America/Ojinaga', [('12 Mar -0700', '13 Mar -0600', '14 Mar -0600'), ('05 Nov -0600', '06 Nov -0700', '07 Nov -0700')])
35 ('America/Panama', [])
36 ('America/Pangnirtung', [('12 Mar -0500', '13 Mar -0400', '14 Mar -0400'), ('05 Nov -0400', '06 Nov -0500', '07 Nov -0500')])
37 ('America/Paramaribo', [])
38 #...