remarks cref c# .net .net-4.0 datetime-comparison

c# - cref - Comparación segura de DateTimes locales y universales



remarks c# (2)

Me acabo de dar cuenta de lo que parece una falla ridícula con la comparación DateTime.

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

Parece que todas las operaciones de comparación en DateTimes no hacen ningún tipo de conversión inteligente si una es DateTimeKind.Local y una es DateTimeKind.UTC. ¿Es la mejor manera de comparar de manera confiable DateTimes además de convertir siempre a los involucrados en la comparación en tiempo real?


Editado, mi respuesta original fue parcialmente incorrecta:

Cuando llamas a .Equal o .Equal , internamente se compara el valor .InternalTicks . Este campo es desigual , porque se ha ajustado un par de horas para representar el tiempo en el tiempo universal. Debería verlo de esta manera: el objeto DateTime representa una hora en una zona horaria sin nombre, pero no una hora universal más zona horaria. La zona horaria es Local (la zona horaria de su sistema) o UTC. Puede considerar esto como una falta de la clase DateTime.

Al convertir a otra zona horaria, el tiempo es, y debe ser, ajustado. Esta es probablemente la razón por la cual Microsoft eligió usar un método en lugar de una propiedad, para enfatizar que se toma una acción al convertir a UTC.

Originalmente escribí aquí que las estructuras se comparan y la bandera de System.DateTime.Kind es diferente. Esto no es verdad: es la cantidad de ticks que difiere:

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

Para comparar de forma segura dos fechas, puede convertirlas al mismo tipo. Si convierte cualquier fecha en hora universal antes de comparar, obtendrá los resultados que busca:

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

La moraleja: nunca compare DateTime ingenuamente


Para tratar con esto, creé mi propio objeto DateTime (llamémoslo SmartDateTime) que contiene DateTime y TimeZone. Anulo todos los operadores como == y Compare y convierto a UTC antes de hacer la comparación usando los operadores originales de DateTime.