プログラマの kon.T です。
前回はサイトの多言語化について解説しましたが、今回は多言語化に伴う「タイムスタンプの最適化」について触れようと思います。まずあなたが管理しているサイトにはさまざまな記事があり、これらに更新時間を示すタイムスタンプが表示される状況を想像してみてください。
このサイトを日本語・中国語の2言語対応にすれば、きっと中国からのアクセスも見込めるでしょう。しかしタイムスタンプが日本時間で表示された場合、1時間の時差がある中国からの訪問者は更新時刻を勘違する危険性があります。そこでサイトの多言語化には、時間の管理も必要となってくるわけです。本稿では会員マイページで、世界中のタイムゾーンを設定できる仕組みについて紹介します。
サーバ時間の取得
日本国内のサーバは日本時間に設定されているのが普通です。そしてサイト上での「時間」は、プログラムが置かれているサーバの設定に依存します。それではまず最初に、サーバの標準時をチェックしてみましょう。サーバに設定されたタイムゾーン情報を取得するには、date_default_timezone_get() 関数を使います。
echo date_default_timezone_get();
echo "<br />". date('Y-m-d / H:i:s');
日本時間に設定されているサーバであれば、次のように表示されるはずです。
Asia/Tokyo
2012-01-16 / 13:50:03
Wikipediaによるとタイムゾーンは現在約40種類存在し、そのうち日本は日本標準時(JST)を採用しています。また日本標準時はUTCよりも9時間進んでいるため「UTC + 9」、「UTC + 9:00」などと表記されます。ちなみに UTC とは協定世界時のことで、GMT(グリニッジ標準時)とほぼ同一のものです。ただユーザーの中には「グリニッジ標準時=英国時間」と思ってしまう人も多いため、後述するサマータイムの絡みからも「GMT +9」ではなく「UTC +9」という表記にした方が無難な気がします。
さて PHP 上でのタイムゾーン区分はどうなっているのかというと、実に540種類に分かれます。これはPHPが主要な都市ごとに標準時を定めているためです。
例えばヨーロッパの場合は大きく西ヨーロッパ標準時(WET / UTC + 0:00)、中央ヨーロッパ標準時(CET / UTC + 0:00)、ヨーロッパ標準時(EET / UTC + 0:00)の3つに分かれ、ドイツ、オーストリア、チェコ、ポーランドの4カ国は共に CET に属します。これらの国々はまったく同一の時間で動いているのですが、しかしPHP上では次の4種類に分かれてしまいます。
Europe/Berlin(ベルリン=ドイツ)
Europe/Prague(プラハ=チェコ)
Europe/Vienna(ウィーン=オーストリア)
Europe/Warsaw(ワルシャワ=ポーランド)
同一のタイムゾーンであっても、サマータイムの実施は国ごとや州ごとに異なる場合があるためにこうなっているのでしょうね。もちろんサイト設計の際に、これらすべてのPHPタイムゾーンを考慮する必要はありません。
タイムゾーンの変更
サーバには一つの定まったタイムゾーンが設定されています。会員(ユーザー)毎に時刻の見え方を変えるには、設定されているタイムゾーン自体を一時変更する必要があります。この一時的な変更には date_default_timezone_set() 関数を使います。
echo date_default_timezone_get();
echo "<br />";
echo date('Y-m-d / H:i:s');
echo "<br /><br />";
date_default_timezone_set("Europe/Berlin");
echo date_default_timezone_get();
echo "<br />";
echo date('Y-m-d / H:i:s');
実行結果
Asia/Tokyo
2012-01-16 / 13:50:03
Europe/Berlin
2012-01-16 / 05:50:03
この例ではまず date_default_timezone_get() で現在のサーバに設定されているタイムゾーンを表示して現在日時を表示。次にタイムゾーンを中央ヨーロッパ標準時(ベルリン)に変更し、改めて日時情報を表示しています。date_default_timezone_set()によって変更されたタイムゾーンは、PHPファイルを実行している間のみ有効ですので、このプログラムを何度実行しても同じ結果が得られるはずです。
サマータイム処理の実装
太陽の出ている時間帯を有効に利用する目的で、現行の時刻に一定の時間を加減する仕組み、あるいはその時刻をサマータイムと呼ぶのはご存知の通り。そして時間を扱う以上、この仕組は組み入れざるを得えないでしょう。しかしサマータイムは地域ごとに取り扱いが違うので注意が必要です。
サマータイムは現行時刻から1時間差っ引くのが通例ですが、場所によっては1時間ではなく30分であったり15分だったりもします。またサマータイムの開始・最終日も異なれば、日本のようにサマータイムを採用していない地域もあるなど、その運用は大きく異なります。そこでまずは該当の日時、あるいは現在日時が、現地でのサマータイム中にあるのか否かを判別しなければなりません。
サマータイム判定は date() 関数を使うことで簡単に知ることができます。
date('I');
if(date('I') == 0){ echo "通常時"}
if(date('I') == 1){ echo "サマータイム中"}
返り値が「0」であれば通常時、「1」であればサマータイム中を意味します。ではサマータイム中である 『2011年8月7日13時10分15秒』 のベルリン時間を表示してみましょう。
date_default_timezone_set("Europe/Berlin");
echo date_default_timezone_get();
echo "<br />";
$target_date = mktime(13,10,15,8,7,2011);
echo date('Y-m-d / H:i:s', $target_date);
echo "<br />";
$summer_chk = date("I" , $target_date);
if($summer_chk == "0"){ echo "通常時";}
if($summer_chk == "1"){ echo "サマータイム中";}
実行結果
Europe/Berlin
2011-08-07 / 13:10:15
サマータイム中
この例ではまず date_default_timezone_set()でタイムゾーンを中央ヨーロッパ標準時(ベルリン)に変更し、確かに変更されたことを確認するために date_default_timezone_get(); をエコーしています。次に該当日時のUnixtimeを取得し、さらにこの日時を定型フォーマットで表示。そして最後にこの日がサマータイム中であるか否かを判定しています。
間違いやすいのですが、この場合は「8月7日の13時10分15秒のベルリン」がサマータイム中であることを示しています。またここで表示している時間はサマータイム中であることから、すでにベルリンの標準時より「1」を引いた時間であるということを理解してください。
日時データの保存
各記事の更新日時をデータベースやファイルに保存する際、記事を入力した「個々の会員にとって標準時」で登録すると処理がややこしくなってしまいます。そこでシステム内での日時データは一つのタイムゾーンに統一し、表示するときにその都度、会員の設定に合わせた調整を行う方がよいわけです。

