JavaScriptでアプリケーションを開発する際、日付の計算は避けて通れない重要な要素の一つです。
特に「30日後を計算する」や「1ヶ月後の月末を取得する」といった日付の加算処理は、予約システムやECサイトの配送日計算など、幅広いシーンで活用されます。
かつてのJavaScriptでは、標準のDateオブジェクトが持つ癖の強さに多くのエンジニアが悩まされてきました。
しかし、現在のJavaScript標準仕様には、より直感的で強力な「Temporal API」が登場し、日付操作の常識が大きく変わりつつあります。
本記事では、従来から使われているDateオブジェクトによる加算方法から、最新のTemporal APIを用いたモダンな実装方法まで、実務で役立つ知識を詳しく解説します。
従来のDateオブジェクトによる日付加算の基本
まずは、長らくJavaScriptの標準として利用されてきたDateオブジェクトを用いた加算方法について見ていきましょう。
Dateオブジェクトには「加算専用のメソッド」は存在しませんが、setDate()とgetDate()を組み合わせることで日付を操作できます。
この手法は、加算した結果が翌月や翌年にまたがる場合でも、JavaScriptが自動的にカレンダーの調整を行ってくれるという特徴があります。
日の加算を行う具体的な手順
特定の日に数日を加えたい場合は、現在の「日」をgetDate()で取得し、そこに加算したい数値を足したものをsetDate()に渡します。
// 現在の日付を取得
const date = new Date('2026-05-10');
// 10日後を加算する
date.setDate(date.getDate() + 10);
console.log(date.toLocaleDateString());
2026/5/20
このコードでは、内部的に「10 + 10 = 20」という計算が行われ、日付が更新されています。
もし加算後の数値がその月の最終日を超えた場合、自動的に翌月へと繰り越されます。
月や年をまたぐ計算の挙動
例えば、5月25日に10日を加算した場合、結果は6月4日になります。
const date = new Date('2026-05-25');
// 10日後を加算する
date.setDate(date.getDate() + 10);
console.log(date.toLocaleDateString());
2026/6/4
このように、開発者が「今月は何日まであるか」を意識せずに計算できる点は、Dateオブジェクトの便利な側面です。
月を加算したい場合はsetMonth()、年を加算したい場合はsetFullYear()を使用することで、同様のロジックで計算が可能です。
Dateオブジェクト使用時の注意点とデメリット
Dateオブジェクトでの日付加算には、いくつか注意すべき重要なポイントがあります。
最も大きな注意点は、Dateオブジェクトは「ミュータブル(可変)」であるという点です。
setDate()などのメソッドを呼び出すと、元のオブジェクトそのものが書き換えられてしまいます。
意図しない書き換えを防ぐためのコピー
元の変数を保持したまま新しい日付オブジェクトを作りたい場合は、事前にコピーを作成する必要があります。
const originalDate = new Date('2026-01-01');
// 新しいインスタンスとしてコピーを作成
const futureDate = new Date(originalDate.getTime());
futureDate.setDate(futureDate.getDate() + 7);
console.log('元の日付:', originalDate.toLocaleDateString());
console.log('加算後の日付:', futureDate.toLocaleDateString());
元の日付: 2026/1/1
加算後の日付: 2026/1/8
このコピーの手間を怠ると、コードの他の場所で使用している日付まで変わってしまい、バグの原因となることが少なくありません。
月の指定が「0」から始まる問題
また、JavaScriptのDateオブジェクトでは、月が0(1月)から11(12月)で管理されているという直感に反する仕様があります。
5月を扱いたい場合に「4」を指定しなければならないこのルールは、多くの開発者の混乱を招いてきました。
モダンな解決策「Temporal API」での日付操作
こうしたDateオブジェクトの課題を解決するために導入されたのが、新しい標準仕様であるTemporal APIです。
Temporal APIは、日付計算を直感的かつ安全に行えるように設計された、モダンなJavaScriptの機能です。
最大の特徴は、すべてのオブジェクトがイミュータブル(不変)であるため、メソッドを呼び出しても元のデータが破壊されないことです。
Temporal.PlainDateを使った直感的な加算
カレンダー上の日付のみを扱う場合、Temporal.PlainDateを使用します。
日付を加算するには、非常にシンプルなadd()メソッドを使用するだけです。
// Temporalオブジェクトの作成
const date = Temporal.PlainDate.from('2026-05-10');
// 1週間と2日を加算する
const newDate = date.add({ weeks: 1, days: 2 });
console.log(newDate.toString());
2026-05-19
add()メソッドの引数には、加算したい単位をオブジェクト形式で指定できます。
これにより、従来のsetDate(getDate() + n)のような冗長な記述から解放されます。
Temporal APIが解決する月末問題
日付計算において特に厄介なのが、「1ヶ月後」を計算する際の月末処理です。
例えば、1月31日の1ヶ月後を計算する場合、2月には31日がありません。
Temporal APIでは、このようなケースを制御するためのオプションが用意されています。
const start = Temporal.PlainDate.from('2026-01-31');
// デフォルトでは「2月28日(または29日)」に調整される
const nextMonth = start.add({ months: 1 });
console.log(nextMonth.toString());
2026-02-28
このように、不整合が起きる場合に「切り捨て(constrain)」を行うか「エラーにする(reject)」かを選択することも可能です。
日付操作における代表的な手法の比較
プロジェクトの要件に応じて、どの手法を採用すべきか判断するための比較表を用意しました。
| 機能・特徴 | Dateオブジェクト | Temporal API | 外部ライブラリ (Day.js等) |
|---|---|---|---|
| 標準性 | 標準(全ブラウザ) | 標準(モダン環境) | 外部パッケージが必要 |
| 不変性 | なし (Mutable) | あり (Immutable) | あり (Immutable) |
| 月のインデックス | 0から始まる | 1から始まる | 1から始まる |
| 加算の記述 | 冗長 | 簡潔 | 簡潔 |
| タイムゾーン処理 | 弱い | 非常に強力 | プラグインで対応 |
小規模なスクリプトやレガシーブラウザのサポートが必要な場合はDateオブジェクトが使われます。
一方で、今後の新規開発においては、メンテナンス性の高いTemporal APIの利用が推奨されます。
実務で役立つ日付加算の具体例
ここからは、実際の現場でよく遭遇する日付加算のユースケースをいくつか紹介します。
有効期限(〇〇日後)の算出
ユーザーに発行するクーポンの有効期限を「発行から14日後」に設定する場合の処理です。
function calculateExpiry(issueDateStr) {
const issueDate = Temporal.PlainDate.from(issueDateStr);
return issueDate.add({ days: 14 });
}
const expiry = calculateExpiry('2026-05-01');
console.log(`有効期限は ${expiry} です。`);
有効期限は 2026-05-15 です。
翌営業日の算出(簡易版)
土日を考慮して、次の平日を算出するロジックも加算の応用で作成できます。
function getNextBusinessDay(date) {
let next = date.add({ days: 1 });
// 土曜日(6)なら2日加算、日曜日(7)なら1日加算
if (next.dayOfWeek === 6) return next.add({ days: 2 });
if (next.dayOfWeek === 7) return next.add({ days: 1 });
return next;
}
const friday = Temporal.PlainDate.from('2026-05-22');
console.log(getNextBusinessDay(friday).toString());
2026-05-25
Temporal APIのdayOfWeekプロパティを使えば、曜日判定も1(月曜)〜7(日曜)で直感的に行えます。
外部ライブラリが必要になるケース
モダンな環境ではTemporal APIで十分ですが、依然としてDay.jsやdate-fnsといった外部ライブラリが好まれるケースもあります。
例えば、「相対的な時間の日本語表示(例:3分前、2日前)」などの複雑なフォーマット出力が必要な場合です。
Temporal APIは計算や保持には優れていますが、多言語対応の表示フォーマットについてはIntl.RelativeTimeFormatなどの別の標準APIと組み合わせて使う必要があります。
ライブラリを導入することで、これらを一つのパッケージで完結させられるメリットがあります。
まとめ
JavaScriptにおける日付の加算は、従来のDateオブジェクトから、より洗練されたTemporal APIへと主役が移り変わっています。
Dateオブジェクトを使用する場合は、オブジェクトが直接書き換えられてしまう特性を理解し、適切にコピーを作成することが重要です。
一方で、最新のプロジェクトであれば、イミュータブルで直感的な操作が可能なTemporal APIを積極的に採用すべきでしょう。
日付加算のロジックを正確に実装することは、アプリケーションの信頼性を高める第一歩です。
本記事で紹介した手法を参考に、要件に合わせた最適な日付操作を選択してください。
