メインコンテンツへスキップ
ブログ一覧に戻る
Web制作・運用

「日時はUTCで保存すれば安全」は、どこまで正しいのか

2026年9月18日
最終更新: 2026年10月8日
7分で読めます

この記事でわかること

UTCの瞬間、地域に結びつく予定、日付だけの値を分け、日時設計の判断軸を解説します。RFC 9557のZと+00:00、オフセットと地域名の違いを確認し、パリの夏時間を使った計算で意図のずれを可視化。将来予定の重複・欠落や規則更新、IANAの互換名、入力と表示の責任、境界テストまで具体的に整理します。

2026年10月8日にRFC 3339の本文を再確認した。UTCは瞬間を共有する基準として有用だが、利用者へ表示する日時や「毎日9時」の予定には地域のタイムゾーン、DST、カレンダー、入力の意図が必要である。保存する値の型、タイムゾーン識別子、表示規則、期限・再計算、ログの基準を分け、UTC保存だけで地域時間の意味や将来のルール変更が消えるとは扱わない。

UTCで保存すると、同じ瞬間を比較しやすくなります。ただし「いつ起きたか」と「現地の何時に実施したいか」は異なるデータです。予約、締め日、誕生日まで一つの日時型へ押し込む前に、保存したい意味を決めます。

30秒で要点

  • 発生済みイベントの瞬間、地域に結びついた予定、日付だけの値を分ける。
  • +09:00はオフセット、Asia/Tokyoは地域の規則を参照する名前。役割は同じではない。
  • 夏時間の重複・欠落、規則更新、入力と表示の責任を決め、境界の例を検証する。
UTCの瞬間と現地予定を分け、パリの冬夏と固定オフセットの1時間差を示す図
説明用の日時設計図。暦の加算と経過時間を混同せず、将来予定は別に契約する。

先に「保存したい意味」を分類する

以下は著者作成の設計表です。特定のDB型やライブラリを一律に指定するものではありません。

表が収まらない場合は、横にスクロールできます

業務の値保持したい意味保存・表示を考える例
注文を受け付けた記録起きた瞬間UTCの瞬間を記録し、必要なら表示地域を別に持つ
毎週月曜の現地9時の会議地域の暦に沿う繰り返し現地時刻、地域名、繰り返し規則、例外日の扱い
利用者の誕生日日付日付として扱い、勝手に午前0時のUTCへ変換しない
国外との契約締切どの地域の何時までか指定地域・入力根拠・確定した瞬間と変更方針

UTCは記録の比較に役立ちますが、「半年後の同じ現地時刻」をUTC秒数の加算だけで作れるとは限りません。逆に「正確に24時間後」という経過時間の要件なら、暦日の加算とは別に扱います。

オフセットだけでは地域の規則は分からない

2020-01-01T00:00+01:00という値から分かるのは、その時点でUTCより1時間進んでいることです。その地点が将来夏時間を使うか、政治的な変更があるかまでは分かりません。

RFC 9557 §1.2には、パリの日時へ6か月を加える例があります。次はその条件を使った説明用の計算表です。経過した秒数を6か月と呼んでいるのではなく、暦の月を進めています。

表が収まらない場合は、横にスクロールできます

条件現地で意図する日時対応するUTC
冬のパリ、オフセット+01:002020-01-01 00:002019-12-31 23:00
6暦月後もパリの00:002020-07-01 00:00、+02:002020-06-30 22:00
+01:00固定のまま同じ暦表示を作る2020-07-01 00:00、+01:002020-06-30 23:00

下2行の瞬間は1時間違います。固定オフセットの時刻が業務上必要な場合もありますが、「地域の予定」の代用だと意味が変わります。同RFCが明示的に禁じるのは、他のプログラムが地域サフィックスを要求するからと、元のオフセットをそのままオフセット形式のゾーンへコピーして満たす操作です。固定オフセットという概念そのものを全面禁止している、とは読みません。

RFC 9557でのZと+00:00

RFC 9557 §2.2–2.3は、Zを「UTCの時刻は既知だが、現地へのオフセットは未知」という意味へそろえています。+00:00はUTCを優先する参照点という含意を保ちます。

これは2026-10-06T00:00:00Zと2026-10-06T00:00:00+00:00が数値上、別の瞬間になるという話ではありません。文字列が表す追加の意味を、システム間でどう伝えるかの問題です。手元の日時ライブラリがこの意味の差を保存・再出力できるかは別途確認が必要です。

IXDTFの地域サフィックスとオフセットが矛盾するときも、無条件に片方を優先してよいとは限りません。§3.3–3.4ではcriticalな情報と任意情報で処理条件が異なります。独自APIで扱うなら、矛盾を拒否するか、利用者へ確認するかを契約に書きます。ライブラリが文字列を受理しただけで意味まで検証済みとは判断しません。

将来の現地予定は別の設計課題

RFC 9557 §1.1は、地域規則の変更で対応する瞬間も変わる将来の現地時刻や、地域を持たないfloating timeを、この拡張形式の対象外としています。したがって「RFC 9557を使えば将来の会議も自動解決」とは言えません。

著者作成の予定入力例なら、次の項目を最初に決めます。

表が収まらない場合は、横にスクロールできます

決定項目架空の会議サービスでの方針例
利用者の意図Europe/Parisの毎週月曜09:00を守る
存在しない現地時刻自動でずらさず、別時刻を選んでもらう
二度現れる現地時刻早い側・遅い側の候補とオフセットを示して選択を記録
規則更新将来の開催分を再評価し、変更があれば担当者へ確認
監査入力値、選択した地域、解決方針、使用した規則の版を記録

この方針がすべてのサービスに適するわけではありません。交通、給与計算、ログの集計では、別の責任分担が必要です。重複を拒否する設計も、自動選択する設計も、利用者の意図と検証可能性を確認して選びます。

IANAの名前とデータの限界

IANA tzデータベースの説明は、地域の過去と予測される将来の民間時刻を扱います。古い時代のすべての地点を完全に再現する保証はなく、将来の規則も変わり得ます。

US/Easternのような旧名は、互換リンクとして対応されている場合があります。名称が古いというだけで無効と判定したり、文字列を一括置換したりしないでください。使用中のライブラリで受理される名前、正規化結果、保存済みデータの読み戻しを確認します。表示名は利用者が選びやすい説明にしても、内部の地域識別子とは分けます。

具体的に何をテストするか

  1. UTCの同じ瞬間を東京とパリで表示し、入力値を失っていないか確認する。
  2. 夏時間の開始・終了付近で、存在しない時刻と二重になる時刻を与える。
  3. 月末や閏日を含む暦の加算と、一定時間の加算を区別する。
  4. オフセットと地域名が矛盾する値、地域不明の入力を渡す。
  5. 規則の版を更新した前後で、将来予定と過去ログの扱いが契約どおりか照合する。

試験結果にはランタイムと時刻規則の版、入力、期待する意味、出力を残します。本稿のパリの計算も説明用の限定例であり、利用中のすべての環境や将来の政治的変更を検証したものではありません。

よくある質問(FAQ)