2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PONOSAdvent Calendar 2020

Day 13

オーストラリアのサマータイムからtz databaseを読み解く

Last updated at Posted at 2020-12-12

PONOS Advent Calendar 2020の13日目の記事です。

昨日は@honeniqさんでした。

サマータイムについて

サマータイム(Daylight Saving Time=DST)といえば以前少し日本でも話題になりましたが、主に日照時間の長い夏の時期に時間を1時間進めるというイメージがあります(私は)。
逆にいえば時間に変動が生じるものであるため、プログラマーとしては本能的に危険を感じるのではないでしょうかw

例えば日本時間を例にしてみます。

日本時間は通常UTC+09:00であり、JST(Japan Standard Time)、つまり日本標準時と呼ばれるものです。
現在の日本にサマータイムはありませんが、1948年から1951年にかけて、日本でもサマータイムが実施されていたこともあるそうです。
サマータイムが適用される場合、**JDT(Japan Daylight-saving Time)**という時刻になり、UTC+10:00ということになるようです。

日本だけでなく、標準時は"S"、サマータイム時は"D"になるというのは世界的に見られるもので、後述のtz databazeからもそれがわかります。

UTC: 2020/12/01 00:00:00
JST: 2020/12/01 09:00:00
JDT: 2020/12/01 10:00:00

※この時刻は例です。実際に日本でこの日時はサマータイムではありません。

つまりUTC自体は当然変更されることはありませんが、タイミングによってJSTが適用されるかJDTが適用されるかで、実際の現地時間が変わると言う考え方です。
プログラムにおいてはUTCを基準に処理していれば時間が逆戻りするということはないということですね。

momentでサマータイムを処理する

プログラムでタイムゾーンを扱いたい場合、大抵ライブラリなどを使用すると思います。
例えばJavaScriptではご存知moment-timezoneを使うととっても日付の扱いが楽になります。
サマータイムも自動的に処理してくれます。

実際に確認してる

太平洋標準時(PST)を例にしてmoment-timezoneで確認してみます。
PSTが適用されるタイムゾーンは米国ロサンゼルスであり、次のサマータイムはPST 2021/03/14 02:00:00からだそうです。
PSTはUTC-08:00であることから、つまりUTC 2021/03/14 10:00:00からサマータイムになることになります。

const moment = require('moment-timezone');
console.log(moment('2021-03-14T09:00:00.000Z').tz("America/Los_Angeles").format());
> 2021-03-14T01:00:00-08:00
console.log(moment('2021-03-14T10:00:00.000Z').tz("America/Los_Angeles").format());
> 2021-03-14T03:00:00-07:00

UTC 2021/03/14 09:00:00の時は2021/03/14 01:00:00であることから、UTC-08:00になっている一方で、
UTC 2021/03/14 10:00:00の時は2021/03/14 03:00:00であることから、UTC-07:00になっており、1時間進んだサマータイムが適用されていることがわかります。

サマータイムなのかどうか

上記のコードでは特に意識することなくサマータイムが反映された時刻が取得されています。
この時間がサマータイムなのかどうなのかを知るためには、moment-timezoneでは**isDST()**関数が用意されています。

console.log(moment('2021-03-14T09:00:00.000Z').tz("America/Los_Angeles").isDST());
> false
console.log(moment('2021-03-14T10:00:00.000Z').tz("America/Los_Angeles").isDST());
> true

この関数の中身の実装は次のようになっていました。

proto.isDST = isDaylightSavingTime;
(省略)
function isDaylightSavingTime() {
    return (
        this.utcOffset() > this.clone().month(0).utcOffset() ||
        this.utcOffset() > this.clone().month(5).utcOffset()
    );
}

現在のUTCオフセットと、1月のオフセットもしくは6月のオフセットを比較し、どちらかのケースで大きければサマータイムということのようです。
これはつまり

  1. サマータイムの場合はオフセットが大きくなる
  2. 1月と6月の両方がサマータイムであることはない

という前提に立っているように思えます。
たしかに1月も6月もサマータイムを実施している(一年の半分以上)国はなさそうですね。。。

ではサマータイムが適用されなかった場合の時間はどうやって求めればいいのだろうか?とふと思います。
上記の内容からすれば、少ないほうのUTCオフセットを取得して、それをUTC時間に適用した時間ということにすれば解決しそうです。

サマータイムは1時間進むというわけではない

もっと楽をするなら、**isDST()==trueだったら1時間引くじゃだめなの?**とも思います。
そこでサマータイムのWikipediaを見てみました。

~引用~
『標準時を1時間進める制度またはその進められた時刻のこと。ただし、オーストラリアのロード・ハウ島では夏時間と通常の時間の差が30分であるなど一律ではない。』

でた!例外あるある!

オーストラリアのタイムゾーン

ということでオーストラリアのタイムゾーンを調べてみたところ、大雑把にいうと次のようになっているようです。

  1. 東部時間(AEST/AEDT)、中部時時間(ACST/ACDT)、西部時間(AWST/AWDT)の3つのタイムゾーンに区分される。
  2. サマータイムは州ごとに採用ありなしが決められており、これらのタイムゾーンの中でもサマータイム適用ありなしの地区が存在する。
  3. 中西部時間(UTC+8:45)という、ユークラという一部地域のみ使用されている、公式ではないタイムゾーンが存在する。
  4. ロード・ハウ時間(UTC+10:30)が存在する。夏時間は+00:30である。

