web-dev-qa-db-ja.com

DateTimeとDateTimeOffset

現在、TimeZoneを意識した方法で.net DateTimesを処理する標準的な方法があります。DateTimeを生成するときはいつでも(たとえばDateTime.UtcNowを使用して)、それを表示するときはいつでもUTCからユーザーのローカルに変換します。時間。

それはうまくいきますが、私はDateTimeOffsetと、それがオブジェクト自身の中でどのようにローカルとUTC時間を捉えるかについて読んでいます。それで問題は、DateTimeOffsetを使うことの利点と私たちがすでに行っていることの違いは何でしょうか。

606
David Reis

DateTimeOffsetは、瞬間的な時間絶対時間とも呼ばれます)の表現です。それによって、私は誰にとっても普遍的である瞬間を意味します( うるう秒 、または time拡張の相対論的効果 を考慮しない)。瞬間的な時間を表すもう1つの方法は、.KindDateTimeKind.UtcであるDateTimeを使用することです。

これはカレンダー時間市民時間としても知られています)とは別のもので、世界中にはさまざまなカレンダーがあります。これらのカレンダーをタイムゾーンと呼びます。カレンダー時間はDateTimeで表されます。ここで、.KindDateTimeKind.Unspecified、またはDateTimeKind.Localです。また、.Localは、結果を使用しているコンピューターがどこに配置されているかについて暗黙のうちに理解しているシナリオでのみ意味があります。 (たとえば、ユーザーのワークステーション)

それでは、なぜUTCのDateTimeOffsetではなくDateTimeなのでしょうか。 それはすべて展望についてです。 例えてみましょう - 私たちは写真家のふりをします。

あなたがカレンダーのタイムライン上に立っていると想像してください。あなたの前にレイアウトされた瞬間タイムライン上の人にカメラを向けます。あなたはあなたのタイムゾーンの規則に従ってあなたのカメラを並べます - それは夏時間のために、またはあなたのタイムゾーンの法的定義への他の変更のために定期的に変わります。 (手がしっかりしていないので、カメラは揺れています。)

写真の中に立っている人は、あなたのカメラが来た角度を見るでしょう。他の人が写真を撮っているならば、それらは異なる角度からのものかもしれません。これがOffsetDateTimeOffset部分が表すものです。

そのため、カメラに「Eastern Time」というラベルを付けた場合、-5から指していることがあり、-4から指していることがあります。世界中にカメラがあり、すべて異なるものにラベルが付けられており、すべて異なる角度から同じ瞬間的なタイムラインを指しています。それらのうちのいくつかはお互いのすぐ隣(または一番上)にあるので、オフセットを知っているだけでは、時間がどのタイムゾーンに関連しているかを判断するのに十分ではありません。

そして、UTCはどうですか?それは、しっかりとした手を持つことが保証されているのは、そこにある1台のカメラです。しっかりと固定された三脚の上にあります。それはどこにも行きません。その視野角をゼロオフセットと呼びます。

Instantaneous Time vs Calendar Time Visualization

それで - このアナロジーは何を教えてくれるのでしょうか?それはいくつかの直感的なガイドラインを提供します。

  • 特に時間を基準にして時間を表している場合は、カレンダー時間でDateTimeを付けて表します。あるカレンダーと別のカレンダーを混同しないように注意してください。 Unspecifiedはあなたの仮定です。 LocalDateTime.Nowから来る場合にのみ役に立ちます。たとえば、DateTime.Nowを取得してデータベースに保存する場合がありますが、取得するときはUnspecifiedと想定する必要があります。私のローカルカレンダーが元々のカレンダーと同じであるとは限りません。

  • あなたがいつもその瞬間を確信していなければならないならば、あなたが瞬間の時間を表していることを確認してください。それを強制するためにDateTimeOffsetを使うか、または慣例によりUTC DateTimeを使います。

  • あなたが瞬間の瞬間を追跡する必要があるが、あなたは「ユーザーがそれが彼らの地元のカレンダーにあったと何時に考えたか」も知りたいならば。 - あなたはmustDateTimeOffsetを使います。これは、たとえば計時システムにとって非常に重要です。たとえば、技術的にも法的にも重要です。

  • 以前に記録したDateTimeOffsetを修正する必要がある場合は、新しいオフセットがユーザーに関連していることを確認するのに十分な情報がオフセットだけにはありません。あなたはalsoタイムゾーンの識別子を保存する必要があります(位置が変わっても新しい写真を撮ることができるように私はそのカメラの名前が必要だと思います)。

    また、 Noda Time に​​はZonedDateTimeという表現がありますが、.Net基本クラスライブラリにはこれに似たものはありません。 DateTimeOffsetTimeZoneInfo.Idの両方の値を格納する必要があります。

  • 時折、「誰でも見ている人」にとってローカルなカレンダー時間を表したいと思うでしょう。たとえば、todayの意味を定義するときなどです。今日は常に真夜中から真夜中までですが、これらは瞬間タイムライン上で無限に近い数の重複する範囲を表しています。 (実際には有限数のタイムゾーンがありますが、オフセットを目盛りまで表現することができます)したがって、このような状況では、「誰が質問しているのか」を制限する方法を理解してください。単一のタイムゾーンに質問するか、必要に応じてそれらを瞬間的な時間に戻すことを処理します。

