システム連携で日時がずれる原因|UTCとJST、ISO 8601の正しい書き方
システム連携でよくある報告です。
- 登録日が1日前になっている
- 朝8時に処理したデータだけ、前日扱いになる
- ExcelからCSVで書き出したら、日付が「46251」という数字になっていた
いずれも日時データの扱いが原因ですが、それぞれ別の理由から起きています。
日時は数字と同じ「値」のはずなのに、なぜずれるのか。
答えは、日時が「いつ」だけでなく「どこの時刻か」という情報を必要とするからです。この情報が欠けたまま受け渡されると、受け取った側が勝手に補ってしまいます。
原因1:UTCとJSTの9時間差
世界の標準時刻はUTC(協定世界時)で、日本時間(JST)はそこから9時間進んでいます。同じ瞬間を両方の書き方で表すと、こうなります。
| 日本時間(JST) | 同じ瞬間のUTC |
|---|---|
| 2026-08-17 08:00 | 2026-08-16 23:00(前日) |
| 2026-08-17 12:00 | 2026-08-17 03:00 |
| 2026-08-17 23:30 | 2026-08-17 14:30 |
注目すべきは1行目です。日本時間の午前9時より前は、UTCではまだ前日になります。
「朝の早い時間に登録したデータだけ日付が前日になる」という現象は、これで説明がつきます。海外のクラウドサービスはUTCで記録することが多く、日本時間に変換せずそのまま表示すると、始業前の時間帯だけ日付がずれて見えるわけです。
不具合が「朝だけ」「特定の時間帯だけ」起きるなら、タイムゾーンを疑う価値があります。
原因2:日時の書き方が統一されていない
日時の表記方法は無数にあります。2026/08/17、08/17/2026、17-08-2026——どれも同じ日を指しますが、機械は解釈に迷います。特に03/04/2026のような表記は、3月4日とも4月3日とも読めます。
この混乱を避けるため、インターネット上で使う日時の書式を定めたのがRFC 3339です。基本形はこうなります。
2026-08-17T09:00:00+09:00
└──日付──┘ └─時刻─┘└オフセット┘
3つの部分に分かれています。
| 部分 | 意味 |
|---|---|
T |
日付と時刻の区切り記号 |
+09:00 |
UTCとの時差(日本は+9時間) |
Z |
+00:00と同じ。UTCそのものを表す |
末尾のZは「Zulu(ズールー)」と読み、UTCを意味します。2026-08-17T00:00:00Zと2026-08-17T09:00:00+09:00は、表記は違うが同じ瞬間を指します。
もう一つの形式:UNIXタイムスタンプ
APIのレスポンスを見ると、日時が数値で返ってくることがあります。
{"created_at": 1786924800}
これはUNIXタイムスタンプと呼ばれ、1970年1月1日0時(UTC)からの経過秒数を表します。上の値は2026年8月17日9時(日本時間)です。
この形式には明確な利点があります。基準がUTCに固定されているため、タイムゾーンの曖昧さが原理的に発生しません。計算や大小比較も容易です。半面、人間が見て日時が分からないという欠点があります。
扱う際は2点に注意が必要です。
| 注意点 | 内容 |
|---|---|
| 秒かミリ秒か | JavaScriptはミリ秒単位、多くの言語や仕様は秒単位。取り違えると1000倍ずれる |
| 2038年問題 | 32ビット整数で扱うと2038年1月19日(値2147483647)で上限に達する |
桁数で見分けられます。10桁なら秒、13桁ならミリ秒です。「日時が1970年になっている」「とんでもない未来の日付になっている」という症状は、この単位の取り違えで起きます。
タイムゾーンのない日時は「解釈待ち」の状態
問題になるのは、オフセットが付いていない日時です。
2026-08-17 09:00 ← どこの9時か不明
この値を受け取ったシステムは、自分の設定に従って解釈します。日本のサーバーならJST、海外のサーバーならUTCと判断するかもしれません。同じデータが環境によって別の時刻になるわけです。
RFC 3339は、この曖昧さを避ける方針を明確に述べています。
地域ごとの夏時間ルールは非常に複雑で、地域の法律によって予測できない時期に変更されうる。したがって真の相互運用性は協定世界時(UTC)を使うことで最もよく達成される
データとして保存・送受信するなら、UTCに揃えるのが基本方針になります。JSONには日付専用の型がないため、この書式を文字列として使うのが実務上の標準です。
【重要】未来の予定はUTCで固定してはいけない
ここまで「UTCで持つ」と書きましたが、例外があります。それが未来の予定です。
RFC 3339には、示唆に富む注記があります。
2005年3月23日のニューヨークにおける17:00に対応するUTC時刻は、夏時間に関する行政上の決定に依存しうる
夏時間の切り替え日は法律で決まっており、政治的な判断で変更されることがあります。過去にも欧米各国で切り替え時期の変更が行われてきました。
つまり「来年3月のニューヨーク現地17:00の会議」をUTCに換算して保存すると、その後に法改正があった場合、保存した値が現地の17:00を指さなくなります。
| データの性質 | 持ち方 |
|---|---|
| 過去の記録(ログ・取引履歴) | UTCで固定する |
| 未来の予定(会議・締切) | 現地時間+地域名で持つ |
「起きた事実」は瞬間が確定しているのでUTCで固定できます。一方「これから起きる予定」は、現地の人にとっての時刻が本質なので、Asia/TokyoやAmerica/New_Yorkといった地域名とセットで保存し、表示のたびに最新のルールで計算するのが正しい設計です。
日本は現在、夏時間を採用していないため国内だけなら意識せずに済みますが、海外拠点や海外サービスと連携する場合には避けて通れません。
原因3:Excelの日付は「数字」である
3つ目の原因はExcel特有のものです。Excelは日付を文字ではなく1900年1月1日からの経過日数として記録しています。これをシリアル値と呼びます。
| 日付 | シリアル値 |
|---|---|
| 1900-01-01 | 1 |
| 1900-02-28 | 59 |
| 1900-03-01 | 61 |
| 2026-08-17 | 46251 |
画面には「2026/8/17」と見えていても、中身は46251という数値です。書式設定を外したりCSVに書き出したりすると、この数字がそのまま出てくることがあります。冒頭の「日付が46251になった」はこれが原因です。
存在しない日付が有効になっている
上の表をよく見ると、60が抜けています。1900年2月28日が59で、3月1日が61。間の60は何かというと、1900年2月29日です。
ところが1900年はうるう年ではありません。西暦年が100で割り切れる年は、400でも割り切れない限りうるう年にならないためです。つまりExcelは実在しない日付を有効なものとして扱っています。
マイクロソフトはこれを不具合と認めたうえで、公式に理由を説明しています。当時普及していた表計算ソフトLotus 1-2-3が同じ扱いをしており、シリアル値の互換性を保つために意図的に合わせたというものです。
そして今も修正されていません。修正すれば他ソフトとの互換性が壊れるうえ、実害が1900年3月1日より前の曜日計算に限られるためです。30年以上前の互換性判断が、現在のファイルにも残り続けているわけです。
MacのExcelで日付が4年ずれる問題
もう一つ、Excelには1904年を起点とする日付システムがあります。古いMac版Excelの既定だったもので、この設定のファイルを混在させると日付がずれます。
マイクロソフトの資料によれば、2つの日付システムの差は1,462日です。同じ日付でも、1900年システムのシリアル値は1904年システムより常に1,462日大きくなります。約4年と1日のずれです。
古いMacで作られたファイルを開いたときに日付が数年ずれていたら、この設定を疑ってください。
実務での指針
整理すると、次の方針が基本になります。
- 保存はUTC、表示はローカル時刻。データベースやログはUTCで統一し、画面に出すときだけ変換する
- やり取りにはオフセット付きの書式を使う。
2026-08-17T09:00:00+09:00のように、時差の情報を必ず含める - 未来の予定は現地時間+地域名で保存する
- Excelから出すCSVは書式に注意する。日付列は文字列として扱うか、書き出し前に表示形式を確認する
CSVでのデータ受け渡しでは、文字コードと並んで日付の扱いが事故の起きやすい箇所です。仕様書に「日付形式:ISO 8601(例:2026-08-17)」と明記しておくだけで、多くのトラブルを防げます。
よくある質問
Q. なぜ末尾がZなのですか?
UTCを表す軍事用の呼称「Zulu time」に由来します。+00:00と同じ意味です。
Q. GMTとUTCは違うものですか?
日常的にはほぼ同じ意味で使われますが、GMTは天文観測に基づく時刻、UTCは原子時計に基づく時刻という違いがあります。システムで扱う際はUTCを使うのが標準です。
Q. データベースにはどちらで保存すべきですか?
過去の記録はUTCが基本です。ただしタイムゾーン対応の型(PostgreSQLのtimestamptzなど)を使えば、保存時に自動でUTCに変換されます。日本国内だけで完結するシステムならJSTで統一する選択もありますが、海外連携が発生した時点で見直しが必要になります。
Q. 「日付だけ」のデータはどう扱えばいいですか?
誕生日や締切日のように時刻を持たないデータは、タイムゾーン変換をしないのが正解です。日時型に変換すると、0時を基準に9時間ずれて前日や翌日になる事故が起きます。2026-08-17という文字列のまま扱うのが安全です。
Q. うるう秒は考慮すべきですか?
通常の業務システムでは意識する必要はほとんどありません。金融取引や科学計測など、秒単位の厳密さが求められる分野でのみ問題になります。
参考にした主な調査・資料
- RFC 3339: Date and Time on the Internet: Timestamps(IETF)— インターネット上での日時表記の仕様。UTC推奨の理由と夏時間に関する注記
- Date systems in Excel(Microsoft)— シリアル値の仕組みと、1900年・1904年システムの1,462日差
- Excel incorrectly assumes that the year 1900 is a leap year(Microsoft)— 1900年をうるう年として扱う仕様と、その理由
まとめ
日時のずれは、原因を分けて考えると整理できます。
- UTCとJSTは9時間差。日本時間の朝9時より前はUTCでは前日になる
- オフセットのない日時は受け取った側が勝手に解釈する
- RFC 3339はUTCでの統一を推奨している
- ただし未来の予定はUTCで固定しない。夏時間は法律で変わりうる
- Excelの日付はシリアル値という数字。1900年うるう年バグは互換性のため今も残る
- 1900年と1904年の日付システムは1,462日ずれる
- 日付だけのデータは変換しない。9時間のずれで前日・翌日になる
「朝だけずれる」「1日だけずれる」「4年ずれる」——ずれ方に注目すれば、原因の切り分けは難しくありません。