web-dev-qa-db-ja.com

ローカルとユニバーサルのDateTimeを安全に比較する

DateTimeの比較で、とんでもない欠陥のように見えることに気づきました。

DateTime d = DateTime.Now;
DateTime dUtc = d.ToUniversalTime();

d == dUtc; // false
d.Equals(dUtc); //false
DateTime.Compare(d, dUtc) == 0; // false

1つがDateTimeKind.Localで、もう1つがDateTimeKind.UTCの場合、DateTimeでのすべての比較操作は、どのタイプのスマート変換も実行できないようです。比較に含まれる両方を常にutc時間に変換する以外に、DateTimeを確実に比較するためのより良い方法はありますか?

40
jdc0589

編集、私の元の答えは部分的に間違っていました:

.Equalまたは.Compareを呼び出すと、内部で値.InternalTicksが比較されます。このフィールドはunequalです。これは、世界時で時刻を表すために数時間調整されているためです。このように表示されるはずです。DateTimeオブジェクトは、名前のないタイムゾーンでtimeを表しますが、世界時とタイムゾーンではありません。タイムゾーンは、ローカル(システムのタイムゾーン)またはUTCです。これは、DateTimeクラスの欠如と考えるかもしれません。

convertingを別のタイムゾーンに変換する場合、時刻は調整され、調整されます。これがおそらく、マイクロソフトがUTCに変換するときにアクションが実行されることを強調するために、プロパティではなくメソッドを使用することを選択した理由です。

もともと私は構造体が比較され、System.DateTime.Kindのフラグが異なることをここに書きました。これは真実ではありません。異なるのはティックの量です。

t1.Ticks == t2.Ticks;       // false
t1.Ticks.Equals(t2.Ticks);  // false

2つの日付を安全に比較するために、それらを同じ種類に変換できます。比較する前に日付を世界時に変換すると、後の結果が得られます。

DateTime t1 = DateTime.Now;
DateTime t2 = t1;
DateTime.Compare(t1.ToUniversalTime(), t2.ToUniversalTime());  // 0
DateTime.Equals(t1.ToUniversalTime(), t2.ToUniversalTime());  // true

道徳:決してDateTime単純に比較しない

46
Abel

これに対処するために、DateTimeとTimeZoneを含む独自のDateTimeオブジェクト(SmartDateTimeと呼ぶことにします)を作成しました。 ==やCompareなどのすべての演算子をオーバーライドし、元のDateTime演算子を使用して比較を行う前にUTCに変換します。

5
Ed Bayiates