.Equal
またはを呼び出すと.Compare
、内部的に値.InternalTicks
が比較されます。これは、ulong
最初の 2 ビットを除いた です。このフィールドは、世界時の時間を表すために数時間調整されているため、等しくToUniversalTime()
ありません。 を呼び出すと、現在のシステムのローカル タイムゾーン設定のオフセットで時刻が調整されます。
このように表示する必要があります。DateTime オブジェクトは、名前のないタイム ゾーンの時刻を表しますが、協定世界時とタイム ゾーンを合わせたものではありません。タイムゾーンはローカル (システムのタイムゾーン) または UTC です。これは DateTime クラスの欠如と考えるかもしれませんが、歴史的には「1970 年以降のティック数」として実装されており、タイムゾーン情報は含まれていません。
別の UTC に変換する場合、時刻は調整されます (調整する必要があります)。これがおそらく、Microsoft がプロパティではなくメソッドを使用して、UTC への変換時にアクションが実行されることを強調することを選択した理由です。
もともと構造体を比較してフラグSystem.DateTime.Kind
が違うとここに書きました。これは正しくありません: 異なるのはティックの量です:
t1.Ticks == t2.Ticks; // false
t1.Ticks.Equals(t2.Ticks); // false
2 つの日付を安全に比較するには、それらを同じ種類に変換できます。比較する前に任意の日付を世界時に変換すると、次の結果が得られます。
DateTime t1 = DateTime.Now;
DateTime t2 = someOtherTime;
DateTime.Compare(t1.ToUniversalTime(), t2.ToUniversalTime()); // 0
DateTime.Equals(t1.ToUniversalTime(), t2.ToUniversalTime()); // true
現地時間を変更せずに UTC 時間に変換する
UTC に変換する代わりに(時間は同じままですが、ティック数は異なります)、 を上書きしDateTimeKind
て UTC に設定することもできます (現在は UTC になっているため、時間を変更しますが、比較します)。ティック数が等しいため、等しい)。
var t1 = DateTime.Now
var t2 = DateTime.SpecifyKind(t1, DateTimeKind.Utc)
var areEqual = t1 == t2 // true
var stillEqual = t1.Equals(t2) // true
DateTime
これは、ビット単位で等しくない可能性があるが、等しいと比較されるか、ビット単位で等しく (時間部分) かつ等しくない場合があるまれなタイプの 1 つだと思います。
.NET 6 の変更点
.NET 6.0 では、TimeOnly
とDateOnly
. これらを使用して、「時刻のみ」、「年の日付のみ」を保存できます。これらを構造体に組み合わせると、元の歴史的な煩わしさのない日付と時刻の構造体ができますDateTime
。
代替案
、、閏秒、カレンダー、タイムゾーンのシフト、期間などを適切に操作することは、.NET では困難DateTime
です。TimeZoneInfo
個人的にNodaTime
は、Jon Skeet の方が好きです。これは、意味のある明確な方法でプログラマーに制御を戻します。
Jon Skeet によるこの洞察に満ちた投稿では、プログラマーがすべてを UTC で保存するだけで DateTime の問題を回避しようとするときに直面する可能性がある問題について詳しく説明しています。
ソースからの背景情報
.NET ソースの構造体を確認するDateTime
と、元は (.NET 1.0 で) が単なるティック数であったことを説明するメモが見つかりますDateTime
が、後でユニバーサルかローカルかを保存する機能が追加されました。時間。ただし、シリアル化すると、この情報は失われます。
これはソースのメモです:
// This value type represents a date and time. Every DateTime
// object has a private field (Ticks) of type Int64 that stores the
// date and time as the number of 100 nanosecond intervals since
// 12:00 AM January 1, year 1 A.D. in the proleptic Gregorian Calendar.
//
// Starting from V2.0, DateTime also stored some context about its time
// zone in the form of a 3-state value representing Unspecified, Utc or
// Local. This is stored in the two top bits of the 64-bit numeric value
// with the remainder of the bits storing the tick count. This information
// is only used during time zone conversions and is not part of the
// identity of the DateTime. Thus, operations like Compare and Equals
// ignore this state. This is to stay compatible with earlier behavior
// and performance characteristics and to avoid forcing people into dealing
// with the effects of daylight savings. Note, that this has little effect
// on how the DateTime works except in a context where its specific time
// zone is needed, such as during conversions and some parsing and formatting
// cases.