やっぱりね、っと。
静的な情報ページに Daylight Saving Time の開始終了「月」だけ記載することのナンセンスさに関する考察なのよ
発端
wikipedia の空港コード一覧の By IATA code のうち「A」~「L」までのフォーマット:
「M」~「Z」には Timezone/DST のカラムがない。そもそもこの「不統一」が情報リソースとしての価値を激減させている。
ひとまずはこの“DST: Mar-Oct”という記載方式自体に初見から違和感があったことは脇に置いて、「自力でこの情報を埋めれるだろうか?」と考えたのが最初。違和感の意味はこの記事全体読めばわかる。
最初に考えたこと: 緯度経度から Timezone/DST を割り出せるか?
元はと言えば空港一覧からの話なので、取れてれば位置情報が取れてる。ここから Timezone/DST を割り出すリーズナブルな方法は、あれば、あるか?
先に「なんにも知らない」という人向けに軽く説明しとく。
- タイム「ゾーン」がないがローカルタイムがある世界が仮にあるならば、人は時計を経度方向への移動のたびに調整しなければならないだろう。
- UTC からの、経度から直接計算されるオフセットは単純な算数で、シンプルには「今いる経度/180*12」である。日本の場合、+135/180.*12 == +9。
- この算数が通用しないことは小学校地理で習う「日付変更線がうねってる」ことだけでも理解出来るだろう。
- そもそも「時計を経度方向への移動のたびに調整」は不便過ぎるだろう。
- だからタイム「ゾーン」がある。日常生活で時計調整を頻繁には必要としない「範囲」を決めるのだ。
- だからタイム「ゾーン」は国ごとに決める。
- だからといって「ユーラシア大陸共通」なんて、「5時は朝なのか深夜なのか」の概念の統一が崩れて、きっと不便だろう、5時は世界共通で「朝ですよー」と言いたい、それが「時計」ってもんだろう。
- だからタイム「ゾーン」は、広い国では複数あるのである。
- に加えて「夏時間」。この話は今は放置。
今上の列挙で言いたいのはひとまず、「緯度と経度」という情報だけでは、ソフトウェアはなんにも出来ない、ということ。「タイムゾーン境界を決定するポリゴン(的な何か)(とそれに紐付く 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じゃない」にならんのけ? ってことな。つまりはこれこそが「違和感」。そんなに枯れてるもんなん?
てわけでまずは。たとえば夏時間採用の歴史が長くて安定してる国の例:
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 #...