1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPのDateTime::subでたまに想定外の出力になるのを気にしなくするサンプルコード

Last updated at Posted at 2018-06-01

これまで、前月の初日や末日を算出するくらいしか、PHPを使った日付周りの処理を書いたことがなかったため
問題視することはなかったですが、
DateTimeのsubを利用して、DateIntervalで一月前やそれ以上前の日付を取得すると、
月ごとの日数に関係なく算出されるため、期待通りの結果がとれない。これって、場合によって面倒。
(過去記事漁ればありそうだけど、自分なりのやつを備忘録)

例えば、2018年6月30日の4ヶ月前を、PHPがデフォルトで持っている仕組みで出力すると以下となる。

$operation_date = '2018-06-30';
$diff = 4;

printf('DatetTimeまんまだと→ ');
$date = new DateTime($operation_date);
$date->sub(DateInterval::createFromDateString($diff. ' month'));
var_dump($date->format('Ymd'));

出力結果は、以下。

DatetTimeまんまだと→ string(8) "20180302"

これは嫌だ。
そこで、サンプルコードを作った結果は、以下。

$operation_date = '2018-06-30';
$diff = 4;

$previous = function ($operation_date, $diff=1) {
    $date = new DateTime($operation_date);
    $diffDate = new DateTime($date->format('Ym01'));

    for($i = 0; $i < $diff; $i++) {
        $diffDate->sub(DateInterval::createFromDateString('1 month'));
        $diffDate = new DateTime($diffDate->format('Ym01'));
    }
    if ($diffDate->format('t') <= $date->format('d')) {
        //end day of month
        $date = new DateTime($diffDate->format('Ym'). $diffDate->format('t'));
    } else  {
        //other day of month
        $date = new DateTime($diffDate->format('Ym'). $date->format('d'));
    }

    var_dump($date->format('Ymd'));
};

rintf('カスタマイズだと→ ');
$previous($operation_date, $diff);
カスタマイズだと→ string(8) "20180228"

例外的なこと考える必要はあるかもしれないけど
ひとまず以上。

2018年6月4日 追記: もっとシンプルに書ける → http://jp2.php.net/manual/ja/datetime.add.php#118342

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?