2015-02-19 19 views
5
DateTime d1=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
DateTime d2=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Local); 
Console.WriteLine(d1==d2);   // prints true 
Console.WriteLine(d1<d2);   // prints false 
Console.WriteLine(d1.CompareTo(d2)); // prints 0 
Console.WriteLine(d1.ToUniversalTime()==d2.ToUniversalTime()); // prints false 

To wygląda jak błąd dla mnie, jeśli nie color me surprised.DateTime Porównaj Ignores Kind?

Czy muszę wywoływać ToUniversalTime() dla każdego porównania lub czy istnieje lepsza alternatywa?

W jaki sposób uniknąć pułapek, takich jak zapomnienie wywołania ToUniversalTime() lub uzyskanie złego wyniku z powodu DateTimeKind.Unspecified?

+0

Nie * dokładnie *, jest w dokumentacji - musisz upewnić się, że czasy są w tej samej strefie czasowej. Poza tym 'DateTime' nie zawiera żadnych informacji o strefie czasowej. Potrzebujesz "DateTimeOffset" do tego –

+1

Dokumenty wyraźnie stwierdzają, że * Przed porównaniem obiektów DateTime, upewnij się, że obiekty reprezentują czasy w tej samej strefie czasowej. Możesz to zrobić, porównując wartości ich właściwości Kind. * –

+1

'NodaTime' na ratunek :) – tchrikch

Odpowiedz

5

Dokumentacja MSDN jest całkiem jasna, że ​​DateTimeKind nie jest brany pod uwagę przy użyciu operatora Równości.

Operator Równości określa, czy dwie wartości DateTime są równe, porównując ich liczbę znaczników. Przed porównaniem obiektów DateTime upewnij się, że obiekty reprezentują czasy w tej samej strefie czasowej. Możesz to zrobić, porównując wartości ich właściwości Kind:.

MSDN - DateTime.Equality Operator

można napisać własną metodę rozszerzenia obejmować porównanie DateTimeKind:

public static bool EqualsWithKind(this DateTime time, DateTime other) 
{ 
     return time.Kind == other.Kind && 
      time == other; 
} 

Uwzględniając uwagi od Panagiotis Kanavos i James Thorpe o DateTimeOffset:

Należy użyć, jeśli przesunięcia mają być takie same, jak przesunięcie lokalne.

public static bool EqualsWithTimezone(this DateTime time, DateTime other) 
{ 
     return new DateTimeOffset(time) == new DateTimeOffset(other); 
} 

używać, jeśli korekcje nie są gwarantowane być taka sama:

public static bool EqualsInclTimezone(this DateTime time, TimeSpan timeOffset, DateTime other, TimeSpan otherOffset) 
{ 
     return new DateTimeOffset(time, timeOffset) == new DateTimeOffset(other, otherOffset); 
} 
+0

Uderzyłeś mnie do tego +1 –

+0

Czy możesz podać mi alternatywę, która pozwoli uniknąć tej pułapki? – laktak

+0

Nie należy używać DateTime, należy użyć DateTimeOffset, który obejmuje przesunięcie tz. Co więcej, należy użyć czasu Noda, który używa rzeczywistej nazwy strefy czasowej i dostosowuje przesunięcia w celu zmniejszenia czasu letniego. Niezbędny do obliczeń podróży lotniczych –

-1

Wygląda poprawne do mnie.

1/1/2015 15:00:00 (UTC) (również GMT - Równe GMT Greenwich Mean Time)

1/1/2015 15:00:00 (lokalny - powiedzmy, że jest czas lokalny w NYC)

te dwa razy i daty SĄ równe w porównaniu.

Ale przekształcić drugi do UTC i przeskakuje do przodu 5 godzin stać UTC/GMT

01.01.2015 20:00:00 - i już nie są takie same!

0

To nie jest błąd, ale wada DateTime. Typ DateTime nie obsługuje informacji strefy czasowej oprócz wskaźnika lokalnego/UTC. Mówi tak w dokumentach - musisz upewnić się, że daty są w tej samej strefie czasowej - nie tylko o tym samym rodzaju. DateTimeKind.Local nie mówi nic o tym, która strefa czasowa jest naprawdę używana.

Jeśli zależy Ci na strefach czasowych, zawsze powinieneś używać typu DateTimeOffset.Został wprowadzony w .NET 3.5 częściowo w celu adresowania stref czasowych. DateTimeOffset jest odpowiednikiem typu SQL Server o nazwie datetimeoffset i zawiera przesunięcie strefy czasowej wraz z czasem, co umożliwia porównywanie i konwersje między przesunięciami strefy czasowej przesunięć. Pozwala to również przechowywać i wykorzystywać pełne informacje o czasie w kodzie i bazie danych, unikając błędów konwersji.

Jest to podobne do korzystania z nvarchar zamiast varchar, aby uniknąć błędów konwersji stron kodowych.

Strefa czasowa może mieć różne przesunięcia, chociaż z powodu oszczędności czasu letniego. Zasady dotyczące czasu letniego zmieniają się również od czasu do czasu - rosyjskie przepisy zmieniły się 4 razy przynajmniej w ciągu ostatnich 10 lat. Windows i .NET nie mają na to poprawki.

Może to być problem, np. W branży turystycznej. W takich przypadkach można użyć biblioteki takiej jak Noda Time, która zawiera bazę danych strefy czasowej IANA ze wszystkimi znanymi regułami strefy czasowej.