もう迷わない!JavaScript日付とタイムゾーンの扱い方 #2 - new Date() の挙動を正しく理解する
はじめに
こんにちは!
今回は new Date() の挙動についてまとめていきます。 JavaScriptは日付の扱いに癖があると言われますが、その原因の一端はこのnew Date()にあると思います。
new Date()の挙動をしっかり理解して、うまく付き合っていきましょう!
日付オブジェクトの生成 (new Date)
- 日付オブジェクトを生成するには
new Date()を用いる new Dateは内部的には UTC しか扱えない
new Date()の挙動
パターン①:引数なし(現在時刻を取得)
const date = new Date(); console.log(date.toISOString()); // 実行環境が JST (UTC+09:00) で2025-05-18 00:00:00 に実行した場合 // -> 2025-05-17T15:00:00.000Z // 実行環境が NY (UTC-04:00) で2025-05-18 00:00:00 に実行した場合 // -> 2025-05-18T04:00:00.000Z
パターン②:YYYY-MM-DD(日付だけ)
const date = new Date("2025-05-18"); console.log(date.toISOString()); // 実行環境に関わらず、2025-05-18T00:00:00.000Z
パターン③:YYYY-MM-DDTHH:mm:ss(日時)
- ローカルタイムとして解釈し、UTCのミリ秒値に換算して保持
const date = new Date("2025-05-18T00:00:00"); console.log(date.toISOString()); // 実行環境が JST (UTC+09:00) の場合 → 2025-05-17T15:00:00.000Z // 実行環境が NY (UTC-04:00) の場合 → 2025-05-18T04:00:00.000Z
パターン④:YYYY-MM-DDTHH:mm:ss+09:00(タイムゾーン付き)
const date = new Date("2025-05-18T00:00:00+09:00"); console.log(date.toISOString()); // 実行環境に関わらず、2025-05-17T15:00:00.000Z
なぜ toISOString() を使って比較するのか?
toISOString()は UTC基準のISO 8601形式 で出力する仕様console.log()は実装によって挙動が異なるtoISOString()は必ずUTC基準の時刻で出力=Z(Zulu = UTC)が付いて表示される+9:00のような表記になることもない
- そのため、比較に有用なので今後のシリーズでは
toISOString()で基本的に比較する
YYYY-MM-DD が UTC として扱われる理由(例外的仕様)
- これは他の引数パターンと整合性がとれておらず、開発者が混乱する原因
- 本来のECMAScriptの仕様上は、日付だけの引数もローカルタイムとして解釈するはずだったが、過去の実装など歴史的な経緯からUTCとして解釈される
タイムゾーンオフセットがない場合、日付のみの形式は UTC 時刻として解釈され、日時形式はローカル時刻として解釈されます。 これは過去には ISO 8601 に適合しない仕様があったためですが、ウェブの互換性のために変更できませんでした。 Date - JavaScript | MDN
まとめ:new Date(...) に与える引数とその挙動の違い
| 入力形式の種類 | 解釈タイムゾーン | 内部処理の挙動 |
|---|---|---|
引数なし (new Date()) |
ローカルタイム | 現在のローカルタイムを UTC に換算してミリ秒で保持 |
"YYYY-MM-DD"(日付のみの文字列) |
UTC(例外的) | 与えられた日付の 00:00:00 を UTC として解釈し、ミリ秒で保持 |
"YYYY-MM-DDTHH:mm:ss" |
ローカルタイム | ローカルタイムとして解釈し、UTC に換算してミリ秒で保持 |
"YYYY-MM-DDTHH:mm:ss+09:00" など |
明示されたタイムゾーン | 指定されたタイムゾーンでの時刻を UTC に換算してミリ秒で保持 |
おわりに
今回はnew Date() の挙動についてまとめました。個人的には、「タイムゾーンを保持しない」、「内部でUNIXのミリ秒を保持」という2点を押さえたことで、かなり理解が深まりました。
次回は、生成した Date を「どう文字列として出力するか?」について、toString() や toISOString()、toLocaleString() の違いと落とし穴を整理していきます。お楽しみに!