DateTime::diff
http://php.net/manual/ja/datetime.diff.php
ふたつの DateTime オブジェクトの差を返す
サンプル
$d1 = new DateTime('2016-03-18');
$d2 = new DateTime('2017-04-19');
$diff = $d1->diff($d2);
var_dump($diff);
/*
yが年差、mが月差、dが日差を表すので、
1年と1月と1日の差があることを表している。
object(DateInterval)#3 (15) {
["y"]=>
int(1)
["m"]=>
int(1)
["d"]=>
int(1)
["h"]=>
int(0)
["i"]=>
int(0)
["s"]=>
int(0)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
int(397)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
*/
ここまでは良い。理解できる。
問題は3月を対象とした場合。
$d1 = new DateTime('2016-01-01');
$d2 = new DateTime('2016-02-01');
$diff = $d1->diff($d2);
echo $diff->m;//1
$d1 = new DateTime('2016-01-01');
$d2 = new DateTime('2016-03-01');
$diff = $d1->diff($d2);
echo $diff->m;//1 !?
閏年のせいというわけでもなく(それだったとしても問題だけど)
$d1 = new DateTime('2015-01-01');
$d2 = new DateTime('2015-02-01');
$diff = $d1->diff($d2);
echo $diff->m;//1
$d1 = new DateTime('2015-01-01');
$d2 = new DateTime('2015-03-01');
$diff = $d1->diff($d2);
echo $diff->m;//1 !?
そもそも閏年であっても3月で無ければ問題ない
$d1 = new DateTime('2016-01-01');
$d2 = new DateTime('2016-04-01');
$diff = $d1->diff($d2);
echo $diff->m;//3 正常
GMTなら3月でも正常表示できる。(なんで?
$d1 = new DateTime('2016-01-01', new DateTimeZone('GMT'));
$d2 = new DateTime('2016-02-01', new DateTimeZone('GMT'));
$diff = $d1->diff($d2);
echo $diff->m;//1
$d1 = new DateTime('2016-01-01', new DateTimeZone('GMT'));
$d2 = new DateTime('2016-03-01', new DateTimeZone('GMT'));
$diff = $d1->diff($d2);
echo $diff->m;//2
ということは、Asia/Tokyoでも9時間足せば正常表示できる?
$d1 = new DateTime('2016-01-01 09:00:00', new DateTimeZone('Asia/Tokyo'));
$d2 = new DateTime('2016-02-01 09:00:00', new DateTimeZone('Asia/Tokyo'));
$diff = $d1->diff($d2);
echo $diff->m;//1
$d1 = new DateTime('2016-01-01 09:00:00', new DateTimeZone('Asia/Tokyo'));
$d2 = new DateTime('2016-03-01 09:00:00', new DateTimeZone('Asia/Tokyo'));
$diff = $d1->diff($d2);
echo $diff->m;//2
出来た。
しっくりこない。
まとめ
- Asia/Tokyoタイムゾーンでは3月との差分が正しく取得できない、の?
- 3月以外にもあるかもしれないけど、調べてない。
- タイムゾーンの影響を受けるのであれば、3月以外では正常に取得できる理由が分からない。
- PHP5.4.xで確認。PHP7等の最新の挙動を確認できる方がいましたら教えてください。
対策
- これだけではQiitaは質問サイトじゃねぇぞ、というツッコミを受けるので、対策を。
function datetime_diff_month(DateTime $d1, DateTime $d2, $absolute = false){
$diff_month = ($d2->format('Y')*12 + $d2->format('n')) - ($d1->format('Y')*12 + $d1->format('n'));
return $absolute ? abs($diff_month) : $diff_month;
}
$d1 = new DateTime('2016-01-01', new DateTimeZone('Asia/Tokyo'));
$d2 = new DateTime('2016-03-01', new DateTimeZone('Asia/Tokyo'));
echo datetime_diff_month($d1, $d2); //2 (^-^)
力技過ぎる・・・。