ご大層なタイトルつけたけど、納得いかない度お高めの日付関連といえば「1ヶ月後」って言ってんのになんでだよーの、あれです。
せっかくなのでDatetimeクラスと並べて書きます
前提条件
- MacOS High Sierra 10.13.3
- PHP7.1.7
今回のお題
PHPの「+1 month」って・・・
strtotimeの+1month
まぁPHP書いたことある人なら、一度は「何でだよ?」って思う、あれです。
<?php
$t1 = strtotime('2018-01-31 00:00:00');
$d1 = strtotime('+1 month', $t1);
echo date('Y-m-d H:i:s', $d1) . "\n";
$t2 = strtotime('2018-02-01 00:00:00');
$d2 = strtotime('+1 month', $t2);
echo date('Y-m-d H:i:s', $d2) . "\n";
$dt1 = new DateTime('2018-01-31 00:00:00');
$dt1->add(new DateInterval('P1M'));
echo $dt1->format('Y-m-d H:i:s') . "\n";
$dt2 = new DateTime('2018-02-01 00:00:00');
$dt2->add(new DateInterval('P1M'));
echo $dt2->format('Y-m-d H:i:s') . "\n";
とりあえず、一番気になっていたstrtotimeのワナはDatetimeでも同じなのか確認しておきます。
早速実行。
2018-03-03 00:00:00
2018-03-01 00:00:00
2018-03-03 00:00:00
2018-03-01 00:00:00
どうしてこうなったんですかね・・・?Datetimeクラスも同じですね。
1/31の1ヶ月後が3/3で、2/1の1ヶ月後が3/1って・・・
改めて並べると、おかしさ満載ですね。
Datetimeクラスが出てきたときに、もしや・・・?って期待したんですけど、まぁそんな変わるわけなかったw
誰かに「1/31の1ヶ月後って何日?」って聞いて、「3/3だよ」って答えられたら「え?」って思いません?
しかし厳密に1/31の1ヶ月後とはいつか?って・・・はて?
ちなみにシェルスクリプトで1ヶ月後って書くと
#!/bin/sh
START='2018-01-31'
TARGET=`date -d "$START 1month" "+%Y-%m-%d"`
echo $TARGET
実行すると
2018-03-03
Linuxがこうだから・・・と言われれば納得する・・・?(モヤモヤするけど)
翌月に同じ日付がある1から28日までは問題ないです。
29から31日が問題になってきます。
とりあえず、+1 monthには、Datetimeクラスだろうが罠があるので、うっかり使うと痛い目にあうよ?っていうお話。
もちろん、-1 monthも。
日付まで必要ない場面なら、1日扱いで+1 monthするのはアリだと思います。
1日ならどの月でも一番最初の日ですからね。
日付まで必要ですっていう場合は、作ってるものの仕様に合わせる必要があるので、こういう場合はどうするのか?っていうところを詰めておく必要があります。
2/29生まれの人は、うるう年じゃない年は、いつ年齢カウントアップなのか?みたいなのと同じです。(4年に1回しか年取らないとか言いはるのは個人の自由ですw)