8

これは難しい質問です。実際、SQL標準のように思えるほど難しいので、そこにある主要なデータベースのほとんどは、それらの実装の手がかりを持っていません。

すべての日時をUTCに変換すると、レコード間の比較が簡単になりますが、タイムゾーン情報が破棄されます。つまり、レコードを使用して計算したり(たとえば、保存された日時に8か月を追加したり)、保存されたタイムゾーンでレコードを取得したりすることはできません。したがって、素朴なアプローチは出ています。

タイムスタンプ(たとえば、postgresのタイムゾーンを持つタイムスタンプ)に加えてUTCからのタイムゾーンオフセットを保存することで十分なように見えますが、DSTにより、異なるタイムゾーンで1年のある時点で同じオフセットを持ち、6か月後に異なるタイムゾーンを持つことができます。 。たとえば、ニューヨークとチリの両方を現在(8月)UTC-4に設定できますが、11月4日以降はニューヨークがUTC-5になり、チリ(9月2日以降)がUTC-3になります。したがって、オフセットだけを保存しても、正確な計算を行うことはできません。上記の素朴なアプローチのように、それも情報を破棄します。

代わりにタイムスタンプ付きのタイムゾーン識別子(例:America / Santiago)を保存するとどうなりますか?これにより、チリの日時とニューヨークの日時を区別できるようになります。しかし、これではまだ十分ではありません。有効期限を保存している場合、たとえば6か月後の深夜0時に、DSTルールが変更された場合(残念ながら政治家が好むように)、タイムスタンプが間違っており、代わりに午後11時または午前1時に有効期限が発生する可能性があります。これは、アプリケーションにとって大きな問題になる場合とそうでない場合があります。したがって、タイムスタンプを使用すると、情報も破棄されます。

本当に正確であるためには、ローカルの日時を(たとえば、タイムゾーンに対応していないタイムスタンプタイプを使用して)タイムゾーン識別子とともに保存する必要があるようです。より高速な比較をサポートするために、使用するタイムゾーンデータベースが更新されるまでUTCバージョンをキャッシュし、キャッシュされた値が変更されている場合は更新することができます。つまり、2つの単純なタイムスタンプタイプに加えて、タイムゾーン識別子と、タイムゾーンデータベースが変更されたかどうかをチェックし、キャッシュされたタイムスタンプに対して適切な更新クエリを実行するある種の外部cronジョブになります。

それは正確な解決策ですか?それとも私はまだ何かが足りないのですか?もっと上手くできますか?

MySQL、SQL Server、Oracle、PostgreSQL、およびTIMESTAMP WITHTIMEZONEを処理するその他のDBMSのソリューションに興味があります。

4

4 に答える 4

1

問題をうまくまとめました。悲しいことに、答えはあなたが説明したことをすることです。

使用する正しい形式は、タイムスタンプが表すことになっているものの語用論に依存します。一般に、過去と将来のイベントに分けることができます(例外はありますが)。

  • 過去のイベントは、別の方法で再解釈することのできないものとして保存することができ、通常は保存する必要があります。(例:数値のタイムゾーンを持つUTCタイムスタンプ)。指定されたタイムゾーンを保持する必要がある場合(ユーザーに情報を提供するため)、これは別個にする必要があります。

  • 将来のイベントには、あなたが説明した解決策が必要です。ローカルタイムスタンプと名前付きタイムゾーン。これは、タイムゾーンルールが変更されたときに、そのイベントの「実際の」(UTC)時刻を変更する必要があるためです。

タイムゾーンの変換がそのようなオーバーヘッドであるかどうか疑問に思いますか?通常はかなり速いです。本当に重大なパフォーマンスの低下が見られる場合にのみ、キャッシュの苦痛を経験します。(ご指摘のとおり)キャッシュを必要とするいくつかの大きな操作があります(実際の(UTC)時間に基づいて数十億行をソートするなど)。

パフォーマンス上の理由から将来のイベントをUTCでキャッシュする必要がある場合は、そうです。キャッシュされた値を更新するプロセスを導入する必要があります。DBのタイプによっては、TZルールがめったに変更されないため、システム管理者がこれを実行できる可能性があります。

于 2012-08-25T15:52:43.367 に答える
0

オフセットが気になる場合は、実際のオフセットを保存する必要があります。タイムゾーン識別子を保存することは、タイムゾーンが時間の経過とともに変化する可能性があることと同じではありません。タイムゾーンオフセットを保存することにより、現在のオフセットに基づく現地時間ではなく、イベント時の正しい現地時間を計算できます。で発生したと見なされた実際のタイムゾーンイベントを知ることが重要な場合は、タイムゾーン識別子を保存することをお勧めします。

時間は物理的な属性ですが、タイムゾーンは政治的な属性であることを忘れないでください。

于 2012-08-25T15:59:57.587 に答える
0

UTCに変換すると、レコードを注文して比較できます。元のタイムゾーンの名前を追加すると、元のtzで表すことができ、(経過時間の代わりに)週、月などの期間を追加/削除できます。 。

あなたの質問では、DSTが変更される可能性があるため、これでは不十分であると述べています。DSTを使用すると、(経過時間以外の)日付を使用した計算が複雑になり、コードが非常に多くなります。うるう年に対処するためのコードが必要なのと同じように、特定のデータ/期間に対してDST修正を適用する必要があるかどうかを考慮する必要があります。何年かの間、答えはイエスであり、他の人はノーです。これらのルールがどれほど複雑になったか については、このwikiページを参照してください。

オフセットの保存は、基本的にこれらの計算結果を保存することです。その計算されたオフセットは、その特定の時点でのみ有効であり、質問で提案したように、後のポイントまたは前のポイントにそのまま適用することはできません。UTC時間で計算を行い、そのタイムゾーンでその時間にアクティブなルールに基づいて、結果の時間を必要なタイムゾーンに変換します。

第一次世界大戦前にはどこにもDSTがなかったことに注意してください。データベースの日付/時刻システムは、これらのケースを完全に処理します。

于 2012-08-25T17:11:49.357 に答える
0

MySQL、SQL Server、Oracle、PostgreSQL、およびTIMESTAMP WITHTIMEZONEを処理するその他のDBMSのソリューションに興味があります。

Oracleは瞬時にUTCに変換しますが、通過する内容に応じてタイムゾーンまたはUTCオフセットを保持します。Oracleは(正しく)タイムゾーンとUTCオフセットを区別し、渡されたものを返します。これには2バイトの追加費用しかかかりません。

Oracleはすべての計算をTIMESTAMP WITH TIME ZONEUTCで行います。これは、月を追加する場合には違いはありませんが、夏時間がないため、日を追加する場合には違いがあります。計算の結果は常に有効なタイムスタンプである必要があることに注意してください。たとえば、1月31日に1か月を追加すると、2月31日が存在しないため、Oracleで例外がスローされます。

于 2017-04-24T06:21:44.217 に答える