A raíz de un comentario con un colega recordé un bug un tanto curioso que tuvimos hace un tiempo, relacionado con los peligros de medir mal intervalos de tiempo. Teníamos un sistema que realizaba ciertos cálculos de manera periódica, y almacenaba un timestamp en un número entero con la fecha y la hora del último cambio para comprobar que no tuviera que actualizar, hasta aquí todo normal, o casi.
El primer problema era cómo se generaba dicho timestamp, ya que lo estábamos haciendo posiblemente de la peor manera, mediante Environment.TickCount. El segundo problema era que la comprobación se hacía mediante una simple comparación de enteros (algo huele mal por aquí) y las constantes se almacenaban también en múltiplos de segundos, es decir, para 5 min teníamos 5x60x1000 metido en una variable.
Tras romperme la cabeza durante un buen rato, me dió por ir a la definición de MSDN de la función TickCount, y descubrí el que podía ser el origen de todo el misterio:
The TickCount property cycles between Int32.MinValue, which is a negative number, and Int32.MaxValue once every 49.8 days.
Es decir, cada 49,8 días nuestro timestamp pasará a ser negativo, con lo cual la comparación con un número negativo daría siempre que estaba actualizado, y por tanto a partir de dicha fecha los datos no se actualizarían.
La solución pasó por sustituir ese horrible timestamp por DateTime.Now.Ticks. Los ticks son un valor long que almacena 100 nanosegundos, es decir, tenemos 10.000 ticks en cada milisegundo. No necesitamos tanta precisión, pero como valor para almacenar puede resultar convenientemente útil. A la hora de comparar bastaría con parsear el valor de ticks y comparar objetos fecha.
Una vez sustituido por DateTime.Now, me ví en la necesidad de generar tests para que esto no volviera a pasar, así que no podía depender de la fecha actual. Para los test, la solución ha sido pasar el valor de la fecha por parámetros, en producción se usa DateTime.Now, y los test usan una fecha fija.
Si quieres leer más:
- En StackOverflow Environment.TickCount vs DateTime.Now
Enjoy!
¡Ojo con los cambios de hora del horario de verano! Creo que lo suyo sería primero pasar la fecha a UTC, me equivoco?