Webアプリケーションのタイムゾーンの問題を解決する





タイムゾーンがモスクワと異なる地域でプロジェクトを開始したとき、現地時間とサーバー時間(モスクワのタイムゾーン)の違いの問題に直面しました。 プロジェクトの論理は日付と時間に強く結び付けられており、モスクワ時間に日付を残すことは不可能であったと言わなければなりません。 ほとんどすべての日付は、DATETIME形式でMySQLデータベースに保存されました。これは、後で判明したように、いくつかのタイムゾーンでアプリケーションを編成するには最適ではありません。



DATETIMEデータ型は、日付と時刻を1000-01-01 00:00:00-9999-12-31 23:59:59の範囲で格納するために使用されます。 サンプリング時には、データベースの一時的な設定に関係なく、日付は記録された日付とまったく同じように抽出されます。 CONVERT_TZ関数を使用して日付を特定のタイムゾーンに変換するか、他の方法で日付を手動で調整できます。



日付を保存する別のタイプTIMESTAMPは、タイムゾーンに応じて、MySQLに日付を保存する唯一のタイプです。 このデータ型は、保存されると、時刻をローカルからUTCに変換し、取得してゾーンに戻します。 重要なのは、すべての操作と出力がDATETIME型に似ていることです (MySQL 5.0以降)。

このタイプには非常に便利な機能もあります。レコードを更新するときだけでなく、NOW()をデフォルト値として設定できます。

TIMESTAMPの欠点は、日付範囲が制限されていることです(1970〜2038)。 このため、履歴イベントや遠い将来のイベントを保存するのには適していませんが、ここではタイムゾーンは重要ではありません。



そのため、コードとSQ​​Lクエリの大規模な書き換えを必要としないソリューションを見つける必要があったため、クエリの時間を調整したり、PHPツールを使用したりするオプションは成功しなかったようです。

その結果、次のことが行われました。

-データベース内のすべての日付がTIMESTAMPに変換されました

-ユーザーセッションを初期化するときに、MySQLとPHPのロケールを設定する次のコードのようなものが追加されました。



<?php

date_default_timezone_set($user->timezone);

db::q("SET `time_zone`='".date('P')."'");

?>







date_default_timezone_set()関数は、パラメーターとしてタイムゾーンの識別子文字列(たとえば、 "Europe / Moscow" )を受け取り、すべての日付および時刻関数に設定します。

SQLクエリは、現在の接続内のすべてのクエリのタイムゾーンを設定します(詳細については公式ドキュメントをご覧ください)。

その結果、このソリューションはさまざまなタイムゾーンでうまく機能し、問題を解決する有効な方法です。



この投稿の結論は簡単です。地理的に広い範囲のプロジェクトでは、タイムスタンプを保存するためにTIMESTAMP型を常に使用する必要があります。これは、将来の頭痛を避けるのに役立ちます。



UPD:正しく述べられているように、ベースは(上記のコードのように)オフセットではなく、タイムゾーンの識別子によって時間を設定する方が正しいです。そうでない場合、このゾーンの夏時間やその他の履歴の変更は考慮されません。 この場合、 mysql_tzinfo_to_sqlを使用してデータベースに関連データをロードし、タイムリーに更新する必要があります。



All Articles