DateTimeとDateTimeOffset


742

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

それはうまくいきますが、私はDateTimeOffsetそれがオブジェクト自体のローカル時間とUTC時間をどのようにキャプチャするかについて読んでいます。だから問題は、DateTimeOffset私たちがすでにやっていることに比べて使用することの利点は何でしょうか?


3
以下にいくつかの素晴らしい答えがあります。しかし、それでも、DateTimeOffsetの使用を開始するように説得したのは何だろうと思います。
HappyNomad 2013年


ストレージに関しては、stackoverflow.com / questions / 4715620 /…も興味深いものです。
Dejan

回答:


1169

DateTimeOffsetは、瞬間時間絶対時間とも呼ばれます)を表します。つまり、すべての人にとって普遍的な瞬間を意味します(うるう秒、または時間拡張の相対論的効果は考慮されません)。瞬間的な時間を表すもう1つの方法は、DateTimewhereを使用すること.KindですDateTimeKind.Utc

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

それでは、なぜDateTimeOffsetUTCの代わりにDateTimeそれはすべて視点に関するものです。 アナロジーを使ってみましょう-私たちは写真家のふりをします。

カレンダーのタイムラインの上に立って、目の前に配置された瞬間的なタイムライン上の人にカメラを向けていると想像してください。タイムゾーンの規則に従ってカメラを整列させます-サマータイム、またはタイムゾーンの法的定義への他の変更のために定期的に変更されます。(手がしっかりしていないため、カメラが揺れています。)

写真に立っている人は、あなたのカメラがどこから来たのかを見るでしょう。他の人が写真を撮っている場合、それらは異なる角度からのものである可能性があります。これが代表のOffset一部ですDateTimeOffset

したがって、カメラに「東部標準時」というラベルを付けると、-5から指していることもあれば、-4から指していることもあります。世界中にカメラがあり、すべてに異なるもののラベルが付けられており、すべて同じ角度のタイムラインを同じ瞬間に向けています。それらのいくつかは互いに隣り合っている(または上にある)ため、オフセットがわかっているだけでは、時間に関連するタイムゾーンを特定するのに十分ではありません。

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

瞬時時間とカレンダー時間の視覚化

だから-このアナロジーは私たちに何を伝えますか?それはいくつかの直感的なガイドラインを提供します

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

  • 常にその瞬間を確信している必要がある場合は、瞬間を表していることを確認してください。DateTimeOffset強制的に使用するかDateTime、慣例によりUTC を使用します。

  • 瞬間的な瞬間を追跡する必要があるが、「ユーザーがローカルカレンダーで何時だと思ったか」も知りたい場合。-次に、を使用する必要ありますDateTimeOffset。これは、たとえば、計時システムにとって非常に重要です-技術的および法的両方の懸念のため。

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

    またことを指摘すべきである野田時間が呼ばれる表現があるZonedDateTimeの.Netベースクラスライブラリは、同様の何かを持っていませんが、このために。DateTimeOffsetTimeZoneInfo.Id値の両方を保存する必要があります。

  • 時々、「誰が見ているか」に対してローカルなカレンダー時間を表すことが必要になる場合があります。たとえば、今日の意味を定義するとき。今日は常に午前0時から午前0時までですが、これらは瞬間的なタイムライン上のほぼ無限の数の重複範囲を表しています。(実際にはタイムゾーンの数は有限ですが、目盛りまでのオフセットを表すことができます)したがって、これらの状況では、「誰が尋ねているのか」を制限する方法を必ず理解してください。単一のタイムゾーンまで質問するか、必要に応じてそれらを瞬時の時間に変換し直すことに対処します。

DateTimeOffsetこの類似性を裏付けるためのその他のいくつかの小さな点と、それをまっすぐに保つためのいくつかのヒントを次に示します。

  • 2つのDateTimeOffset値を比較する場合、比較する前に、まずゼロオフセットに正規化されます。つまり、同じ瞬間の瞬間2012-01-01T00:00:00+00:002012-01-01T02:00:00+02:00指し、したがって同等です。

  • ユニットテストを実行していて、オフセットを確認する必要がある場合は、値とプロパティの両方を個別にテストDateTimeOffset.Offsetます。

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

恥知らずなプラグ:

このアナロジーは非常に価値があると多くの人が私に話してくれたので、私はそれをPluralsightコースのDate and Time Fundamentalsに含めました。2番目のモジュール「Context Matters」のカメラアナロジーの段階的なウォークスルーは、「カレンダー時間と瞬間時間」というタイトルのクリップにあります。


