🌍

タイムゾーン呪いの書 (知識編)

43 min read

「タイムゾーン呪いの書」は、もともと 2018年に Qiita に投稿した記事でしたが、大幅な改訂を 2021年におこない、同時にこちらの Zenn に引っ越すことにしました。

この改訂では Software Design 誌の 2018年 12月号に特集の一章として寄稿した内容も取り込みつつ、夏時間をめぐって各地で起きつつある変化について 2021年 6月現在の状況なども追加しました。そんな追記もしていたら記事全体が長大になってしまったため、この「知識編」と、「実装編」「Java 編」に記事を分けました。「知識編」は、導入にあたる第一部です。

Qiita のほうは、引っ越した旨とこの引っ越し先へのリンクだけ追記して、しばらくそのまま残すつもりです。

はじめに

タイムゾーンという概念のことは、ほとんどの人が聞いたことがあると思います。ソフトウェア・エンジニアでも多くの方が、時刻やタイムゾーンにかかわるプログラムを、なにかしら書いたことがあるでしょう。ですが、日本に住んで日本の仕事をしていると、国内時差もなく [1] 夏時間もなく [2] 日本標準時 (Japan Standard Time) のみでほぼ用が足りてしまうので、このタイムゾーンという厄介な概念についてちゃんと調べる機会は多くありません。実際、成り立ちから実装上の注意点まで解説したような日本語の文書は、残念ながらこれまであまり見つかりませんでした。

日本国内限定で開発しているならタイムゾーンなんてややこしいことは考えなくていい、と考える人は多いかもしれません。しかし、作ったソフトウェアやサービスを他の国や地域に展開するチャンスは、いつやって来るかわかりません。そのとき、間違った実装の時刻処理が展開の障害となってしまったら、とても悲しいことです。

2018年には、日本でも夏時間の導入が 2020年開始を目指して検討されました。ソフトウェア・エンジニアをふくむ多くの人の反対もあって、同年中に断念されましたが [3] いつか導入してしまうかもしれません。実際、日本で夏時間導入が検討されたのは、近年でもこの一度だけだったわけではありません。 [4] 日本国内でも、急に状況が変わるリスクは常にあります。日本国内が前提であっても、まともに実装しておくに越したことはありません。

本記事では、タイムゾーンをあつかおうとすると常につきまとう「呪い」、筆者がタイムゾーンに苦しんだ恨み [5] を、ソフトウェア・エンジニアリングの視点から闇に踏み込んで記述し、この呪いからの適切な逃げかた、そして呪いを受けつつも真っ向から立ち向かうための戦いかたについて、筆者の主観で紹介します。本記事が、時刻やタイムゾーンの処理を「まともに」実装する一助となれば幸いです。

本記事では参考実装として、日付・時刻とタイムゾーンの問題に真正面から立ち向かっている Java の JSR 310: Date and Time API をときどき参照します。

記事中に情報の不足や誤りなどを発見されましたら [6] ぜひコメントなどをお送りください。他の言語やソフトウェアにおける実装についても、コメントや別の記事などでの情報提供をお待ちしております。[7] 一部 Wikipedia なども参照しながら記述していますが、日本語版の Wikipedia には英語版との食い違いがあるようです。そのような場合は、基本的には英語版のほうを信用するようにしています。 [8]

時差、標準時、タイムゾーン

「『午後 1時』っていったら、だいたい昼くらいだよね」という認識を世界中で共有したければ、地球に住むかぎり「時差」から逃げることはできません。ある地域でいう「午後 1時」はその地域のある瞬間をあらわす「時刻」ですが、同じ瞬間に「午前 9時」の地域もあります。これがややこしさの元凶であり、出発点です。 [9]

とはいえ、時刻を「その地点で太陽が南中する時刻をその地点の正午とする」なんて定義にしてしまうと、極端にいえば東西方向に一歩歩くだけでもわずかに時差が発生してしまいます。たとえば東西に少しだけ離れた品川と新宿の間にも、多少の時差が発生することになります。 [10] [11]

そんなことでは法律・商業・社会などいろいろな面で不便なので、地理的に近い一定の広さの地域では同じ時刻を使うことにしました。その時刻 (系) をその地域の「標準時」と呼び、同じ標準時を使う地域を「タイムゾーン」と呼びます。たとえば「日本標準時」を使う「日本全体」が一つのタイムゾーンです。 [12]

地域の人が日常生活に用いる時刻のことを特に指して「常用時」 (civil time) とも呼びます。 [13]

タイムゾーンの境界は、一般的には国境や州境、市境などの政治的境界に準じます。タイムゾーンの役割を考えればそのほうが便利なのはもちろんですが、そもそもタイムゾーンや標準時とは国際的に条約などで定めているわけではなく、国や地域の政府がそれぞれ「自分のところのこの地域はこの時刻でやるぜ!」と宣言しているだけだからでもあります。 [14]

タイムゾーンの定義と用法

前述のように、「タイムゾーン」は「同じ標準時を使う地域」として標準時を基準に定義するのが一般的です。 [15] 「標準時」は後述の「夏時間」とは独立で、たとえばアメリカのコロラド州とアリゾナ州は同じ「山岳部標準時」を使いますが、夏時間制に違いがあります。 [16] そしてこの二州は、この定義では同じタイムゾーンに属します。

しかしこの「タイムゾーン」という用語は、実態としてはとても多様であいまいな使われかたをしています。後述する Time Zone Database (tzdb) のタイムゾーン ID のように、コロラド州とアリゾナ州のようなケースを異なるタイムゾーンとして分ける例は数多くあります。逆に、政治主体が違うので本来的には異なる「標準時」の定義を持つものの、時差としては同等な標準時を使っていた国や地域を、まとめて一つのタイムゾーンと呼んだ例もあります。 [17] さらには後述する UTC+9 などの特定の時差そのものをタイムゾーンと呼ぶこともあります。

タイムゾーンをあつかうときは、この用語のあいまいさを念頭に置いておきましょう。

UTC: タイムゾーンの基準

世界中の国や地域の人々が、時刻の話をまじえながらコミュニケーションをとるには、どこかに基準が必要です。世界各地の人々が、国や地域間の相対的な時差を何通りにも組み合わせて話をするというのは、ちょっと非現実的です。

国際的な基準として初期に使われたのが「グリニッジ標準時」 (GMT: Greenwich Mean Time) です。 [18] GMT はロンドンのグリニッジから観測される太陽の位置にもとづく時刻であり、これは太陽に合わせる一般の人々の日常生活にも、つまり「常用時」としても、そのまま有用でした。しかし、別の見方をすると GMT は地球の自転と観測にもとづく時刻ともいえます。地球の自転周期は常に一定というわけではなく、わずかなふらつきがあります。物理的に厳密な「24時間」とは一致しません。 [19]

