Scott Hanselman

KB928388 Breaking Tests with Windows DST TimeZone Patch and Past Dates

February 09, 2007 Comment on this post [18] Posted in Musings | NUnit | Programming
Sponsored By

UPDATE: It appears that what we suspected is true, Windows understands one set of DST rules. Whatever the current DST rules are are applied to all dates. This doesn't make sense to me as that would make the 2005 test below fail also, and it doesn't. More as it comes in.

UPDATE#2: Seems that a new "Dynamic DST" section is added for future OS's, like Vista, for handling future DST time changes. This change will affect all Windows OS's equally - that is, you don't need to custom code for one OS versus another. If congress, in their infinite wisdom, decides to change the laws of Time and Space again, Vista and other OS's will require only a registry change, and past time rules will still apply. Thanks to Tim Heuer for helping puzzle through it all.

One of our Architects at Corillian, Paul Gomes, led the team that designed our .NET-based OFX Banking Server. That product happens to have ridiculously good Code Coverage and a metric-crapload of Unit Tests. Recently a build server had the Daylight Savings Time (DST) Windows KB928288 patch applied. Immediately an internal Date-related test failed. 

Paul dug into it and boiled it down to this simplified test that takes a date in March of 2006 and converts it to GMT.

   1:  [TestFixture]
   2:  public class DSTTest
   3:  {
   4:        private const string DATEFORMAT = 
@"yyyyMMddHHmmss.fff[0\:G\MT]";
   5:   
   6:        public DSTTest(){}
   7:   
   8:        [Test]
   9:        public void TestDateInThePast()
  10:        {
  11:              DateTime myDate = DateTime.ParseExact(
                       "2006/03/17 11:42:33",
                       "yyyy/MM/dd HH:mm:ss",
                       CultureInfo.InvariantCulture);
  12:              string myDateAsString = myDate.ToUniversalTime().ToString(
DATEFORMAT, CultureInfo.InvariantCulture);
  13:              Assert.AreEqual("20060317194233.000[0:GMT]",
                       myDateAsString);
  14:        }
  15:  }

The output is interesting. Note that we're comparing strings in this case for clarity.

Output from unit test:

TestCase 'DSTTest.DSTTest.TestDateInThePast'
failed:
String lengths are both 25.
Strings differ at index 9.
expected: <"20060317194233.000[0:GMT]">
but was:  <"20060317184233.000[0:GMT]">
---------------------^
c:\dsttest\dsttest.cs(19,0): at DSTTest.DSTTest.TestDateInThePast()

I first thought that this was no problem and I said to Paul:

Makes sense…that date in your test is inside the DST boundary, so we switch from -8 to -7.  11:00 becomes 18:00, rather than 19:00. We “sprung forward.”

However, Paul reminded me that we were testing a date within 2006! We're testing the 17th of March, 2006, outside of DST. Note the table below. I'd expect that day to be DST for 2007, but not 2006.