なんとややこしい!うっ・・頭がっ・・

tz databaseを読み解く

中部時間の中でのサマータイムの有無

moment-timezone(や多くのライブラリ)はタイムゾーンを扱うための情報としてtz databaseを使用しています。
その中身を読み解いてオーストラリアのタイムゾーンがどういう設定になっているか実際にみてみたいと思います。

今回は上記のサイトからtzdata2020d.tar.gzをダウンロードしました。
その中にあるたくさんのファイルから、オーストラリアが定義されているaustralasiaを開いてみます。

オーストラリア中部時間に属するダーウィンを具体例にとって見てみます。関係する箇所は下記の部分です。

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
# Northern Territory
Zone Australia/Darwin    8:43:20 -      LMT     1895 Feb
                         9:00   -       ACST    1899 May
                         9:30   Aus     AC%sT
# Rule  NAME    FROM    TO      -       IN      ON      AT      SAVE    LETTER/S
〜(省略)〜
Rule    Aus     1943    1944    -       Mar     lastSun 2:00    0       S
Rule    Aus     1943    only    -       Oct      3      2:00    1:00    D

Zoneから始まる行は、そのタイムゾーンに対する設定になっています。
Ruleから始まる行は、時間の変更がある場合のルールになっており、ZoneにおけるRULESで指定されているルールが適用される関係性のようです。
また、気になるFORMATの部分ですが、AC%sTとなっている部分は、RuleにおけるLETTER/Sの項目が適用されるようです。
ですので、SであればACST(標準時間)、DであればACDT(夏時間)ということになります。
また、SAVEに1:00
となっている部分は、標準時間のUTCオフセット(STDOFF)に対して、さらにずれる部分のようです。夏時間は1時間ずれることを意味しています。

また、それぞれのZoneには名前がつけられています。この名前こそがよく見るAsia/Tokyoという部分です。

このような関係性であるため、このZoneにつけられた名称、Australia/Darwinと**オーストラリア中部標準時時(ACST)**とは必ずしも1:1の関係ではないことがわかります。

具体的には、オーストラリアのアデレードもオーストラリア中部時間に属しています。

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
Zone Australia/Adelaide 9:14:20 -       LMT     1895 Feb
                        9:00    -       ACST    1899 May
                        9:30    Aus     AC%sT   1971
                        9:30    AS      AC%sT

ここで注目なのは適用されているルールが異なる点です。

**[UNTIL]**の設定はそのルールが適用される期限を意味しています。
ダーウィンでは現在は"Aus"が適用されており、アデレードでは現在"AS"という設定が適用されています。
"Aus"の設定は前述の通りですが、FROM、TOを見るとわかる通り、現在適用される変則ルールはありませんのでサマータイムはなさそうです。
一方の"AS"は下記の通りです。

# South Australia
# Rule  NAME    FROM    TO      -       IN      ON      AT      SAVE    LETTER/S
〜(省略)〜
Rule    AS      2008    max     -       Apr     Sun>=1  2:00s   0       S
Rule    AS      2008    max     -       Oct     Sun>=1  2:00s   1:00    D

ここからみるとアデレードでは2008年以降、サマータイムが設定されています。
このようにして、同じオーストラリア中部時間に属する場所でも、サマータイムの適用の有無が変わるようになっているようです。

ユークラという公式ではないが実際に使われているタイムゾーンはどうなっているのか

探してみました。

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
〜(省略)〜
Zone Australia/Eucla     8:35:28 -      LMT     1895 Dec
                         8:45   Aus +0845/+0945 1943 Jul
                         8:45   AW  +0845/+0945

FORMATの部分がACSTなどの3種類のオーストラリア時間のいずれでもなく、直接UTCオフセットが書き込まれています。
「どうやら標準時はUTC+08:45であり、夏時間はUTC+09:45っていうタイムゾーンですよ」ってことを表している名前???
むむむ。

ちなみにユークラに適用されているAWルールは次の通りで、

# Western Australia
#
# Rule  NAME    FROM    TO      -       IN      ON      AT      SAVE    LETTER/S
〜(省略)〜
Rule    AW      2007    2009    -       Mar     lastSun 2:00s   0       S
Rule    AW      2007    2008    -       Oct     lastSun 2:00s   1:00    D

現在サマータイムはなさそうです。

ロード・ハウ島はどうなっているのか

ここまでくるともう探すだけです。

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
〜(省略)〜
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
# Lord Howe Island
# Rule  NAME    FROM    TO      -       IN      ON      AT      SAVE    LETTER/S
〜(省略)〜
Rule    LH      2008    max     -       Apr     Sun>=1  2:00    0       -
Rule    LH      2008    max     -       Oct     Sun>=1  2:00    0:30    -

なるほど、1981年まではAESTだったようですね。
現在は独自の時間になっていて、標準時がUTC+10:30、夏時間がUTC+11:00であることがわかります。
確かにWikipediaにある通り、ロード・ハウ島のサマータイムは30分だけ早くなるようですね。

まとめ

サマータイムだからといって1時間ずれると思ったら大間違いやで!というのと、いかに世界のタイムゾーンが複雑であるかというのを肌で感じました。
日本に住んでいるとタイムゾーンって一つですからねー。

ここまできたらロード・ハウ島にいってサマータイムを実際に感じてみたいですね!

明日は@FW14Bさんです!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?