また、数種類の「世界時」 (UT: Universal Time) [20] が GMT を継承して定義されましたが、これらもやはり地球の自転にもとづくもので、同じ問題がありました。

地球の自転によらずに、原子時計をもとに定めた時刻が「国際原子時」 (TAI: Temps Atomique International) です。こちらは物理的に厳密な一秒を刻みますが、そうすると地球の一周と TAI の一日の間に「ズレ」が生じます。

一日・一秒の長さがその時々で変わるのも、地球の一周と生活上の一日がずれるのも、どちらも不便です。そこで「協定世界時」 (UTC: Coordinated Universal Time) という折衷案というべき時刻系が提案され、現在では UTC が多くの分野で基準として採用されています。 UTC は、原子時計で厳密な一秒を刻みつつも、地球の自転に基づく世界時 (UT1) との差が 0.9秒を超えないように、「うるう秒」を導入しながら調整を続けている時刻系です。うるう秒はめんどうで嫌われがちですが、一秒の長さがその時々で変わるか、地球の一周と実生活の一日がずれるか、うるう秒か、どれかの不便は受け入れないとならないのです。

ちなみにうるう秒のしくみには、「59分 60秒」が挿入される「正のうるう秒」だけではなく、「59分 59秒」が削除される「負のうるう秒」もあります。ただし、策定から 2021年までの間に「負のうるう秒」の実施例はありません。

ソフトウェアや通信の分野では UTC がおもに使われ、また GMT は UTC と同等とあつかわれることが多いです。

こうして現在では、各国や地域の時刻は UTC からの時差 (オフセット) で表現するのが一般的になりました。たとえば UTC から 9時間進んだ日本の時刻は UTC+9, UTC+09:00, +09:00 のように表記します。多くのタイムゾーンは UTC から 1時間単位の差ですが、そうではないオーストラリア中部標準時 (UTC+09:30) やネパール標準時 (UTC+05:45) のようなタイムゾーンも存在します。

「地域ベース」と「オフセット」

前述したように、地域によらない UTC+09:00 のような特定の時差そのものを「タイムゾーン」と呼ぶこともあります。「地域をあらわすタイムゾーン」と「地域によらず特定の時差をあらわすタイムゾーン」を用語で区別できたらいいのですが、残念ながらこれらを区別する一般的な用語はなさそうです。 [21] [22]

本記事では JSR 310 を参考に、前者を「地域ベースのタイムゾーン」 (region-based time zone) と、後者を「固定オフセット」または単に「オフセット」と呼ぶことにします。具体的には java.time.ZoneIdjava.time.ZoneOffset を参照してください。

タイムゾーンの切り替わり

ある地域のタイムゾーンのオフセットは、さまざまな理由で、別のオフセットに切り替わることがあります。その代表が、悪名高い「夏時間」 [23] です。

夏時間

単なる国や地域ごとの時差だけでもめんどうな話なのに、それ以上に世界を混沌の渦におとしいれているのが夏時間です。夏時間は一般に「明るいうちに仕事を終えて余暇を長く過ごせるように」実施されるので、ある地域が夏時間に切り替わるときには、その地域では少し [24] 時刻が進みます。

日本は夏時間に縁が薄いので、切り替わるとき具体的に何が起こるのか、知らない方もいるかもしれません。これはなかなかアクロバティックで、切り替えのときは時刻がいきなり吹っ飛びます。

たとえば 2020年のアメリカ合衆国では 3月 8日 (日) に夏時間に切り替わりました。 [25] そのタイミングは切り替わる前の時刻でいう午前 2時で、その日の午前 1時 59分 59秒から 1秒経ったと思ったら午前 3時 0分 0秒になっていた、という具合です。カリフォルニア州を例に経過を 1秒ごとに並べると、以下のようになります。

カリフォルニア州の時刻 UTC からの差 (オフセット)
2020-03-08 01:59:58 太平洋標準時 (PST) -08:00
2020-03-08 01:59:59 太平洋標準時 (PST) -08:00
2020-03-08 03:00:00 太平洋夏時間 (PDT) -07:00
2020-03-08 03:00:01 太平洋夏時間 (PDT) -07:00

つまり、カリフォルニア州に 2020年 3月 8日 午前 2時 30分という時刻は存在しませんでした。

夏時間から標準時に戻るときはさらにトリッキーで、一見すると同じ時刻を二度経験することになります。再び 2020年のカリフォルニア州を例に取ると、その時刻は以下のように経過しました。

カリフォルニア州の時刻 UTC からの差 (オフセット)
2020-11-01 01:00:00 太平洋夏時間 (PDT) -07:00
2020-11-01 01:00:01 太平洋夏時間 (PDT) -07:00
2020-11-01 01:59:59 太平洋夏時間 (PDT) -07:00
2020-11-01 01:00:00 太平洋標準時 (PST) -08:00
2020-11-01 01:00:01 太平洋標準時 (PST) -08:00

つまり、カリフォルニア州には 2020年 11月 1日 午前 1時 30分という時刻が二回存在しました。

本記事で「タイムゾーンの呪い」と呼ぶ最大のものは、地域ベースのタイムゾーンを使うと、このような「存在しない時刻」や「二重に存在する時刻」の問題が常にセットでついてくる、というものです。ひとたび地域ベースのタイムゾーンを使ってしまったら、もう逃げることはできません。

夏時間よもやま話

夏時間には逸話がいろいろあるので、ここでいくつか紹介します。

2021年の日本では夏時間は採用されていませんが、第二次世界大戦の直後に夏時間が実施されていたことがあります

2021年現在は、どの国でも夏時間に切り替わってから一年以内に標準時に戻ります。しかし第二次世界大戦中のイギリスでは、夏時間に切り替わったまま戻らず、翌年に二重に夏時間に切り替わったことがあります。

夏時間制を導入している国や地域でも、そのすべてでアメリカ合衆国のように安定した「切り替え規則」があるとは言いがたいようです。たとえばチリでは 2016年前後に夏時間制が何度も変更されましたブラジルでは 2008年まで夏時間の実施地域や切り替え日が毎年個別に公示されていて、その公示が夏時間開始の直前になったこともあるようです

夏時間以外の切り替わり

夏時間以外にも、地域のタイムゾーンのオフセットが切り替わることがあります。その国や地域の政府によるその時々の政治的決定が、おもな理由です。

たとえば 2011年の年末にはサモア独立国の標準時が UTC-11:00 から UTC+13:00 に切り替わりました。この切り替わりは 12月 29日の終わりがそのまま 12月 31日の始まりに続く形で実施され、サモアでは 2011年 12月 30日がまるまる存在しなかったことになりました。

