整数時間ではない UTC からのずれ
· 約 1 分
世界のおよそ五分の一が、UTC から整数時間ではないずれの上で暮らしています。そうでないと決めてかかったソフトウェアは、その人たちに対して少し誤るのではなく、30分または45分誤ります。そのほうが悪質です。
一時間刻みの二十四時間帯という頭の中の模型は、高くつく形で誤っています。十億をはるかに超える人々に対して、自信たっぷりに30分または45分ずれたコードを生むからです。一時間まるごとの誤りなら、少なくとも誤りに見えます。45分の誤りは打ち間違いに見え、そのまま出荷されます。
全一覧
:30 のずれ
| ずれ | どこ |
|---|---|
| UTC-09:30 | マルキーズ諸島 |
| UTC-03:30 | ニューファンドランド・ラブラドール州 |
| UTC+03:30 | イラン |
| UTC+04:30 | アフガニスタン |
| UTC+05:30 | インド、スリランカ |
| UTC+06:30 | ミャンマー、ココス諸島 |
| UTC+09:30 | 中央オーストラリア — 北部準州、南オーストラリア州 |
| UTC+10:30 | ロード・ハウ島(標準時) |
:45 のずれ
| ずれ | どこ |
|---|---|
| UTC+05:45 | ネパール |
| UTC+08:45 | 西オーストラリア州南東部(ユークラ、非公式) |
| UTC+12:45 | チャタム諸島(標準時) |
インドだけで14億人です。イラン、アフガニスタン、ミャンマー、スリランカ、ネパールを足せば、オーストラリアやカナダを数える前に地球の五分の一を超えます。
もう一種類の変わったずれ
整数時間でないずれは、よく知られた変わり種です。同じくらい重い話があと二つあります。
幅は24時間ではなく26時間です。 キリバスのキリティマティ島は UTC+14、ベーカー島とハウランド島は UTC-12。26時間の幅があり、つまり地球上のどこかで暦の上の三つの異なる日付が同時に使われている瞬間が存在します。二日分の窓ですべての時間帯を覆えると想定したコードは、一日に二度誤ります。
夏時間はつねに一時間とは限りません。 常住人口およそ380人のオーストラリアの小島ロード・ハウ島は30分ずれます。冬は UTC+10:30、夏は UTC+11:00。これをするのは地球上でここだけであり、日付ライブラリにとって最良の試験例です。60分の切り替えを決め打ちした実装はそこでだけ誤り、ほかのどこでも誤らない。つまり、あなたの書く他のすべての試験に通ってしまいます。
何が壊れるか
最寄りの時に丸めること。 もっともよくある失敗です。ずれを整数の時間として計算するコードは、インドを黙って +5 に切り捨てます。国内のすべての利用者に対して30分の誤りです。
ずれを整数で保存すること。 時間数として宣言された列は、カトマンズを表現できません。たいていはデータが入ってから気づきます。
時の列を土台にした格子の画面。 一日を24個の等しい升目に並べ、各時間帯の現地時が升目の境界に合うと想定した予定表や計画表は、三十分帯と四十五分帯を置き違えます。本サイトの会議調整の帯は、現地時ではなく瞬間を列として使います。だから +05:45 の行は、UTC の行が04:00 を示す列で09:45 を示します。整った嘘ではなく、それが真実だからです。
三十分の夏時間切り替えをまたぐ所要時間の計算。 夏時間の切り替えがちょうど 3,600,000 ミリ秒だと想定すると、ロード・ハウ島で、そしてそこでだけ誤った答えになります。
正しくやる
直し方は、ほとんどすべての時間帯の不具合を直すのと同じです。ずれを自分で計算してはいけません。 実行環境に尋ねてください。
現代の実行環境はどれも IANA のデータベースを備えており、ある時間帯のある瞬間のずれを、分単位で正しく答えます。カトマンズもロード・ハウも含めてです。JavaScript なら timeZoneName: 'longOffset' を指定した Intl.DateTimeFormat、あるいはその時間帯の壁時計の読みを UTC と比べる方法です。本サイトの計算は後者を採っています。1900年より前のデータにある、分未満まで刻まれた地方平均時のずれでも正確なままだからです。
そのうえで三つの規則を守ってください。
- ずれは分です。 けっして時ではありません。変数名が
offsetHoursなら、それ自体がすでに不具合です。 - カトマンズとロード・ハウで試験してください。 ほかのすべてが持ち越させてくれる二つの前提を、この二つが壊します。
- 時間帯を丸めてはいけません。 表示がどうしても概算になるなら、そう書いてください。配置を楽にするために利用者の時計を黙って30分動かしてはいけません。
解いてみせる例 — 45分が格子に何をするか
一日を24列に並べ、一列を一時間とし、参加者それぞれの勤務時間を塗る会議調整の画面を考えます。素朴な実装は、基準の行を時間帯のずれ(時間単位)だけずらして各行を計算します。
ロンドン対ニューヨークならうまくいきます。ニューヨークの行は、ロンドンの行を右に五升ずらしたものです。ロンドン対カトマンズではうまくいきません。カトマンズは5時間45分進んでおり、これは5.75升です。四分の三升などというものはありません。実装は丸めます — たいていは6に — そしてその行のすべての読みが15分早くなります。
誤りは査読を生き延びるほど小さく、影響が出るほど大きい。格子がカトマンズで09:00 と示す09:00 の会議は、現地では本当は08:45 であり、参加する人は自分の一日に十五分遅れて入ることになります。
直し方は、列を時として扱うのをやめることです。各列を_瞬間_にして、その瞬間に各時間帯の現地の壁時計が何を示すかを実行環境に尋ねてください。すると +05:45 の行は、UTC の行が04:00 を示すところで09:45 を示します。見た目に格子とそろわない — それが誠実な描画です。本サイトの会議調整はまさにこれを行っており、カトマンズの行のぎざぎざした端は欠点ではなく特長です。
歴史上のずれはもっと奇妙です
標準化以前、ずれは地方平均太陽時であり、秒まで正確でした。IANA のデータベースはそれを記録しています。
オランダは1909年から1937年まで UTC+00:19:32.13 でした。リベリアは1972年まで UTC-00:44:30 でした。実行環境に1920年のある日の Europe/Amsterdam のずれを尋ねれば、秒まで含めた正確な値を返します。
だからこそ本サイトの下にあるずれの関数は秒で計算し、分への丸めは表示の層でしか行いません。分で保存する実装は、オランダの歴史から32秒を黙って落とすことになります。誰も気づきませんが、それでも誤りです。