概要
JavaScriptにおけるnew Date()は、単なる日付取得ツールではありません。日付操作はもちろん、タイムゾーン変換、フォーマット変換、相対日付計算など、多彩な機能を備え、開発を支える強力なツールです。しかし、実装方法によって異なる挙動になる可能性があるため、意図しない結果を招きやすい落とし穴も存在します。
この記事では、new Date()
を使った日付の値を定義する上で注意すべきポイントについて紹介しています。
new Date()を使った初期化に気を付けましょう
new Date()はいろんな方法で定義することができます。
たとえば、下記の4つの方法でnew Date()
を使って日付を定義することができます。
// 現在時刻取得
const now = new Date()
// 文字列から生成
const dateFromStr = new Date("2023-12-25")
// 数値から生成
const dateFromNumber = new Date(2023, 11, 25)
// タイムスタンプから生成
const dateFromMiliSec = new Date(1672102400000)
"いろんな使い方で定義できて、とても便利ですね〜"
と
思うかもしれませんが、下記の結果に気づいたときはとてもショックでした。
数値からnew Date()で初期化するとき
その他の方法と違って、数値で日付を定義する場合、第2パラメータの月の値は0から始まる値となるため、下記の例では11+1
が実際に定義した日付になります。
はい、11を書いて、12月になるので注意してください。
const dateFromNumber = new Date(2023, 11, 25)
// 出力:Mon Dec 25 2023 00:00:00 GMT+0900 (Japan Standard Time)
対策:
数値だけで日付を指定する場合、new Date()の2番目のパラメータは対象月から1を引いた値を指定しましょう。
文字列からnew Date()で初期化するとき
ちなみに、下記のコードは日本の東京のタイムゾーンで実行しています。
// 区切り記号にスラッシュを使う形式の文字列 下記は同値
// "2024,05,01", "2024.05.01", "2024 05 01",
// "2024,5,01", "2024,05,1"
// "2024.5.01", "2024.05.1"
// "2024-5-01", "2024-05-1", "2024-5-1"
console.log(new Date("2024/05/01"))
// 出力:Wed May 01 2024 00:00:00 GMT+0900 (Japan Standard Time)
// 区切り記号にハイフンを使う形式のISO文字列
console.log(new Date("2024-05-01"))
// 出力:Wed May 01 2024 09:00:00 GMT+0900 (Japan Standard Time)
なぜか、yyyy-MM-dd
だけの時刻が9時間ずれています。
たとえば、上記の時刻をGMT+8(中国標準時間)に換算すると、
区切り記号にスラッシュを使う形式の文字列は日付が変わるのに対して、
区切り記号にハイフンを使う形式のISO文字列は日付が変わりませんでした。
// 区切り記号にスラッシュを使う形式の文字列
Wed May 01 2024 00:00:00 GMT+0900 (Japan Standard Time)
=> Tue Apr 30 2024 23:00:00 GMT+0800 (China Standard Time)
// 区切り記号にハイフンを使う形式のISO文字列
Wed May 01 2024 09:00:00 GMT+0900 (Japan Standard Time)
=> Wed May 01 2024 08:00:00 GMT+0800 (China Standard Time)
すでに気付いているかもしれませんが、下記の2パターンの動作結果になります。
-
区切り記号にハイフンを使う形式のISO文字列の場合:
=> UTC時間(GMT+0000)で日付が定義され、ローカル日付に自動的に換算されます。 - それ以外の形式の場合:
=> ローカル時間でそのまま日付が定義されます。
もしバラバラな方法で日付を定義すると、海外出張をしているユーザーの画面に表示される値は実際のデータと異なる日付になる場合がありますので、注意が必要です。
対策:
バックエンド側から戻り値をnew Date()に渡したい場合は、同じフォーマットになるようインタフェースの仕様から決める必要があります。
もしそれが難しい場合は、date-fnsなどのライブラリを使って、formatしたstring値をnew Date()に渡しましょう。
import { format } from 'date-fns';
const date = new Date(format(returnValue, 'yyyy-MM-dd'))
上記コード例はあくまで参考であり、具体的な実装は状況に応じて調整する必要があります。
より高度な日付処理が必要な場合は、Moment.js, Day.jsなどのライブラリも検討しましょう。
結論
- new Date()に数値だけを渡して日付を設定する際は、2番目のパラメータ(月)が対象月から1を引いた値になることに注意しましょう
- バックエンドとのやり取りで使用する日付フォーマットを明確に定義しましょう
- new Date()に渡す値はフォーマットを統一しましょう