DateTime.UtcNow is generally preferable to DateTime.Now

DateTime.UtcNow is generally preferable to DateTime.Now

  • Comments 9

This seems to be commonly known and accepted best practice to use DateTime.UtcNow for non-user facing scenarios such as time interval and timeout measurement.

I’ve just done an audit of the Roslyn codebase and replaced most DateTime.Now calls with DateTime.UtcNow. I thought it’d be useful to post my changeset description here (although none of it is new – I just summarize some common knowledge readily available in the sources linked below).

====

Replacing DateTime.Now with DateTime.UtcNow in most cases.

We should be using DateTime.Now only in user-facing scenarios. It respects the timezone and Daylight Savings Time (DST), and the user feels comfortable when we show them the string that matches their wall clock time.

In all other scenarios though DateTime.UtcNow is preferable.

First, UtcNow usually is a couple of orders of magnitude faster, since Now is basically first calling UtcNow and then doing a very expensive call to figure out the time zone and daylight savings time information. Here’s a great chart from Keyvan’s blog (modified to avoid allocations of the Stopwatch object):

image

Second, Now can be a big problem because of a sudden 1-hour jump during DST adjustments twice a year. Imagine a waiting loop with a 5-sec timeout that happens to occur exactly at 2am during DST transition. The operation that you expect to timeout after 5 sec will run for 1 hour and 5 seconds instead! That might be a surprise.

Hence, I'm replacing DateTime.Now with DateTime.UtcNow in most situations, especially polling/timeout/waiting and time interval measurement. Also, everywhere where we persist DateTime (file system/database) we should definitely be using UtcNow because by moving the storage into a different timezone, all sorts of confusion can occur (even "time travel", where a persisted file can appear with a future date). Granted, we don't often fly our storage with a supersonic jet across timezones, but hey.

For precise time interval measurements we should be using System.Diagnostics.StopWatch which uses the high resolution timer (QueryPerformanceCounter). The resolution of both DateTime.Now and DateTime.UtcNow is very low – about 10 ms – this is a huge time interval!

For a cheap timestamp, we should be generally using Environment.TickCount - it's even faster than DateTime.UtcNow.Ticks.

I'm only leaving DateTime.Now usages in test code (where it's never executed), in the compiler Version parsing code (where it's used to generate a minor version) and in a couple of places (primarily test logging and perf test reports) where we want to output a string in a local timezone.

Sources:

* http://www.keyvan.ms/the-darkness-behind-datetime-now
* http://stackoverflow.com/questions/62151/datetime-now-vs-datetime-utcnow
* http://stackoverflow.com/questions/28637/is-datetime-now-the-best-way-to-measure-a-functions-performance

  • Great tip, never thought about it, even while seeing performance reports pointing to DateTime.Now costs. The small things that make difference. I didn't know I had a cheap alternative.

  • IMHO using DateTimeOffset (datetimeoffset type in SQL Server) is better for many applications since you 'free' yourself from having to worry about converting to or from UTC - when it comes time to display it to the user, you can have it display in their timezone regardless of what it started out as.

    *So* many headaches/bugs come up from people forgetting to 'normalize' onto UTC, that it really doesn't seem worth using 'just' DateTime in the vast majority of cases.

    And there's still DateTimeOffset.UtcNow to use for that case, which should be very fast since it's DateTime.UtcNow with TimeSpan.Zero :)

  • Why would you use localized time for Version generation?

    In global companies with projects developed from multiple time zones it is likely to ruin the ordering. Consider this very real and likely situation:

    I build and release an app from New Jersey. Version generated from wall clock is 1.234.

    The app has a bug which is picked by my colleague from Bangalore.

    In 15 minutes she fixes, tests and releases a new patched version, which is 1.155.

    It is late night in Jersey City, but early morning in Bangalore. So my version is larger than hers. Imagine how misleading it will be to debug any problem in this situation.

  • Consider not using DateTime.UtcNow either but a 'SystemTime' abstraction. Reading DateTime.UtcNow can also be significantly optimized.

    dhickey.ie/.../SystemClock.aspx

  • Folks, I just noticed that Keyvan's benchmark counts allocations of the Stopwatch object. If he reuses the same Stopwatch instance, the perf will be much much better than shown on his graph. I've posted my own graph in the post above without allocations for Stopwatch.

  • Oleg - we just use it as a random number generator when we need a random looking version :)

  • James - also thanks for the DateTimeOffset tip :)

  • @Kirill Could you add the labels for the xy-axis on the chart. I am not sure what we are comparing. I just see numbers only which is not that informative. Thanks.

  • Sk - sorry about that - follow the link to Keyvan's article, he has detailed explanations and the benchmark source code.

Page 1 of 1 (9 items)
Leave a Comment
  • Please add 4 and 3 and type the answer here:
  • Post