Edited at

PHPのstrtotime関数で日付を操作をするときの注意点

More than 1 year has passed since last update.

PHPのstrtotime()では2017-03-31の1ヶ月後は「2017-04-31」となり、

「2017-04-31」は「2017-05-01」として解釈される

例)以下のように月が重複して作成される

<?php

// 現在の日付から半年間の月のリストを作成する

$target_date = "20170331";

for ($i=0; $i < 6; $i++) {
$target_ym_list[] = date('Ym', strtotime($target_date . '+' . $i . ' month'));
}
var_dump($target_ym_list);
?>

array(6) {
[0]=>
string(6) "201703"
[1]=>
string(6) "201705"
[2]=>
string(6) "201705"
[3]=>
string(6) "201707"
[4]=>
string(6) "201707"
[5]=>
string(6) "201708"
}

昔から現場ではよく問題となっていましたが、今だ撲滅はされていません。

(「PHP 1か月前」とかでググると以下のようなソースが簡単に見つかるため)

<?php

// 1ヶ月後の日時を取得
echo date("Y-m-d",strtotime($target_day . "+1 month"));
?>

解決方法としては、以下のように指定日時を月はじめに変換するとよい。

<?php

// 現在の日付から半年間の月のリストを作成する

$target_date = "20170331";
// 指定日時を月はじめに変換する
$target_date = date("Ym01", strtotime($target_date));

for ($i=0; $i < 6; $i++) {
$target_ym_list[] = date('Ym', strtotime($target_date . '+' . $i . ' month'));
}
var_dump($target_ym_list);
?>

array(6) {
[0]=>
string(6) "201703"
[1]=>
string(6) "201704"
[2]=>
string(6) "201705"
[3]=>
string(6) "201706"
[4]=>
string(6) "201707"
[5]=>
string(6) "201708"
}