前提
以下のバージョンにおける情報です。
- PHP 5 >= 5.2.0
- PHP 7
ISO8601と互換性がないDateTime::ISO8601
PHPには DateTime::ISO8601
という定義済み定数があります。
この定義済み定数を利用して、以下のようなコードでフォーマットされた日付の文字列を取得できます。
$date = new DateTime();
echo $date->format(DateTime::ISO8601); // 2019-01-09T14:20:03+0000
上のコードを実行すると 2019-01-09T14:20:03+0000
のような文字列を取得できます。
DateTime::ISO8601
を指定して取得された文字列なので、ISO8601
に互換性があることを期待したのですが、なんと互換性はありません。
ISO8601
が規定している形式とは異なってしまっています。
ISO8601で規定されている形式
では、ISO8601とどう異なっているのでしょうか。
ISO8601には「基本形式」と「拡張形式」の2種類の形式があります。
それぞれ以下のようなものです。
形式 | 表記 |
---|---|
基本形式 | 20190109T142003+0000 |
拡張形式 | 2019-01-09T14:20:03+00:00 |
一見、 DateTime::ISO8601
で得られる文字列は「拡張形式」のように見えますが、よく見るとタイムゾーンの表記が異なります。
拡張形式のタイムゾーンにはコロンが入りますが、 DateTime::ISO8601
で得られる文字列にはコロンが入っていません。
よって、基本形式と拡張形式のどちらにも互換性のない文字列となってしまっています。
ISO8601に互換性のない文字列によって起こる問題
このISO8601に互換性のない文字列をPHP内だけで扱う場合には問題は起きないかもしれません。
しかし、APIなど外部と連携するプログラムを書く場合には注意が必要です。
APIレスポンスとして受信した側が、この文字列を日時としてパースできない可能性があるからです。
JavaScriptの場合
JavaScriptでは一部のブラウザで、パースできない問題があります。
APIをPHPで構築しフロントエンドのJavaScriptでそれを呼び出す、というシチュエーションは多くあるので要注意です。
new Date('2019-01-09T14:20:03+0000')
ブラウザ | パース可否 |
---|---|
Chrome 71 | ○ |
Firefox 57 | ○ |
Safari 12 | ✗ |
Edge 18 | ○ |
IE11 | ✗ |
(Node.js v10) | ○ |
Rubyの場合
Ruby 2.4.0で試したところ、パース可能でした。
DateTime.parse('2019-01-09T14:20:03+0000')
Pythonの場合
Python 3.6.2で試したところ、パース可能でした。
from dateutil.parser import parse
parse('2019-01-09T14:20:03+0000')
ISO8601に互換性のあるフォーマットの日時を取得するには
では、 ISO8601
に互換性のあるフォーマットの日時文字列を取得したい場合はどうしたらいいでしょうか。
その場合には DateTime::ISO8601
ではなく DateTime::ATOM
を使用します。
$date = new DateTime();
echo $date->format(DateTime::ATOM); // 2019-01-09T14:20:03+00:00
上のコードでは、 2019-01-09T14:20:03+00:00
のようなISO8601の拡張形式に互換性のある文字列が取得できます。
ドキュメント