Search code examples
c#datetimetimezoneutc

What is this about adjustment rules when converting DateTime to UTC?


In the MSDN page for TimeZoneInfo.ConvertTimeToUtc(), there is this info box:

If the current computer's local time zone includes multiple adjustment rules, this overload of the ConvertTimeToUtc method can return results that differ from the TimeZone.ToUniversalTime and DateTime.ToUniversalTime methods. TimeZone.ToUniversalTime always applies the current adjustment rule to time zone conversion, whether or not dateTime lies within its date range. And when executing on .NET Framework 3.5, DateTime.ToUniversalTime also applies the current adjustment rule to time zone conversion, whether or not dateTime lies within its date range.

I'm not sure I understand what this means. What are these adjustment rules, and how will the results differ between ConvertTimeToUtc() and TimeZone.ToUniversalTime()?


Solution

  • Here's an example. My computer at the time of writing this post is set to the US Pacific time zone, and today is March 2, 2015. It is currently Pacific Standard Time (or PST), which is 8 hours behind UTC.

    DateTime dt = new DateTime(2006, 4, 1, 0, 0, 0);
    TimeZoneInfo tzi = TimeZoneInfo.Local;
    DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tzi);
    

    In the above code, I am converting another value, midnight April 1st 2006, from my time zone to UTC. At that particular point in time, Pacific Standard Time (or PST) was in effect. The above code uses TimeZoneInfo, and is the correct way to do this. The output is April 1st 2006 at 8:00 AM UTC.

    Now look at this code:

    DateTime dt = new DateTime(2006, 4, 1, 0, 0, 0);
    TimeZone tz = TimeZone.CurrentTimeZone;
    DateTime utc = tz.ToUniversalTime(dt);
    

    It would appear to do almost the same thing. But it returns an incorrect value of 7:00 AM UTC.

    This occurs because the United States changed it's daylight saving time rules effective 2007. On the date in the example, DST was not in effect by the rule that was in place at that time, but it would be in effect if the current rule was in place then.

    Quite simply, the TimeZoneInfo object is aware of this change, but the TimeZone object is not. It mistakenly assumes the current rule was always in effect.

    The same thing will occur with other methods on the TimeZone class, which is why the MSDN reference says:

    Important
    Whenever possible, use the TimeZoneInfo class instead of the TimeZone class.

    Also, the TimeZone class has been removed from the new .Net CoreCLR project.

    Regarding "adjustment rules" - the MSDN remark is referring specifically to the TimeZoneInfo.AdjustmentRule class, which is used to track changes to time zone offsets that can occur on a regular or irregular basis within a time zone. Daylight Saving Time is one such type of change that can occur, but there are others as well.

    You may wish to read the StackOverflow wikis about daylight saving time and time zones to understand the mechanics behind these changes.

    You might also try my Pluralsight course, Date and Time Fundamentals, which explains these concepts in even greater detail.

    See also: What is the difference between DateTime.ToUniversalTime and TimeZoneInfo.ConvertTimeToUtc?