PHP の「サポートされているタイムゾーン」を保存するためのベスト プラクティスは何なのか疑問に思っています。各ユーザーのタイムゾーンを保存しているので、UTC との間で現地時間に変換できます。varchar 型のフィールドに文字列として格納しますか? この場合、サポートされている最長のタイムゾーン文字列は? これらを保存するためのより良い方法はありますか? PHP の datetime オブジェクトのように DST が自動的に考慮されないため、単にタイムゾーン オフセットを保存することはできません。
3 に答える
これは、この質問のほぼ正確な複製です: データベースにタイムゾーンを保存する適切な方法は?
しかし、私はあなたが言及した他のいくつかの点に対処します:
PHP タイム ゾーンはIANA タイム ゾーンです。
名前を に保存するだけ
varchar
です。タイムゾーン名のフィールド長について は、ここでいくつかの議論があります。varchar(32)
動作しますが、安全を期すために、将来の変更のために余分な余地を残しておきます. 255 はおそらくやり過ぎですが、おそらくvarchar(50)
妥当でしょう。多くの人が UTC をデータベースに保存することを推奨しています。これは良い習慣である場合もありますが、常に行うべきこととして推奨されている場合は好きではありません。UTC を使用する正当な理由と、現地時間を使用する正当な理由があります。
UTC を使用する場合は、タイム ゾーン名が必要になり、入力と出力で現地時間との間で変換する必要があります。
現地時間を使用する場合は、現地時間に加えてタイム ゾーンオフセットを常に保存する必要があります。これは、DST への移行時に現地時間が曖昧になる可能性があるためです。一部のデータベースには、
TIMESTAMP WITH TIMEZONE
Oracle、Postgres、またはDATETIMEOFFSET
SQL Sever など、このためだけのタイプがあります。残念ながら、MySql にはこのための型がないため、2 つの列が必要になります。データが一度だけ記録され、変更されていない場合 (記録されたイベント時間など)、これらのオプションのいずれかが実行可能です。UTC には、数学と変換の準備ができているという利点があります。現地時間には、オブザーバーの視点が維持されるという利点があります。.Net に関するDateTimeと DateTimeOffset を参照してください。ただし、ここでも概念は適用されます。
これらの時刻を編集する場合は、いずれにしてもタイム ゾーン名が必要になるため、保存しておくことをお勧めします。記録されたタイムスタンプごとに保存するか、ユーザーごとに 1 回だけ保存するかを決定できます。ユーザーが自分のタイム ゾーンを変更した場合にどうするかを考える必要があります。それはどこにでも適用されるべきですか?それとも、新しく記録されたエントリのみですか?
UTC として保存しないと考えることができる実用的な理由がいくつかあります。
数百行または数千行を出力するレポートを実行していて、目的の出力が記録された現地時間である場合、UTC からの変換をタイトなループで何度も繰り返す必要があるため、レポートの実行時間が遅くなる可能性があります。 .
表示されているとおりに時刻を正確に保存することが法的に要求される場合があります。技術者でない監査人は、いかなる種類の変換も許可せず、UTC 時間を違法と見なす可能性があります。現地時間にオフセットを加えた値を見ると、おそらくオフセット部分は気にせず、現地時間の値で満足するでしょう。ばかげているように思えるかもしれませんが、これらの要件が存在する業界や法域があります。
場合によっては、実際には 1 つの瞬間を参照するのではなく、特定の時間のローカライズされた表現を参照したいことがあります。アメリカ中に、すべて午前 6 時にオープンするレストランがあるとします。午前 6 時は、太平洋時間では東部時間とは異なります。これらを UTC として保存すると、特に DST の変更に関して、無効な仮定につながる可能性があります。
他のほとんどの場合、UTC として保存することをお勧めします。ただし、特定の要件に最適なものを決定する必要があります。
私は常に日付と時刻を UNIX タイムスタンプとして整数フィールドに保存します。そうすれば、データベースから何を取得するかを正確に知ることができます。このリストの文字列表現を使用して、タイムゾーンをテキスト フィールドに格納することをお勧めします。
たとえば、stackoverflow とも呼ばれるデータベース内の、stackoverflow と呼ばれるこのようなテーブル:-
+--+----------+-------------+
|id|date_time |time_zone |
+--+----------+-------------+
|1 |1373212914|Europe/London|
|2 |1373212914|Europe/Rome |
+--+----------+-------------+
次に、DateTime オブジェクトを次のようにハイドレートします。
$dsn = 'mysql:dbname=stackoverflow;host=127.0.0.1';
$user = 'stackoverflow';
$password = 'stackoverflow';
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
$sql = 'select date_time, time_zone from stackoverflow';
$statement = $dbh->prepare($sql);
$statement->execute();
$results = $statement->fetchAll();
foreach($results as $result){
$datetimes[] = (new \DateTime())->setTimestamp((int)$result['date_time'])->setTimezone(new \DateTimeZone($result['time_zone']));
}
var_dump($datetimes);
これにより、次の出力が得られます:-
array (size=2)
0 =>
object(DateTime)[3]
public 'date' => string '2013-07-07 17:01:54' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/London' (length=13)
1 =>
object(DateTime)[4]
public 'date' => string '2013-07-07 18:01:54' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Rome' (length=11)
テーブルを調べると、両方のエントリのタイムスタンプが同じであることがわかります。これは に相当し2013-07-07 16:01:54 UTC
ますが、クライアントに送信されると、保存されたタイムゾーンで正しく表されます。
すべての時刻を UTC として保存し、タイムゾーン オフセットを持つ別のフィールドを作成します。
これは実際には PHP の問題ではなく、タイムゾーンを使用するためのデータベースのベスト プラクティスです。常に UTC でデータを保存します。-10 などの TZ オフセット用の別のフィールド、または「Europe/Amsterdam」などのタイムゾーンとして別のフィールドを用意します。私にとっては、python で pytz を使用してこの問題に対処しています。
DST はいつでも回復できます。