タイムゾーンに関するあれこれ

最近、仕事で日本以外のタイムゾーンに関する仕事をしていて、いろいろ知識が自分の中で溜まってきたのでアウトプットすることにしました。

こんな感じで進めていこうかと思います。

1. タイムゾーンとは
2. サマータイムとは
3. タイムゾーン情報のデータ

## タイムゾーンとは

「時差」って言葉はきいたことがあると思います。
たとえば、2017/03/04 現在、東京とハワイの時差は19時間です。
では、この時差はどういうふうに設定されるかというと、地域ごとに協定世界時(以後UTC)からの差分が設定されており、そこから計算します。

たとえば、東京は UTC+09:00 が設定されており、ハワイは UTC-10:00 が設定されています。
ですので、この値からハワイは、東京の 19時間より前の時刻になっているということがわかり、東京の時計が20時を示してある瞬間、ハワイの時計では1時を示しています。

そして、大阪、札幌もこの東京と同じ日時設定のルールにしたがっており、こういうときに、「大阪、札幌、東京は同じタイムゾーンに所属する」といえます。

参考: 「[時間帯(標準時) - Wikipedia](https://ja.wikipedia.org/wiki/%E6%99%82%E9%96%93%E5%B8%AF_(%E6%A8%99%E6%BA%96%E6%99%82))」

さて、この UTC からの差分なのですが、日本の場合は常に +09:00 なので馴染みがないのですが、地域ごとには政治により特定の期間だけ UTC からの差分が変わったりします。
そして、この特定の期間だけ UTC からの差分が変わるルールの代表例としてはサマータイムがあります。

## サマータイムとは

Daylight Saving Time(DST) とも呼ばれたりします。
これは具体的にどんな感じかというと、特定の期間だけ UTC のオフセットが1時間多くなります。

たとえば、アメリカ合衆国のニューヨークは通常は UTC-05:00 なのですが、サマータイム期間中は UTC-04:00 になります。
つまり、東京(UTC+09:00)とニューヨークの時差が通常は14時間なのにサマータイム期間中は時差が13時間になります。

さて、このサマータイムがエンジニアにとってやっかいなのは、通常期間のときからサマータイムに切り替わるとき、サマータイムから通常の期間に切り替わるときです。

通常期間からサマータイムに切り替わるときは1時間時計を進めます。
ニューヨークでは 2007 年以降、毎年3月第2日曜の2時にそれが発生します。

```
2017/03/12 01:59 -05:00
↓ (1分後)
2017/03/12 03:00 -04:00
```

つまり、2時台の1時間飛ばされるので、この日は1日24時間ではなく23時間になります。

また、サマータイムから通常期間に切り替わるときは、特定の1時間を2度繰り返します。
ニューヨークでは 2007 年以降、毎年11月第1日曜の2時にそれが発生します。

```
2017/11/05 01:00 -04:00
↓ (59分後)
2017/11/05 01:59 -04:00
↓ (1分後)
2017/11/05 01:00 -05:00
↓ (1時間後)
2017/11/05 02:00 -05:00
```

つまり、1時間を繰り返すので、この日は1日24時間ではなく25時間になります。

参考: 「[夏時間](https://ja.wikipedia.org/wiki/%E5%A4%8F%E6%99%82%E9%96%93)」

## タイムゾーン情報のデータ

プログラミング言語のライブラリや OS がサマータイムを計算するためには、各タイムゾーンはいつからサマータイムを始めるなどのデータが必要になります。

自分が把握している範囲だと、このタイムゾーンのデータは2種類あります。
Windows OS がもっているデータと tz database です。

### Windows OS がもっているデータ

1つ目のタイムゾーンのデータは、Microsoft が提供している Windows 内にあるデータです。
レジストリの HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones に存在するようです。

タイムゾーンIDは以下のような感じです。

(UTC+09:00) 大阪、札幌、東京 -> Tokyo Standard Time
(UTC-05:00) 東部標準時 (米国およびカナダ) -> Eastern Standard Time

このタイムゾーン情報のデータは以下などのように Windows Update で更新されるようです。

参考: 「[2016 年 6 月 DST およびタイム ゾーンの Windows 用更新プログラム](https://support.microsoft.com/ja-jp/help/3162835/june-2016-dst-and-time-zone-update-for-windows)」


### tz database

2つ目のタイムゾーンのデータは、[tz database](https://ja.wikipedia.org/wiki/Tz_database)  です。

UNIX や Java ランタイムではこのデータを使用しています。

タイムゾーンIDは以下のような感じです。

(UTC+09:00) 大阪、札幌、東京 -> Asia/Tokyo
(UTC-05:00) 東部標準時 (米国およびカナダ) -> America/New_York

ID はアジアやヨーロッパの地方名のあとに都市名を記載する形になっています。

tz database はテキストファイルで読むことができます。
[このサイト](https://www.iana.org/time-zones)の Data Only Distribution と書かれているファイル(tzdatayyyyX.tar.gz)から確認できます。
たとえば、America/New_York は上記 tar.gz 内の northamerica というファイルにかかれており、以下に定義されています。

```
# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:03:58
			-5:00	US	E%sT	1920
			-5:00	NYC	E%sT	1942
			-5:00	US	E%sT	1946
			-5:00	NYC	E%sT	1967
			-5:00	US	E%sT
```

GMTOFF は GMT or UTC(?) からのオフセットが書かれています。
RULES はサマータイムなどの情報が定義されているルール名があります。
FORMAT は JST や EST などの標準時などが書かれており、「%s」は後述の RULES に当てはまった場合の変数が格納されたりします。
UNTIL はいつまでこのオフセット、ルールを使うかが明記されています。

次に、上記の例で記載された「US」ルールをみてみます。

```
# New South Wales
# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
Rule	US	1918	1919	-	Mar	lastSun	2:00	1:00	D
Rule	US	1918	1919	-	Oct	lastSun	2:00	0	S
Rule	US	1942	only	-	Feb	9	2:00	1:00	W # War
Rule	US	1945	only	-	Aug	14	23:00u	1:00	P # Peace
Rule	US	1945	only	-	Sep	lastSun	2:00	0	S
Rule	US	1967	2006	-	Oct	lastSun	2:00	0	S
Rule	US	1967	1973	-	Apr	lastSun	2:00	1:00	D
Rule	US	1974	only	-	Jan	6	2:00	1:00	D
Rule	US	1975	only	-	Feb	23	2:00	1:00	D
Rule	US	1976	1986	-	Apr	lastSun	2:00	1:00	D
Rule	US	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
```

このルールでは主にサマータイムの開始、終了が記載されています。

FROMとTOはサマータイム、通常時の開始、終了の年が記載されています。
IN ON ATには切り替えの日時、SAVE にはどれくらい時刻をズラスかが記載され
LETTER/S はこの値が前述の Zone の定義内の FORMAT の %s に格納されます。
なので、前述の America/New_York の Zone 定義ですと、LETTER/S が S の場合は、FORMAT の値が「EST」(Eastern Standard Time)になりますし、D の場合は、「EDT」(Eastern Daylight Time)になります。

2008年以降に関する記載は以下の部分ですね。

```
Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
```

3月8日から最初の日曜2時にはEST(標準のUTC-05:00)になり、11月1日から最初の日曜2時にEDT(サマータイムのUTC-04:00)になります。