Dateオブジェクトは「ある一瞬」を表す
JavaScriptの Date は、ある特定の一瞬を表すオブジェクトです。内部的には、1970年1月1日UTC(いわゆる「Unixエポック」)からの経過ミリ秒数という、ただの数値でしかありません。年・月・日・タイムゾーン・フォーマットといったものは、すべてこの数値の上に被せた「見せ方」にすぎないわけです。
now.getTime() が返すのは、ミリ秒単位の生の数値です。Date でやること——比較する、日数を足す、フォーマットする——はすべて、この数値をいじって別の形で読み直しているだけ、と考えるとスッキリします。
このイメージは常に頭の片隅に置いておいてください。Date は「パリの3月14日」という情報を持っているわけではありません。あくまで世界共通の瞬間を表していて、それをパリのタイムゾーンで見れば3月14日、ロサンゼルスで見れば3月13日、というふうに表示が変わるだけなのです。
Date オブジェクトの作り方
Date を作る方法は、大きく分けて4つあります。
注目してほしいポイントが2つあります。
- 引数で指定するコンストラクタの月は0始まりです。
2は3月、1月は0になります。これはバグの温床になりがちですが、API全体を通して月は常に0始まりなので、少なくとも一貫性はあります。 new Date("2026-03-14")(時刻なし)は UTCの午前0時 として解釈されます。一方、new Date("2026-03-14T09:30")(Zなし)は ローカル時刻 として解釈されます。この非対称さは、JavaScriptの日付処理でよくハマるポイントです。
「今この瞬間」を数値で取得したいなら、オブジェクト生成のコストがかからない Date.now() を使うのがおすすめです。
経過時間やタイムアウトの計測など、カレンダー的な計算が不要な場面では Date.now() がベストな選択肢です。
日付から各要素を取り出す
Date オブジェクトを作ったら、あとはゲッターを使って年・月・日といった各要素を取り出します。それぞれにローカルタイム版とUTC版の2種類が用意されています。
ローカル系のメソッドは、コードを動かしているマシンの設定に左右されます。ユーザーやサーバーをまたいで日付を保存したり比較したりするなら、必ず UTC を明示的に指定してください。さもないと、原因不明のバグを追いかけるハメになります。基本方針はシンプルで、DB やログに残す値には UTC 系のゲッター、画面に表示する値にはローカル系のゲッターを使い分けるのが鉄則です。
getYear() は使わないでください。これは 年 - 1900 を返すレガシーなメソッドで、互換性のためだけに残されています。年を取得したいときは、迷わず getFullYear() を使いましょう。
人に見せるための日付フォーマット
自分が気にする用途で date.toString() を使うのは避けてください。出力はロケールや JavaScript エンジンによって変わってしまいます。覚えておく価値があるフォーマッタは 2 つあります。
機械が読みやすい標準的な文字列が欲しいときは、toISOString() を使います。
ログ出力やJSON保存、ネットワーク送信にはこの形式を使います。常にUTCで、曖昧さがありません。
ユーザー向けに表示する文字列が欲しい場合は、Intl.DateTimeFormat か、その薄いラッパーである toLocale* 系メソッドを使いましょう。
Intl.DateTimeFormat はロケール、タイムゾーン、そして欲しいフィールドの組み合わせを一通り面倒見てくれます。${year}-${month}-${day} のように手動で組み立てる前に、まずこちらを検討しましょう。月が1つズレるバグが生まれるのは、だいたいあの手の文字列結合です。
JavaScriptで日付を比較する
同じ時刻を表す2つの Date オブジェクトでも、=== での比較は等しくなりません。=== は値ではなくオブジェクトの同一性を見ているからです。比較するときはタイムスタンプ同士を突き合わせましょう。
比較演算子は内部で数値に変換されるので、日付の大小比較にはそのまま使えます。
引き算をすれば、ミリ秒単位での差分が得られます。日数にしたいなら 1000 * 60 * 60 * 24 で割ってください。最初のうちは定数として書き出しておくといいでしょう。そのうち 86_400_000 を見ただけで「ああ、1日分だな」とわかるようになります。
JavaScript で日付を加算・減算する
addDays のようなメソッドは用意されていません。定石は setDate や setMonth などを使うことです。これらは範囲外の値を渡しても、ちゃんと繰り上がり・繰り下がりを処理してくれます。
特に押さえておきたいポイントが2つあります。
new Date(date)は日付のコピーを作ります。setDateは元の値を書き換える(ミューテート)ので、先にコピーを取らないと呼び出し元の値まで変わってしまいます。- 31日ある月に対して
setDate(35)とすると、自動的に翌月へ繰り越されます。setMonth(14)も同様に、年が進みます。そのおかげで、見た目ほど日付の計算は面倒ではありません。
ただし、営業日の計算、繰り返しイベント、月をまたぐ期間といった込み入った処理には、ライブラリ(date-fns、Luxon、あるいは次世代の Temporal API)を使いましょう。「数日足す」程度を超えるカレンダー計算を自前で書き始めると、まず沼にはまります。
タイムゾーンのずれに要注意
JavaScript の日付処理でバグの温床となる最大の要因がタイムゾーンです。最低限これだけは頭に入れておきましょう。
Dateが内部で保持しているのは UTC の瞬間(インスタント)です。タイムゾーンが反映されるのは、値を取り出したりフォーマットしたりするタイミングだけです。getHours()やgetDate()などが返す値は、コードを実行しているマシンの ローカル タイムゾーンに基づきます。サーバーとブラウザでここが食い違うことはよくあります。new Date("2026-03-14")(日付のみ)は UTC として解析されます。new Date("2026-03-14T00:00")(時刻あり・タイムゾーンなし)はローカルとして解析されます。new Date(2026, 2, 14)(各要素を渡す形式)もローカルです。
表示用に特定のタイムゾーンを指定したい場合は、Intl.DateTimeFormat に timeZone を渡します。
同じ瞬間を、異なる見え方で。Date オブジェクト自体は何も変わっていません。
実際に動かしてみる
ここまでの内容を組み合わせて、「どれくらい前に起きたか」を整形して表示する関数を書いてみましょう。
タイムスタンプを受け取って、人間が読める文字列として返す。実務で書く日付コードの9割はこの形です。2つの瞬間を引き算して、単位で割り、丸めて、フォーマットする。
この章のまとめ
DateはUTCの瞬間を表します。タイムゾーンが登場するのは、値を読み出すときやフォーマットするときだけです。- タイムスタンプが欲しいときは
Date.now()、カレンダー的な処理をしたいときはnew Date()を使いましょう。 - 保存やログ出力には
toISOString()、ユーザー向け表示にはIntl.DateTimeFormatが定番です。 - 日付の比較は
getTime()か</>で。===は絶対にNGです。 - 月は0始まりです。日付だけの文字列をパースするときの落とし穴にも注意。
- 本格的な日付計算をするなら、ライブラリに任せましょう。
次回:URLとクエリ文字列
日付はURLにもよく登場します。日付範囲で絞り込んだり、タイムスタンプをクエリパラメータとして渡したり。URLを手作業でパースしたり組み立てたりするのは、日付を手でフォーマットするのと同じくらいバグの温床です。標準ライブラリにはこれをきれいに扱える URL オブジェクトが用意されているので、次回はそれを見ていきます。
よくある質問
JavaScriptで現在の日時を取得するには?
引数なしで new Date() を呼べばOKです。実行した瞬間を表す Date オブジェクトが返ってきます。単に1970年からの経過ミリ秒(タイムスタンプ)が欲しいだけなら Date.now() のほうが高速で、オブジェクトを生成しない分ムダがありません。
2つの日付を比較するにはどうすればいい?
Date オブジェクト同士ではなく、タイムスタンプで比較するのが基本です。a.getTime() < b.getTime() はもちろん、a < b も < が日付を数値に変換してくれるので動きます。ただし a === b はダメです。=== はオブジェクトの同一性を見るので、同じ瞬間を表す Date でも別インスタンスなら絶対に一致しません。
JavaScriptで日付をフォーマットするには?
ユーザーに見せる用途なら Intl.DateTimeFormat か date.toLocaleDateString() が鉄板です。ロケールやタイムゾーンをちゃんと扱ってくれます。機械が読む形式なら date.toISOString() で 2026-03-14T09:30:00.000Z のような標準的な文字列が得られます。date.toString() はロケール依存なので、保存用途には使わないほうが無難です。
日付が1日ズレるのはなぜ?
だいたいタイムゾーンが原因です。new Date('2026-03-14') はUTCの午前0時として解釈されますが、date.getDate() は ローカルタイム の日付を返すので、タイムゾーンによっては前日になってしまいます。UTCの日付が欲しいなら getUTCDate() を使うか、最初からローカル基準で動く new Date(year, month, day) で組み立てるのが安全です。