hnwの日記

古いPHPでDateTime::modify(’+0 days’) すると時間がずれるバグ

表題の通りですが、PHPの特定のバージョンにおいて、生成したDateTimeオブジェクトに対して時刻の操作を行うと期待と1時間ずれてしまうことがあります。

<?php
$dt = date_create('@0');
var_dump($dt->format('c')); // string(25) "1970-01-01T00:00:00+00:00"
$dt->modify('+0 days');
var_dump($dt->format('c')); // string(25) "1970-01-01T01:00:00+00:00" (PHP 5.3.9 - 5.4.7)


上記コードの場合で言えば、Unix epoch(Unix time 0秒)のDateTimeオブジェクトを生成してmodifyメソッドで0日後を指定すると、なぜかDateTimeオブジェクトの指す時刻が1時間後になってしまうのです。


このバグの再現には、次の条件が揃う必要があります。

  • PHP 5.3.9 - 5.3.29 または 5.4.0 - 5.4.7
  • 実行環境の現在時刻が夏時間
  • DateTimeオブジェクトをUnix time指定で作成している("@12345"のように)
  • 作成したDateTimeオブジェクトに対してmodifyメソッドやsetTimestampメソッドで時刻操作する


バグの再現に夏時間が必須となると日本人である我々には関係ないようにも見えますが、たとえばTravis CI上のPHP 5.3上でテストを実行すると、今の時期は上記4条件のうち最初の2つを満たしてしまいます。実際に私はハマりました。


このバグは「PHP :: Bug #62896 :: "DateTime->modify('+0 days')" Modifies DateTime Object」で修正されており、PHP 5.4.8以降ではこのような不思議な現象は起こりません。