タイムゾーンの呪いは、こんな風にも降りかかってきます。夏時間で 1時間くらい長くなったり短くなったりすることは考慮していても、日付が一日まるまるなくなるかもしれない、などという想定までは、したことがない人が多いのではないでしょうか。

夏時間制の終わり

2021年現在、夏時間制の廃止が世界各地で議論されています。夏時間制の廃止はソフトウェア・エンジニアとして長期的には歓迎できることですが、今まで実施されていたものが実施されなくなるというのは、そんなに単純な話ではありません。状況を注視する必要があるでしょう。

たとえば EU における夏時間制は、欧州議会の議決では 2021年を最後に廃止されることになっていました。 [26] しかし Brexit やコロナ禍もあって、その 2021年の 3月になってもまだ状況は不透明だったようです。 [27] [28]

EU の状況をさらにややこしくしているのは、夏時間廃止後の新しい標準時を「旧来の標準時」に戻すのか「それまでの夏時間」に新しく合わせるのか、最終的には各国にまかされているらしい、ということです。なるべくそろえたい思惑はさすがにあるようですが、最終的にどうなるか、どうやら 2021年 6月現在もわかっていません。極端にいえば、いままで同じ「中央ヨーロッパ標準時 (CET)」を使っていて時差のなかったドイツ・フランス・イタリアの間に、来年からは時差が生じる、なんてことがあるかもしれません。タイムゾーンの呪いは、意識していなかったところから襲ってきます。恐ろしい話です。 [29]

また、カリフォルニア州では 2018年の住民投票で夏時間の変更が支持されました。 [30] 2021年 6月時点ではまだ具体的な変更の予定はないようですが、これから変わるかもしれません。

カリフォルニア州の変更で要注意なのは、「ロサンゼルス時間」を「太平洋時間」の代表として用いているソフトウェアがある、ということでしょう。後述しますが、実は Java の標準 API がそうです。たとえばワシントン州シアトルの冬の時刻を表現するつもりで「太平洋標準時 (PST)」を使っていると、それが内部的にはロサンゼルス時間あつかいになっているわけです。そんな中でカリフォルニア州のみ夏時間が廃止されたら…、どうするんでしょうね。タイムゾーンの呪いには、なにか恐ろしいことが起きそうだとはわかっていても、各国や地域の政治的決定が定まるまでどうなるかわからない、という面があります。考えたくない話です。

ソフトウェア技術における時刻

さて、ここまで時刻とタイムゾーンの一般的なしくみをおもに紹介してきました。ここからは、ソフトウェアや通信の分野に特有の技術的な内容を取り上げていきます。

Unix time: 世界共通の時間軸

世界各地の「時刻」には時差がありますが、それでも時間は世界中で同じように流れており、時間軸は世界共通です。その時間軸上の一点は、世界中で共通の同じ一瞬です。 [31] たとえば、日本の 2020年 7月 1日 午後 3時 0分 0秒と、イギリスの 2020年 7月 1日 午前 7時 0分 0秒は、その時間軸上では同じ一点です。各国や地域の中ではそれぞれの現地時刻を使っていれば問題ありませんが、タイムゾーンをまたぐ場合、特にインターネットが関わるしくみの中では、世界共通の時間軸で時刻をあつかいたくなるというものです。

前述したように UTC という共通の基準があるので、要はその時間軸を UTC で表現すればいいのです。ですが、その時間軸上で年・月・日・時・分・秒の繰り上げなどいちいち計算するのは無駄が多いです。そこでソフトウェアの分野では、よく Unix time を使って時刻を表現します。

Unix time は、日本語では「Unix 時間」、英語では "POSIX time" や "(Unix) epoch time" などとも呼ばれ、時刻を UTC の 1970年 1月 1日 0時 0分 0秒からの経過秒数で表現するものです。この UTC の 1970年 1月 1日 0時 0分 0秒を "epoch" と呼びます。

Unix time がわかっていれば、任意のタイムゾーンにおける年・月・日・時・分・秒は簡単に計算できるはず…ですが、一つ問題が残ります。うるう秒です。うるう秒はそもそも予測困難な自転速度のふらつきを埋めるためのしくみなので、うるう秒が導入されるタイミングを将来にわたって確定することはできません。これでは、未来の時刻に対応する Unix time が計算できません。

そこで Unix time は「経過時間」としての厳密さを捨てて利便性を優先し、うるう秒を無視することになっています。最近では UTC における 2016年 12月 31日 23時 59分 59秒と 2017 年 1月 1日 0時 0分 0秒の間に正のうるう秒が挿入されましたが、このとき Unix time の 1483228800 は 2秒間続きました。その経過を 0.5秒ごとに並べると、次のようになります。

UTC における時刻 小数部を含む Unix time
2016-12-31 23:59:59.00 1483228799.00
2016-12-31 23:59:59.50 1483228799.50
2016-12-31 23:59:60.00 1483228800.00
2016-12-31 23:59:60.50 1483228800.50
2017-01-01 00:00:00.00 1483228800.00
2017-01-01 00:00:00.50 1483228800.50
2017-01-01 00:00:01.00 1483228801.00

Unix time の整数部だけを見ると同じ秒が 2秒間続くだけなので、そんなに問題ないように見えます。しかし、小数部がありながら小数部が普段どおりにカウントされると、時刻が逆進したことになるので注意が必要です。 [32]

うるう秒の「希釈」

せっかく UTC で導入されたうるう秒ですが、すべてのソフトウェアで「一秒単位の厳密な時刻」が必要なわけではありません。逆進問題も含め、うるう秒は過去に多くの問題を引き起こしてもきました。 [33]

そこで、必要なさそうな場合は UTC で獲得した一秒の厳密さを再度捨てて、うるう秒を周辺の数時間で「希釈」する手法が 2000年ごろの議論 [34] から生まれました。これは近年のソフトウェアやクラウドサービスで一般的な手法になりつつありますが、この「希釈」にはいくつか流派があります。

たとえば Java の JSR 310 で使われる「Java タイム・スケール」は、最初の議論から派生して生まれた UTC-SLS (Coordinated Universal Time with Smoothed Leap Seconds) [35] をベースにしています。 UTC-SLS は、うるう秒が導入される日の最後の 1000秒に均等にうるう秒を分散させて希釈し、うるう秒を見えなくしてしまうものです。つまり、正のうるう秒による Java タイム・スケールの希釈期間では、表面上の 1秒が経過するのに実際には 1.001秒かかる、ということですね。

一方 AWS や Google Cloud などのクラウドサービスでは、少し別の流派が一般的になりつつあります。彼らの手法は "Leap Smear" [36] と呼ばれることが多く、おもに NTP を介して提供されます。

