with way only now example best c# datetime comparison resolution

way - ¿Cómo se comparan los objetos DateTime con una tolerancia especificada en C#?



datetime c# methods (6)

Por defecto C # compara los objetos DateTime con los 100ns tic. Sin embargo, mi base de datos devuelve los valores de DateTime al milisegundo más cercano. ¿Cuál es la mejor manera de comparar dos objetos DateTime en C # usando una tolerancia especificada?

Editar: estoy lidiando con un problema de truncamiento, no un problema de redondeo. Como Joe señala a continuación, un problema de redondeo introduciría nuevas preguntas.

La solución que funciona para mí es una combinación de los siguientes.

(dateTime1 - dateTime2).Duration() < TimeSpan.FromMilliseconds(1)

Esto devuelve verdadero si la diferencia es menor a un milisegundo. La llamada a Duración () es importante para obtener el valor absoluto de la diferencia entre las dos fechas.


Debe eliminar el componente milisegundos del objeto de fecha. Una forma es:

DateTime d = DateTime.Now; d.Subtract(new TimeSpan(0, 0, 0, 0, d.Millisecond));

También puede restar dos fechas

d.Subtract (DateTime.Now);

Esto devolverá un objeto de intervalo de tiempo que puede usar para comparar los componentes de días, horas, minutos y segundos para ver la diferencia.


Normalmente utilizo los métodos TimeSpan.FromXXX para hacer algo como esto:

