Last week after a brief talk with a colleague I remembered a rather curious bug that we had some time ago, related to the dangers of measuring time intervals in the wrong way. We had a system that made certain calculations on a regular basis. This system stored a timestamp of the last sync date, so if the date was shorter that certain interval, it did not have to update. So far everything normal, or almost.
Update: As a redditor commented out, the article was missing some information. The system stored on plain text the last sync date, and the process could end after that. Later the process was restarted and the date was checked again.
The first problem was how we generated this timestamp, since we were doing it in the worst way possible, through Environment.TickCount. The second problem was that checking was done by a simple comparison of integers (something stinks around here) and the constants were also stored in multiples of miliseconds, i.e. for 5 min we had 5 x 60 x 1000 into a variable.
After losing more time than I expected to, y went to the the definition of the TickCount function on MSDN, and I discovered what could be the root of all evil:
The TickCount property cycles between Int32.MinValue, which is a negative number, and Int32.MaxValue once every 49.8 days.
I.e. each 49.8 days our timestamp will be negative, with which the comparison with a negative number would always look smaller than the interval we asked for, therefore, from that date the data wouldn’t be updated.
The solution was simple: Replacing that horrible Environment.TickCount with DateTime.Now.Ticks, which is a long value that won’t overflow, and that stores 100 nanoseconds per tick, having 10,000 ticks in each millisecond. We do not need such precision, but as value to store it can be conveniently useful. When comparing it is enough to parse the value of ticks and compare the Date objects, having a more robust comparison.
Once replaced by DateTime.Now, I saw the need to generate tests for this not to happen again, so we could not rely on the current date. For the test, the solution has been to pass the value of the date parameters, DateTime.Now is used in production, and a fixed date is used for test.
Update: DateTime.Now could have problems when the daylight saving time changes, so we should use DateTime.UtcNow to avoid issues.
Update 2: As another redditor commented, Stopwatch would be the way to go if we could be sure that the process that makes the check is constantly running.
If you want to read more:
- On StackOverflow Environment.TickCount vs DateTime.Now