TimeZoneに基づいてDateTimeを保存するためのベストプラクティス


16

ユーザーがTimeZoneに基づいて予定をスケジュールできるWebアプリケーションを開発します。そして、ユーザーの予定日時をサーバー日時としてデータベースフィールドに保存しています。スケジュール情報を表示しながら、データベースから値を取得し、ユーザーtimzoneに変換しました。コードベースでの処理ユーザーのタイムゾーンに基づいてDateTimeを変換しています。このベストプラクティスなのか、それとも簡単な方法が存在するのか教えてください。

回答:


33

非計算プログラミングで最も困難な問題の1つ、つまり、エンドユーザーに日付と時刻を適切に表すことへようこそ。

現実的には、タイムスタンプはどのように解釈されるかに関係なく、固定された単一の表現に格納される必要があります。そして、最悪のユースケースの1つ、つまり予定のスケジュールを選択しました。最悪の一般的なユースケースは空の旅です。旅行はあるタイムゾーンで始まり、別のタイムゾーンで終わる可能性があります。

常に、常に、常にUTCで保存し、ユーザーの優先または明示的に指定されたタイムゾーンで表示します。 可能な限り、ユーザーにタイムスタンプを入力するときにタイムスタンプがあると信じているタイムゾーンをユーザーに教えてください(たとえば、明示的なタイムゾーンフィールドを持ち、優先ゾーンを事前に入力します)。


1
+1。そしてその柔軟性。共通で一貫性のある普遍的な標準参照時間を持つことで、ローカルゾーンの「参照解除」が正しく行われます。
レーダーボブ

実際、アポイントメントのスケジュールは、UTCとして保存しない数少ない時間の1つです。DSTルールが変更された場合(またはUTCからのオフセット)、アポイントメント時間はどうなりますか?ほとんどの場合、予定時刻はローカルで同じままにする必要があります。つまり、UTC値が変更されます。UTCを簡単に導出できる「TimeInTimeZone + TimeZone」を表す値を保存する必要があります。クロスタイムゾーンスケジューリング(航空会社など)には制約があり、おそらく両方の組み合わせが使用されることを意味します。
時計仕掛けミューズ

