「日付が1日ズレる」の正体 - タイムゾーンの落とし穴と実務での扱い方
執筆: デジタル道具屋 編集部 / バックエンド担当
海外チームを含むサービス開発で、ユーザー時刻のローカライズ実装と分析基盤への保存形式を統一する作業を担当してきた編集チームです。
本記事の執筆方針と編集ポリシーについてはAbout ページをご覧ください。
導入:「お客様の集計だけ1日ズレている」事件


YYYY-MM-DD として保存しておったか、もしくは new Date() を JST のサーバーで実行して日付丸め込みをしておったのではないかね?」
1. UTC、JST、ローカル時刻の関係を整理

- UTC:協定世界時。世界標準。サーバー保存の事実上のデファクト
- JST:日本標準時。常に UTC+9(日本では夏時間が無い)
- ローカル時刻:実行環境(OS / ブラウザ)が認識しているタイムゾーンでの時刻
- DST(Daylight Saving Time):夏時間。米国の多くの州や欧州では年に2回切り替え。日本には無い
「日本に住んでるユーザー向けだから JST 固定でいい」と決めても、ユーザーが海外旅行中に予約を取るケースなどで容易に破綻します。 原則は「保存は UTC、表示時にユーザーのタイムゾーンへ変換」です。
2. JavaScript で日付がズレる典型パターン
パターン1:new Date('2026-05-08') は UTC として解釈される

ECMAScript の仕様(ISO 8601 拡張)では、YYYY-MM-DD 形式(時刻なし)は UTC として扱われます。 一方で YYYY/MM/DD や 2026-05-08T00:00:00(タイムゾーン無し)はローカル時刻と解釈されます。 この差で、JST 環境では1日ズレる事故が頻発します。
// JST 環境
new Date('2026-05-08').toString()
// → "Fri May 08 2026 09:00:00 GMT+0900 (JST)"
// 内部的には UTC 2026-05-08 00:00 なので、JST では 09:00
new Date('2026/05/08').toString()
// → "Fri May 08 2026 00:00:00 GMT+0900 (JST)"
// こちらはローカル時刻として 0:00パターン2:toISOString() は常に UTC を返す
JST 環境で new Date('2026-05-08T08:00:00+09:00').toISOString() は '2026-05-07T23:00:00.000Z' となり、日付部分が前日になります。 これを .split('T')[0] で日付だけ取り出すと、5/8 のはずが 5/7 として保存されてしまいます。

toLocaleDateString('sv-SE') がおすすめ。YYYY-MM-DD 形式でローカル時刻のまま取れるわよ。」3. 実務で守るべき設計ルール
- サーバー・DB には UTC で保存:
TIMESTAMP WITH TIME ZONEやDATETIME(UTC) - API のレスポンスは ISO 8601 + Z 表記:
2026-05-08T12:34:56.789Z - ユーザーのタイムゾーンはプロフィールに保存:
Asia/Tokyoのような IANA 名で - 表示はユーザータイムゾーンで:
Intl.DateTimeFormatやdate-fns-tzを活用 - 「日付だけ」のフィールドは特に注意:誕生日や祝日は UTC ではなくローカル日付として扱う設計に
サマータイム(DST)が刺さるケース
米国・欧州の DST 切り替え当日は、ローカル時刻が「1時間飛ぶ」または「同じ時刻が2回ある」事態になります。 例えば米国西海岸では 3月 第2 日曜の 02:00 が突然 03:00 になります。 毎日 02:30 にバッチを動かすシステムは、その日だけバッチが「存在しない時刻」になり実行されません。 バッチ系は 必ず UTC で時刻を指定するのが鉄則です。

4. 試しながら理解する
「いま UTC で何時?」「東京と NY とロンドンの時差はいくつ?」を即座に確認するなら、当サイトのタイムゾーン変換ツールが便利です。 打ち合わせの設定や、ログのタイムスタンプを別ロケールで読み解くときに使ってください。
🚨 現場での失敗あるある
日本のチームだけで開発・リリースしたサービスを海外展開する直前で、 「全 API レスポンスの日時が JST タイムゾーン無し文字列だった」と発覚するパターンが頻出します。 サービス開始時から ISO 8601 + Z 表記で統一しておけば、後からの追加コストはほぼゼロです。
参考にした一次情報
本記事の内容は、以下の公式仕様や一次情報を参照して執筆しています。
- RFC 3339 - Date and Time on the Internet: Timestamps
IETF
https://www.rfc-editor.org/rfc/rfc3339
- IANA Time Zone Database
IANA
https://www.iana.org/time-zones
- ECMAScript Date Time String Format
ECMA TC39
https://tc39.es/ecma262/#sec-date-time-string-format
この記事の内容を実際に試す
解説した内容は、以下のツールでブラウザ上から無料で試せます。