しかしサーバが日本時間に設定されているからといって、日本時間を基準にすべきでないでしょう。今後もし日本がサマータイムに対応すれば内部計算が合わなくなってしまいますから。そこで日時データはサマータイムの影響を受けないUTC、あるいは Unixtime で保存するのが正解のような気がします。
会員ごとの標準時設定
時間情報を正確に表示するには、「個々の会員にとっての標準時」を事前に登録する必要があります。調べてみたところ、サマータイムを加味すると60種類のタイムゾーンに分かれるようです。これが正しいかどうかは別として、右図のようなタイムゾーンリスト作成して見ました。内部構造は次の通り。
<OPTION value="Asia/Brunei" >UTC +08:00 中国、シンガポール</OPTION>
<OPTION value="Asia/Irkutsk" >UTC +08:00 ロシア第7標準時 - IRKT</OPTION>
<OPTION value="Asia/Tokyo" >UTC +09:00 日本、韓国、パラオ </OPTION>
<OPTION value="Asia/Yakutsk" >UTC +09:00 ロシア第8標準時 - YAKT</OPTION>
<OPTION value="Australia/Darwin">UTC +09:30 ノーザンテリトリー(豪)</OPTION>
マイページではまず会員が設定したタイムゾーンを読み取り、date_default_timezone_set() 関数でタイムゾーンを変更します。これでマイページは、会員が設定したタイムゾーンで稼働することとなります。
おわりに
表示日時をタイムゾーンに合わせて変化させる場合は、表示中のタイムゾーン情報を表示した方がユーザーに優しいと言えるでしょう。
2011-08-07, 13:0:15 (UTC+0100)
例えば上記の例は、協定世界時より1時間遅いタイムゾーンを基準として表示しています。ただこれだとサマータイムが加味されているのか否か解かり辛いため、下記のような表記が望ましいでしょう。
2011-08-07, 13:0:15 (WET: Western European Time, UTC+0100)
↑※西ヨーロッパ時間で UTC+0100 なので、これはサマータイム中ということになります。
今回は会員が事前にタイムゾーンを設定する、マイページの例を取り上げました。精度は多少落ちますが、接続元のIPやブラウザ表示言語を読み取ることでも、ユーザーのタイムゾーンを推定することが可能です。