One of the first things most .NET developers learn to do with
DateTime is to get the current value from the system clock.
DateTime now = DateTime.Now;
This is probably the most horrible introduction to date and time that you could have. In my less-than-humble opinion, this is one method that should be deprecated from .NET. Let's look at some of the deficiencies:
The "Local" kind is not all that useful
If you examine the
DateTime.Kind property, you will find that it can be one of three values,
Utckind is very useful. It unambiguously identifies the instant in time that the value represents. Anyone told that these are UTC times will know what they mean. (They do have to be told that separately though.)
- As strange as it may seem, the
Unspecifiedkind is actually fairly useful. While it can't resolve to a particular instant, it does represent a point on a calendar. It doesn't pretend to know who's calendar it is talking about. Sometimes, that's exactly what we need.
- But a
Localkind puts us in an uncomfortable position - we pretend to be representing something meaningful, when really the value we have is completely ambiguous. The fact that the time was local is lost as soon as you pass it off to someone else. Their idea of "local" might be completely different than yours. In other words - a
DateTimecrosses any type of context boundary.
Who cares about the server's time anyway?
A great deal of code that we write ends up executing on a server. In the modern era of cloud computing, we have no guarantees about where that server might be located. Calling
DateTime.Now from an ASP.Net web page, or a web service, or the equivalent from a databases (such as
getdate() in SQL Server) provides a result that is often meaningless.
Ideally, everyone should set their servers to UTC. That avoids a lot of issues with how operating systems track time zone changes and sync with the computer's BIOS. But there are no guarantees of this. One can't just take the value from
DateTime.Now that came from a server and use it in some random client. Chances are - that client's time zone is completely different than the server's.
Local kinds don't round trip!
Ok, let's just assume for a moment that you are writing code that will never go out of your local office. You have a database server somewhere on your LAN (or on your own computer perhaps), and your network admin has all machines running in the same time zone. Let's take the value from DateTime.Now and store it to the database (using the proper parameratized inputs in ADO.Net or Entity Framework, for example). Then go and retrieve it back from the database into a DateTime field. One would expect that since the value was taken locally, persisted locally, and retrieved locally, that it would still be local. But no! Take a look at the .Kind property and now it is Unspecified!
This is actually a good thing, because we didn't transmit any time zone information to the database. It would be bad if we made the assumption that it was local when we retrieved it. But then, what good is Local for then?
Daylight Saving Time
People often forget that computer clocks are adjusted when transitioning to or from Daylight Saving Time. Have you ever seen (or written) code like this?
DateTime then = DateTime.Now; // ... do some work ... DateTime now = DateTime.Now; TimeSpan duration = now - then;
If so, and your code is running at the right moment, then you have introduced a major problem that will show up at least twice a year in many places around the world. In the spring, when Daylight Saving Time (aka "Summer Time") is introduced, you could have a full extra hour in your calculated duration! Then in the fall, when Daylight Saving Time ends and standard time is restored, you could actually have a negative value for your duration!
Clearly, if you want to measure the elapsed time of some operation, you should be using the
Stopwatch class. But sometimes you can't do that. Perhaps you are leaving this thread and coming back at a much later time.
Ok then, what should I use instead?
If you want to stick to
DateTime, the only appropriate property that unambiguously represents a moment in time is
DateTime.UtcNow. This will give you the current date and time at UTC, using the UTC kind. If you do any math on these values, like the code above, your answers will be correct (although not as precise as a
But many times, that's not good enough. I may actually want to know the time of the local computer. Maybe I'm writing a WinForms or WPF client application that is talking to the client's own clock. In that case, you should get to know and love the
DateTimeOffset object. If you aren't familiar with this object, you should look at my write-up at StackOverflow.
We have two options to poll the system clock as a
// Get the computer's local time DateTimeOffset dto1 = DateTimeOffset.Now; // Get the computer's time in UTC DateTimeOffset dto2 = DateTimeOffset.UtcNow;
Either of these values will accurately represent a single instant in time. If we are asking for
DateTimeOffset.Now, we will get a value that represents the local time on the computer where the code is running - but the offset we get will tell us how that value relates to UTC, and will yield a different offset when in standard time or Daylight Saving Time.
When getting the current system time, values such as
2013-04-25 9:26 AM are not very useful except for display. What we want instead is
2013-04-25 9:26 AM -0700. That way, when the values are stored or transmitted, we don't lose track of the context. This is easily done from .Net with
DateTimeOffset.Now, so there really isn't any reason to use
DateTime.Now at all. If we don't want to show the offset for display, we don't have to. And we can easily (and implicitly) use a
DateTimeOffset in place of where a
DateTime would normally go.
Call For Radical Change!
Please, Microsoft - in the next version of .Net framework, mark
[Obsolete]. Developers should be encouraged to use
Update: I actually proposed this in CoreFX issue 626. While I still feel strongly that
DateTime.Now is usually a smell of time-related problems, I'm satisfied with the idea of adding it to a static code analysis or Roslyn-based analyzer, rather than deprecating it from the framework itself.
Even more details on this subject are in Jon Skeet's excellent post, What's wrong with DateTime anyway?. This is the basis and inspiration for his excellent NodaTime library, which provides a much better API for working with dates and times. I highly recommend using NodaTime over any of the built-in date time objects whenever possible.