以下は、この類推を裏付けるDateTimeOffsetに関する他のいくつかのちょっとしたことと、それをまっすぐに保つためのいくつかのヒントです。

  • 2つのDateTimeOffset値を比較する場合、それらは比較の前に最初にゼロオフセットに正規化されます。言い換えれば、2012-01-01T00:00:00+00:002012-01-01T02:00:00+02:00は同じ瞬間を指しているので等価です。

  • 単体テストを実行していて、オフセットを確実にする必要がある場合は、both _ DateTimeOffset値と.Offsetプロパティを別々にテストしてください。

  • DateTimeを任意のDateTimeOffsetパラメータまたは変数に渡すことを可能にする一方向の暗黙の変換が.Netフレームワークに組み込まれています。そうするとき、.Kindが重要です 。あなたがUTCの種類を渡す場合、それはゼロオフセットで持ち込みますが、あなたが.Local.Unspecifiedのどちらかを渡すならば、それは local であると仮定するでしょう。フレームワークは基本的に、「さて、あなたは私にカレンダー時間を瞬間時間に変換するように頼んだが、これがどこから来たのかわからないので、私はただローカルカレンダーを使うつもりだ」と言っている。指定していないDateTimeを別のタイムゾーンのコンピュータにロードした場合、これは大きな問題です。 (私見 - それは例外をスローする必要があります - しかし、それはしません。)

恥知らずなプラグイン:

多くの人がこのアナロジーが非常に有益だと思うことを私と共有してきたので、私はそれを私のPluralsightコース Date and Time Fundamentals に含めました。 2番目のモジュール「Context Matters」には、「Calendar Time vs. Instantaneous Time」というタイトルのクリップで、カメラの類推の段階的なチュートリアルがあります。

994
Matt Johnson

マイクロソフトから:

DateTimeOffset値に対するこれらの用途は、DateTime値に対する用途よりはるかに一般的です。その結果、DateTimeOffsetは、アプリケーション開発のデフォルトの日付と時刻の種類と見なす必要があります。

source: "DateTime、DateTimeOffset、TimeSpan、TimeZoneInfoの選択" _ msdn _

私たちのアプリケーションが特定の時点を扱うとき(例えばレコードが作成/更新されたとき)、ほとんどすべてにDateTimeOffsetを使います。補足として、SQL Server 2008でもDATETIMEOFFSETを使用しています。

日付だけ、時間だけ、あるいはどちらかを一般的な意味で扱いたいときには、DateTimeが役に立つと思います。たとえば、毎日午前7時にオフにしたいというアラームがある場合は、DSTに関係なく午前7時にオフにしたいので、DateTimeDateTimeKindを使用してUnspecifiedに保存できます。しかし、アラーム発生の履歴を表現したい場合は、DateTimeOffsetを使用します。

DateTimeOffsetDateTimeを組み合わせて使用​​するときは特に注意してください。特に型を割り当てて比較するときは注意が必要です。また、DateTimeは比較時にタイムゾーンオフセットを無視するため、同じDateTimeKindであるDateTimeインスタンスのみを比較します。

246
Clay

DateTimeには、現地時間とUTCの2つの異なる時間しか格納できません。 Kind プロパティはどちらを示します。