2008年のうるう秒で Google が実施した最初の Leap Smear は、うるう秒をその「前」の「20時間」に「非線形に」分散させるものでした。次の 2012年から 2016年のうるう秒における Google の Leap Smear は、うるう秒の「前後」の「20時間」に「線形に」分散させるものになりました。

現在では Google はうるう秒の「前後」の「24時間」に「線形に」分散させるやりかたを標準とすることを提案しています2015年と 2016年に Amazon が実施した Leap Smear もこれと同様のもので、クラウドサービスではこのやりかたが一般的になると思ってよさそうな雰囲気です。

tzdb: タイムゾーン表現の業界標準

ソフトウェアの分野でタイムゾーンをあらわす最も業界標準的なデータが Time Zone Database [37] でしょう。見たことのある方も多いであろう Asia/TokyoEurope/London のような ID は、この Time Zone Database のものです。

もともと "tz database" や、略して "tzdb" と、または単に "tz" などと呼ばれていました。本記事中ではおもに "tzdb" と呼びます。 Unix-like な OS で使われるパス名から "zoneinfo" とも呼ばれます。 Arthur David Olson たちが始めたもので、遅くとも 1986年にはメンテナンスされていた記録があります。 [38] Olson の名前から "Olson database" と呼ばれることもあります。

tzdb の ID は、最初の / の前に大陸・海洋名を、後ろにそのタイムゾーンを代表する都市名・島名などを用いてつけられます。 [39] 国名は基本的に使われません。 [40] America/Indiana/Indianapolis のように 3要素で構成されるタイムゾーンも、少数ながら存在します。

tzdb の管理は 2011年に ICANN の IANA に移管されました [41] が、いまでもメンテナンスは個人のボランティアをベースにおこなわれています。 [42] タイムゾーンは世界のどこかで意外なほど頻繁に変わっており、年に数回は新しいバージョンの tzdb がリリースされます。前述のサモアのように政治的決断で変わる場合、夏時間制を新しく導入する場合・廃止する場合、国や地域の境界が変わる場合など、さまざまなケースがあります。登録済みの過去のデータに間違いが見つかって修正することもあります。 [43] tzdb の更新は実際にタイムゾーンが変わる直前になることも多く、前述のサモア標準時の変更が tzdb に適用されたのは、実際に標準時が変わる 2011年 12月のわずか 4ヶ月前のことでした。

tzdb は、特に 1970年 1月 1日以降のすべてのタイムゾーンの変更、夏時間などのオフセット切り替え規則、うるう秒の情報まで、さまざまな情報を包含することを目標にメンテナンスが続けられています。 tzdb は OS や Java などの実行環境、各言語のライブラリなどに組み込まれていて、更新が出るとそれぞれのメンテナによって取り込まれ、更新を組み込んだアップデートとしてそれぞれ世界中に配信されています。

tzdb には 1970年 1月 1日以前の情報もある程度まで含まれていますが、暦の違い、歴史資料の問題などもあって、古い情報を正確なものにしようとはあまり考えられていないようです。 [44] 特にタイムゾーン ID は「1970年以降も区別する必要のあるタイムゾーン」のみを定義する、という方針のようです。たとえばブラジルのサンパウロを含む一部地域で 1963年に実施された夏時間をあらわすために America/Sao_Paulo の新設が提案されたことがありますが、この方針により却下されています

Military time zones

Z の一文字で UTC をあらわす記法を見たことがある人は多いと思います。これは、おもに米軍で使われる "Military time zones" から来ています。 UTC-12 から UTC+12 まで一時間単位の 25 のタイムゾーンに、大文字のアルファベット (Jを除く) を対応させます。 UTC+05:30 のような一時間単位ではないタイムゾーンには * (star) をつけて E* ("Echo-Star") などと呼ぶこともあるようです。 [45]

Military time zones は RFC 822RFC 2822 などにも記載があり、これを標準で処理できる言語やライブラリは多くあります。しかし Z 以外はあまり使わないほうがいいでしょう。

その第一の理由は、初期の RFC 822 の Military time zones の記述が、間違っていたことです。 [46] そして、その間違いをもとに間違った実装をしていたソフトウェアも、歴史的にいくつかありました。その間違いは後の RFC 2822 で指摘されていますが、過去の実装との互換性の問題も考慮して RFC 2822 では「他にその意味を確認できる情報がないかぎり、これらはすべて -0000 (「タイムゾーン不明」の意味がある) と等価にあつかうべし (SHOULD)」ということになっています。

さらに UTC+13 のように Military time zones ではあつかえないタイムゾーンもあります。 Z 以外はあまり知られてもおらず、わざわざ使う理由はあまりないように思います。

タイムゾーン略称

JST: Jerusalem Standard Time?

日本標準時 (Japan Standard Time) は、よく JST と略して呼ばれます。これは tzdb にも以下のように言及があります。

# From Hideyuki Suzuki (1998-11-09):
# 'Tokyo' usually stands for the former location of Tokyo Astronomical
# Observatory: 139 degrees 44' 40.90" E (9h 18m 58.727s),
# 35 degrees 39' 16.0" N.
# This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
# edited by National Astronomical Observatory of Japan....
# JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
# The law is enacted on 1886-07-07.

Asia/Tokyo の定義 も以下のようになっています。 (J%sT%s のところに S (標準時) を入れたり D (夏時間) を入れたりする記法です。現在の日本で夏時間が実施されているわけではありませんが。)

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
Zone    Asia/Tokyo      9:18:59         -       LMT     1887 Dec 31 15:00u
                        9:00    Japan   J%sT

しかし、もう少し tzdb を眺めてみると、以下のように Jerusalem Standard Time を JST と呼んでいるコメントも同時に存在するのです。

# From Ephraim Silverberg (2001-01-11):
#
# I coined "IST/IDT" circa 1988.  Until then there were three
# different abbreviations in use:
#
# JST  Jerusalem Standard Time [Danny Braniss, Hebrew University]
# IZT  Israel Zonal (sic) Time [Prof. Haim Papo, Technion]
# EEST Eastern Europe Standard Time [used by almost everyone else]

とはいえ tzdb 公式の解釈としては、以下のコメントのように "Jerusalem Standard Time" としての JST は除外 (ruled out) されてはいます。

# Since timezones should be called by country and not capital cities,
# I ruled out JST.  As Israel is in Asia Minor and not Eastern Europe,
# EEST was equally unacceptable.  Since "zonal" was not compatible with
# any other timezone abbreviation, I felt that 'IST' was the way to go
# and, indeed, it has received almost universal acceptance in timezone
# settings in Israeli computers.

