サンプル・プログラムの実行例

サンプル・プログラムのダウンロード
RFC3339.php | サンプル・プログラム本体 |
解説:UNIX時間をUTCに変換
UNIXタイムスタンプは、UNIX epoch(1970年1月1日 0時0分0秒)を0とする秒数である。これを UTC に変換するには、組み込み関数 gmdate を使う。

ISO 8601 形式のUTC表示は、「年:月:日T時:分:秒Z」である。年は西暦、時は24時制である。月、日、時、分、秒が1桁であるときには2桁目を0で埋める(ゼロサプレス)。
0135: /**
0136: * UNIXタイムスタンプからRFC3339 UTCタイムスタンプを返す
0137: * @param int $unix UNIXタイムスタンプ
0138: * Unix epoch(1970年1月1日00:00:00 GMT))からの通算秒
0139: * @return ISO 8601(RFC 3339) UTC
0140: */
0141: function unix2utc($unix) {
0142: return (gmdate('Y-m-d', $unix) . 'T' . gmdate('H:i:s', $unix) . 'Z');
0143: }
解説:UTCをローカル時間に変換
1番目の引き数として ISO 8601 の UTC、2番目の引数としてローカル時間とUTCとの差(時)、3番目の引数としてローカル時間とUTCの差(分)を指定する。3番目の引数は省略可能である。

ISO 8601 のローカル時間表記は、「年:月:日T時:分:秒±UTCとの差(時):UTCとの差(分)」である。規格上、UTCの時、分、秒は省略可能であるので、省略された場合の処理が回りくどくなっている。
UTC は、いったんUNIXタイムスタンプに戻し、あらためてローカル時間表記に変換する。
0145: /**
0146: * ISO 8601(RFC 3339) UTCタイムスタンプをローカルのタイムスタンプに変換する
0147: * @param string $utc ISO 8601(RFC 3339) UTCタイムスタンプ
0148: * @param int $tz_hourタイムゾーン(UTCと地方時の差;時)
0149: * @param int $tz_min タイムゾーン(分:省略時=0)
0150: * @return stringローカルのタイムスタンプ(ISO 8601(RFC 3339)表記)
0151: * NULL=エラー(入力文字列が規定外など)
0152: */
0153: function utc2local($utc, $tz_hour, $tz_min=0) {
0154: $tz_hour = func_get_arg(1);
0155: //可変長変数を使う
0156: $tz_min = (@func_num_args() >= 3) ? func_get_arg(2) : (0);
0157:
0158: if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+\:[0-9]+\:[0-9]+Z/i', $utc) == 1) {
0159: list($year, $month, $day, $hour, $minuite, $second) = sscanf($utc, '%d-%d-%dT%d:%d:%dZ');
0160: } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+\:[0-9]+Z/i', $utc) == 1) {
0161: list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dT%d:%dZ');
0162: $second = 0;
0163: } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+Z/i', $utc) == 1) {
0164: list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dT%dZ');
0165: $minuite = 0; $second = 0;
0166: } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+Z/', $utc) == 1) {
0167: list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dZ');
0168: $hour = 0; $minuite = 0; $second = 0;
0169: } else {
0170: return NULL; //UTC書式エラー
0171: }
0172:
0173: $tt = mktime($hour + $tz_hour, $minuite + $tz_min, $second, $month, $day, $year);
0174:
0175: $s = date('Y-m-d', $tt) . 'T' . date('H:i:s', $tt);
0176: $f = ($tz_hour < 0) ? '-' : '+';
0177:
0178: return sprintf('%s%s%02d:%02d', $s, $f, abs($tz_hour), $tz_min);
0179: }
解説:メインプログラム
0241: // メインプログラム ============================================================
0242: $utc = unix2utc(time()); //内蔵時計の日時をUTCに変換する
0243: $tz_hour = date('Z') / (60 * 60); //タイムゾーン(時)
0244: $tz_name = date('T'); //タイムゾーン略称
0245: $local = utc2local($utc, $tz_hour); //JST = UTC + 09:00
0246: $errmsg = ($local == NULL) ? 'ローカル時間が計算できない' : '';
0247:
0248: $HtmlBody = makeCommonBody($utc, $local, $tz_name, $errmsg);
0249:
0250: // 表示処理
0251: echo $HtmlHeader;
0252: echo $HtmlBody;
0253: echo $HtmlFooter;
ローカル時間とのタイムゾーンは、組み込み関数 date に引数 'Z' を与えることで求めることができる。また、タームゾーンの略称は、 date に引数 'T' を与えることで求めることができる。

なお、 date に引数 'c' を与えることで、ISO 8601 形式のローカル時間を求めることができるが、これはPHP 5で加わった機能なので、今回は使用を見送りにした。

ここで、timeの代わりに組み込み関数 filemtime を使えば、ファイルのタイムスタンプ(最終更新日時)を ISO 8601 にすることができる。

余談になるが、標準関数 mktime の引き数の順番は、時,分,秒,月,日,年だが、年の部分は2桁または4桁の西暦年号を代入する。2桁の場合、 0~69 の間の値は 2000~2069 に、70~100 は 1970~2000 にマッピングされる。
参考サイト
- タイムスタンプの必要性:ぱふぅ家のホームページ
- 国際原子時と協定世界時:ぱふぅ家のホームページ
- PHPでRFC3339形式のタイムスタンプを解釈する:ぱふぅ家のホームページ
- RFC 3339(和訳)
コンテンツの中にある時刻表記は、クライアントPCが置かれている地域の現地時間なのか、それともサーバが置かれている地域の現地時間なのか、はたまた世界標準時なのか――タイムゾーン(世界標準時間と地方時間の差)を明らかにする必要がある。
そこで今回は、与えた日時をインターネットの標準形式である ISO 8601形式で表示するプログラムを紹介する。
ISO 8601 形式は RFC 3339 とほぼ同じ内容である。日本では、JIS X 0301 として規格化されている。
(2021年3月27日)PHP8対応,リファラ・チェック改良。
(2019年5月4日)JST以外にも対応した(タイムゾーン汎用)。