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.