DateTime
標準形式からUTCへの変換はどのように機能しますか?
具体的には、DateTime
あるタイムゾーンでオブジェクトを作成し、別のタイムゾーンに切り替えて実行ToUniversalTime()
した場合、変換が正しく行われ、時間が正確に表現されていることをどのようにして知ることができますか?
DateTime
オブジェクトにアタッチされた暗黙のタイムゾーンはありません。その上で実行ToUniversalTime()
すると、コードが実行されているコンテキストのタイムゾーンが使用されます。
たとえば、DateTime
1970年1月1日のエポックからを作成するDateTime
と、世界のどこにいても同じオブジェクトが得られます。
グリニッジでコードを実行ToUniversalTime()
しているときに実行すると、同じ時間が発生します。バンクーバーに住んでいるときにそれを行うとDateTime
、-8時間のオフセットオブジェクトが得られます。
これが、あらゆる種類の日付変換またはローカリゼーションを行う必要がある場合に、時間関連情報をUTC時間としてデータベースに保存することが重要である理由です。コードベースが別のタイムゾーンでサーバー機能に移動したかどうかを検討してください;)
編集:ジョエルの答えからのメモ-DateTime
デフォルトでは、オブジェクトはとして入力されDateTimeKind.Local
ます。日付を解析してとして設定するとDateTimeKind.Utc
、ToUniversalTime()
変換は実行されません。
そして、これが「日時を使用したコーディングのベストプラクティス」に関する記事と、.Netを使用した日時の変換に関する記事です。
まず、がすでに UTC であることがわかっているKind
かどうかを確認します。DateTime
その場合は、同じ値を返します。
それ以外の場合は、ローカル時間であると想定されます。これは、それが実行されているコンピューターに対してローカルであり、特に、プライベート プロパティが最初に遅延初期化されたときにコンピューターが使用していたタイム ゾーンです。つまり、アプリケーションの起動後にタイム ゾーンを変更すると、古いタイム ゾーンが引き続き使用される可能性が高くなります。
タイム ゾーンには、現地時間を UTC 時間に、またはその逆に変換するのに十分な情報が含まれていますが、あいまいまたは無効な時間もあります。(2 回発生する現地時間と、夏時間のためにまったく発生しない現地時間があります。) これらのケースを処理するための規則は、ドキュメントで指定されています。
日付と時刻のインスタンス値があいまいな時刻の場合、このメソッドはそれが標準時刻であると想定します。(あいまいな時間とは、ローカル タイム ゾーンの標準時間または夏時間にマップできる時間です) 日付と時刻のインスタンス値が無効な時間である場合、このメソッドはローカル タイム ゾーンの時刻からローカル時間を単純に減算します。 UTC を返すための UTC オフセット。(無効時間とは、夏時間調整規則の適用により存在しない時間です。)
返される値にはKind
ofDateTimeKind.Utc
があるため、それを呼び出すとToUniveralTime
、オフセットが再度適用されることはありません。(これは .NET 1.1 からの大幅な改善です!)
非ローカル タイム ゾーンが必要な場合TimeZoneInfo
は、.NET 3.5 で導入されたものを使用する必要があります (以前のバージョンにはハッキーなソリューションがありますが、適切ではありません)。瞬間を表すにはDateTimeOffset
、.NET 2.0SP1、.NET3.0SP1、および .NET 3.5 で導入された which の使用を検討する必要があります。ただし、これにはまだ実際のタイム ゾーンが関連付けられていません。UTC からのオフセットだけです。つまり、たとえば、1 時間後の現地時間がわからないことを意味します。DST ルールは、その特定の瞬間に同じオフセットを使用するタイム ゾーン間で異なる場合があります。やや単純化されているのとはTimeZoneInfo
対照的に、歴史的および将来のルールを考慮に入れるように設計されています。TimeZone
基本的に、.NET 3.5 でのサポートは以前よりも大幅に改善されていますが、適切なカレンダー計算にはまだ何かが必要です。Joda Timeを .NET に移植したい人はいますか? ;)
@wompの発言に加えて、DateTime の Kind プロパティをチェックして、既にUTC 日付であるかどうかを確認します。
DateTime.ToUniversalTime は、ローカル タイムゾーンのタイムゾーン オフセットを削除して、DateTime を UTC に正規化します。次に、別のタイムゾーンの正規化された値で DateTime.ToLocalTime を使用すると、そのタイムゾーンで正しく表現するために、そのタイムゾーンのタイムゾーン オフセットが正規化された値に追加されます。