web-dev-qa-db-ja.com

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

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

19
user46506

非計算プログラミングにおける最も難しい問題の1つへようこそ-エンドユーザーに日付と時刻を適切に表します。

現実的には、タイムスタンプはどのように解釈されるかに関係なく、固定された単一の表現で保存する必要があります。どんなに頑張っても、あいまいなケースが常にあり、固定された表現なしでは解決できないためです。そして、最悪のユースケースの1つを選択しました-予約のスケジュール。最も悪い一般的な使用事例は飛行機旅行です。旅行はあるタイムゾーンで始まり、別のタイムゾーンで終わる可能性があります。

常に、常に、常にUTCに保存し、ユーザーの優先または明示的に指定されたタイムゾーンで表示します。可能な場合は、ユーザーがタイムスタンプを入力するときに、どのタイムゾーンであると考えるかをユーザーに伝えます( eg、明示的なタイムゾーンフィールドを持ち、優先ゾーンを事前に入力します)。

35
Ross Patterson

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

日付と時刻がユーザーによって入力され、サーバーがその日付/時刻情報をデータベースに保存する以外の処理を行わず、入力された時刻が表示されている場所に適応することが期待されていない場合(たとえば、ユーザーが「8:00 PM」と入力し、それが世界のどこに表示されているかに関係なく「8:00 PM」と表示される必要があります)。最も簡単な方法は、タイムゾーン情報なしでローカル時間としてDateTimeを格納することです。

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

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

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

もう一つのコンセプトは、「毎週火曜日午後8時」のような「時間表現」のコンセプトです。人々が予定をスケジュールできるようにすることを具体的に述べました、そしてあなたが定期的な予定がある場合、あなたはそのような表現が必要です。標準的な表現言語は知りませんが、どの言語を使用しても、指定した人のタイムゾーンに対応します。これを明示的にするのが最善です。 「毎週火曜日の太平洋標準時の午後8時」。時間式の場合、これを常に文字列として保存し、システムの時間形式を一切含まないようにします。

参照 これについての詳細は私のブログで

2
AgilePro

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

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

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

そのような場合、予定がデータベースに保存された日時をいつ記録するか、どのタイムゾーンおよびdstが含まれているかどうか。このようにして、ローカル時刻をいつでも、現在の状態または過去の履歴に基づいて計算することができます。タイムゾーンは非常に静的ではないため、状況はさらに複雑になります。

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

2
Arwin