0
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?

異なるPHPバージョン(8.5と7.0)でDateTimeとDateTimeImmutableを比較したら、DateTimeが約7%速い

0
Posted at

はじめに

一覧画面の表示速度を調査している中で、行ごとに日時オブジェクトを新規生成している処理を見つけました。
そこから、そもそも DateTime と DateTimeImmutable はどちらが速いのか、PHPのバージョンが変わると速度はどう変わるのかが気になり、ベンチマークで検証しました。この記事では、その検証結果を扱います。

環境: PHP 7.0 / PHP 8.5

modify()を呼ぶかどうかで2ケースに分ける

DateTime と DateTimeImmutable の違いは、DateTime は自分自身を書き換えるミュータブルなクラスで、DateTimeImmutable は変更のたびに新しいインスタンスを返すイミュータブルなクラスです。
この違いが具体的にどう挙動を変えるかは、DateTimeクラスとDateTimeImmutableクラスの違いを理解するで分かりやすく実例付きで解説されています。

この違いがパフォーマンスにどう影響するかを見るため、入力文字列 2026-08-08 08:00:00 に対して、

  • そのまま出力
  • 1ヶ月後
  • 1ヶ月前

の3ケースを用意して比較を検討しました。
「そのまま出力」は modify() を呼ばずオブジェクト生成のコストだけを見るケースで、残り2つは modify() を呼んで変更のコストも含めたケースです。

検証方法

PHP 7.0とPHP 8.5、それぞれで同じベンチマークスクリプトを実行し、所要時間を計測しました。

入力文字列は2026-08-08 08:00:00で固定

const INPUT_DATE_STRING = '2026-08-08 08:00:00';

DateTime 版の計測関数

指定回数ループしながらオブジェクトを生成し、必要なら modify() で変更し、format() で文字列に戻します。

/**
 * DateTime(ミュータブル)で同じ処理を$iterationCount回繰り返し、所要時間を計測する。
 *
 * @param int    $iterationCount   繰り返し回数
 * @param string $relativeModifier DateTime::modify()に渡す相対指定。空文字なら変更しない
 * @return float 所要時間(ミリ秒)
 */
function benchmarkDateTime($iterationCount, $relativeModifier)
{
    $startTime = microtime(true);
    for ($i = 0; $i < $iterationCount; $i++) {
        $dateTime = new DateTime(INPUT_DATE_STRING);
        if ($relativeModifier !== '') {
            // DateTimeはミュータブル: modify()は$dateTime自身を書き換える(戻り値を受け直す必要はない)
            $dateTime->modify($relativeModifier);
        }
        $dateTime->format('Y-m-d H:i:s');
    }
    return (microtime(true) - $startTime) * 1000;
}

DateTimeImmutable 版の計測関数

modify() の戻り値を変数に受け直す点だけが異なります。

/**
 * DateTimeImmutable(イミュータブル)で同じ処理を$iterationCount回繰り返し、所要時間を計測する。
 *
 * @param int    $iterationCount   繰り返し回数
 * @param string $relativeModifier DateTimeImmutable::modify()に渡す相対指定。空文字なら変更しない
 * @return float 所要時間(ミリ秒)
 */
function benchmarkDateTimeImmutable($iterationCount, $relativeModifier)
{
    $startTime = microtime(true);
    for ($i = 0; $i < $iterationCount; $i++) {
        $dateTime = new DateTimeImmutable(INPUT_DATE_STRING);
        if ($relativeModifier !== '') {
            // DateTimeImmutableはイミュータブル: modify()は元を変えず新しいインスタンスを返すため、必ず受け直す
            $dateTime = $dateTime->modify($relativeModifier);
        }
        $dateTime->format('Y-m-d H:i:s');
    }
    return (microtime(true) - $startTime) * 1000;
}

3ケースそれぞれに対して呼び出す関数

この2つを、「そのまま出力」「1ヶ月後」「1ヶ月前」の3ケースそれぞれに対して呼び出す関数が runCase() です。

/**
 * 1つの日時操作ケース(そのまま/1ヶ月後/1ヶ月前)について、3方式すべてを計測して出力する。
 *
 * @param string $caseLabel        出力見出しに使うケース名
 * @param string $relativeModifier 各benchmarkXxx()に渡す相対指定。空文字なら「そのまま出力」ケースになる
 * @param int    $iterationCount   繰り返し回数
 */
function runCase($caseLabel, $relativeModifier, $iterationCount)
{
    echo "=== {$caseLabel} (n={$iterationCount}) ===\n";
    printBenchmarkResult('strtotime()+date()', benchmarkStrtotime($iterationCount, $relativeModifier));
    printBenchmarkResult('DateTime', benchmarkDateTime($iterationCount, $relativeModifier));
    printBenchmarkResult('DateTimeImmutable', benchmarkDateTimeImmutable($iterationCount, $relativeModifier));
    echo "\n";
}

3ケースをまとめて実行する関数

runAllCases() で3ケースをまとめて実行し、ループ回数1万回と10万回それぞれで3回ずつ計測しました。

/**
 * 3つのケース(そのまま出力/1ヶ月後/1ヶ月前)を指定回数で計測する。
 *
 * @param int $iterationCount 繰り返し回数
 */
