🥞
【PHP】Carbon で 「YYYY-MM-DDTHH:MM:SSZ」の形式で強制的にUTC時刻にされてしまう罠
概要
PHPのCarbonを使用した際に日付形式「YYYY-MM-DDTHH:MM:SSZ」(ISO 8601)の場合にある罠。
サンプル
使用するCarbonのコンストラクタです。
Carbon::__construct
$time = null, $tz = null
Create a new Carbon instance.
サンプルコード(失敗編)
<?php
echo (new Carbon('2020-11-05T12:34:56Z'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56Z', 'UTC'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56Z', 'Asia/Tokyo'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56Z', 'America/Vancouver'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
結果は何故か全て同じ…
サンプルコード(成功編)
<?php
echo (new Carbon('2020-11-05T12:34:56Z'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56Z'))->timezone('UTC')->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56Z'))->timezone('Asia/Tokyo')->toString();
// Thu Nov 05 2020 21:34:56 GMT+0900
echo (new Carbon('2020-11-05T12:34:56Z'))->timezone('America/Vancouver')->toString();
// Thu Nov 05 2020 04:34:56 GMT-0800
タイムゾーンを設定することで正確な時間の取得が可能になりました。
原因
末尾の「Z」を削除すると普通にタイムゾーンごとの結果が受け取れます。
<?php
echo (new Carbon('2020-11-05T12:34:56'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56', 'UTC'))->toString();
// Thu Nov 05 2020 12:34:56 GMT+0000
echo (new Carbon('2020-11-05T12:34:56', 'Asia/Tokyo'))->toString();
// Thu Nov 05 2020 21:34:56 GMT+0900
echo (new Carbon('2020-11-05T12:34:56', 'America/Vancouver'))->toString();
// Thu Nov 05 2020 04:34:56 GMT-0800
可能性ですがおそらく、内部処理的にはタイムゾーン設定後に日時の設定を行っているようです。
そのため、末尾にZが着いていると以下の処理を行っているものと考えられます。
1.タイムゾーンを設定
2.日時の末尾にZが付いてる
3.タイムゾーンはUTCの時間
最後にCarbonはPHPの DateTime class を拡張しているので DateTimeクラスを使用していれば、おそらく同様の現象が発生すると思います。
(未確認)
Discussion