4
@ZackJannsen DateTimeOffsetC#の場合DATETIMEOFFSET、SQL Serverで永続化する必要があります。 DATETIME2またはDATETIME(必要な範囲に応じて)通常のDateTime値で十分です。はい-タイムゾーン+ dtoまたはutcの任意の組み合わせから現地時間を解決できます。違いは、解決するたびに常にルールを計算したいですか、それとも事前に計算したいですか?多くの場合(法律上の問題の場合もあります)、DTOの方が適しています。
Matt Johnson-Pint 2013年

3
@ZackJannsen質問の2番目の部分では、可能な限りサーバー側で行うことをお勧めします。Javascriptはタイムゾーンの計算にはそれほど適していません。必要な場合は、これらのライブラリのいずれかを使用してください。ただし、サーバー側が最適です。他に詳細な質問がある場合は、新しいSO質問を開始してください。可能な場合は回答します。ありがとう。
Matt Johnson-Pint 2013年

4
@JoaoLeme-それはどこから入手したかによります。DateTimeOffset.Nowサーバー上で言うと、サーバーのオフセットが実際に取得されることは間違いありません。ポイントは、DateTimeOffset型がそのオフセットを保持できることです。クライアントでそれを簡単に実行してサーバーに送信すると、サーバーはクライアントのオフセットを認識します。
Matt Johnson-Pint

8
カメラの類推は本当に大好きです。
Sachin Kainth、2014

2
それは正解です。ただし、DTOは(現地時間、オフセット)のペアではなく、(現地時間、オフセット)のペアとして保存されます。つまり、UTCからのオフセットはすでに現地時間に反映されています。utcに戻すには、オフセットの符号を反転し、ローカル時間に適用します。
Matt Johnson-Pint 2014

328

マイクロソフトから:

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

出典:「DateTime、DateTimeOffset、TimeSpan、TimeZoneInfoの選択」MSDN

DateTimeOffsetアプリケーションは特定の時点(たとえば、レコードが作成/更新されたとき)を処理するため、ほぼすべてのものを使用します。補足として、DATETIMEOFFSETSQL Server 2008でも使用します。

なるほどDateTime、一般的な意味で、あなただけの日付に対処したい場合に有用であるとのいずれかとの回のみ、または契約を。あなたは午前7時に毎日オフに行きたいというあなたは、アラームを持っている場合たとえば、あなたはその中に格納することができDateTime利用DateTimeKindのをUnspecifiedあなたはそれが関係なく、DSTの午前7時にオフに行きたいので。ただし、アラーム発生の履歴を表す場合は、を使用しますDateTimeOffset

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


146
受け入れられた回答は長すぎ、類推は緊張しており、これははるかに優れた、より簡潔な回答IMOです。
ネクサスは

10
私もこの答えが好きだと言って賛成です。最後の部分では-確認Kindも同じですが、比較は誤っている可能性があります。両方の側がDateTimeKind.Unspecified同じタイムゾーンから来たことを本当に知らない場合。両側がDateTimeKind.Localである場合、ほとんどの比較は問題なく行われますが、ローカルタイムゾーンで片側があいまいであるためにエラーが発生する可能性があります。実際、DateTimeKind.Utc比較のみが確実であり、DateTimeOffset通常は推奨されます。(乾杯!)
Matt Johnson-Pint 2016

1
+1これに追加します:選択するDataTypeは意図を反映している必要があります。どこでもDateTimeOffsetを使用しないでください。オフセットが計算とデータベースからの読み取り/永続化に重要な場合は、DateTimeOffsetを使用します。それが問題ではない場合は、DateTimeを使用します。これにより、(DataTypeを見るだけで)オフセットに関連性​​がなく、TimesがC#コードが実行されているサーバー/マシンのローカリティに対して相対的である必要があることを理解できます。
MikeTeeVee

「しかし、アラーム発生の履歴を表現したい場合は、DateTimeOffsetを使用します。」これがなぜだと思うのか説明してもらえますか?このページのすべての情報を読んで記入することもできますが、そのような情報を読みやすい方法で提供することもできます。これは非常に読みやすい答えです。
Barrosy

77

DateTimeは、現地時間とUTCの2つの異なる時間のみを保存できます。種類のプロパティがいるかを示します。

DateTimeOffsetは、世界中のどこからでも現地時間を保存できるようにすることで、これを拡張します。また、その現地時間とUTC間のオフセットも保存れます。UTCオフセットを格納するためにクラスに追加のメンバーを追加しない限り、DateTimeがこれを実行できないことに注意してください。または、UTCでのみ機能します。どちらもそれ自体は素晴らしいアイデアです。


33

DateTimeOffset意味のある場所がいくつかあります。1つは、定期的なイベントや夏時間に対処する場合です。たとえば、毎日午前9時にアラームを鳴らしたいとします。「UTCとして保存し、現地時間として表示する」ルールを使用すると、夏時間が有効な別の時間にアラームが鳴ります。

