PHP では次のようなコードで翌月の同じ日の日付を取得することができます。
$date = new DateTime('2017-01-1');
echo $date->modify('next month')->format('Y-m-d'); // 2017-02-01
これを日付を変えて次のようにすると、意図した日付を取得することができません。
$date = new DateTime('2017-01-31');
echo $date->modify('next month')->format('Y-m-d'); // 2017-03-03
ここでいう「意図した日付」=「翌月の同じ日の日付」とは次のとおりです。
- 翌月に同じ日の日付が存在する場合、その日付
- たとえば 1 月 1 日の場合、2 月 1 日は存在するので、2 月 1 日を翌月の同じ日の日付とする
- 翌月に同じ日の日付が存在しない場合、翌月末日の日付
- たとえば 1 月 31 日の場合、2 月 31 日は存在しないので、2 月 28 日を翌月の同じ日の日付とする(うるう年の場合は 2 月 29 日)
この仕様を実装したのが以下のコードです。
$date = new DateTime();
$date->setDate(2017, 1, 31);
$next = getNextMonth($date);
echo $next->format('Y-m-d');
function getNextMonth($baseDate)
{
$date = clone $baseDate;
$day = (int)$date->format('d');
if ($day <= 28) {
$date->modify('next month');
return $date;
}
$date->modify('first day of next month');
$year = (int)$date->format('Y');
$month = (int)$date->format('m');
if (!checkdate($month, $day, $year)) {
$day = (int)$date->format('t');
}
$date->setDate($year, $month, $day);
return $date;
}
28 日までは単純に
$date->modify('next month')
で OK ですが、29 日以降は翌月に同じ日がない場合があるので、
checkdate($month, $day, $year)
で日付が存在するか確認して、存在しなければ末日を返すようにしています。
このコードは翌月固定ですが、n ヶ月後としたい場合は引数に月数を追加して少し修正すれば OK です。
なお、PHP: DateTime::modify - Manual にはこれとは違った実装方法が載っています。