PHPめも

PHPで作成したWEBアプリで未来や過去の日時に変更して動作確認したいことは結構あります。
いくつかやり方はあります。

dateコマンドを使う

よく使われるのはdateコマンドでサーバの時間を変更してしまうことでしょう。
ただ他のWEBアプリに影響が出たり、PHP-FPMのキャッシュが更新されなかったりと何かと悪影響が出るのでおすすめしないです。

現在日時を確認

# date
Fri Nov  3 01:24:56 UTC 2023

2023年11月4日12時に変更

# date --set "2023/11/04 12:00:00"
Sat Nov  4 12:00:00 UTC 2023

確認

# date
Sat Nov  4 12:00:03 UTC 2023

戻す

# ntpdate -s -b ntp.jst.mfeed.ad.jp

Docker環境で operation not permitted のエラーが出る場合は docker-compose.yml へ設定を追加します。

services:
  app:
    # これを追加
    privileged: true

ntpdate が無い場合は入れます。

# apt install ntpdate

Carbonを使う

setTestNow が使えます。
ただ使えるようにあらかじめ書いておかないといけないです。

$knownDate = Carbon::create(2001, 5, 21, 12);          // create testing date
Carbon::setTestNow($knownDate);                        // set the mock (of course this could be a real mock object)
echo Carbon::getTestNow();                             // 2001-05-21 12:00:00
echo Carbon::now();                                    // 2001-05-21 12:00:00
echo new Carbon();                                     // 2001-05-21 12:00:00
echo Carbon::parse();                                  // 2001-05-21 12:00:00
echo new Carbon('now');                                // 2001-05-21 12:00:00
echo Carbon::parse('now');                             // 2001-05-21 12:00:00
echo Carbon::create(2001, 4, 21, 12)->diffForHumans(); // 1 month ago
var_dump(Carbon::hasTestNow());                        // bool(true)
Carbon::setTestNow();                                  // clear the mock
var_dump(Carbon::hasTestNow());                        // bool(false)
echo Carbon::now();                                    // 2023-10-03 07:59:07
// Instead of mock and clear mock, you also can use withTestNow():

Carbon::withTestNow('2010-09-15', static function () {
    echo Carbon::now();
});                                                    // 2010-09-15 00:00:00

https://carbon.nesbot.com/docs/#api-testing

Chronosを使う

Carbonと同様に setTestNow が使えます。
ただ使えるようにあらかじめ書いておかないといけないです。

Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));

$time = new Chronos(); // 1975-12-25 00:00:00
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00

https://book.cakephp.org/chronos/2/ja/index.html#id11

php-timecopを使う

PHPの拡張モジュールを入れる方法です。
個人的におすすめ。

PECLが用意されていますが、PHP7.2までしか対応していません。
https://pecl.php.net/package/timecop

Gitもありますが、同様メンテナンスが止まっています。
https://github.com/hnw/php-timecop

さらに調べると本家からforkして2023年11月時点でPHP8.2まで対応しているのでこれを使います。
https://github.com/kiddivouchers/php-timecop

インストール

# cd /usr/local/src/
# git clone https://github.com/kiddivouchers/php-timecop.git
# cd php-timecop
# phpize
# ./configure
# make
# make install
# vi /usr/local/etc/php/php.ini
extension=timecop.so

WEBサーバを再起動して timecop が含まれているか確認します。

# php -m

使用方法

使える関数は3つです。

if (function_exists('timecop_freeze')) {
    $unixtimestamp = (new \DateTime('2023-11-04 12:00:00'))->format('U');

    // 日時を固定
    timecop_freeze($unixtimestamp);

    echo (new \DateTime())->format('Y-m-d H:i:s').'<br>';
    echo date('Y-m-d H:i:s').'<br>';

    // 日時へ変更
    timecop_travel($unixtimestamp);

    echo (new \DateTime())->format('Y-m-d H:i:s').'<br>';
    echo date('Y-m-d H:i:s').'<br>';

    sleep(10);

    echo (new \DateTime())->format('Y-m-d H:i:s').'<br>';
    echo date('Y-m-d H:i:s').'<br>';

    // 日時を戻す
    timecop_return();
}

結果

2023-11-04 12:00:00
2023-11-04 12:00:00
2023-11-04 12:00:00
2023-11-04 12:00:00
2023-11-04 12:00:10
2023-11-04 12:00:10

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-11-03 (金) 11:07:37