おそらく他にもありますが、上記の例は実際に私が過去に遭遇したものです(これはDateTimeOffsetBCLに追加する前でした-当時の私の解決策は、明示的に時刻をローカルのタイムゾーンに保存して保存することでした。タイムゾーン情報と一緒に:基本的にDateTimeOffset内部で何が行われるか)。


12
DateTimeOffsetはDSTの問題を修正しません
JarrettV、2013年

2
TimeZoneInfoクラスを使用すると、DSTの規則が適用されます。.net 3.5以降を使用している場合は、TimeZoneクラスまたはTimeZoneInfoクラスのいずれかを使用して、タイムゾーンオフセットと組み合わせて夏時間を処理する必要がある日付を処理します。
Zack Jannsen 2013年

1
はい、例外の良い例(アラームアプリ)ですが、日付よりも時間の方が重要な場合は、アプリケーションのスケジュールデータ構造に個別に保存する必要があります。つまり、発生タイプ=毎日、時間= 09:00です。ここでのポイントは、開発者が記録、計算、またはユーザーに提示する日付のタイプを認識する必要があることです。特に、アプリはよりグローバルになりがちですが、ソフトウェアを作成するための標準および大きなアプリストアとしてインターネットがあります。サイドノードとして、Microsoftが別個の日付と時刻の構造を追加することも期待しています。
Tony Wall 14

3
JarrettとZackのコメントの要約:DateTimeOffset だけではDSTの問題は処理されないようですが、DateTimeOffsetをTimeZoneInfoと組み合わせて使用​​すると処理できます。これは、種類がUtcであるDateTimeと同じです。どちらの場合も、瞬間を投影しているカレンダーのタイムゾーン(オフセットだけでなく)を知っている必要があります。(可能であれば、ユーザーのプロファイルに保存するか、クライアント(Windowsなど)から取得します)。いいでしょう?
Jeremy Cook、

「DateTimeOffsetが意味をなす場所がいくつかあります。」---間違いなく、それは多くの場合よりも理にかなっています。
ロニー・オーバービー

23

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

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

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

一方、DateTimeOffsetにはオフセットが明示的に含まれています。タイムゾーンの名前が含まれていない場合がありますが、少なくともオフセットは含まれています。シリアル化すると、サーバーのローカル時刻ではなく、明示的に含まれているオフセットが値に含まれます。


14
上記のすべての答えを、私は疑問に思う誰もあなたの単一の文を書くことを気にしない理由を合計それをすべてアップThe most important distinction is that DateTime does not store time zone information, while DateTimeOffset does.
Korayem

9
DateTimeOffsetはタイムゾーン情報を格納しません。「DateTime、DateTimeOffset、TimeSpan、TimeZoneInfoのいずれかを選択する」というタイトルのMS文書では、「DateTimeOffset値は特定のタイムゾーンに関連付けられているわけではなく、さまざまなタイムゾーンのいずれかに由来している可能性がある」と述べています。とはいえ、DateTimeOffsetはタイムゾーンAWAREであり、UTCからのオフセットが含まれています。これにより、すべての違いが生じ、日付情報を扱うアプリ開発を扱うときにMSが推奨するデフォルトクラスになります。データがどの特定のタイムゾーンから来たかに本当に
関心が

1
はい。ただし、多くの場所で示されているように、+または-時間は、現在のタイムゾーンについて何も言わず、最終的には役に立たなくなります。何をする必要があるかに応じて、日時をKind.Unspecifiedとして保存し、そのタイムゾーンのIDを保存することもできます。
アーウィン

13

この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

9

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



7

主な違いは、現在のタイムゾーン以外のタイムゾーンの現地時間に変換するためにDateTimeOffset使用できることTimeZoneInfoです。

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


3
@Bugeo Bugeoは真実ですが、リスクがあります。最初にそれぞれに対して「ToUniversalTime」を呼び出すことにより、2つのDateTimeを比較できます。比較に1つの値、つまりDateTimeKind = Unspecifiedがある場合、戦略は失敗します。この失敗の可能性は、現地時間への変換が必要な場合に、DateTimeよりもDateTimeOffsetを検討する理由です。
Zack Jannsen 2013年

上記のように、このシナリオでは、最終的に何も意味しないDateTimeOffsetを使用するよりも、TimeZoneIdを格納する方がよいと思います。
アーウィン2018

2

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

XmlConvert.ToDateTimeOffset

XmlConvert.ToString

すべての利点があるため、先に進み、DateTimeOffsetとTimeZoneInfoを使用します。XML(またはすべてのビジネスオブジェクト)に対してシリアル化される、またはXMLからシリアル化されるエンティティを作成するときは注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.