PHPで日付を加算する基本的な方法
PHPで日付や時刻を加算する場合は、基本的に DateTimeImmutable を使用する方法がおすすめです。
DateTimeImmutable は、日付を変更する処理を実行しても元のオブジェクトを書き換えません。
変更後の日時を、新しいオブジェクトとして返します。
<?php
$date = new DateTimeImmutable('2026-07-11');
$tomorrow = $date->modify('+1 day');
echo $date->format('Y-m-d');
// 2026-07-11
echo $tomorrow->format('Y-m-d');
// 2026-07-12
元の日付を保持したまま複数の日付を計算できるため、意図しないデータ変更を防ぎやすくなります。
DateTimeImmutableを推奨する理由
PHPには、似た機能を持つ DateTime クラスもあります。
ただし、DateTime は変更可能なオブジェクトです。
modify() や add() を実行すると、元のオブジェクト自体が変更されます。
<?php
$date = new DateTime('2026-07-11');
$date->modify('+1 day');
echo $date->format('Y-m-d');
// 2026-07-12
一方、DateTimeImmutable は元の値を変更しません。
<?php
$date = new DateTimeImmutable('2026-07-11');
$result = $date->modify('+1 day');
echo $date->format('Y-m-d');
// 2026-07-11
echo $result->format('Y-m-d');
// 2026-07-12
特別な理由がない限り、日付計算には DateTimeImmutable を使用すると安全です。
戻り値を必ず受け取る
DateTimeImmutable は元のオブジェクトを変更しないため、戻り値を受け取る必要があります。
次のコードでは、計算結果が保存されません。
<?php
$date = new DateTimeImmutable('2026-07-11');
$date->modify('+1 day');
echo $date->format('Y-m-d');
// 2026-07-11
正しくは、戻り値を変数に代入します。
$date = $date->modify('+1 day');
または、別の変数に保存します。
$tomorrow = $date->modify('+1 day');
modify()を使って日付を加算する方法
簡単な日付加算には、modify() が便利です。
modify() には、+1 day や +2 weeks などの相対的な日時文字列を指定できます。
日数を加算する
<?php
$date = new DateTimeImmutable('2026-07-11');
$result = $date->modify('+3 days');
echo $result->format('Y-m-d');
// 2026-07-14
1日後を求める場合は、次のように書けます。
$tomorrow = $date->modify('+1 day');
10日後を求める場合は、次のようにします。
$afterTenDays = $date->modify('+10 days');
週を加算する
<?php
$date = new DateTimeImmutable('2026-07-11');
$result = $date->modify('+2 weeks');
echo $result->format('Y-m-d');
// 2026-07-25
1週間後は7日後として処理されます。
$nextWeek = $date->modify('+1 week');
月を加算する
<?php
$date = new DateTimeImmutable('2026-07-11');
$result = $date->modify('+1 month');
echo $result->format('Y-m-d');
// 2026-08-11
ただし、月末の日付に対して月を加算すると、予想外の結果になることがあります。
月末の計算については、後ほど詳しく解説します。
年を加算する
<?php
$date = new DateTimeImmutable('2026-07-11');
$result = $date->modify('+1 year');
echo $result->format('Y-m-d');
// 2027-07-11
通常の日付であれば問題ありませんが、2月29日に1年を加算する場合は注意が必要です。
時間を加算する
<?php
$dateTime = new DateTimeImmutable('2026-07-11 10:30:00');
$result = $dateTime->modify('+2 hours');
echo $result->format('Y-m-d H:i:s');
// 2026-07-11 12:30:00
分を加算する
<?php
$dateTime = new DateTimeImmutable('2026-07-11 10:30:00');
$result = $dateTime->modify('+45 minutes');
echo $result->format('Y-m-d H:i:s');
// 2026-07-11 11:15:00
秒を加算する
<?php
$dateTime = new DateTimeImmutable('2026-07-11 10:30:00');
$result = $dateTime->modify('+30 seconds');
echo $result->format('Y-m-d H:i:s');
// 2026-07-11 10:30:30
複数の単位をまとめて加算する
modify() では、日・時間・分などをまとめて指定できます。
<?php
$dateTime = new DateTimeImmutable('2026-07-11 10:30:00');
$result = $dateTime->modify(
'+1 day +2 hours +30 minutes'
);
echo $result->format('Y-m-d H:i:s');
// 2026-07-12 13:00:00
曜日や月末を指定する
modify() では、曜日や月末を表す相対表現も使用できます。
<?php
$date = new DateTimeImmutable('2026-07-11');
$nextMonday = $date->modify('next Monday');
$firstDay = $date->modify('first day of next month');
$lastDay = $date->modify('last day of next month');
人が読んでも意味を理解しやすい点が、modify() の利点です。
DateIntervalとadd()を使う方法
加算する期間を明示的に表現したい場合は、DateInterval と add() を使用します。
<?php
$date = new DateTimeImmutable('2026-07-11');
$interval = new DateInterval('P3D');
$result = $date->add($interval);
echo $result->format('Y-m-d');
// 2026-07-14
P3D は、3日間を表します。
DateIntervalの基本的な書式
DateInterval では、ISO 8601形式で期間を指定します。
主な指定方法は次のとおりです。
| 指定 | 意味 |
|---|---|
P1D | 1日 |
P2W | 2週間 |
P1M | 1か月 |
P1Y | 1年 |
PT1H | 1時間 |
PT30M | 30分 |
PT45S | 45秒 |
P1DT2H | 1日と2時間 |
P1Y2M3D | 1年2か月3日 |
P1DT2H30M | 1日2時間30分 |
日付部分は P から始まり、時間部分を含める場合は T を付けます。
Mは月と分で意味が変わる
M は、記述する位置によって意味が変わります。
new DateInterval('P2M');
// 2か月
new DateInterval('PT2M');
// 2分
T より前の M は月、T より後の M は分を表します。
複数の期間をまとめて指定する
<?php
$dateTime = new DateTimeImmutable('2026-07-11 10:30:00');
$interval = new DateInterval('P1M3DT2H15M');
$result = $dateTime->add($interval);
echo $result->format('Y-m-d H:i:s');
// 2026-08-14 12:45:00
P1M3DT2H15M は、次の期間を表します。
- 1か月
- 3日
- 2時間
- 15分
同じ期間を再利用する
DateInterval は、同じ期間を複数の計算で使う場合に便利です。
<?php
$billingInterval = new DateInterval('P1M');
$currentDate = new DateTimeImmutable('2026-07-11');
$nextDate = $currentDate->add($billingInterval);
$followingDate = $nextDate->add($billingInterval);
契約期間、試用期間、請求間隔などを値として管理しやすくなります。
modify()とDateIntervalの使い分け
modify() と DateInterval は、目的に応じて使い分けます。
modify()が向いているケース
簡単な日付加算や、人が読んで意味を理解しやすい表現を使いたい場合に向いています。
$expirationDate = $createdAt->modify('+30 days');
$nextMonday = $date->modify('next Monday');
$monthEnd = $date->modify('last day of next month');
DateIntervalが向いているケース
期間を変数として管理したい場合や、複数の処理で再利用したい場合に向いています。
$trialPeriod = new DateInterval('P30D');
$expirationDate = $createdAt->add($trialPeriod);
サービス層やドメインロジックで期間を明示したい場合にも適しています。
現在日時に加算する方法
現在日時を基準に日付を加算する場合は、now を指定します。
<?php
$now = new DateTimeImmutable('now');
$oneHourLater = $now->modify('+1 hour');
echo $oneHourLater->format('Y-m-d H:i:s');
ただし、実行環境のタイムゾーンに依存するため、タイムゾーンを明示することをおすすめします。
タイムゾーンを明示する
<?php
$timezone = new DateTimeZone('Asia/Tokyo');
$now = new DateTimeImmutable(
'now',
$timezone
);
$oneHourLater = $now->modify('+1 hour');
echo $oneHourLater->format('Y-m-d H:i:sP');
P を指定すると、UTCからの時差も出力できます。
2026-07-11 08:00:00+09:00
アプリケーション全体のタイムゾーンを指定する
PHP全体のデフォルトタイムゾーンは、次のように設定できます。
date_default_timezone_set('Asia/Tokyo');
ただし、大規模なアプリケーションや複数のタイムゾーンを扱うシステムでは、DateTimeZone を明示的に渡したほうが処理を追いやすくなります。
文字列の日付に加算する方法
フォームやデータベースから取得した日付文字列も、DateTimeImmutable に変換してから加算できます。
<?php
$inputDate = '2026-07-11';
$date = new DateTimeImmutable($inputDate);
$result = $date->modify('+7 days');
echo $result->format('Y-m-d');
// 2026-07-18
時刻を含む文字列を処理する
<?php
$inputDateTime = '2026-07-11 15:30:00';
$dateTime = new DateTimeImmutable(
$inputDateTime,
new DateTimeZone('Asia/Tokyo')
);
$result = $dateTime->modify('+90 minutes');
echo $result->format('Y-m-d H:i:s');
// 2026-07-11 17:00:00
日付文字列を厳密に検証する方法
外部から受け取った日付を処理する場合、new DateTimeImmutable($input) だけでは厳密な検証になりません。
PHPの日付パーサーは柔軟で、存在しない日付を翌月へ繰り越して解釈することがあります。
たとえば、2026-02-30 は単純にエラーになるとは限りません。
createFromFormat()を使う
入力形式が決まっている場合は、createFromFormat() を使用します。
<?php
$input = '2026/07/11';
$date = DateTimeImmutable::createFromFormat(
'!Y/m/d',
$input
);
if ($date === false) {
throw new InvalidArgumentException(
'日付の形式が正しくありません。'
);
}
echo $date->format('Y-m-d');
// 2026-07-11
先頭の ! は、指定されていない時刻部分を初期化するための指定です。
!Y/m/d の場合、時刻は 00:00:00 になります。
getLastErrors()で警告も確認する
createFromFormat() は、存在しない日付を警告付きで補正する場合があります。
そのため、戻り値が false かどうかだけでなく、警告とエラーも確認します。
<?php
function parseDate(string $value): DateTimeImmutable
{
$date = DateTimeImmutable::createFromFormat(
'!Y-m-d',
$value
);
$errors = DateTimeImmutable::getLastErrors();
$hasErrors = $errors !== false
&& (
$errors['warning_count'] > 0
|| $errors['error_count'] > 0
);
if ($date === false || $hasErrors) {
throw new InvalidArgumentException(
'正しい日付をYYYY-MM-DD形式で指定してください。'
);
}
return $date;
}
この方法で、次のような存在しない日付を検出できます。
parseDate('2026-02-30');
PHP 8.2以降では、警告やエラーがない場合、getLastErrors() は false を返します。
そのため、$errors !== false の確認が必要です。
月末の日付に月を加算するときの注意点
PHPの日付計算で特に注意が必要なのが、月末に対する月加算です。
1月31日に1か月を加算する例
<?php
$date = new DateTimeImmutable('2026-01-31');
$result = $date->modify('+1 month');
echo $result->format('Y-m-d');
// 2026-03-03
直感的には 2026-02-28 を期待するかもしれません。
しかし、PHPではいったん2月31日のような状態を作り、存在しない日数を翌月へ繰り越します。
2026年2月は28日までなので、3日分が3月へ繰り越され、結果は 2026-03-03 になります。
+1 monthは翌月末への丸めではない
次のコードは、「翌月の同じ日、存在しなければ月末」という意味にはなりません。
$nextMonth = $date->modify('+1 month');
月末をどのように扱うかは、業務仕様として明示する必要があります。
翌月の初日を求める
<?php
$date = new DateTimeImmutable('2026-01-31');
$result = $date->modify('first day of next month');
echo $result->format('Y-m-d');
// 2026-02-01
翌月の末日を求める
<?php
$date = new DateTimeImmutable('2026-01-31');
$result = $date->modify('last day of next month');
echo $result->format('Y-m-d');
// 2026-02-28
存在しない場合だけ月末に丸める
「翌月の同じ日を維持し、存在しない場合は月末にする」という仕様は、自分で実装します。
<?php
function addMonthsClamped(
DateTimeImmutable $date,
int $months
): DateTimeImmutable {
$originalDay = (int) $date->format('j');
$targetMonth = $date
->modify('first day of this month')
->modify(sprintf('%+d months', $months));
$lastDay = (int) $targetMonth->format('t');
$targetDay = min($originalDay, $lastDay);
return $targetMonth->setDate(
(int) $targetMonth->format('Y'),
(int) $targetMonth->format('n'),
$targetDay
);
}
実行例は次のとおりです。
$date = new DateTimeImmutable('2026-01-31');
echo addMonthsClamped($date, 1)->format('Y-m-d');
// 2026-02-28
うるう年にも対応できます。
$date = new DateTimeImmutable('2024-01-31');
echo addMonthsClamped($date, 1)->format('Y-m-d');
// 2024-02-29
連続加算では基準日を失わないようにする
月末丸めを連続して実行すると、元の日付を失う場合があります。
$contractDate = new DateTimeImmutable('2026-01-31');
$february = addMonthsClamped($contractDate, 1);
// 2026-02-28
$march = addMonthsClamped($february, 1);
// 2026-03-28
毎月31日を基準にしたい場合は、直前の計算結果ではなく、元の契約日を基準にします。
$contractDate = new DateTimeImmutable('2026-01-31');
$february = addMonthsClamped($contractDate, 1);
// 2026-02-28
$march = addMonthsClamped($contractDate, 2);
// 2026-03-31
請求日や契約更新日の計算では、この違いが重要です。
1か月後と30日後の違い
次の2つは、同じ意味ではありません。
$date->modify('+1 month');
$date->modify('+30 days');
たとえば、2026年2月1日を基準にすると、結果は異なります。
<?php
$date = new DateTimeImmutable('2026-02-01');
echo $date->modify('+1 month')->format('Y-m-d');
// 2026-03-01
echo $date->modify('+30 days')->format('Y-m-d');
// 2026-03-03
カレンダー上の翌月
$nextMonth = $date->modify('+1 month');
厳密に30日後
$afterThirtyDays = $date->modify('+30 days');
月額契約や請求サイクルでは、単純な日数ではなく、カレンダー上の月を基準にすることが一般的です。
一方、試用期間や有効期間では、30日という固定日数を使用する場合があります。
うるう年の日付加算
PHPは、通常の日付加算でうるう年を自動的に考慮します。
<?php
$date = new DateTimeImmutable('2024-02-28');
echo $date->modify('+1 day')->format('Y-m-d');
// 2024-02-29
echo $date->modify('+2 days')->format('Y-m-d');
// 2024-03-01
通常の日数加算では、うるう年を手動で判定する必要はありません。
2月29日に1年を加算する
2月29日に1年を加算する場合は注意が必要です。
<?php
$date = new DateTimeImmutable('2024-02-29');
echo $date->modify('+1 year')->format('Y-m-d');
// 2025-03-01
2025年には2月29日が存在しないため、1日分が3月へ繰り越されます。
存在しない場合は月末に丸める
「翌年の同じ月日を維持し、存在しない場合は月末にする」という仕様は、独自に実装します。
<?php
function addYearsClamped(
DateTimeImmutable $date,
int $years
): DateTimeImmutable {
$month = (int) $date->format('n');
$day = (int) $date->format('j');
$targetYear = (int) $date->format('Y') + $years;
$firstDay = $date->setDate(
$targetYear,
$month,
1
);
$lastDay = (int) $firstDay->format('t');
return $firstDay->setDate(
$targetYear,
$month,
min($day, $lastDay)
);
}
$date = new DateTimeImmutable('2024-02-29');
echo addYearsClamped($date, 1)->format('Y-m-d');
// 2025-02-28
日付を減算する方法
日付を減算する場合は、modify() にマイナスの値を指定します。
modify()で減算する
<?php
$date = new DateTimeImmutable('2026-07-11');
echo $date->modify('-1 day')->format('Y-m-d');
// 2026-07-10
echo $date->modify('-2 weeks')->format('Y-m-d');
// 2026-06-27
echo $date->modify('-1 month')->format('Y-m-d');
// 2026-06-11
sub()で減算する
DateInterval を使う場合は、sub() を使用できます。
<?php
$date = new DateTimeImmutable('2026-07-11');
$interval = new DateInterval('P10D');
$result = $date->sub($interval);
echo $result->format('Y-m-d');
// 2026-07-01
減算処理であることが明確になるため、DateInterval を使う場合は sub() が読みやすい書き方です。
24時間後と翌日の違い
日付計算では、「翌日」と「経過時間として24時間後」を区別する必要があります。
日本時間では差が出にくいものの、夏時間を採用している地域では結果が異なる場合があります。
カレンダー上の翌日
$nextDay = $date->modify('+1 day');
これは、カレンダー上の日付を1日進める処理です。
壁時計上の24時間後
$afterClockHours = $date->modify('+24 hours');
これは、日時文字列の相対指定として24時間を進めます。
夏時間をまたぐ場合、UTC基準の経過秒数が必ず86,400秒になるとは限りません。
経過時間として正確に24時間後
経過時間として正確に24時間、つまり86,400秒後を求める場合は、DateInterval('PT24H') を使用します。
$result = $date->add(
new DateInterval('PT24H')
);
または、Unixタイムスタンプに86,400秒を加算します。
$result = $date->setTimestamp(
$date->getTimestamp() + 86400
);
用途に応じて使い分ける
// カレンダー上の翌日
$nextDay = $date->modify('+1 day');
// 壁時計上の24時間後
$afterClockHours = $date->modify('+24 hours');
// 経過時間として正確に24時間後
$afterElapsedHours = $date->add(
new DateInterval('PT24H')
);
海外向けシステムや、ユーザーごとにタイムゾーンが異なるサービスでは重要な違いです。
strtotime()で日付を加算する方法
strtotime() と date() を組み合わせても、日付を加算できます。
<?php
$timestamp = strtotime('2026-07-11 +3 days');
if ($timestamp === false) {
throw new RuntimeException(
'日時を解析できませんでした。'
);
}
echo date('Y-m-d', $timestamp);
// 2026-07-14
基準日時を第2引数に指定する
<?php
$baseTimestamp = strtotime('2026-07-11');
if ($baseTimestamp === false) {
throw new RuntimeException(
'基準日時を解析できませんでした。'
);
}
$resultTimestamp = strtotime(
'+10 days',
$baseTimestamp
);
if ($resultTimestamp === false) {
throw new RuntimeException(
'日時を計算できませんでした。'
);
}
echo date('Y-m-d', $resultTimestamp);
// 2026-07-21
実務ではDateTimeImmutableを優先する
strtotime() でも処理できますが、実務では DateTimeImmutable のほうが扱いやすい傾向があります。
主な理由は次のとおりです。
- タイムゾーンを明示しやすい
- 元の日付を保持できる
- 日付をオブジェクトとして扱える
- メソッドチェーンを使用できる
- 型を意識した設計に向いている
- テストしやすい
- Unixタイムスタンプと日付の意味が混在しにくい
新しく実装するコードでは、基本的に DateTimeImmutable を選ぶとよいでしょう。
Unixタイムスタンプに秒数を加算する方法
Unixタイムスタンプに秒数を直接加算することもできます。
<?php
$timestamp = strtotime('2026-07-11 10:00:00');
if ($timestamp === false) {
throw new RuntimeException(
'日時を解析できませんでした。'
);
}
$result = $timestamp + 86400;
echo date('Y-m-d H:i:s', $result);
これは、正確に86,400秒後を表します。
ただし、夏時間のあるタイムゾーンでは、翌日の同じ時刻になるとは限りません。
「カレンダー上の翌日」を求める場合は、次のような処理が適しています。
$nextDay = $date->modify('+1 day');
「正確に86,400秒後」を求める場合は、タイムスタンプ加算や PT24H を使用します。
営業日を加算する方法
土日を除外して営業日を加算する場合は、単純な +N days では処理できません。
土日を除外する
<?php
function addBusinessDays(
DateTimeImmutable $date,
int $days
): DateTimeImmutable {
if ($days < 0) {
throw new InvalidArgumentException(
'日数には0以上の整数を指定してください。'
);
}
$result = $date;
$added = 0;
while ($added < $days) {
$result = $result->modify('+1 day');
$dayOfWeek = (int) $result->format('N');
if ($dayOfWeek <= 5) {
$added++;
}
}
return $result;
}
使用例は次のとおりです。
$date = new DateTimeImmutable('2026-07-10');
// 金曜日
echo addBusinessDays($date, 1)->format('Y-m-d');
// 2026-07-13
format('N') は、曜日を1から7の数字で返します。
| 数値 | 曜日 |
|---|---|
| 1 | 月曜日 |
| 2 | 火曜日 |
| 3 | 水曜日 |
| 4 | 木曜日 |
| 5 | 金曜日 |
| 6 | 土曜日 |
| 7 | 日曜日 |
祝日も除外する
<?php
function addBusinessDaysWithHolidays(
DateTimeImmutable $date,
int $days,
array $holidays = []
): DateTimeImmutable {
if ($days < 0) {
throw new InvalidArgumentException(
'日数には0以上の整数を指定してください。'
);
}
$holidayMap = array_fill_keys(
$holidays,
true
);
$result = $date;
$added = 0;
while ($added < $days) {
$result = $result->modify('+1 day');
$dayOfWeek = (int) $result->format('N');
$dateString = $result->format('Y-m-d');
$isWeekend = $dayOfWeek >= 6;
$isHoliday = isset(
$holidayMap[$dateString]
);
if (!$isWeekend && !$isHoliday) {
$added++;
}
}
return $result;
}
使用例は次のとおりです。
$holidays = [
'2026-07-20',
'2026-08-11',
];
$date = new DateTimeImmutable('2026-07-17');
$result = addBusinessDaysWithHolidays(
$date,
1,
$holidays
);
echo $result->format('Y-m-d');
// 2026-07-21
実務では、次の休日も考慮する必要があります。
- 国民の祝日
- 振替休日
- 国民の休日
- 年末年始
- 会社独自の休業日
- 店舗ごとの定休日
期限日を計算する実用例
指定日数後の期限を計算するクラスは、次のように実装できます。
<?php
declare(strict_types=1);
final class ExpirationDateCalculator
{
public function calculate(
DateTimeImmutable $startedAt,
int $validDays
): DateTimeImmutable {
if ($validDays < 0) {
throw new InvalidArgumentException(
'有効日数には0以上の整数を指定してください。'
);
}
return $startedAt->add(
new DateInterval(
sprintf('P%dD', $validDays)
)
);
}
}
使用例は次のとおりです。
$calculator = new ExpirationDateCalculator();
$startedAt = new DateTimeImmutable(
'2026-07-11 10:00:00',
new DateTimeZone('Asia/Tokyo')
);
$expiresAt = $calculator->calculate(
$startedAt,
30
);
echo $expiresAt->format('Y-m-d H:i:sP');
// 2026-08-10 10:00:00+09:00
30日後と30日間有効は異なる
「30日後」と「30日間有効」は、業務上の数え方によって結果が変わります。
開始日時の30日後を期限にする場合は、次の計算です。
$expiresAt = $startedAt->modify('+30 days');
開始日を1日目として30日間有効にする場合は、最終日が29日後になる可能性があります。
$lastValidDate = $startedAt->modify('+29 days');
期限を設計するときは、次の点を明確にする必要があります。
- 開始日を1日目に含めるか
- 期限日の何時まで有効か
- 期限日時を含むか、含まないか
- 営業日基準か、暦日基準か
- ユーザーのタイムゾーンを基準にするか
PHPのバージョンによる例外処理の違い
PHPのバージョンによって、無効な相対日時文字列を指定したときの挙動が異なります。
modify()の無効な文字列
PHP 8.3以降では、無効な文字列を modify() に渡すと、DateMalformedStringException が発生します。
<?php
try {
$date = new DateTimeImmutable(
'2026-07-11'
);
$result = $date->modify(
$userInput
);
} catch (DateMalformedStringException $e) {
throw new InvalidArgumentException(
'日時の指定が正しくありません。',
previous: $e
);
}
固定文字列をコード内に直接書く場合は問題になりにくいですが、ユーザー入力を渡す場合は例外処理が必要です。
DateInterval::createFromDateString()の注意点
次のコードは、有効な文字列であれば正しく動作します。
$interval = DateInterval::createFromDateString(
'-10 days'
);
$result = $date->add($interval);
ただし、無効な文字列を渡した場合の挙動はPHPのバージョンによって異なります。
PHP 8.3以降では、オブジェクト指向形式で DateMalformedIntervalStringException が発生します。
<?php
try {
$interval = DateInterval::createFromDateString(
$userInput
);
} catch (DateMalformedIntervalStringException $e) {
throw new InvalidArgumentException(
'期間の指定が正しくありません。',
previous: $e
);
}
外部入力を相対日時文字列として処理する場合は、使用しているPHPのバージョンを確認する必要があります。
PHPで日付を加算するときのよくある間違い
DateTimeImmutableの戻り値を受け取らない
$date = new DateTimeImmutable('2026-07-11');
$date->modify('+1 day');
echo $date->format('Y-m-d');
// 2026-07-11
正しくは、戻り値を代入します。
$date = $date->modify('+1 day');
DateTimeが元の値を変更することを見落とす
$date = new DateTime('2026-07-11');
$tomorrow = $date->modify('+1 day');
// $dateも2026-07-12になっている
元の値を残したい場合は、clone が必要です。
$date = new DateTime('2026-07-11');
$tomorrow = (clone $date)
->modify('+1 day');
ただし、最初から DateTimeImmutable を使用するほうが簡単です。
P1MとPT1Mを混同する
new DateInterval('P1M');
// 1か月
new DateInterval('PT1M');
// 1分
+1 monthを翌月末への丸めと考える
$date = new DateTimeImmutable('2026-01-31');
$result = $date->modify('+1 month');
// 2026-03-03
翌月末を求めたい場合は、次のようにします。
$result = $date->modify(
'last day of next month'
);
+1 monthと+30 daysを同じと考える
$date->modify('+1 month');
$date->modify('+30 days');
この2つは異なる計算です。
月単位の契約なら +1 month、固定日数の有効期間なら +30 days など、目的に応じて選択します。
タイムゾーンを指定しない
$date = new DateTimeImmutable('now');
このコードは、PHPのデフォルトタイムゾーンに依存します。
タイムゾーンを明示する場合は、次のようにします。
$date = new DateTimeImmutable(
'now',
new DateTimeZone('Asia/Tokyo')
);
実在しない日付を戻り値だけで判定する
$date = DateTimeImmutable::createFromFormat(
'!Y-m-d',
'2026-02-30'
);
if ($date === false) {
// これだけでは不十分
}
getLastErrors() の警告も確認する必要があります。
PHPの日付加算で推奨する基本形
一般的な日付加算では、次の形を基本にすると扱いやすくなります。
<?php
declare(strict_types=1);
$timezone = new DateTimeZone(
'Asia/Tokyo'
);
$baseDate = new DateTimeImmutable(
'2026-07-11 10:00:00',
$timezone
);
$result = $baseDate->modify('+7 days');
echo $result->format(
'Y-m-d H:i:sP'
);
期間を明示する場合
<?php
declare(strict_types=1);
$timezone = new DateTimeZone(
'Asia/Tokyo'
);
$baseDate = new DateTimeImmutable(
'2026-07-11 10:00:00',
$timezone
);
$sevenDays = new DateInterval('P7D');
$result = $baseDate->add($sevenDays);
echo $result->format(
'Y-m-d H:i:sP'
);
正確に24時間後を求める場合
<?php
declare(strict_types=1);
$timezone = new DateTimeZone(
'America/New_York'
);
$baseDate = new DateTimeImmutable(
'2026-11-01 00:00:00',
$timezone
);
$result = $baseDate->add(
new DateInterval('PT24H')
);
echo $result->format(
'Y-m-d H:i:sP'
);
月末を考慮する場合
翌月末を求める場合は、単純な +1 month ではなく、目的を明示します。
$nextMonthEnd = $date->modify(
'last day of next month'
);
元の日を維持し、存在しない場合だけ月末に丸める場合は、専用の関数を使用します。
PHPの日付加算に関するまとめ
PHPで日付を加算するときは、基本的に DateTimeImmutable を使用するのがおすすめです。
簡単な日付加算には、modify() が適しています。
$result = $date->modify('+7 days');
期間を明示的に管理したい場合は、DateInterval と add() を使用します。
$result = $date->add(
new DateInterval('P7D')
);
日付計算では、特に次の点に注意が必要です。
DateTimeImmutableの戻り値を必ず受け取るDateTimeは元のオブジェクトを変更する+1 monthは翌月末への丸めではない+1 monthと+30 daysは異なる- 2月29日に1年を加えると3月1日になる場合がある
- 外部入力は
createFromFormat()とgetLastErrors()で検証する - カレンダー上の翌日と正確な24時間後を区別する
- タイムゾーンを明示する
- 営業日や月末処理は業務仕様として実装する
通常の処理では、次の方針で使い分けるとよいでしょう。
- 簡単な相対計算は
modify() - 再利用する期間は
DateInterval - 元の日付を保持するなら
DateTimeImmutable - 月末やうるう年は専用のルールを実装する
- 正確な経過時間は
PT24Hなどで表現する - ユーザー入力は厳密に検証する
単純な日付加算だけであればコードは短く書けますが、月末、うるう年、タイムゾーン、営業日、期限の境界が関係する場合は、業務上のルールを明確にしたうえで実装することが重要です。
以上、PHPの日付の加算を行う方法についてでした。
最後までお読みいただき、ありがとうございました。










