この回答は、報奨金に対応するために更新されました。元の未編集の回答は境界線より下にあります。
バウンティの所有者によって追加されたほとんどすべての質問ポイントは、タイムゾーンのコンテキストで、MySQLとPHPの日時がどのように相互作用するかに関するものです。
MySQLにはまだ哀れな タイムゾーンのサポート 、つまり、インテリジェンスはPHP側でなければなりません。
- MySQLの接続タイムゾーンを設定 上記のリンクに記載されているようにUTCに。これにより、
NOW()
を含む、MySQLによって処理されるすべての日時が発生します。 、きちんと処理されます。 - 常に
DATETIME
を使用してください 、TIMESTAMP
は絶対に使用しないでくださいTIMESTAMP
で特別な動作が明示的に必要な場合を除きます。 。これは以前よりも痛みが少なくなります。- 大丈夫です 持っている場合は、Unixエポック時間を整数として保存します。 レガシー目的などのために。エポックはUTCです。
- MySQLの優先日時形式は、PHPの日付形式文字列
Y-m-d H:i:s
を使用して作成されます。
- すべてを変換する MySQLに保存する場合のPHPのUTCへの日時。これは以下に概説するように些細なことです
- MySQLから返された日時は、PHPのDateTimeコンストラクターに安全に渡すことができます。 UTCタイムゾーンも必ず渡してください!
- PHPDateTimeをエコーでユーザーのローカルタイムゾーンに変換します 、すぐに。ありがたいことに、他のDateTimeとのDateTimeの比較と計算では、それぞれが存在するタイムゾーンが考慮されます。
- あなたはまだPHPで提供されているDSTデータベースの気まぐれに任されています。 PHPとOSのパッチを最新の状態に保ちます。 MySQLをUTCの至福の状態に保ち、潜在的なDSTの煩わしさを1つ取り除きます。
ほとんどに対応します ポイントの。
最後にやっかいなことです:
- 以前にデータを挿入したことがある場合(たとえば、
NOW()
を使用した場合はどうすればよいですか? )タイムゾーンを気にせずに、すべての一貫性を維持しますか?
これは本当に迷惑です。他の回答の1つは、MySQLの CONVERT_TZ
、私は個人的に、選択と更新中にサーバーネイティブとUTCのタイムゾーンを切り替えることでそれを行いましたが、'私はそのようにハードコアだからです。
アプリは、ユーザーごとにDST自体を設定/選択できる必要もあります。
する必要はなく、すべきではありません 現代ではこれを行ってください。
最新バージョンのPHPには、DateTimeZone
があります。 クラス。
DateTimeZoneを
// UTC default
date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
$nowish = new DateTime('2011-04-23 21:44:00');
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.
// This will be PDT right now, UTC-7
$la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
$nowish->setTimeZone($la);
// and show the result
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00
この手法を使用することにより、システムは自動的に 現在DSTになっているかどうかをユーザーに確認せずに、ユーザーに適切なDST設定を選択します。
同様の方法を使用して、選択メニューをレンダリングできます。単一のDateTimeオブジェクトのタイムゾーンを継続的に再割り当てできます。たとえば、このコードは、現時点でのゾーンとその現在の時刻を一覧表示します。
$dt = new DateTime('now', new DateTimeZone('UTC'));
foreach(DateTimeZone::listIdentifiers() as $tz) {
$dt->setTimeZone(new DateTimeZone($tz));
echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}
クライアント側の魔法を使用することで、選択プロセスを大幅に簡素化できます。 Javascriptには、むらがありながら機能的 があります。 UTCオフセットを分単位で取得するための標準メソッドを使用した日付クラス 。これを使用して、ユーザーの時計が正しいという盲目的な仮定の下で、可能性のあるタイムゾーンのリストを絞り込むことができます。
この方法を自分で行う方法と比較してみましょう。実際に日付計算を実行する必要があります毎回 日時を操作するだけでなく、ユーザーが本当に気にしない選択をユーザーに押し付けます。これは最適ではないだけでなく、コウモリのグアノは非常識です。ユーザーにDSTサポートが必要なときに指示するように強制することは、トラブルと混乱を求めています。
さらに、これに最新のPHP DateTimeおよびDateTimeZoneフレームワークを使用する場合は、非推奨のEtc/GMT...
を使用する タイムゾーン文字列
名前付きタイムゾーンの代わりに。これらのゾーン名は将来のPHPバージョンから削除される可能性があるため、削除するのは賢明ではありません。私はこれらすべてを経験から言います。
tl; dr :最新のツールセットを使用して、日付計算の恐怖を避けてください。 名前付きのリストをユーザーに提示します 時間帯。 日付をUTCで保存 、これはDSTの影響を受けません。日時を表示されているユーザーが選択した名前付きタイムゾーンに変換します 、以前ではありません。
要求に応じて、GMTオフセットを分単位で表示する利用可能なタイムゾーンのループを次に示します。残念な事実を示すために、ここで議事録を選択しました。すべてのオフセットが1時間以内にあるわけではありません。 DST中に、実際には1時間ではなく30分先に切り替わるものもあります。結果として得られるオフセット(分単位)は必要 JavascriptのDate.getTimezoneOffset
のそれと一致します 。
$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc);
foreach(DateTimeZone::listIdentifiers() as $tz) {
$local = new DateTimeZone($tz);
$dt->setTimeZone($local);
$offset = $local->getOffset($dt); // Yeah, really.
echo $tz, ': ',
$dt->format('Y-m-d H:i:s'),
', offset = ',
($offset / 60),
" minutes\n";
}