動かざることバグの如し

近づきたいよ 君の理想に

PHPで「1ヶ月前の今日」を求めることはできない

久々にPHPFXXK案件に遭遇してしまった・・・・・

やりたかったこと

一ヶ月前の今日を求める

例を挙げると

  • 2016年4月28日 → 2016年3月28日
  • 2016年1月28日 → 2015年12月28日

ただし2016年3月31日のように先月にその日付が存在しない(先月日数<今月日数)場合は先月末日を返してほしい

たったこれだけ

PHPで書いてみる

<?php
// not work
date_default_timezone_set('Asia/Tokyo');
echo date('Y-m-d', strtotime('2016-03-31 -1 month'));

=>2016-03-02

ん??????????????????????????????

どうしてこうなった

そもそもPHPの日付の計算において、少なくとも◯ヶ月前、◯ヶ月後を求めようとすると単純につきの足し引きのみ行われる

  • 2016-03-31の1ヶ月前は2016-02-31
  • 2月は29日(2016年は閏年)までなので超過した日数は翌月に繰り越される
  • 結果、2016-02-29に超過分の2日が足されて2016-03-02

改善策

モダン(笑)なDatetimeオブジェクトでも同じ結果だったので自分で関数作るしかない

<?php
// 先月の当日求める
function hoge($date){
    $dt = new DateTime($date);
    $dt2 = clone $dt;
    return ($dt->modify('-1 month')->format('m')===$dt2->format('m')) ? $dt->modify('last day of previous month')->format('Y-m-d') : $dt->format('Y-m-d');
}
echo hoge('2014-03-31'),PHP_EOL;
echo hoge('2016-03-31'),PHP_EOL;
echo hoge('2014-03-15'),PHP_EOL;
echo hoge('2014-12-31'),PHP_EOL;
echo hoge('2014-01-31'),PHP_EOL;

以下が返ってくるはず

2014-02-28
2016-02-29
2014-02-15
2014-11-30
2013-12-31