function runAllCases($iterationCount)
{
    runCase('そのまま出力', '', $iterationCount);
    runCase('1ヶ月後', '+1 month', $iterationCount);
    runCase('1ヶ月前', '-1 month', $iterationCount);
}

echo 'PHP ' . PHP_VERSION . "\n";
echo '入力: ' . INPUT_DATE_STRING . "\n\n";

runAllCases(10000);
runAllCases(100000);

計測結果

そのままの出力:ほぼ差がない

ループ10万回、3回計測の平均です。

PHP DateTime DateTimeImmutable DateTimeが速い割合
7.0 111.6ms 112.2ms 0.5%
8.5 89.2ms 89.6ms 0.4%

両バージョンとも1%未満で、実質差がありません。
→modify() を呼ばないため、ほとんど差はありませんでした。

「1ヶ月後」「1ヶ月前」:DateTimeが一貫して速い

同じ条件で「1ヶ月後」「1ヶ月前」を計測すると、結果が変わります。

PHP ケース DateTime DateTimeImmutable DateTimeが速い割合
7.0 1ヶ月後 163.6ms 173.5ms 5.7%
7.0 1ヶ月前 161.4ms 175.2ms 7.9%
8.5 1ヶ月後 144.9ms 156.9ms 7.6%
8.5 1ヶ月前 139.7ms 151.3ms 7.7%

4パターンとも DateTime が速く、平均すると約7%の差になります。
理由は推測ですが、DateTimeImmutable は modify() を呼ぶたびに新しいインスタンスを生成するのに対し、
DateTime は既存のインスタンスをそのまま書き換えるため、オブジェクトの生成回数そのものが1回少なくなることが影響していると考えられます。

余談

strtotime()+date()も測ってみた

同じベンチマークで、オブジェクトを使わない strtotime() + date() も測りました。

/**
 * strtotime()+date() で「文字列 → タイムスタンプ → 文字列」を$iterationCount回繰り返し、所要時間を計測する。
 * オブジェクトを一切生成しない、最も低レベルな方式。
 *
 * @param int    $iterationCount   繰り返し回数
 * @param string $relativeModifier strtotime()の第一引数に渡す相対指定(例: '+1 month')。空文字なら変更しない
 * @return float 所要時間(ミリ秒)
 */
function benchmarkStrtotime($iterationCount, $relativeModifier)
{
    $startTime = microtime(true);
    for ($i = 0; $i < $iterationCount; $i++) {
        $timestamp = strtotime(INPUT_DATE_STRING);
        if ($relativeModifier !== '') {
            // 第二引数に基準タイムスタンプを渡すことで「その時刻からの相対指定」として解釈させる
            $timestamp = strtotime($relativeModifier, $timestamp);
        }
        date('Y-m-d H:i:s', $timestamp);
    }
    return (microtime(true) - $startTime) * 1000;
}

DateTime と比べると、次のようになりました(ループ10万回、3回計測の平均)。

PHP ケース DateTime DateTimeImmutable strtotime()+date()
7.0 そのまま出力 111.6ms 112.2ms 102.3ms
7.0 1ヶ月後 163.6ms 173.5ms 164.0ms
7.0 1ヶ月前 161.4ms 175.2ms 163.9ms
8.5 そのまま出力 89.2ms 89.6ms 82.1ms
8.5 1ヶ月後 144.9ms 156.9ms 140.1ms
8.5 1ヶ月前 139.7ms 151.3ms 140.0ms

PHP 7.0・8.5では、strtotime() + date() が3方式の中で最速か、DateTime と僅差の
最速でした。

オブジェクトを一切作らない分速い、という結果です。

PHP 5.6でも計測してみた

PHP 5.6でも同じスクリプトを動かしたところ、ループ10万回・3回計測の平均は次のようになりました。

PHP ケース DateTime DateTimeImmutable strtotime()+date()
5.6 そのまま出力 156.6ms 155.3ms 150.4ms
5.6 1ヶ月後 235.9ms 258.3ms 490.5ms
5.6 1ヶ月前 231.8ms 247.2ms 493.1ms

PHP 7.0・8.5では最速だった strtotime() + date() が、
PHP 5.6の「1ヶ月後」「1か月前」では DateTime の約2倍遅くなっています。
→PHP 5.6から7.0にかけて、DateTime と DateTimeImmutable クラスの modify() が大きく最適化された可能性があります。

まとめ

  • 生成するだけなら DateTime と DateTimeImmutable に差はほぼありませんでした。
  • 変更のたびに新しいインスタンスを作る DateTimeImmutable の場合、modify() を使うメソッドを実行すると、DateTimeと比較して約7%程度遅くなる結果となりました。
  • strtotime() + date() がDateTime と DateTimeImmutable よりも速い結果となりました。
  • しかし、PHP 5.6では逆にstrtotime() + date() が DateTime と DateTimeImmutable よりも遅い結果となりました。
    →PHP 5.6から7.0にかけて、このDateTimeおよびDateTimeImmutableクラスの modify() が大きく最適化された可能性があります。
0
0
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
0
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?