LoginSignup
2
1

More than 5 years have passed since last update.

PHPの1ヶ月後とは何か

Posted at

ご大層なタイトルつけたけど、納得いかない度お高めの日付関連といえば「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)

2
1
0

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
2
1