【PHP】strtotimeの罠


今日相談を受けた事象が面白かったので記事にします。

事象

既存のPHPで来月の年月を取得する処理があり
リリース時は正常に動いていたのに、今日(1/31)見たら年月がズレていたようです。

ソースコードを見せて貰ったら以下のようになっていました。

echo date('Ym', strtotime(date('Ym-1') . ' + 1 month'));

原因

まず、date('Ym-1') がおかしいですね。
date('Ym01')とかdate('Y-m-01')とかにするべきですね。

では、なぜリリース時に正常に動いていたのか。
ここでやっとタイトルの「strtotimeの罠」が関わってきます。

strtotime(date('Ym-1') . ' + 1 month')

これは、2019/1/31であれば

strtotime('201901-1 + 1 month')

と、なります。

ここでstrtotime様はこう考えます。

201901-1?なんやそれ、知らんわ
とりあえず今日の日付から+1monthしとこ
今日は1/31だから1ヶ月後は2/31・・・ってそんな日無いわ!
よっしゃ!繰り上げで3/3にしとこ!

エラーになどしません。
PHPらしいですね。

これにより、1/31に実行すると3月を返してしまい、1ヶ月ズレてしまいます。

もしリリース日やテスト日が月の上旬〜中旬であれば
strtotime様の月繰り上げが発生しないので
出力が年月だけだと不具合に気づきません。

この不具合はテストやってもなかなか出てこないと思うので
実装段階で気を付けないといけないですね。