:::: MENU ::::

Tuesday, December 23, 2008

It’s been a few months since I started getting acquainted with the System.DateTimeOffset type and I can honestly say I don’t see any reason to use System.DateTime anymore.

I’ve even gone as far as ask whether anyone knew when I would rather use DateTime over DateTimeOffset. The responses I got were along the lines of ‘backwards compatibility’ or ‘when you need an abstract time’. My recommendation is that if you haven’t yet looked at the type, go do it now and after that, start using it.

So what is this DateTimeOffset? When representing a date/time, especially in an internationally-faced system, you have to include a time-zone. DateTime did a very poor job handling time-zones, like being insensitive to changes. DateTimeOffset is the exact same thing as DateTime, only it takes heed of time-zones. For instance, comparing two DateTimeOffsets with the same UTC time in different time-zones will result in equality.
Moreover, DateTime also had only three modes: Local, UTC and Unspecified, whereas DateTimeOffset has an Offset property, allowing you to create dates in any time-zone you like.

Things to note:

  1. DateTime can be implicitly converted to DateTimeOffset, but not vice-versa. To do that, you would have to use DateTimeOffset’s DateTime property.
    When converting this way, the DateTime’s kind will always be Unspecified.
2.  DateTimeOffset dateTimeOffset = DateTimeOffset.UtcNow;
DateTime dateTime = dateTimeOffset.DateTime;
  1. When parsing a DateTimeOffset, note that you can specify AssumeUniversal and AssumeLocal using the DateTimeStyles enum. These come in handy when the string you’re parsing has no time-zone data.
4.  if (!DateTimeOffset.TryParse(myDateString, CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal, out dateTimeOffset))
    dateTimeOffset = default(DateTimeOffset);
  1. It is a best practice to store all of your dates as UTC in the database, regardless of the physical location of your users / servers. When doing this, be sure to manually change your DateTimeOffset objects to UTC using ToUniversalTime and only then use the DateTime property as I have previously noted.
SaveTimeToDatabase(dateTimeOffset.ToUniversalTime().DateTime);

Note that you do not need to convert DateTimeOffset objects to any time-zone to do calculations / comparisons. The only time you need to convert them to a time-zone is for displaying them to the user.

  1. If you want to store a user’s time-zone (on a database that doesn’t support date/times with time-zones), it would be best to have a translation table and use the TimeZoneInfo class’s Ids (for instance: TimeZoneInfo.Local.Id). Then you could use TimeZoneInfo.FindSystemTimeZoneById to translate that value to a TimeZoneInfo and use that object’s BaseUtcOffset property to get the difference from UTC.
    This may seem a bit cumbersome, but considering the fact that time-zones change due to daylight savings time, you can’t just store the difference from UTC and would be better suited allowing Windows to take care of these issues for you.
    Here’s a sample of this method of conversion:
7.  string id = "Israel Standard Time";
8.  DateTimeOffset utcnow = DateTimeOffset.UtcNow;
9.   
DateTimeOffset now = utcnow.ToOffset(TimeZoneInfo.FindSystemTimeZoneById(id).BaseUtcOffset);

Side note: When storing these in the database, it would be prudent to use SQL Server 2008’s datetimeoffset type, which is the equivalent of DateTimeOffset and takes care of the time-zones in the same manner.

More