1
ああ、それよりも悪くなります。私は定期的に他の国の同僚とミーティングを行っていますが、時間の変更のルールは私の国とは異なります。それが起こるとき、正しい答えは何ですか?実際、コンピュータはそれを知ることができません:-(
ロスパターソン

3

日付/時刻情報を処理する最も簡単な方法は、アプリケーションの要件によって異なります。

日付と時刻がユーザーによって入力され、サーバーがデータベースに保存する以外にその日付/時刻情報で処理を行わず、入力された時刻が表示されている場所に合わせられると予想されない場合(たとえば、 、ユーザーは「8:00 PM」と入力し、世界のどこにいても「8:00 PM」と表示されるはずです)、最も簡単な方法は、タイムゾーン情報なしで現地時間としてDateTimeを保存することです。

一方、サーバーが入力されたDateTimeをトリガーとして使用して何かを行う必要がある場合、または時刻を現在のタイムゾーンに正しく調整する必要がある場合、最善のオプションはDateTimeをUTC時間として保存し、ローカルに調整することですデータベースから読み取るたびに(ユーザーの現在の場所の)時間。


「現地時間で保存」の場合は-1、「UTCで保存」の場合は+1。
ロスパターソン

@RossPatterson:「ローカル時間で保存する」ための「-1」を説明できますか?私がそれを与えられた条件を考えると、なぜそれが悪い考えであるべきなのか興味があります。
バートヴァンインゲンシェナウ

1
たとえば、ユーザーのローカル時間を使用すると、すべての値が事実上数十の異なるデータ型の1つになります。つまり、「TIMESTAMP> '2013-08-27T12:00:00'」のように、それらに対してデータベース操作を実行することはできません。それは、夏時間の変換をいつ、いつ適用するかわからないことを意味します。
ロスパターソン

@RossPatterson:ありがとう。ほとんどの場合、現地時間は適切な解決策ではないことに同意します。
バートヴァンインゲンシェナウ

2

関連する2つの概念を混同しないことが重要です。

実際の時点、つまり特定の日の特定の時間を操作している場合、これを行う唯一の方法は、常にユニバーサルUTC時間値を使用することです。 これをタイムゾーン関連の値として保存しようとしないでください。この時間値をユーザーに表示するときは、常にその時間のユーザータイムゾーンに変換します。(そして、時間帯に依存する時刻と日付の両方を忘れないでください。)

もう1つの概念は、「毎週火曜日の午後8時」などの「時間表現」の概念です。人々がアポイントメントをスケジュールできるようにすることを具体的に述べましたが、アポイントメントを繰り返している場合は、そのような表現が必要です。私は標準的な表現言語を知りませんが、あなたが使用するものは何でも、それを指定した人のタイムゾーンに相対的です。これを明示するのが最適です。たとえば、「太平洋時間帯の毎週火曜日の午後8時」。時刻式の場合、これを常に文字列として保存し、システム時刻形式を一切使用しません。

私のブログでこれに関する議論もっと見る


1

ここでの多くの回答は、UTCとして保存することを示しています。しかし、これには本当に注意してください。たとえば、12:00に予定をスケジュールしているが、夏時間への変更後に予定が行われた場合、どうなりますか?UTCは、予定が保存されたときにdstがアクティブであったかどうかに関する情報を保持しません。多くの大きな有名なシステムがこのエラーを引き起こしました。ユーザーは夏の午前9時にメールを送信し、冬の送信時刻は午前8時に表示されます。日時が記録されたときではありません。

もっと良いのは、ユーザーが常に選んだ時間を持ちたいと思うことです。UTC変換、時間変換、タイムゾーン情報、なし。2016年3月21日の08:00から12:00までの予約はまさにそれです。現地時間またはUTC時間を使用せず、時間を指定しません(jsonではzも+もありません。基本的に、.NETではDateTime.Kind = DateTimeKind.Unspecifiedがあります)。

もちろん、異なるタイムゾーンの人と会議を行う会社であり、会社のカレンダーなどでこの情報を表示したいが、ユーザーが自分のタイムゾーンの何時かを表示できるようにするというユースケースの場合、より複雑になります。時間は、異なるタイムゾーンの異なる人々(供給者と顧客)に対して正確でなければなりません。

これらのケースでは、あなたも記録したいかもしれとき予定が何タイムゾーンで、データベースに保存された含まdstのか、もし。そのようにして、現在の時刻または過去の予定に合わせて、ローカル時刻を他の任意の時刻にいつでも戻すことができます。タイムゾーンは静的ではないため、事態はさらに複雑になります。

幸いなことに、ここでhttp://nodatime.org/のようなライブラリが登場し、強く推奨されます。日付をより一貫して使用します。その場合でも、インターフェイスを使用してモック化できるように、すべての日時変数とロジックを独自のラッパーでラップすることをお勧めします。そうすれば、後でロジックを切り替えることができます。


私はあなたの結論にまったく賛成しませんが、夏時間の変更に合わせて予定されている正午の会議は、数年先に予約された正午の毎週の会議と同様、特別な挑戦です。
ベント

もちろん、異なるタイムゾーンの人とミーティングを行う会社であり、会社のカレンダーなどでこの情報を表示したいが、ユーザーが自分のタイムゾーンの時間を確認できるようにする場合は、それはより複雑になります。」-それはほとんどすべての会社です。中国とインド以外のほとんどの企業は、タイムゾーンを越えた予約を無視できません。
ロスパターソン

そうすれば、現在時刻や過去の意図に合わせて、ローカル時刻をいつでも計算できます。タイムゾーンは静的ではないため、事態はさらに複雑になります。」-1回あなたは、あなたが計算をするつもりだことを受け入れて、本当に時間のための単一の表現を選択する必要があります。UTC、EST(EST5EDTではない)、IST、その他。ただし、同じフィールドに複数のタイムゾーンに基づいた値を設定して、それらに対して正当な集計処理を行うことはできません。表示処理、確かに。しかし、それは簡単な部分です。
ロスパターソン

少なくとも、正しく、UTCに変換できます。振り返って、この情報からいつでも計算テーブルまたは値を作成できます。しかし、あなたは他の方法で行くことはできません。SQL 2016はこれをネイティブにサポートし始めますが、残念ながらまだ-少なくとも歴史的に-まったく正しいレジストリデータに依存していませんが、それはさらに別の改善点です。
アーウィン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.