What are the New DateTime Features in Whidbey [Anthony Moore]
DateTime has received quite a number of new features in Whidbey. Several of them have been mentioned in other blog posts. Here is a summary of all the new features added.
After extensive design and discussion we decided to put more information into the DateTime class to address some serious issues with its usage. The original DateTime was a 64 bit integer that counted the number of ticks since the date 01 Jan 0001 in 100 nanosecond increments. It’s upper limit was the date 12 Dec 9999. It was not possible to make DateTime take up more than 64 bits in compatible way, but it was possible to make use of some of the unused space. DateTime actually only needs 62 bits to store its range of ticks, so we stored some important information in the other 2 bits. The next two features are possible because of this change. This should not affect you unless you look at the raw form of the data. The Ticks property remains compatible and does not include this exclude data. Serialization across versions also stays compatible.
Robust During Daylight Savings Transitions
A local “clock” time, such as the tick count in the V1.1 DateTime is unreliable in a time zone that has daylight savings time. During the transition out of daylight savings time, when you wind the clock back, there is a repeated hour which becomes ambiguous. This is one reason why using UTC times are preferred to local times for most operations. However, the .NET Framework defaults to using local times in most places because it is more RAD, and this information loss happens even if you only temporarily convert to local time.
In Whidbey, local times are robust to daylight savings time transitions. The extra bits are used to differentiate between the hour that is in daylight savings time and the one that is not, so you can reliably convert from UTC to local and back again without information loss.
A caveat is that local times still do not adjust for daylight savings time when you compare, add or subtract, so it is recommended that you use UTC times for most arithmetic. This is for compatibility, as there are some scenarios where adjusting for daylight savings time is right thing, and others when it is not.
The V1.1 DateTime had no context on what time zone it was being interpreted as being in. This was up to the application using it. It created problems when the DateTime’s were passed from one system to another. This is a problem if you are writing something like a serialization engine, where you are passed DateTime instances for which you don’t have this context. With Whidbey, there is a new Kind property with the values Unspecified, Local and UTC. This can be explicitly specified, but most APIs that such as DateTime.Now will set this value correctly if they know it for sure. One example where this is used is in DateTime.ToUniversalTime. If you call this on a DateTime that is definitely already UTC, it will become a no-op instead of blindly reapplying the offset.
A caveat with this is that due to compatibility requirements, this information largely informational. It is not used by most methods on DateTime itself, and it is not used by default in APIs we have already shipped. If you compare, add or subtract DateTime instances, this information is not used, so you still need to ensure you are comparing DateTime from the same time zone.
An obvious limitation is the ability to store time zones other than local or UTC. There may be a solution for this in a future version.
Serialization in XML
XmlConvert, Web Services and DataSet all assume that DateTime instances are local, which breaks scenarios where date-only or UTC DateTime instances are used. This problem is discussed in this post. In Whidbey there are options to correctly serialize UTC or date-only DateTime instances.
TryParse and TryParseExact
Like the numeric types, it is possible to parse DateTime instances using TryParse and TryParseExact that will not throw exceptions if the parsing operations fails. This can make code cleaner and faster. If invalid input is not a genuinely exception situation, we recommend using these.
The “o” Format and DateTimeStyles.AdjustToUniversal
There has been confusion about the correct way store and retrieve a DateTime in text. All of the single-character formats in V1.1 were subject to information loss of some kind. There is a new single-character format “o”, which preserves all the information. If you combine this with the new parsing flag DateTimeStyles.AdjustToUniversal, even the time zone and Kind will be correctly preserved. Details here..
ToBinary and FromBinary
Now that the format has changed, using the Ticks for binary storage is no longer sufficient for preserving all the information in the DateTime. To preserve the Kind and time zone information as well, use DateTime.ToBinary and DateTime.FromBinary. Details here.
DateTimeStyles.AssumeLocal and DateTimeStyles.AssumeUniversal
When parsing in V1.1, there would be a default adjustment to local time if there was time zone information in the input string, but no conversion otherwise. The flag DateTimeStyles.AdjustToUniversal would make this an adjustment to UTC instead, but would still do nothing if there was no time zone information. These new parsing flags will allow you to specify what time zone you interpret a DateTime as being in if not is specified. More information in this post. this post.
The “F” Format
This new format is useful when using DateTime.ParseExact. It will allow a variable number of second fraction digits. Details Here.