【PHP】JavaScriptが出力するISO 8601形式の時刻をDateTimeオブジェクトに変換する
はじめに
PHPをバックエンド、JavaScriptをフロントエンドで使っていて、フロントから投げた日付データをPHPで取り扱う際に少しハマったため、メモとして残しておきます。
PHPのバージョン
- PHP 8.0.8
JavaScriptの作成するISO 8601形式の日付
JavaScriptではDate
オブジェクトから、次のようにするとISO 8601形式の文字列を生成できます。
const today = new Date('2022-10-18 15:00:00');
console.log(today.toISOString());
この出力結果は以下のようになります。末尾の"Z"はUTCを表します。
2022-10-18T06:00:00.000Z
PHPでJavaScriptのISO 8601形式の日付をDateTimeオブジェクトに変換する
PHPでJavaScriptのtoISOString()
が生成するISO 8601形式の文字列をDateTime
オブジェクトに変換するためには注意が必要です。PHPのマニュアルでDateTimeオブジェクトを見ると、DateTime::ISO8601
という書式が定義されていますが、これはマニュアルに記載がある通り使えません。
注意: このフォーマットは、ISO-8601 と互換性がありません。 しかし、後方互換性を保つために残されています。 ISO-8601 と互換性を保つためには、 DateTimeInterface::ISO8601_EXPANDED, DateTimeInterface::ATOM を使うようにしてください。
注釈にあるようにDateTime::ATOM
またはDateTime::ISO8601_EXPANDED
を使えとなっていますので、試しに使ってみます。
$date = DateTime::createFromFormat(DateTime:ATOM, "2022-10-18T06:00:00.000Z");
var_dump($date);
この出力結果は以下のようになります。
bool(false)
なんと、パースに失敗します。
PHPのDateTime::ATOM
は、JavaScriptのtoISOString()
の吐き出す形式と互換性がありません。
あらためて、PHPのマニュアルを見てみると、DateTime::ATOM
は次のように定義されています。
const string DateTimeInterface::ATOM = "Y-m-d\TH:i:sP";
ここからわかるように、書式にミリ秒が指定されていません。このため、パースに失敗します。
対策
対策として、ミリ秒に対応した書式を指定します。これには、DateTime::RFC3339_EXTENDED
を使用しますが、PHPはタイムゾーンとしてUTCを表す"Z"に対応していないため、"Z"を置換しておく必要があります。
$strDate = preg_replace("/Z$/", "UTC", "2022-10-18T06:00:00.000Z");
$date = DateTime::createFromFormat(DateTime::RFC3339_EXTENDED, $strDate);
$date->setTimeZone(new DateTimeZone("Asia/Tokyo"));
var_dump($date);
出力結果は以下のようになります。
object(DateTime)#1 (3) {
["date"]=>
string(26) "2022-10-18 15:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "Asia/Tokyo"
}
(2022/10/31追記)
もう1つの対策として、日時を扱うライブラリとして有名なCarbonを使うという方法もあります。Carbon::parse()
メソッドが多様な書式に対応しているので、特別な処理を必要とせずに、Carbon
オブジェクトに変換できます(Carbon
クラスはDateTime
クラスを継承しています)。
Laravelなどでは標準で採用されていることも多いので、こちらを使うのがよいかもしれません。
use Carbon\Carbon;
$date = Carbon::parse("2022-10-18T06:00:00.000Z");
$date->setTimeZone(new DateTimeZone("Asia/Tokyo"));
var_dump($date->toDateTimeString());
出力結果は以下のようになります。
string(19) "2022-10-18 15:00:00"
まとめ
JavaScriptが生成したISO 8601形式の時刻をPHPで取り扱う際の注意点についてまとめてみました。
サーバーとJSON形式でやり取りする際に、JavaScriptはDate
オブジェクトをtoISOString()
を使ってISO 8601形式に変換します。PHPで処理する際の注意点に関する情報がなかなか見つからなかったため、この記事が参考になれば幸いです。
ディスカッション
コメント一覧
まだ、コメントがありません