Here's where it gets really weird. Let's try the 12th of March, and try dates in 2005, 2006, and 2007. Note that when the time is 02:59:59am on March 12th, 2006, the test succeeds, but it fails at 3am, one minute later. Again, note that this is using a date in 2006, where DST started in April.

   1:              [Test]
   2:              public void TestDateIn2007Succeeds()
   3:              {
   4:                    DateTime myDate = DateTime.ParseExact(
"2007/03/12 03:00:00",
"yyyy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture);
   5:                    string myDateAsString = myDate.ToUniversalTime().ToString(
                             DATEFORMAT, CultureInfo.InvariantCulture);
   6:                    Assert.AreEqual("20070312100000.000[0:GMT]",myDateAsString);
   7:              }
   8:   
   9:              [Test]
  10:              public void TestDateIn2006Succeeds()
  11:              {
  12:                    DateTime myDate = DateTime.ParseExact(
"2006/03/12 02:59:59",
"yyyy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture);
  13:                    string myDateAsString = myDate.ToUniversalTime().ToString(
                             DATEFORMAT, CultureInfo.InvariantCulture);
  14:                    Assert.AreEqual("20060312105959.000[0:GMT]",myDateAsString);
  15:              }
  16:   
  17:              [Test]
  18:              public void TestDateIn2006Fails()
  19:              {
  20:                    DateTime myDate = DateTime.ParseExact(
"2006/03/12 03:00:00",
"yyyy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture);
  21:                    string myDateAsString = myDate.ToUniversalTime().ToString(
                             DATEFORMAT, CultureInfo.InvariantCulture);
  22:                    Assert.AreEqual("20060312110000.000[0:GMT]",myDateAsString);
  23:              }
  24:   
  25:              [Test]
  26:              public void TestDateIn2005Succeeds()
  27:              {
  28:                    DateTime myDate = DateTime.ParseExact(
"2005/03/12 03:00:00",
"yyyy/MM/dd HH:mm:ss",
                             CultureInfo.InvariantCulture);
  29:                    string myDateAsString = myDate.ToUniversalTime().ToString(
                             DATEFORMAT, CultureInfo.InvariantCulture);
  30:                    Assert.AreEqual("20050312110000.000[0:GMT]",myDateAsString);
  31:              }
  32:        }
  33:  }

What are we missing, dear reader? Is there a problem (bug?) with the registry-based Windows DST Patch?

I'm leaning towards assuming it's us, but I wanted to ask you. It seems that the data points towards this patch not working with dates in 2006. Not a huge deal, but non-trivial,IMHO.

As an aside, but very slightly related note, Steve Harman had an interesting bug where his Unit Tests were expecting to see "Tijuana" at the end of his TimeZone's Display Name. Since Mexico isn't following our lead (if it could be called a "lead") and changing their DST, so Tijuana isn't in PST proper anymore.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
February 09, 2007 0:19
Scott, see Michael Kaplan's article here: http://blogs.msdn.com/michkap/archive/2007/02/05/1606868.aspx

It's apparently a bug by design.
February 09, 2007 0:50
I don't think that the patch is broken, but rather the implementation of how timezones (and their daylight savings adjustments) are configured in the registry. I don't believe there is a history to the setting. Check out HKLM:\software\microsoft\Windows NT\CurrentVersion\Time Zones and look at your favorite time zone.

There is a TZI item that holds the information on when to change the clock. There is a place for the month and the day (if you've applied the patch, you will see a 3 and a 2 in there, indicating the 2nd Sunday of March as well as a 1 and an 11, indicating the 1st Sunday in November. I don't know what the rest represent :).

However, I don't believe it has an associated year with the setting. So, when these values are changed, the system believes that the clock has changed and will change on those days every year.

Now, whether or not the framework is trying to do some other calculations on top of this is left up to someone else to investigate.
February 09, 2007 1:40
orcmid - I don't see from Michael Kaplan's post how DST changes in 2006 are mentioned or are a bug by design. Did I miss something?

Mark - That's odd...if that was the case, it'd be failing on ALL past dates.
February 09, 2007 3:10
Scott,
Mark is right - DST boundaries have no history in versions of Windows before Vista.

http://blogs.msdn.com/oldnewthing/archive/2003/10/24/55413.aspx
February 09, 2007 3:21
This is really really LAME.

So, if this is true, Kevin and Mark, and it looks like it is, then why is 2005 working?
February 09, 2007 3:45
Hmm...
I ran the tests on my Vista machine and I had to set my timezone to Alaskan (I'm Eastern EST) to get your test to pass...
Using 2.0 framework I ran your tests and came up with the following results:
2001=Pass
2002=Pass
2003=Pass
2004=FAIL
2005=FAIL
2006=Pass
2007=Pass

I don't want to chase a rabbit, but: What version of Windows and Framework is this running against?
February 09, 2007 3:47
I think we're running against either XP or 2003R2 on 1.1. You think the Framework is trying to be tricky?
February 09, 2007 3:47
2005 succeeds because the 2nd Sunday in 2005 is March 13, not March 12. So your clock hasn't changed according to the rules.
February 09, 2007 3:50
Oops, David beat me to it. I was just about to say the same thing.
February 09, 2007 3:58
Craptastic. Confirmed by Microsoft internal folks:

"On the blog they are testing with March 12. That isn’t the best day to use, because that is right around the period when the new DST begins. In 2006 March 12 is the date while in 2005 it is not in (new) DST rules.

DST is now defined as second Sunday or March, so for 2005 that day is outside of the extended DST period.

They are correct in that there is only one definition of DST (year independent) and it applies to the past and future, so since we changed for 2007 items from the second Sunday of March to first Sunday of April is previous years could be off, because they are in the extended DST period, but that year never had it"
February 09, 2007 4:44
Ok, now I definitely give up on computers and I'm moving out into the woods with a big stick and some rocks. All the calculations and stuff aside, it seems to me that Microsoft would have made this a bit of a higher priority and tested the tar and everything else out of it. When three OS's from the same company produce different results with the same test code something sparks of MAJOR inconsistencies.

I'm going to have to play with these tests myself and see what I see just to make my head hurt a little more... ;)
February 09, 2007 4:49
And speaking of time issues...

When I posted this last comment I noticed that the date is correct, BUT the time shows 9:44:19 PM (Pacific Standard Time, UTC-08:00).
It's 5:45 PM where I'm at. In Colorado. Mountain Standard Time. 1 hour difference?

Just an observation. :p

Packing stick and rocks now.
February 09, 2007 5:04
Ok, one more comment then I swear I'll go away.

In thinking about this, instead of using a single entry to designate DST, why not use multiple entries? This of course would require a history of changes to DST. But isn't that readily available via a Google search? A "table" of the current system timezone and all DST data regarding historical changes could easily be implemented and "popped" into place for the OS to check and create its calculations based on the current system date and use for any other dates passed to these functions.

This is obviously a simplistic view and maybe approach, and possibly not even viable for anything below a new OS due to possible dependency issues, but it makes some kind of sense to me.

</soapbox> (hopefully that wasn't interpreted as HTML... can't tell until I click Save.)
February 09, 2007 5:39
This is the reason MS added the dynamic time zone info to Vista.

I'd bet good money that the lawmakers who decide to do things like change the DST dates have no clue what the actual ramifications will be.
February 09, 2007 10:25
Kevin's right - the apparently simple ramifications of a piece of legislation like the Energy Policy Act of 2005 spread throughout the world. But if you think that was bad, take a look at Western Australia that, in the final event, got just over 2 weeks notice that they were starting daylight saving time on December 3, 2006 (OK - they knew about if for a while before, but the legislation was finally signed 2 weeks before). MS have a patch out there for that too. Oh, and next year, that date will be the last Sunday of October, like the rest of Australia.

Watch out folks for the other time zones around the world that have had their display names changed by this fix, and the boatload of new timezones that have been introduced to cope with new political realities, especially in Eastern Europe.

All in all, it's not simple ... and this isn't the end. There will be ongoing changes in these definitions in the years ahead. And did anybody note that there is a clause in the US Energy Policy Act that calls for evaluation in a few years, at which time we might revert to the previous definitions :-)

February 09, 2007 16:11
Which systems have they released patches for? I'm assuming XP, 2k3, and Vista, but are they going to release a patch for win2k? I'm pretty sure NT is out. Anyone know of a 3rd party patch? We still run a LOT of NT machines here at work... (Yes, we have plans to get rid of them, but the majority of them aren't going anywhere before March.)
February 09, 2007 22:47
Tim,
From what I've heard, there will be no official patch for 2000 and before. There are, however a couple of solutions for those platforms.

http://support.microsoft.com/kb/914387
http://www.intelliadmin.com/blog/2007/01/unofficial-windows-2000-daylight.html
March 01, 2007 8:02
I had ran DST patch(KB931836) for Windows XP sp2 on my m/c and ran the test suggested by Scott.I got the same results.
I was just trying to analyze the same and found that:
I can see two STRINGS under EST in registry
"HKEY_lOCAL_MACHINE\SOFTWARE\MCROSOFT\WINDOWSNT\CURRENTVERSION\TIMEZONES\EASTERN STANDARD TIME\DYNAMICDST" -- 2006 AND 2007.
As per the comments mentioned in blog, DST is year independent.Can somebody explain be the significance of "2006" and "2007" in registry?I persume that for any dates before 2007 will be taken care by "2006" registry entry and any date from 2007 to future will be taken "2007".
Additionally can somebody explain the area of concerns if DST is not considering YEAR for time calculation.
PKS

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.