if((myDate - myOtherDate) > TimeSpan.FromSeconds(10)) { //Do something here }


if (Math.Abs(dt1.Subtract(dt2).TotalSeconds) < 1.0)


¿Qué tal un método de extensión para DateTime para hacer un poco de una interfaz fluida (eso es furor verdad?)

public static class DateTimeTolerance { private static TimeSpan _defaultTolerance = TimeSpan.FromSeconds(10); public static void SetDefault(TimeSpan tolerance) { _defaultTolerance = tolerance; } public static DateTimeWithin Within(this DateTime dateTime, TimeSpan tolerance) { return new DateTimeWithin(dateTime, tolerance); } public static DateTimeWithin Within(this DateTime dateTime) { return new DateTimeWithin(dateTime, _defaultTolerance); } }

Esto depende de una clase para almacenar el estado y definir un par de sobrecargas del operador para == y! =:

public class DateTimeWithin { public DateTimeWithin(DateTime dateTime, TimeSpan tolerance) { DateTime = dateTime; Tolerance = tolerance; } public TimeSpan Tolerance { get; private set; } public DateTime DateTime { get; private set; } public static bool operator ==(DateTime lhs, DateTimeWithin rhs) { return (lhs - rhs.DateTime).Duration() <= rhs.Tolerance; } public static bool operator !=(DateTime lhs, DateTimeWithin rhs) { return (lhs - rhs.DateTime).Duration() > rhs.Tolerance; } public static bool operator ==(DateTimeWithin lhs, DateTime rhs) { return rhs == lhs; } public static bool operator !=(DateTimeWithin lhs, DateTime rhs) { return rhs != lhs; } }

Luego en tu código puedes hacer:

DateTime d1 = DateTime.Now; DateTime d2 = d1 + TimeSpan.FromSeconds(20); if(d1 == d2.Within(TimeSpan.FromMinutes(1))) { // TRUE! Do whatever }

La clase de extensión también contiene una tolerancia estática predeterminada para que pueda establecer una tolerancia para todo su proyecto y utilizar el método Dentro sin parámetros:

DateTimeTolerance.SetDefault(TimeSpan.FromMinutes(1)); if(d1 == d2.Within()) { // Uses default tolerance // TRUE! Do whatever }

Tengo algunas pruebas de unidad, pero eso sería demasiado código para pegar aquí.


Por defecto C # compara los objetos DateTime con el milésimo de segundo.

En realidad, la resolución es del tic 100ns.

Si está comparando dos valores de DateTime de la base de datos, que tienen una resolución de 1s, no hay problema.

Si está comparando con un DateTime de otra fuente (por ejemplo, el DateTime actual usando DateTime.Now)), entonces necesita decidir cómo quiere que se traten las fracciones de segundo. Por ejemplo, redondeado al más cercano o truncado? Cómo redondear si es exactamente medio segundo.

Sugiero redondear o truncar a un número entero de segundos, luego compararlo con el valor de la base de datos. Aquí hay una publicación que describe cómo redondear un DateTime (este ejemplo se redondea a minutos, pero el principal es el mismo).


Tuve un problema similar al del que preguntaba original, pero para hacer las cosas más interesantes estaba guardando y recuperando Nullable<DateTime> .

Me gustó la respuesta de joshperry y la extendí para que funcione a mis fines:

public static class DateTimeTolerance { private static TimeSpan _defaultTolerance = TimeSpan.FromMilliseconds(10); // 10ms default resolution public static void SetDefault(TimeSpan tolerance) { _defaultTolerance = tolerance; } public static DateTimeWithin Within(this DateTime dateTime, TimeSpan tolerance) { return new DateTimeWithin(dateTime, tolerance); } public static DateTimeWithin Within(this DateTime dateTime) { return new DateTimeWithin(dateTime, _defaultTolerance); } // Additional overload that can deal with Nullable dates // (treats null as DateTime.MinValue) public static DateTimeWithin Within(this DateTime? dateTime) { return dateTime.GetValueOrDefault().Within(); } public static DateTimeWithin Within(this DateTime? dateTime, TimeSpan tolerance) { return dateTime.GetValueOrDefault().Within(tolerance); } } public class DateTimeWithin { public DateTimeWithin(DateTime dateTime, TimeSpan tolerance) { DateTime = dateTime; Tolerance = tolerance; } public TimeSpan Tolerance { get; private set; } public DateTime DateTime { get; private set; } public static bool operator ==(DateTime lhs, DateTimeWithin rhs) { return (lhs - rhs.DateTime).Duration() <= rhs.Tolerance; } public static bool operator !=(DateTime lhs, DateTimeWithin rhs) { return (lhs - rhs.DateTime).Duration() > rhs.Tolerance; } public static bool operator ==(DateTimeWithin lhs, DateTime rhs) { return rhs == lhs; } public static bool operator !=(DateTimeWithin lhs, DateTime rhs) { return rhs != lhs; } // Overloads that can deal with Nullable dates public static bool operator !=(DateTimeWithin lhs, DateTime? rhs) { return rhs != lhs; } public static bool operator ==(DateTime? lhs, DateTimeWithin rhs) { if (!lhs.HasValue && rhs.DateTime == default(DateTime)) return true; if (!lhs.HasValue) return false; return (lhs.Value - rhs.DateTime).Duration() <= rhs.Tolerance; } public static bool operator !=(DateTime? lhs, DateTimeWithin rhs) { if (!lhs.HasValue && rhs.DateTime == default(DateTime)) return true; if (!lhs.HasValue) return false; return (lhs.Value - rhs.DateTime).Duration() > rhs.Tolerance; } public static bool operator ==(DateTimeWithin lhs, DateTime? rhs) { return rhs == lhs; } }

Y una prueba unitaria rápida para verificar que todo esté funcionando correctamente:

[TestMethod] public void DateTimeExtensions_Within_WorksWithNullable() { var now = DateTime.Now; var dtNow1 = new DateTime?(now); var dtNow2 = new DateTime?(now.AddMilliseconds(1)); var dtNowish = new DateTime?(now.AddMilliseconds(25)); DateTime? dtNull = null; Assert.IsTrue(now == dtNow1.Within()); // Compare DateTime to DateTime? Assert.IsTrue(dtNow1 == dtNow2.Within()); // Compare two DateTime? using a different syntax Assert.IsTrue(dtNow1 == dtNow2.Within()); // Same value should be true Assert.IsFalse(dtNow1 == dtNowish.Within()); // Outside of the default 10ms tolerance, should not be equal Assert.IsTrue(dtNow1 == dtNowish.Within(TimeSpan.FromMilliseconds(50))); // ... but we can override this Assert.IsFalse(dtNow1 == dtNull.Within()); // Comparing a value to null should be false Assert.IsTrue(dtNull == dtNull.Within()); // ... but two nulls should be true }