zoneinfoから各国のタイムゾーンを確認する (タイムゾーンの見方を説明。例外あり)

## **はじめに**

何かと話題のタイムゾーンですが、見方の探し方からいつも迷うので記事に起こしました。
確認に使用したtzdataのバージョンはtzdata2018eです。

## **タイムゾーンの確認方法**

### **タイムゾーンが記載されているファイル**

Linuxの各国タイムゾーンは、/usr/share/zoneinfoの各国に対応するバイナリファイルの最後尾に大体記載されています。

```
$ tail -n 1 zoneinfo/Asia/Tokyo
JST-9
```

日本は"日本標準時 (Japan Standard Time)"を採用していて、グリニッジ標準時から-9時間ずれています。
という意味合い。

他の国を見てみましょう。Americaらへんを適当に。

```
$ tail -n 1 zoneinfo/America/New_York
EST5EDT,M3.2.0,M11.1.0
```

情報が増えましたね。ぱっと見よくわからないので正式定義を確認します。

### **タイムゾーン表記の意味**

[Adding or changing time zone settings](https://www.di-mgt.com.au/wclock/tz.html)、[Syntax for TZ strings](https://www.di-mgt.com.au/wclock/help/wclo_tzsyntax.html)を参考にしながら記載。実際の定義はPOSIX 1003.1 section 8.3.に記載されているそうです。

表記の定義は以下。

```
stdoffset[dst[offset][,start[/time],end[/time]]]
```

各パラメーターの見方を簡単に解説

|パラメーター|意味|補足|
|:---|:---|:---|
|std|その地域の標準な時刻||
|offset|UTC(協定世界時、グリニッジ標準時と同じ時刻)からの差分|単位は時間。:区切りで分と秒も指定可能|
|dst|サマータイム適用時の時刻|日本だとJDTになるっぽいですね|
|start|サマータイムの開始タイミング||
|end|サマータイムの終了タイミング||
|time|サマータイム開始時間がある場合の時刻指定|デフォルトは2:00|

**start, endについて**

こちらの表記が特殊で、3種類の記載方法があります。

|記載|意味|例|備考|
|:---|:---|:---|:---|
|Jn|ユリウス通日のn日目1 < n < 365)|1月1日がJ2|2/29は除外|
|n|開始を0としたユリウス通日のn日目(0 < n < 365)|1月1日がJ1|2/29もあり|
|Mm.n.d|m月n週目のd曜日(日曜日が0)|M8.2.6なら8月2週目の土曜日|n=5指定は最終週となる。<br>5週目がない場合は4週目に適用|


### **サマータイム期間の見方例**

定義を元に、先ほどのNew_Yorkを確認しましょう。

**ニューヨーク**

```
$ tail -n 1 zoneinfo/America/New_York
EST5EDT,M3.2.0,M11.1.0
```

