Every programmer has to deal with dates and times at some point, almost every system you encounter uses some notion of time. Despite being so ubiquitous, dates and times can be some of the most challenging parts of an application. The problem is that they are easy to use incorrectly and if you are not careful it can lead to some of the most difficult bugs to track down. I "dated" many times, and the least I can say is that not all of them went well, especially the first ones.
In this post, I will list some insights that might help you avoid the mistakes I made while dealing with dates and times.
Storing Date and Time
If your application does care about the original timezone the date and time was generated from: Store the DateTime in UTC and the source’s offset from UTC.
An example would be an application used by the security guy in a different time zone than UTC:
- You want to keep track of the hour an event logged to check later if it accrued during work hours or not
- You want this information to be stored in your database because the user might change his timezone after a record was saved in the database so you can’t rely on the conversion done in the client-side
If your application doesn’t care about the timezone it originated from then it’s simple: Store the DateTime in UTC In both cases, you should avoid storing those values as strings on your database, always use one of your database's data types.
Manipulating Date Time
If there is one thing that you should take away from this post it’s this rule: Always manipulate your dates and time as UTC
In .Net Core, there are a few built-in data types that you should learn. All of these are immutable value objects implemented as structs, they are not classes. In other words, they are used in the same way as simple types, like
booleans. They are:
Each of these types is for a specific purpose and has its quirks. The most used one I guess is
DateTime, and oh boy did I struggle with it a lot before I understood that not all instances of DateTime have the same kind, and it's that kind that controls the behavior of DateTime when passed into various methods:
DateTimeKind.Unspecified: Great for floating values but not for much else, its value is ambiguous unless you make some assumptions which I don't recommend you do. These are some ways you might get an Unspecified DateTime kind:
new DateTime(2019,11,25, 7,0,0); DateTime.Parse("2019-12-25 6:30:00");
You might get those values from a user's input, and by parsing it you get an Unspecified Kind which is not bad. But you might want to add some context to it before moving on, so if you know the user's timezone you might want to apply it and use a
DateTimeOffset going forward instead.
Here is an example why it's a bit dangerous to use unspecified kind in certain functions :
date.ToUniversalTime(); // Will assume date is Local date.ToLocalTime(); // Will assume date is UTC
DateTimeKind.Local: My recommendation to you would be to just never use Local DateTimeKind, especially for measuring elapsed time, when doing math or in any distributed system. These are some ways you can create a Local DateTimeKind
date = DateTime.Now; date = DateTime.Today;
This kind doesn't round trip, the local gets lost and the value becomes unspecified anytime you try to do something with it, for example, if you serialize to JSON or XML there is nothing that could indicate that it was ever local, when you de-serialize it to a DateTime it will be unspecified.
DateTimeKind.Utc: This is much easier, never ambiguous and safe for mathematical operations, in other words, you can subtract two dates that are Utc and you are guaranteed to not have errors due to time zones or daylight saving time.
dateUtc = DateTime.UtcNow; dateUtc = new DateTime(2019,11,25, 7,0,0, DateTimeKind.Utc); date = DateTime.Parse("2019-12-25 6:30:00"); //💀Unspecified Kind dateUtc = DateTime.SpecifyKind(date, DateTimeKind.Utc); //👍 now it's specified as Utc
Enough informations, time for an exercise : let’s say you have to code an application that schedules events in the future.
- What would your user form ask from the user that wants to add a new event? And what would you send to the server once he clicks Save?
- What will you store in the database? On the calendar view of your application, how would you format the values?
- How would you decide on the server that it’s time or not to send a reminder notification 5 minutes before an event?
- A user scheduled an event, and the government of his country just decided that they will no longer have a Daylight saving hour, are your solutions to the previous questions still going to work?
For further reading about this topic, here is a list of some useful resources:
- Date and Time Fundamentals, Pluralsight course by Matt Johnson