web-dev-qa-db-ja.com

DateTime.ToUniversalTime()はどのように機能しますか?

標準のDateTime形式からUTCへの変換はどのように機能しますか?

より具体的には、あるタイムゾーンでDateTimeオブジェクトを作成し、別のタイムゾーンに切り替えてその上でToUniversalTime()を実行すると、変換が正しく行われ、その時間まだ正確に表現されていますか?

61
derGral

DateTimeオブジェクトにアタッチされる暗黙的なタイムゾーンはありません。 ToUniversalTime()を実行すると、コードが実行されているコンテキストのタイムゾーンが使用されます。

たとえば、1970年1月1日のエポックからDateTimeを作成すると、世界のどこにいても同じDateTimeオブジェクトが得られます。

グリニッジでコードを実行しているときにToUniversalTime()を実行すると、同じ時間になります。バンクーバーに住んでいる間にそれを行うと、-8時間のオフセットDateTimeオブジェクトを取得します。

これが、何らかの種類の日付変換またはローカライズを行う必要がある場合、時間関連情報をデータベースにUTC時間として保存することが重要な理由です。コードベースが別のタイムゾーンのサーバー施設に移動したかどうかを検討してください;)

編集:ジョエルの答えからのメモ-DateTimeオブジェクトはデフォルトで_DateTimeKind.Local_と入力されます。日付を解析し、_DateTimeKind.Utc_として設定した場合、ToUniversalTime()は変換を実行しません。

そして、ここに "Date Timesによるコーディングのベストプラクティス" に関する記事と、 。NetによるDateTimesの変換 に関する記事があります。

71
womp

まず、KindDateTimeがすでにUTCであることがわかっているかどうかを確認します。その場合、同じ値を返します。

それ以外の場合は、ローカル時間と見なされます-実行しているコンピューターのローカル時間、特に、プライベートプロパティが最初に遅延初期化されたときにコンピューターが使用していたタイムゾーンのローカル時間です。つまり、タイムゾーンを変更した場合afterアプリケーションが開始された場合、まだ古いものを使用している可能性が十分にあります。

タイムゾーンには、現地時間をUTC時間に、またはその逆に変換するのに十分な情報が含まれていますが、あいまいまたは無効な時間があります。 (現地時間は2回発生し、現地時間は夏時間のために発生することはありません。)これらのケースを処理するためのルールは ドキュメント で指定されています:

日付と時刻のインスタンス値があいまいな時間である場合、このメソッドはそれが標準時間であると想定します。 (あいまいな時間は、ローカルタイムゾーンの標準時間または夏時間にマップできる時間です)日付と時刻のインスタンス値が無効な時間である場合、このメソッドはローカルタイムゾーンのローカル時間を単純に減算しますUTCを返すUTCオフセット。 (無効な時間とは、夏時間調整規則の適用のために存在しない時間です。)

返される値のKindDateTimeKind.Utc。したがって、ToUniveralTimeを呼び出すと、オフセットは再び適用されません。 (これは.NET 1.1と比べて大幅に改善されています!)

非ローカルタイムゾーンが必要な場合は、.NET 3.5で導入された TimeZoneInfo を使用する必要があります(以前のバージョンにはハッキーなソリューションがありますが、ニースではありません)。インスタントを表すには、 DateTimeOffset の使用を検討する必要があります。これは、.NET 2.0SP1、.NET3.0SP1、および.NET 3.5で導入されました。ただし、それに関連付けられている実際のタイムゾーンはまだありません。UTCからのオフセットだけです。つまり、たとえば現地時間は1時間後になるのか分からないということです。DSTルールは、特定の瞬間に同じオフセットを使用したタイムゾーン間で異なる場合があります。 TimeZoneInfoは、やや単純な TimeZone とは対照的に、歴史的および将来のルールを考慮するように設計されています。

基本的に、.NET 3.5のサポートは以前よりもはるかに優れていますが、適切なカレンダー演算に必要なものが残っています。誰でも空想的な移植 Joda Time .NETに? ;)

34
Jon Skeet

@ womp発言 、さらにDateTimeのKindプロパティをチェックして、alreadyがUTC日付であるかどうかを確認します。

7
Joel Coehoorn

DateTime.ToUniversalTimeは、ローカルタイムゾーンのタイムゾーンオフセットを削除して、DateTimeをUTCに正規化します。その後、別のタイムゾーンの正規化された値でDateTime.ToLocalTimeを使用すると、そのタイムゾーンでの正しい表現のために、そのタイムゾーンのタイムゾーンオフセットが正規化された値に追加されます。