2015-02-19 16 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 

Questo mi sembra un bug, se non lo è color me surprised.DateTime Compare Ignora Kind?

Devo chiamare ToUniversalTime() per ogni confronto o esiste un'alternativa migliore?

Come evitare le insidie ​​come dimenticare di chiamare ToUniversalTime() o ottenere un risultato errato a causa di DateTimeKind.Unspecified?

+0

Non * esattamente *, è nella documentazione - è necessario assicurarsi che gli orari siano nello stesso fuso orario. Inoltre, 'DateTime' non include alcuna informazione sul fuso orario. Hai bisogno di 'DateTimeOffset' per questo documento –

+1

dichiara chiaramente questo * Prima di confrontare gli oggetti DateTime, assicurati che gli oggetti rappresentino le volte nello stesso fuso orario. Puoi farlo confrontando i valori delle loro proprietà Kind. * –

+1

'NodaTime' per il salvataggio :) – tchrikch

risposta

5

La documentazione MSDN è abbastanza chiara che DateTimeKind non viene preso in considerazione utilizzando l'operatore Equality.

L'operatore di uguaglianza determina se due valori di DateTime sono uguali confrontando il loro numero di zecche. Prima di confrontare gli oggetti DateTime, assicurarsi che gli oggetti rappresentino le ore nello stesso fuso orario. Puoi farlo confrontando i valori della loro proprietà Kind.

MSDN - DateTime.Equality Operator

Si potrebbe scrivere il proprio metodo di estensione per includere il confronto DateTimeKind:

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

Tenendo conto delle osservazioni da Panagiotis Kanavos e James Thorpe su DateTimeOffset:

Da utilizzare se gli offset sono garantiti come gli offset locali.

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

Utilizzare se gli offset non sono garantiti per essere lo stesso:

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

Mi avete battuto su di esso +1 –

+0

Potete darmi un'alternativa che eviti questo trabocchetto? – laktak

+0

Non utilizzare DateTime, utilizzare DateTimeOffset che include l'offset tz. Meglio ancora, usa Noda Time che usa il nome del fuso orario effettivo e regola gli offset per l'ora legale. Indispensabile per i calcoli di viaggio aereo –

-1

è corretto per me.

1/1/2015 15:00:00 (UTC) (anche GMT - Pari al GMT Greenwich Mean Time)

1/1/2015 15:00:00 (locale - diciamo ora locale è a New York)

queste due volte e date sono uguali al confronto.

Ma convertire il secondo per UTC e salta avanti di 5 ore per diventare UTC/GMT

1/1/2015 20:00:00 - e non sono più uguali!

0

Non è esattamente un bug ma un difetto di DateTime. Il tipo DateTime non supporta le informazioni sul fuso orario a parte un indicatore locale/UTC. Lo dice nei documenti - devi assicurarti che le date siano nello stesso fuso orario - non solo per avere lo stesso tipo. DateTimeKind.Local non dice nulla su quale fuso orario viene realmente utilizzato.

Se si preoccupano dei fusi orari, è necessario utilizzare sempre il tipo DateTimeOffset.È stato introdotto in .NET 3.5 in parte per risolvere i fusi orari. DateTimeOffset è equivalente al tipo datetimeoffset di SQL Server e contiene l'offset fuso orario insieme al tempo, consentendo confronti e conversioni tra fuso orario offset. Ciò consente inoltre di memorizzare e utilizzare le informazioni complete sull'ora nel codice e nel database, evitando errori di conversione.

Questo è simile all'utilizzo di nvarchar anziché varchar per evitare errori di conversione delle codepage.

Un fuso orario può avere compensazioni diverse a causa dell'ora legale. Anche le regole di risparmio dell'ora legale cambiano di volta in volta - le regole russe sono cambiate almeno 4 volte negli ultimi 10 anni. Windows e .NET non hanno una soluzione per questo.

Questo può essere un problema, ad esempio nel settore dei viaggi. In questi casi è possibile utilizzare una libreria come Noda Time, che contiene il database del fuso orario IANA con tutte le regole del fuso orario note.