Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

PHPにおける時間表記のISO-8061、DATE_ATOM、DATE_RFC3309、DATE_W3Cの違いは何か

ISO-8601時刻表記について

ISO-8601はあまり使わない時刻を表記する形式ではあるがAtomフィード時刻表記でその互換規格として利用されます。Atomについては最近記事を書いたのでそちらを参照してください。RSSより便利なAtomデータの詳細と利用方法について簡単にまとめてみた - Yuta.Kikuchiの日記 はてなブックマーク - RSSより便利なAtomデータの詳細と利用方法について簡単にまとめてみた - Yuta.Kikuchiの日記ISO-8601とは簡単に説明すると時刻の表記を以下のような形式で表現します。

  • 年、月、日の関係はYYYY-MM-DDと表記する。(2012-01-24、20120124)。
  • 年、年内の日番号はYYYY-DDDと表記する。(2012024) 2012年の24日目。
  • 年、週、曜日をYYYY-Www-Dと表記する。(2012-W04-2) 2012年の4週目の火曜日。すなわち2012/01/24。
  • 時刻の表記にはhh:mm:ssの形式が利用される。
    • 10時30分20.5秒 ( 10:30:20,5 )
    • 10:30,5(1130,5)は10:30:30と同じ。
    • 10.5は10:30と同じ。
  • timezone指定
    • UTCでは時刻の後ろにZを添える。2012-01-24T12:00Z
    • UTC以外では時刻の後ろに+-hh:mm、+-hhmm、+-hhのいずれかを添える。2012-01-24T12:00+09:00(日本時間での2012/01/24の12時)
  • 日付と時刻の間にはTを入れる。2012-01-24T12:00+09:00
  • 期間を表記する場合は開始日時/終了日で表記する。2012-01-01T00:00+09:00/2012-01-24T12:00+09:00 (2012/01/01の0時〜2012/01/24の12時)

年/月/日の表記が省略表記等自由に表現できることや期間の表現が可能であるというメリットはありますが、定義が曖昧なのと人の目には分かりづらい表記のように思います。(timestampよりはましですが)。しかしほとんどのプログラミング言語ミドルウェアはこの表記をサポートしているということで覚えた方が良いという事です。

AtomのDateコンストラクタ

RFC 4287 The Atom Syndication Format 日本語訳 はてなブックマーク - RFC 4287 The Atom Syndication Format 日本語訳 ここのDateコンストラクタ定義によるとRFC3339に準拠している必要があるようですが、この規格自体がISO-8601やW3C.NOTE-datetime-19980827、W3C.REC-xmlschema-2-20041028と互換性があります。以下はDateコンストラクタの簡単な例になります。

<updated>2012-01-24T00:00:00Z</updated>
<updated>2012-01-24T00:00:00.00Z</updated>
<updated>2012-01-24T00:00:00+09:00</updated>
<updated>2012-01-24T00:00:00.00+09:00</updated>

PHPでの各規格の表記の違い

PHP: DateTime - Manual はてなブックマーク - PHP: DateTime - Manual
ここに載っているDateTime Manualの表記の違いについてコメントしますが、結論からするとISO8601だけ少し表記が違うぐらいの差でしかありません。なぜなら上のISO-8601の定義から同じ時刻を示すからです。規格自体が変わらないのだとすれば定数を増やすのは無意味と感じてしまいます。

定数 実データ
DATE_ISO8601 2012-01-23T23:14:15+0900
DATE_RFC3339 2012-01-23T23:14:15+09:00
DATE_ATOM 2012-01-23T23:14:15+09:00
DATE_W3C 2012-01-23T23:14:15+09:00

PHP: date - Manual はてなブックマーク - PHP: date - Manual
こちらのdate関数の説明も更に混乱を招きます。date関数の第一引数に'c'を指定するとISO8601形式と書いてありますが、実際には他の3パターンの時刻表記で表示されます。以下はPHPのサンプルコードとその実行結果です。どれも同じ値を示しますが混乱しないように注意しましょう。

<?

//timezone設定
date_default_timezone_set('Asia/Tokyo');

//ISO 8601
echo date( DATE_ISO8601, time() ) . "\n";
echo date( 'Y-m-d\TH:i:sO', time() ) . "\n";

//ATOM
echo date( 'c', time() ) . "\n";
echo date( 'Y-m-d\TH:i:sP' ) . "\n";
echo date( DATE_ATOM, time() ) . "\n";

//RFC3339
echo date( 'Y-m-d\TH:i:sP' ) . "\n";
echo date( DATE_RFC3339, time() ) . "\n";

//W3C
echo date( 'Y-m-d\TH:i:sP' ) . "\n";
echo date( DATE_W3C, time() ) . "\n";
2012-01-24T00:00:00+0900
2012-01-24T00:00:00+0900
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00
2012-01-24T00:00:00+09:00

Pythonで表記するとどうなるか

折角なのでPythonでも上の時刻表期に挑戦してみます。ISO-8601とRFC3339を見てみます。それぞれパース用のパッケージが作成されています。ISO-8601RFC3339です。今回は標準モジュールのimportでISO-8601とrfc3339.pyを利用してRFC3339の時刻表記の作成を行いたいと思います。

  • ISO-8601
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import tzinfo, timedelta, datetime
class TZ(tzinfo):
    def utcoffset(self, dt): return timedelta(minutes=+540)
print datetime(2012, 01, 24, 00, 00 tzinfo=TZ()).isoformat()
  • RFC3339
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rfc3339 as rfc3339
rfc3339.UTC_TZ=rfc3339.tzinfo(540,'Z')
print rfc3339.now()