DateTimeOffsetは、世界中のどこからでも現地時間を保存できることでこれを拡張します。また、その現地時間とUTCの間の offset も格納されます。そのUTCオフセットを格納するためにクラスに追加のメンバを追加しない限り、DateTimeがこれを行えないことに注意してください。それともUTCでのみ動作します。それ自体それ自体良い考えです。

62
Hans Passant

DateTimeOffsetが意味をなすところがいくつかあります。 1つは、定期的な予定や夏時間に対処しているときです。毎日午前9時にアラームが鳴るように設定したいとしましょう。 「UTCとして保存、現地時間として表示」ルールを使用すると、夏時間が有効になっているときにアラームが 異なる 時刻に発生します。

おそらく他にもありますが、上記の例は実際に私が過去に遭遇したものです(これはBCLにDateTimeOffsetを追加する前のものでした。それと同時にタイムゾーン情報を保存します:基本的にDateTimeOffsetは内部的に何をするか)。

32
Dean Harding

最も重要な違いは、DateTimeはタイムゾーン情報を格納しないのに対し、DateTimeOffsetは格納することです。

DateTimeはUTCとLocalを区別しますが、それに関連する明示的なタイムゾーンオフセットは絶対にありません。何らかのシリアル化または変換を行う場合は、サーバーのタイムゾーンが使用されます。 UTC時間をオフセットするために分を追加して手動で現地時間を作成した場合でも、シリアル化の手順に少し時間がかかることがあります。これは、(DateTimeに明示的なオフセットがないため)サーバーのタイムゾーンオフセットを使用するためです。

たとえば、Json.NetとISOの日付形式を使用してKind = LocalでDateTime値をシリアル化すると、2015-08-05T07:00:00-04のような文字列が得られます。最後の部分(-04)は、DateTimeや計算に使用したオフセットとは関係がないことに注意してください。これは、純粋にサーバーのタイムゾーンオフセットです。

一方、DateTimeOffsetは明示的にオフセットを含みます。それはタイムゾーンの名前を含まないかもしれません、しかし、少なくともそれはオフセットを含みます、そしてあなたがそれをシリアル化するならば、あなたはサーバの現地時間が何であるかの代わりにあなたの値に明示的に含まれるオフセットを得ることになるでしょう。

20
Triynko

答えのほとんどは良いですが、私は詳細についてはMSDNのいくつかのリンクを追加することを考えました

9
dekdev

大きな違いは、現在のタイムゾーン以外のタイムゾーンで現地時間に変換するためにDateTimeOffsetTimeZoneInfoと組み合わせて使用​​できることです。

これは、さまざまなタイムゾーンのユーザーがアクセスするサーバーアプリケーション(ASP.NETなど)で役立ちます。

7
Joe

Microsoft からのこのコードはすべてを説明しています。

// Find difference between Date.Now and Date.UtcNow
  date1 = DateTime.Now;
  date2 = DateTime.UtcNow;
  difference = date1 - date2;
  Console.WriteLine("{0} - {1} = {2}", date1, date2, difference);

  // Find difference between Now and UtcNow using DateTimeOffset
  dateOffset1 = DateTimeOffset.Now;
  dateOffset2 = DateTimeOffset.UtcNow;
  difference = dateOffset1 - dateOffset2;
  Console.WriteLine("{0} - {1} = {2}", 
                    dateOffset1, dateOffset2, difference);
  // If run in the Pacific Standard time zone on 4/2/2007, the example
  // displays the following output to the console:
  //    4/2/2007 7:23:57 PM - 4/3/2007 2:23:57 AM = -07:00:00
  //    4/2/2007 7:23:57 PM -07:00 - 4/3/2007 2:23:57 AM +00:00 = 00:00:00
5
Mojtaba

DateTimeOffsetの唯一のマイナス面は、MicrosoftがXmlSerializerクラスでそれをサポートすることを(設計上)忘れていたことです。しかし、それはその後XmlConvertユーティリティクラスに追加されました。

XmlConvert.ToDateTimeOffset

XmlConvert.ToString

すべての利点から、DateTimeOffsetとTimeZoneInfoを使用してください。XMLとの間でシリアル化される、またはXMLからシリアル化される可能性のあるエンティティを作成するときは注意してください。

2
Tony Wall