EST5EDT
⇒標準な時刻はESTを、サマータイムはESTを適用する。通常のUTCとの時刻差は+5時間。
[wikipedia](https://ja.wikipedia.org/wiki/%E6%9D%B1%E9%83%A8%E5%A4%8F%E6%99%82%E9%96%93)よりESTはUTCとの差分+4時間なので、サマータイム期間中は1時間時刻が早まります。

M3.2.0,M11.1.0
⇒3月の第2週、日曜日の2:00～11月の第1週、日曜日の2:00までがサマータイム期間となります。
時間指定がないのでデフォルトの2:00が適用されます。

**フィジー**

ちょっと面白かったので紹介。作成されたzoneinfoを覗いているとフィジーのようにサマータイム終了が1月2週目月曜日 +147時間 とトリッキーな地域もあるようです。

```
$ tail -n 1 zoneinfo/Pacific/Fiji
<+12>-12<+13>,M11.1.0,M1.2.1/147
```

見てる感じstd/dstが数字表記+のものは、UTCとの時刻差は-(符号が逆)になるようですね。

フィジーの通常時間(<+12>)

```
$ TZ=:`pwd`/zoneinfo/Pacific/Fiji date
2018年  8月 12日 日曜日 11:55:02 +12
$ TZ=:`pwd`/zoneinfo/GMT date
2018年  8月 11日 土曜日 23:55:07 GMT
```

フィジーのサマータイム時間(<+13>)

```
$ TZ=:`pwd`/zoneinfo/GMT date
2018年  1月  1日 月曜日 04:01:37 GMT
$ TZ=:`pwd`/zoneinfo/Pacific/Fiji date
2018年  1月  1日 月曜日 17:01:40 +13
```

## **例外**

tzdataでは基本的にはタイムゾーン表記通りにサマータイムが変わるのですが、実際には毎年のようにサマータイムの適用時期が変わる国もあります。
最新のtzdata2018eを見てると例えばモロッコがそんな感じでした。

時刻定義を一部抜粋。

```
...
Rule    Morocco 2016    only    -       Jun      5       3:00   0       -
Rule    Morocco 2016    only    -       Jul     10       2:00   1:00    S
Rule    Morocco 2017    only    -       May     21       3:00   0       -
Rule    Morocco 2017    only    -       Jul      2       2:00   1:00    S
Rule    Morocco 2018    only    -       May     13       3:00   0       -
Rule    Morocco 2018    only    -       Jun     17       2:00   1:00    S
Rule    Morocco 2019    only    -       May      5       3:00   0       -
Rule    Morocco 2019    only    -       Jun      9       2:00   1:00    S
Rule    Morocco 2020    only    -       Apr     19       3:00   0       -
Rule    Morocco 2020    only    -       May     24       2:00   1:00    S
...
Rule    Morocco 2037    only    -       Oct      4       3:00   0       -

# Zone  NAME            GMTOFF  RULES   FORMAT  [UNTIL]
Zone Africa/Casablanca  -0:30:20 -      LMT     1913 Oct 26
                         0:00   Morocco WE%sT   1984 Mar 16
                         1:00   -       CET     1986
                         0:00   Morocco WE%sT

```

実際の定義を見てみると、3月の第5週2:00～10月の第3週3:00までをサマータイムとしています。

```
$ tail -n 1 zoneinfo/Africa/Casablanca
WET0WEST,M3.5.0,M10.5.0/3
```

なんか作者のつけているコメントを見ていると、色々推測を交えながら苦労して実装したのが伺えますね。

```
# From Paul Eggert (2015-06-08):
# For now, guess that later spring and fall transitions will use 2015's rules,
# and guess that Morocco will switch to standard time at 03:00 the last
# Sunday before Ramadan, and back to DST at 02:00 the first Sunday after
# Ramadan.  To implement this, transition dates for 2016 through 2037 were
# determined by running the following program under GNU Emacs 24.3, with the
# results integrated by hand into the table below.
```

日本のサマータイム導入もこうやってtzdataを開発されている方の頭を悩ませる結果にならなければいいんですけどね

## **zdumpで正確なサマータイム時期の確認**

@angel_p_57 さんよりいただいたコメントを元に追記です。

正確なサマータイム以降時期を見るならzdumpコマンドが使えます。

```
@zdump -v /usr/share/zoneinfo/America/New_York
/usr/share/zoneinfo/America/New_York  Sun Nov 18 16:59:59 1883 UT = Sun Nov 18 1
2:03:57 1883 LMT isdst=0 gmtoff=-17762
/usr/share/zoneinfo/America/New_York  Sun Nov 18 17:00:00 1883 UT = Sun Nov 18 1
2:00:00 1883 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/America/New_York  Sun Mar 31 06:59:59 1918 UT = Sun Mar 31 0
1:59:59 1918 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/America/New_York  Sun Mar 31 07:00:00 1918 UT = Sun Mar 31 0
3:00:00 1918 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/America/New_York  Sun Oct 27 05:59:59 1918 UT = Sun Oct 27 0
1:59:59 1918 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/America/New_York  Sun Oct 27 06:00:00 1918 UT = Sun Oct 27 0
...
```

タイムゾーン表記を頑張って読むより正確に情報がわかりそうですね。

## **余談**

上記のzoneinfoは、[サマータイム導入には反対だが「日本夏時間」を試してみた](https://qiita.com/belgianbeer/items/f678ae6264a674d33887)を参考にビルドしてみました。

```
wget https://data.iana.org/time-zones/releases/tzdb-2018e.tar.lz
tar xf tzdb-2018e.tar.lz
cd tzdb-2018e
```

確か普通にmake出来たよな～と思いつつ、READMEも確認してmakeしたら以下エラーが。

```
$ make
awk -v DATAFORM=`expr main.zi : '\(.*\).zi'` -f ziguard.awk \
          africa antarctica asia australasia europe northamerica southamerica etcetera systemv factory backward  >main.zi.out
malloc(): memory corruption
Aborted (core dumped)
Makefile:565: recipe for target 'main.zi' failed
make: *** [main.zi] Error 134
```

調べても`zic`を使用する方法しか見当たらなかったし、参考も`zic`を使用しているので落ちた場所のファイル達を`zic`にかけてみたらファイルが出来ました。
スクリプトにするとこんな感じ。
気持ち悪いけどzoneinfoの関連する国だけ差し替えるのが普通みたいなので、気にしないでおきます。

```shell:make_zoneinfo.sh
LIST=`make 2> /dev/null| grep main.zi.out | awk -F">" '{print $1}' `
for data in $LIST;
do
	zic $data -d zoneinfo;
done

ln -s /etc/localtime zoneinfo/localtime
```

## **参考**

まとめるきっかけ
[サマータイム導入には反対だが「日本夏時間」を試してみた](https://qiita.com/belgianbeer/items/f678ae6264a674d33887)

見方の参考
[Adding or changing time zone settings](https://www.di-mgt.com.au/wclock/tz.html)
[Syntax for TZ strings](https://www.di-mgt.com.au/wclock/help/wclo_tzsyntax.html)