AZ Tools
← ガイド

バグなくタイムゾーンと Unix タイムスタンプを扱う

日付と時刻は不釣り合いに多くのバグを生みます。人間に当たり前に思えることが、コンピューターには本当に複雑だからです: タイムゾーンはずれ、時計は年に二度1時間を飛ばし、「今日」は自分の立っている場所に依存します。本ガイドは中心となる考え方を説明し、ほとんどの日付処理ミスを未然に防ぐいくつかの規則を示します。

時刻は絶対的な瞬間として保存する

最も重要な唯一の規則: 瞬間は絶対的でタイムゾーンに依存しない瞬間として保存・送信します — Unix タイムスタンプ(1970年1月1日 UTC からの秒またはミリ秒)か、UTC の ISO 8601 文字列(末尾が Z)で。瞬間は地球上どこでも同じで、人間向けの表現だけが変わります。

人に値を表示するとき、つまり最も外側の縁でだけローカルのタイムゾーンに変換します。システムの内側は UTC に保ちます。最も苦しい日付バグの多くは、どのゾーンでのローカルかを記録せずに「ローカル」時刻を保存し、値を永遠に曖昧にすることから生じます。

UTC、オフセット、タイムゾーンは同じではない

UTC はグローバルな基準時計です。+09:00 のようなオフセットは、ある瞬間の UTC からの固定のずれです。America/New_York のようなタイムゾーンは、歴史上の各時点でどのオフセットが適用されるか — いつ変わるかを含めて — を記述する名前付きの規則の集合です。

この区別が重要なのは、一つのゾーン内でもオフセットが変わるからです。ニューヨークは冬は -05:00、夏は -04:00 です。オフセットだけを保存すると規則を失い、未来のローカル時刻を正しく計算できません。「毎日ニューヨーク時間の午前9時」を予約するのに、固定オフセットではなくゾーン名が必要なのはこのためです。

夏時間は素朴な仮定を壊す

年に二度、夏時間を採用するゾーンは飛びます。春には1時間が飛ばされ、その日 02:30 のようなローカル時刻はそもそも存在しません; 秋には1時間が繰り返され、01:30 が二度起き曖昧になります。毎日が24時間だと、あるいは与えられたローカル時刻が常に存在すると仮定するコードは、いずれ誤った結果を出すか、クラッシュします。

UTC で作業すればこれを丸ごと回避できます。UTC には夏時間がないからです。表示のためにローカル時刻へ変換するときや人の入力を解釈するときにだけ、その隙間と重なりに直面します — まさにそこで、手作りの計算ではなく検証済みの日付ライブラリが仕事をすべきです。

秒、ミリ秒、そして2038年

Unix タイムスタンプはよく二つの単位で来て、混ぜるのは頻繁なバグです: ほとんどの Unix ツールと API は秒を、JavaScript の Date はミリ秒を使います。1000倍ずれた値はたいてい単位を取り違えた印です — タイムスタンプが急に56000年や、1970年に戻っていたりします。

サイズの上限もあります: 符号付き32ビット整数に保存された Unix 時間は2038年1月19日にオーバーフローします。現代のシステムは64ビット値を使い実用上は問題をなくしましたが、古いシステムが遠い未来の日付を誤って扱う理由を知っておく価値はあります。

ほとんどのバグを防ぐ規則

このどれも日々深い専門知識を要しません — いくつかの習慣が大多数の場合をカバーします。

  • 瞬間は UTC で保存・交換する(Unix タイムスタンプか Z 付きの ISO 8601); 表示のときだけローカルに変換。
  • 未来のローカル時刻が重要なら IANA のゾーン名(例: Europe/Paris)を保持する; オフセットだけでは不十分。
  • 「1日」や「1か月」のために固定の秒数を足すようなカレンダー計算をしない — 夏時間と月の長さを知る日付ライブラリを使う。
  • あらゆる境界で秒かミリ秒かを明確にし、どちらの意味かを表示する。

関連ツール