それでも "Jerusalem Standard Time" という呼びかた自体は各所で現役です。 [47] GE Digital のドキュメントに含まれていたり Windows のタイムゾーン情報に含まれていたりします。 "Jerusalem Standard Time" という呼びかたが現に存在するということは、略して JST と呼ぶ人々も、当地にはもちろんいるでしょう。名前の衝突は、特にソフトウェア間のやり取りではとても厄介ですね。

タイムゾーン略称は非推奨

JST のようなタイムゾーン略称は一見使いやすいのですが、このように、実は略称から目当てのタイムゾーンを一意に特定できるとはかぎりません。プログラムの記述や、ソフトウェアに読み込ませる可能性のあるデータに、タイムゾーン略称を用いるのは避けるべきでしょう。手元でしばらくは動いていたのに他の国や地域の顧客がついたらデータがおかしくなり始めた、みたいな地獄が待っています。

実際、旧 Java 標準 API の java.util.TimeZone では、「3文字のタイムゾーン ID は非推奨」と明記されています。新 JSR 310 の java.time.ZoneId では、略称は標準ではサポートされず、略称とタイムゾーンの対応を別にエイリアスとして指定するしくみになっています。

不幸にもタイムゾーン略称を含むデータを読み込まなければならない場合は、あきらめて決め打ちするしかありません。データ処理プロセスのできるだけ初期のステージのうちに対処しましょう。さらに、各略称をどのタイムゾーンとして読み込むのか、そのソフトウェアやサービスの仕様として明文化しておきましょう。 [48] さらに Java などの処理系やライブラリが暗黙のうちに略称を解釈してしまうことがあるため、その仕様まですべて把握し、開発中のソフトウェアやサービス自身の仕様としても改めて明記しましょう。

開発中のソフトウェアやサービスからタイムゾーン略称入りのデータが出力されるようになっていたら、できるかぎり即座にやめましょう。代わりに +09:00 などのオフセットや、地域ベースの Asia/Tokyo などの tzdb ID を使いましょう。オフセットと地域ベースのどちらがいいのかはこのあと「実装編」などで検討しますが、いずれにせよ略称はダメです。互換性などの理由でどうしても略称をやめられない場合は、これもすべて仕様として明文化しましょう。

タイムゾーン略称を使うのは、人間対人間の文脈が明らかなコミュニケーションのみにしておきましょう。タイムゾーン略称が引き起こす問題を、もういくつか紹介します。

CST

JST よりわかりやすく略称が衝突している例が CST です。 java.util.TimeZone の Javadoc でも明示的に触れられているほどです。

日本やアメリカ合衆国でソフトウェア・エンジニアとして働いていると CST を「中部標準時 (Central Standard Time)」のことと思ってしまいがちです。しかし「中国標準時 (China Standard Time, Chinese Standard Time)」も CST です。さらに、「キューバ標準時 (Cuba Standard Time)」 も CST です。 [49]

CST: "China Standard Time" は tzdb にも現役で収録されていますJST: "Jerusalem Standard Time" のように除外されているわけでも、非推奨にもなっているわけでもありません。

# The following alphabetic abbreviations appear in these tables
# (corrections are welcome):
#            std  dst
#            LMT        Local Mean Time
#       2:00 EET  EEST  Eastern European Time
#       2:00 IST  IDT   Israel
#       5:30 IST        India
#       7:00 WIB        west Indonesia (Waktu Indonesia Barat)
#       8:00 WITA       central Indonesia (Waktu Indonesia Tengah)
#       8:00 CST        China
#       8:00 HKT  HKST  Hong Kong (HKWT* for Winter Time in late 1941)
#       8:00 PST  PDT*  Philippines
#       8:30 KST  KDT   Korea when at +0830
#       9:00 WIT        east Indonesia (Waktu Indonesia Timur)
#       9:00 JST  JDT   Japan
#       9:00 KST  KDT   Korea when at +09

中国標準時の Asia/Shanghai の定義が以下です。最後の行の [UNTIL] 列が空欄なので、これが現在でも有効ということですね。 (%sJ%sT と同様です。)

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
# Beijing time, used throughout China; represented by Shanghai.
Zone    Asia/Shanghai   8:05:43 -       LMT     1901
                        8:00    Shang   C%sT    1949 May 28
                        8:00    PRC     C%sT

キューバ標準時の America/Havana も同様に定義されています。

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
Zone    America/Havana  -5:29:28 -      LMT     1890
                        -5:29:36 -      HMT     1925 Jul 19 12:00 # Havana MT
                        -5:00   Cuba    C%sT

EST, EDT, CST, CDT, MST, MDT, PST, PDT

CST の衝突について紹介しましたが、その CST を含むアメリカ合衆国のタイムゾーン略称を、優先的に処理するようになっている言語やライブラリがいくつかあります。 Ruby の TimeJava の旧 java.util.TimeZone がその例です。これは RFC 822RFC 2822 にこれらの略称が明記されていることが、おおもとの理由としてあるようです。

しかしこの略称のあつかいがソフトウェアによって微妙に異なるのです。上で例に挙げた Ruby と Java でも異なり、実は Java のほうが「間違っている」と言ってよさそうなものなのですが、互換性などの理由でいまでも部分的に引きずっています。いままではそれを「仕様」としてどうにかやってきましたが、近年さかんに議論されている夏時間制の廃止を引き金として、問題として表面化するかもしれません。このことについて以下で紹介します。

略称の解釈による問題: Java の例

これらの略称は本来、それぞれ標準時・夏時間のどちらか一方に対応します。たとえば PST はあくまで Pacific "Standard Time" (太平洋「標準時」) であって PST が太平洋夏時間を指すことはありません。太平洋「夏時間」は、あくまで Pacific "Daylight Saving Time" の PDT です。

つまり PST があらわすのは常に -08:00 であり、あくまで「夏になるとカリフォルニアの時間が PST (-08:00) から PDT (-07:00) に切り替わる」のであって、「夏になると PST-07:00 になる」わけではありません。上記の RFC 2822 にも PST is semantically equivalent to -0800 などと明記されています

Ruby の Time はこれに沿った実装をしています。 Ruby の TimePST を常に -8 としてあつかい、そして PDT を常に -7 としてあつかいます。これが正しい解釈です。

しかし古くからの Java 標準 API (とそれを継承した Joda-Time) は、これを違うあつかいにしてしまいました。 PST などの略称を America/Los_Angeles などの地域ベースのタイムゾーン ID に対応づけてしまったのです。一見するとこれでもよさそうですが、問題は何でしょうか。

