web-dev-qa-db-ja.com

SQL ServerでTimeZoneを適切に処理する方法

私のローカル開発サーバーは中東にありますが、運用サーバーは英国にあります。

ユーザーにタイムゾーンで日付を表示する必要があります。たとえば、ユーザーがサウジアラビアにいる場合、サウジアラビアの形式に従って時刻を表示する必要があります。

TimeZoneという新しいデータベーステーブルを作成して、時刻をUTCで保存する必要がありますか?

39
user960567

残念ながら、これに対する迅速な修正はありません。アプリケーションの国際化は、日付/時刻の比較や出力フォーマットなど、さまざまな分野の核心部分となるため、最初の設計に関する議論の一部にすべきです。

とにかく、正しいことを行うには、タイムゾーン情報を時刻とともに保存することが不可欠です。言い換えると、日付/時刻20130407 14:50無意味であり、タイムゾーンの現在のUTCオフセットが含まれていないことを認識(注1)、または(b)これらの値を挿入するすべてのロジックが最初に特定の固定オフセット(ほとんどの場合0)に変換されるようにします。これらのいずれもない場合、2つの時間値はincomparableであり、データはcorruptです。 (後者の方法は火で遊んでいます(注2)、 ところで;しないでください。)

SQL Server 2008+では、 datetimeoffset データ型を使用して、オフセットを時間とともに直接保存できます。 (完全を期すために、2005年以前には、2番目の列を追加して、当時の現在のUTCオフセット値(分単位)を格納します。)

これらのプラットフォームには通常、日付/時刻+タイムゾーンを現地時間に自動的に変換し、出力用にフォーマットするメカニズムがすべてユーザーの地域設定に基づいているため、これによりデスクトップタイプのアプリケーションが簡単になります。

本質的に切り離されたアーキテクチャであるWebの場合、バックエンドデータが適切に設定されていても、変換やフォーマットを行うにはクライアントに関する情報が必要なので、より複雑になります。これは通常、ユーザー設定設定(アプリケーションが出力前に物事を変換/フォーマットする)を介して行われるか、すべての人に対して同じ固定フォーマットとタイムゾーンオフセットで物事を単に表示します(これは現在Stack Exchangeプラットフォームが行っていることです)。

バックエンドデータが適切に設定されていないと、非常に迅速に複雑でハッキングされることがわかります。私はそれらのパスのいずれかをダウンすることをお勧めしません。

注1:

タイムゾーンのUTCオフセットは固定されていません。ゾーンのUTCオフセットがプラスまたはマイナス1時間変動する夏時間を検討してください。また、ゾーンの夏時間は定期的に異なります。したがって、datetimeoffset(またはlocal timeUTC offset at that timeの複合)を使用すると、情報を最大限に回復できます。

注2:

データ入力を制御することです。入ってくる値を検証するための確実な方法はありませんが、計算を含まない単純な標準を適用することをお勧めします。パブリックAPIがオフセットを含むデータ型を予期している場合、その要件は呼び出し元に明らかです。

そうでない場合、呼び出し元はドキュメントを参照する必要があります(ドキュメントを読み取る場合)、または計算が誤って行われるなど。オフセットが必要な場合、特に分散システム(または、ここのケースのように、別のサーバー上のWeb /データベースだけでも)。

とにかくオフセットを保存すると、1石で2羽の鳥が死にます。 nowが不要な場合でも、必要に応じて後で利用できるようになります。確かにそれはより多くのストレージを必要としますが、最初に記録されたことがない場合、データは失われるため、トレードオフの価値があると思います。

51
Jon Seigel

SQL Serverでのタイムゾーン変換のための包括的なソリューションを開発しました。 GitHubでのSQL Serverタイムゾーンサポート を参照してください。

タイムゾーン間の変換や、夏時間を含むUTCとの変換を適切に処理します。

広告の回答に記載されている「T-SQLツールボックス」ソリューションと概念は似ていますが、Microsoftの代わりに、より一般的なIANA/Olson/TZDBタイムゾーンを使用し、データを新しいリリースとして維持するユーティリティを備えていますTZDBが出てきます。

使用例(OPに答えるため):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

追加のAPIと詳細な説明については、 GitHubのreadme を参照してください。

また、これはUDFベースのソリューションであるため、パフォーマンスを主な目的として設計されていないことに注意してください。 OracleとMySQLにCONVERT_TZ関数がどのように存在するかと同様に、この機能がSQL Serverに組み込まれているとなお良いでしょう。

15

SQL Serverで日時とタイムゾーンの処理に苦労している人を助けるために、「T-SQL Toolbox」プロジェクト codeplex を開発して公開しました。オープンソースであり、完全に無料で使用できます。

これは、追加の構成テーブルをそのまま使用してプレーンT-SQLを使用する簡単な日時変換UDFを提供します。

あなたの例では、次のサンプルを使用できます。

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

これにより、ユーザーの変換された日時値が返されます。

サポートされているすべてのタイムゾーンのリストは、T-SQL Toolboxデータベース内でも提供されるテーブル "DateTimeUtil.Timezone"にあります。

7
adss

SQL Serverは、内部タイムゾーンがUTCで保存される2005年以降に変更を加えました。これは主に、ログ複製を伴う地理レプリケーションとHAプロジェクターによるものであり、ログ配布時間を異なるタイムゾーンで保存すると、古い方法ではそれらを復元できなくなりました。

したがって、すべてをUTC時間で内部的に保存することにより、SQL Serverはグローバルに適切に機能することができました。 Outlookなどの他のMS製品も日付/時刻をUTCとして内部的に保存し、パッチを適用する必要のあるオフセットを作成するため、これが夏時間をWindowsで扱うのが面倒な理由の1つです。

私は、世界中に何千ものサーバー(ただし、MS SQL Serverではなく、すべての種類のサーバー)が分散している会社で働いています。すべてをUTCに強制的に強制しなければ、全員が狂ってしまいます。非常に迅速に。

6
Ali Razeghi

明らかなものがない場合がありますが、ユーザーのタイムゾーンと言語形式を使用して日付を表示するだけの場合、最も簡単な方法は、常にデータベースのUTCに日付を格納し、クライアントアプリケーションにUTCからローカルに変換させることです。タイムゾーンを使用し、ユーザーの地域設定を使用して日付を適切にフォーマットします。

1
20c