So you think you know how to use the DateTime struct in C#? You might be surprised.
C# provides a struct which is a value type called DateTime that implements various interfaces including IComparable, IConvertible, IFormattable, and ISerializable. Internally, it’s just a 64 bit integer. That’s it. All the functionality that I’ve explained in the last two episodes relies on just 64 bits. And really, the DateTime uses just 62 of these bits for the actual date and time. The last 2 bits are used to identify what kind of DateTime this is.
62 bits form a potentially really big number. What could possibly need such a large number? The DateTime doesn’t store its value in text. It doesn’t store for example 2020-07-01T12:30Z. What it does is keep track of how many 100 nanosecond intervals have passed since midnight zero hours of January 1st of the year 1 in the Gregorian calendar. That’s why it needs such a large number. There’ve been a lot of 100 nanoseconds since then.
Let’s start with how you obtain a DateTime instance. Your two primary methods will likely be DateTime.Now() to get a DateTime representing the current local date and time and DateTime.UTCNow() to get a DateTime representing the current date and time as UTC. You also have several constructors that allow you to pass in specific year, month, day, hour, minute, and second parameters. Let’s say you called the constructor that only needs a year, month, and day. What time should you get with that? Remember, this is a DateTime struct and not just a Date struct.
If you only provide a date, then the time portion gets set to midnight zero hours and the DateTime type is left unspecified.
What does unspecified mean? Sometimes, like here when the time was not included at all, then the system doesn’t know what to do with it. So it just makes the type Unspecified instead of Local or UTC.
The DateTime struct has no concept of a timezone. Sure, it can track if it’s local or not. But local to where? Microsoft tried to fix this in .Net 2.0 with the DateTimeOffset struct which allows you to specify a local date and time that’s tied to a specific offset from UTC. That seems great. But even the DateTimeOffset struct has problems because while it’s good at specifying a particular instant that’s clear exactly when it occurred, it has no way of knowing what the time will be even a minute later. That’s because you need more than just an offset to know how time should be handled. You really need to know which time zone the DateTimeOffset represents. Only then can you determine if daylight savings time is about to begin or not.
For this, you do have a new TimeZoneInfo class but it remains disconnected from the DateTime and DateTimeOffset structs. It’s very easy to get things mixed up.