カリフォルニアでは夏時間となる 2020-07-01 12-34-56PST を組み合わせた文字列 2020-07-01 12:34:56 PST は、本来 2020-07-01 12:34:56 -08:00 として解釈しなければなりません。しかし、古くからの Java 標準 API はこの PSTAmerica/Los_Angeles に対応させるので、これは 2020-07-01 12:34:56 America/Los_Angeles になります。するとこれは、カリフォルニアでは 2020-07-01 が夏時間であることから、最終的には2020-07-01 12:34:56 -07:00 と解釈されてしまいます。

「2020年 7月 1日が夏時間なのは明らかなんだから、そもそも 2020-07-01 12:34:56 PST なんて書くのが悪いじゃないか」と思うかもしれません。…しかし、本当にそれだけでしょうか?

同じことは MST (山岳部標準時) でも起こります。古い Java API は MSTAmerica/Denver に対応づけます。 Denver があるコロラド州には夏時間があり、冬に -07:00 だった America/Denver は、夏には -06:00 になります。これは PST と同じ状況で、上と同様の「2020-07-01 12:34:56 MST なんて書くのが悪い」という主張は、たしかに Denver では正しいです。

同じ「山岳部時間」を使う州にアリゾナ州があります。上の「タイムゾーンの定義と用法」で触れましたが、アリゾナ州は一部を除いて夏時間を採用していません。ということは 2020-07-01MST を組み合わせた 2020-07-01 12:34:56 MST は、一部を除くアリゾナ州では有効なはずの表現であり、これは本来 2020-07-01 12:34:56 -07:00 と解釈しなければなりません。しかし Java API はこれを 2020-07-01 12:34:56 -06:00 と解釈してしまいます。

このことは、以下の Java コードで容易に確認できます。 [50]

import java.time.format.DateTimeFormatter;
import java.time.ZonedDateTime;

public final class MountainTime {
    public static void main(final String[] args) throws Exception {
        System.out.println(ZonedDateTime.parse("2020/01/01 12:34:56 MST", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/01/01 12:34:56 MDT", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/07/01 12:34:56 MST", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/07/01 12:34:56 MDT", FORMATTER));

        // America/Phoenix はアリゾナ州で、夏時間を採用していません。
        System.out.println(ZonedDateTime.parse("2020/01/01 12:34:56 America/Phoenix", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/01/01 12:34:56 America/Phoenix", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/07/01 12:34:56 America/Phoenix", FORMATTER));
        System.out.println(ZonedDateTime.parse("2020/07/01 12:34:56 America/Phoenix", FORMATTER));
    }

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss zzz");
}

この出力は以下のようになります。 (ここでは Java 8 で確認していますが OpenJDK 16.0.1 でも同様の結果になることを確認しています。)

$ java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-8u292-b10-0ubuntu1~20.04-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

$ java MountainTime
2020-01-01T12:34:56-07:00[America/Denver]
2020-01-01T12:34:56-07:00[America/Denver]
2020-07-01T12:34:56-06:00[America/Denver]
2020-07-01T12:34:56-06:00[America/Denver]
2020-01-01T12:34:56-07:00[America/Phoenix]
2020-01-01T12:34:56-07:00[America/Phoenix]
2020-07-01T12:34:56-07:00[America/Phoenix]
2020-07-01T12:34:56-07:00[America/Phoenix]

ここで、「カリフォルニア州では 2018年の住民投票で夏時間制の廃止が支持された」という話があったのを思い出してみましょう。

MST に対応する America/Denver の場合、この Denver は夏時間を採用する多数派で、夏時間を採用しないアリゾナ州は少数派の例外でした。一方で、夏時間制を廃止する議論が進んでいるのはいまのところカリフォルニア州くらいです。夏時間を採用しないほうが圧倒的に少数派なのです。そして PST に対応する America/Los_Angeles はカリフォルニア州です。将来 PST は少数派の例外のほうに対応づいてしまう可能性があります。

タイムゾーン略称については、これからもなにが起こるのかよくわかりません。よく使われる PST ですらこんな状態です。「タイムゾーン略称はこわい」と多くの方に思ってもらえたら、この章を書いたかいがあります。

発展: 日付と暦

さて、ここまで地球の自転にともなう周期 (一日・時刻) についておもに見てきました。では地球の公転にともなう周期 (一年・日付) はどうでしょうか。

太陰暦や日本の元号などの国・地域固有の暦という文化こそ一部にありますが、現在では「グレゴリオ暦」がいわゆる「西暦」として普及し、少なくとも技術的には共通言語として成立するようになりました。このグレゴリオ暦を使ってここ数十年の日付のみをあつかっているかぎりは、暦で悲惨な思いをすることは少ないでしょう。

しかしひとたび昔の日付をあつかおうとすると、暦の話もまた、時刻とタイムゾーンのように広大な闇が広がっています。グレゴリオ暦以前の暦である「ユリウス暦」や、グレゴリオ暦をグレゴリオ暦以前にまで強引に適用した「先発グレゴリオ暦」など、さまざまな種類の暦が出てきて、ソフトウェア・エンジニアを混乱の渦に突き落とします。

とはいえ、本記事内で暦の問題まであつかおうとすると、記事が倍以上の分量になってしまいそうです。ここでは、とてもよくまとまったブログ記事を紹介して、その代わりとしたいと思います。

「西暦1年は閏年か?」 (2020年 10月 30日、なぎせゆうきさんのブログ記事)

そして実装へ

時刻とタイムゾーンというこの厄介な概念について話を続けると、きりがありません。とはいえ一般的な知識は、ある程度ここまでで概観できたと思います。

では、この知識を具体的に実装に落とし込むときには、何にどう気をつけたらいいでしょうか。

Qiita に載せていた 2018年版の旧記事では、ここから Java を具体例として実装について紹介していました。さらに Software Design 誌の 2018年 12月号では Java に限定しない実装の一般論も書きました。本記事ではその Software Design 誌の内容を取り込んで、さらに Java 特有のトピックにも追加をした結果、記事全体の分量が大幅に増えてしまいました。そこで、実装の一般論と Java 特有の話は別の記事に分けることにしました。

ここでは同筆者による実装編と Java 編のみにリンクを張っていますが、他の方による、他の言語やソフトウェアなどの話をまとめた記事を教えていただけたら、こちらで紹介させていただくかもしれません。 [51]

おまけ: 環境変数 TZ

(特に Unix-like な) OS のタイムゾーン設定といえば環境変数 TZ でした。 [52] もともと tzdb 自体が、環境変数 TZ の裏方でもある zoneinfo の元データとしてメンテナンスされたものです。

ここで「TZ の設定が、どのようなメカニズムで実際の動作に反映されるのか」とかの解説を始めると、長文記事がもう一本できてしまうので、本記事では割愛します。 [53] しかし TZ の「書式」はいろんなところで顔を出すので、この「知識編」で軽く触れておいたほうがいいと判断し、おまけとして追記することにしました。

UTC+9? JST-9?

日本時間は UTC から 9時間先行していますが、これを一般に UTC+9UTC+09:00 などと表記するのは前述したとおりです。一方で、環境変数 TZJST-9 などと設定したことがある方は多いのではないでしょうか。

符号が +- で逆転していて、混乱しますよね。

この TZ の書式はいわゆる歴史的事情 [53:1] というやつです。歴史上の経緯まで紐解くのはたいへんなので踏み込みませんが、この書式を一般化したものは、現在 POSIX の一部として明記 [54] されています。さらに glibc のマニュアルにも解説 [55] があります。

POSIX からその書式を引用します。 (空白文字はわかりやすさのための筆者による追記)

std offset [dst [offset] [,start[/time],end[/time]]]

必須項目は std offset ですね。 JST-9JST の部分が std にあたり、次の -9 の部分が offset にあたります。 JST は忌まわしきタイムゾーン略称ですが、これは歴史の経緯でいかんともしがたいところです。そして offset は以下のように解説されています。

Indicates the value added to the local time to arrive at Coordinated Universal Time.

「現地時刻にその値を足すことで UTC になる値」ですね。日本時間は UTC より 9時間先行するので、「日本時間に負の値 -9 を足すことで UTC になる」わけです。身も蓋もない話ですが、日本時間が JST-9 のように - になるのは、「定義からそういうもの」ということでした。

PST8PDT

ここで TZ の書式をもう一度見てみましょう。

std offset [dst [offset] [,start[/time],end[/time]]]

日本時間は JST-9 とシンプルですが、一般化した書式はなんだか長いですよね。必須ではない [...] の項目がいくつもあります。この dst と、二つ目の offset はなんでしょうか。

アメリカ合衆国のタイムゾーン略称で、単なる PSTEDT ではない PST8PDTEST5EDT という表記を見たことがある人もいるかもしれません。これこそが std offset [dst] まで使った表記です。たとえば PST8PDT は「標準時は PST8 時間足すと UTC になる。そして夏時間は PDT である」を意味する TZ の表記だったのですね。

この書式はアメリカ合衆国のタイムゾーン以外でも有効で、たとえばイギリスで GMT0BST や、フランス・ドイツで CET-1CEST と書いたりもできます。日本に夏時間が導入されたら JST-9JDT とかになります。ただ、アメリカ合衆国の PST8PDT, MST7MDT, CST6CDT, EST5EDT だけは一部で特別あつかいをされていて、たとえば対応する項目が tzdb 中に直接書いてあったりもします。

Zone    EST5EDT                  -5:00  US      E%sT
Zone    CST6CDT                  -6:00  US      C%sT
Zone    MST7MDT                  -7:00  US      M%sT
Zone    PST8PDT                  -8:00  US      P%sT

二つ目の offset が省略されていると、「夏時間は標準時より 1時間先行する」というのがデフォルトの解釈になります。ほとんどの国や地域の夏時間制では、夏時間は標準時より 1時間先行するので、二つ目の offset を書くことはほぼありません。希少な例外である Lord Howe 島では、どうやら LHST-10:30LHDT-11 などと書くようです。

それ以降の [,start[/time],end[/time]]] を直接書く機会は、ほぼないでしょう。興味がある方は POSIX [54:1] や glibc のマニュアル [55:1] を読んでみてください。

TZ=Asia/Tokyo

昔から Unix-like な環境をさわっている人としては、つい「TZ に設定するのは JST-9 だ」という気がしてしまうのですが、少なくとも現在では TZ=Asia/Tokyo などと tzdb ID を直接 TZ に設定できるし、そうすることが多いようです。 [56]

そもそもタイムゾーン略称を使わないほうがいいこと (前述) や、この表記にあまり汎用性がないこと [57] を考えると、現在では TZ にも tzdb ID を使うのがいいのではないでしょうか。 [58]

脚注
  1. 今は。 ↩︎

