PHPでISO 8601(RFC 3339)形式のタイムスタンプを表示する

(1/1)
インターネットのコンテンツは、世界中で閲覧することができる。
コンテンツの中にある時刻表記は、クライアントPCが置かれている地域の現地時間なのか、それともサーバが置かれている地域の現地時間なのか、はたまた世界標準時なのか――タイムゾーン(世界標準時間と地方時間の差)を明らかにする必要がある。
そこで今回は、与えた日時をインターネットの標準形式である ISO 8601形式で表示するプログラムを紹介する。

ISO 8601 形式は RFC 3339 とほぼ同じ内容である。日本では、JIS X 0301 として規格化されている。

(2021年3月27日)PHP8対応,リファラ・チェック改良。
(2019年5月4日)JST以外にも対応した(タイムゾーン汎用)。

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

PHPでISO 8601(RFC 3339)形式のタイムスタンプを表示する

サンプル・プログラムのダウンロード

圧縮ファイルの内容
RFC3339.phpサンプル・プログラム本体

解説:UNIX時間をUTCに変換

ユーザー関数 unix2utc は、与えたUNIX時間を ISO 8601(RFC 3339)形式のUTC(協定世界時)に変換する。
UNIXタイムスタンプは、UNIX epoch(1970年1月1日 0時0分0秒)を0とする秒数である。これを UTC に変換するには、組み込み関数  gmdate  を使う。

ISO 8601 形式のUTC表示は、「年:月:日T時:分:秒Z」である。年は西暦、時は24時制である。月、日、時、分、秒が1桁であるときには2桁目を0で埋める(ゼロサプレス)。

 135: /**
 136:  * UNIXタイムスタンプからRFC3339 UTC タイムスタンプを返す
 137:  * @param   int $unix UNIXタイムスタンプ
 138:  *                      Unix epoch(1970年1月1日 00:00:00 GMT))からの通算秒
 139:  * @return  ISO 8601(RFC 3339) UTC
 140: */
 141: function unix2utc($unix) {
 142:     return (gmdate('Y-m-d', $unix. 'T' . gmdate('H:i:s', $unix. 'Z');
 143: }

解説:UTCをローカル時間に変換

ユーザー関数 utc2local は、与えた RFC 3339形式UTCISO 8601ローカル時間(現地時間)に変換する。
1番目の引き数として ISO 8601UTC、2番目の引数としてローカル時間とUTCとの差(時)、3番目の引数としてローカル時間とUTCの差(分)を指定する。3番目の引数は省略可能である。

ISO 8601 のローカル時間表記は、「年:月:日T時:分:秒±UTCとの差(時):UTCとの差(分)」である。規格上、UTCの時、分、秒は省略可能であるので、省略された場合の処理が回りくどくなっている。
UTC は、いったんUNIXタイムスタンプに戻し、あらためてローカル時間表記に変換する。

 145: /**
 146:  * ISO 8601(RFC 3339) UTC タイムスタンプをローカルのタイムスタンプに変換する
 147:  * @param   string $utc ISO 8601(RFC 3339) UTCタイムスタンプ
 148:  * @param   int $tz_hour タイムゾーン(UTCと地方時の差;時)
 149:  * @param   int $tz_min  タイムゾーン(分:省略時=0)
 150:  * @return  string ローカルのタイムスタンプ(ISO 8601(RFC 3339)表記)
 151:  *                 NULL=エラー(入力文字列が規定外など)
 152: */
 153: function utc2local($utc, $tz_hour, $tz_min=0) {
 154:     $tz_hour = func_get_arg(1);
 155:     //可変長変数を使う
 156:     $tz_min = (@func_num_args() >3? func_get_arg(2: (0);
 157: 
 158:     if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+\:[0-9]+\:[0-9]+Z/i', $utc) == 1) {
 159:         list($year, $month, $day, $hour, $minuite, $second) = sscanf($utc, '%d-%d-%dT%d:%d:%dZ');
 160:     } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+\:[0-9]+Z/i', $utc) == 1) {
 161:         list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dT%d:%dZ');
 162:         $second = 0;
 163:     } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+T[0-9]+Z/i', $utc) == 1) {
 164:         list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dT%dZ');
 165:         $minuite = 0;   $second = 0;
 166:     } else if (preg_match('/[0-9]+\-[0-9]+\-[0-9]+Z/', $utc) == 1) {
 167:         list($year, $month, $day, $hour, $minuite) = sscanf($utc, '%d-%d-%dZ');
 168:         $hour = 0;  $minuite = 0;   $second = 0;
 169:     } else {
 170:         return NULL;    //UTC書式エラー
 171:     }
 172: 
 173:     $tt = mktime($hour + $tz_hour, $minuite + $tz_min, $second, $month, $day, $year);
 174: 
 175:     $s = date('Y-m-d', $tt. 'T' . date('H:i:s', $tt);
 176:     $f = ($tz_hour < 0? '-' : '+';
 177: 
 178:     return sprintf('%s%s%02d:%02d', $s, $f, abs($tz_hour), $tz_min);
 179: }

解説:メインプログラム

 241: // メインプログラム ============================================================
 242: $utc = unix2utc(time());                //内蔵時計の日時をUTCに変換する
 243: $tz_hour = date('Z') / (60 * 60);       //タイムゾーン(時)
 244: $tz_name = date('T');                   //タイムゾーン略称
 245: $local = utc2local($utc, $tz_hour);     //JST = UTC + 09:00
 246: $errmsg = ($local == NULL? 'ローカル時間が計算できない' : '';
 247: 
 248: $HtmlBody = makeCommonBody($utc, $local, $tz_name, $errmsg);
 249: 
 250: // 表示処理
 251: echo $HtmlHeader;
 252: echo $HtmlBody;
 253: echo $HtmlFooter;

メインプログラムでは、組み込み関数  time  により内蔵時計の時間を取得し、これを UTC に変換する。
ローカル時間とのタイムゾーンは、組み込み関数  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 にマッピングされる。

参考サイト

(この項おわり)
header