  2. 今は。 ↩︎

  3. 「自民、五輪サマータイムを断念」 (2018年10月31日、共同通信社) ↩︎

  4. 「サマータイム制度に反対する意見」 (2008年7月14日、日本労働弁護団) ↩︎

  5. つまり筆者の呪い。 ↩︎

  6. たぶんたくさんある。 ↩︎

  7. 筆者も知りたいので。 ↩︎

  8. リンクは日本語版のほうだったりします。 ↩︎

  9. ところでインターネットタイム (Wikipedia) ってどうなったんですかね。 ↩︎

  10. 標準時とタイムゾーンという概念が普及する前は、その街で見える太陽の位置にその街の時計を合わせていたので、実際にそれに近い状態だったようです。 (Wikipedia:標準時#標準時の歴史) ↩︎

  11. 日本標準時が施行された 1887年より前には、東京にも東京の地方時がありました。昔の日時を操作していると顔を出すことがある +09:18:59 などのオフセットは、このころの東京地方時を UTC との時差で表現しようとしたものです。次の記事に詳しい解説があります: 「18分59秒をめぐって日本標準時の歴史をひもとくことに」 (2018年 12月 12日、エムスリーテックブログ) ↩︎

  12. 広い地域にまたがる「標準時」の概念は、鉄道の普及とともに「鉄道時間 (railway time)」としてまずイギリスで 1847 年に導入され、そこから 1884年の国際子午線会議を通して各国に広がったようです。 (Wikipedia(en):Standard time) ↩︎ ↩︎

  13. 「標準時」は後述する「夏時間」とは別の時刻ですが、「常用時」は、それが標準時であれ夏時間であれ「その地域のその時点で人々が使っている有効な時刻」のことを指します。 ↩︎

  14. いわゆる「日付変更線」も同様で、日付変更線という「線」が国際的に定められているわけではありません。 ↩︎

  15. "A time zone is an area that observes a uniform standard time for legal, commercial and social purposes." (Wikipedia (en): Time zone) ↩︎

  16. コロラド州は夏時間を採用し、アリゾナ州の大部分は夏時間を採用していません↩︎

  17. 古い Windows 95 などで、タイムゾーンの設定が「(GMT+09:00) 東京、大阪、札幌、ソウル、ヤクーツク」などとなっていたのを覚えている方もいるかもしれません。 ↩︎

  18. グリニッジ標準時は、前述の「鉄道時間」 [12:1] でもありました。 ↩︎

  19. 物理的に厳密な 24時間ってなんだ、という相対論的なツッコミはおいておいてください。 ↩︎

  20. 世界時の種類には UT0, UT1, UT2 などがあります。 UT2 の用途は後述の UTC でほぼ置き換えられ、もう実質的に使われていないようですが。 ↩︎

  21. あくまで筆者が知るかぎりでは。ご存じの方がいらっしゃいましたら、ぜひ教えてください。 ↩︎

  22. Stack Overflow の質問 "Daylight saving time and time zone best practices" や、同 tag wiki の timezone では "time zone" と "time zone offset" と呼び分けています。 ↩︎

  23. アメリカ系では "Daylight Saving Time" と、ヨーロッパ系では "Summer Time" と呼ばれることが多いです。 ↩︎

  24. ほとんどの地域では 1時間進みます。 30分だけ進むオーストラリアの Lord Howe 島のような地域も、少数ながら存在します。 ↩︎

  25. 2007年以降 2021年時点のアメリカ合衆国では、毎年三月の第二日曜日に夏時間に切り替わり、その後十一月の第一日曜日に標準時に戻る、という規則になっています。 ↩︎

  26. 「欧州議会、サマータイム廃止の法案を可決 2021年に」 (2019年 3月 28日、朝日新聞) ↩︎

  27. 「これで最後?EUが夏時間へ 廃止検討するも議論進まず」 (2021年 3月 27日、朝日新聞) ↩︎

  28. "Why Europe Couldn’t Stop Daylight Saving Time" (March 11, 2021, Bloomberg) ↩︎

  29. 「サマータイム廃止でイタリアは最後の夏時間」 (2021年 3月 21日、ニューズウィーク日本版内 World Voice) ↩︎

  30. 「カリフォルニア州、住民は夏時間の変更を支持」 (2018年11月19日、日本貿易振興機構) ↩︎

  31. 相対論的なツッコミは (ry ↩︎

  32. ちなみに歴史的には「Unix time という言葉は秒単位 (秒精度) の整数までしか指さない」という説もあります。それにのっとると「Unix time の小数部」というのはちょっとおかしいのですが、現代の POSIX の clock_gettime は秒またはナノ秒単位ということなので、本記事の Unix time は小数部を持つ数も指す定義にしています。 ↩︎

  33. 『「うるう秒」障害がネットで頻発』 (2012年 7月 2日、 WIRED NEWS) ↩︎

  34. そのような手法が公に議論されたのは、ケンブリッジ大学の Markus Kuhn 氏による 2000 年の UTS (Smoothed Coordinated Universal Time) が最初のようです。 ↩︎

  35. 2006年には IETF Internet Draft としても公開されています。 ↩︎

  36. "Smear" は「なすりつける」「こすって不鮮明にする」のような意味です。 ↩︎

  37. Wikipedia:tz database ↩︎

  38. "seismo!elsie!tz ; new versions of time zone stuff" (Nov 25, 1986) ↩︎

  39. 日本語でも「東京時間で」「ニューヨーク時間で」などというのと同じような感覚だと思います。 ↩︎

  40. 国が関係する状態は変わりやすいので、政治的事情による変更に対して頑健であるためだとする記載があります。人が生活する単位としての「都市」はそれよりは長く維持される傾向にあると考えられているようです。要出典。ちなみに初期の提案では、国名を使うつもりがあったようです。 ↩︎

  41. "ICANN to Manage Time Zone Database" (October 14, 2011) ↩︎

  42. ちなみに、現在 tzdb データのメンテナンスの中心人物である Paul Eggert 氏のページには、多くの重要な情報がまとまっています。 ↩︎

  43. たとえば Asia/Tokyo でも、古い BSD ユーザーにはおなじみの South Ryukyu Islands 時間問題 がありました。その South Ryukyu Islands 時間問題に関する調査報告などもあります。比較的最近でも、第二次世界大戦中の情報について一部修正されたりしています。 ↩︎

  44. 古い歴史には解釈にも揺れがあるため、「正確なもの」はそもそも定義できない、とも考えられます。 ↩︎

  45. Wikipedia (en): Indian Standard Time ↩︎

  46. 実際に米軍で使われているものと正負が逆だった、という、なかなか豪快な間違いでした。 RFC 822 は A-1 としていますが、実際に米軍で使われていた A+1 です。 ↩︎

  47. もちろん、これを "Israel Standard Time" などと呼び替えるのがきわめて難しいのは想像に難くないでしょう。 tzdb が ID に国名を使わない方針にしたのと同じ理由で、都市名で呼ぶのが現実的だということではないでしょうか。 ↩︎

  48. たとえば「JST+09:00 として読み込む」など。 ↩︎

  49. アメリカ合衆国とはややこしい関係にある国ばかりですが、偶然か必然か。 ↩︎

  50. このサンプル・コードは、古い Java API ではなく新しい JSR 310 の DateTimeFormatter を使っていますが、同様の挙動を見せています。この Java とタイムゾーン略称の歴史をさかのぼると、実は旧 API で一度は修正されています。しかし JSR 310 の DateTimeFormatter でも一部機能でこの挙動が再導入されていて、このサンプル・コードはその例になっています。実はもう少し深堀りしてみたのですが長大な内容になったので、その話は「Java 編」の「おまけ」として分離しました。興味のある方はそちらをご覧ください。 ↩︎

  51. Ruby (特に Ruby on Rails) の話や JavaScript (temporal とか) をふくむ Web ブラウザ環境の話、あと MySQL や PostgreSQL と JDBC の話など、深いところを読んでみたいトピックはいろいろあります。筆者も Ruby の話 (Rails 以外) と Linux の話を少々くらいは書けるかもしれませんが、本当に詳しい方におまかせしたいなあ、と思っています。 ↩︎

  52. いまでも違うわけではありませんが。 ↩︎

  53. どなたか「Unix(-like) 編」を書いて、ぜひ歴史なども含めてじっくり解説してください。 ↩︎ ↩︎

  54. 8. Environment Variables, The Open Group Base Specifications Issue 7, 2018 edition. ↩︎ ↩︎

  55. 21.5.6 Specifying the Time Zone with TZ, The GNU C Library ↩︎ ↩︎

  56. TZ=Asia/Tokyo って、実は昔からできたんでしょうか? 筆者が Unix-like な環境をさわり始めた 2000年前後には TZ=JST-9 とするのが一般的だった気がしていて、いつごろを境に実装や慣習が変わっていったのか、筆者は把握できていません。情報をお持ちの方がいらっしゃいましたら、ぜひお寄せください。 (というか「Unix 編」を…) ↩︎

  57. たとえばカリフォルニア州だけ夏時間を廃止したら、カリフォルニア州の環境だけ、いちいち TZ=PST8PDT から TZ=PST8 に変えなければなりません。最初から TZ=America/Los_Angeles としてあれば tzdb を更新するだけで済みます。 ↩︎

  58. Paul Eggert 氏のページにも、これを支持する記述がいくつかあります。 ↩︎

この記事に贈られたバッジ