Time Zone Mayhem

2009 June 17
by Craig Sutherland

We just resolved an interesting problem tonight with some unit tests in CruiseControl.NET. But before I get to the resolution, here is some background.

We have a number of developers around the world. For example, I live in New Zealand, which is UTC+12. Some of the other developers live in Europe, which is UTC+1 (although it is currently UTC+2 due to daylight savings). And just to confuse things, our build server – CCNetLive – is in Chicago, Illinois, UTC-5 currently.

One of the developers had written some unit tests that was checking some date/time comparisons in the underlying code. When he tested it on his machine, it worked beautifully – no problems whatsoever. Same for my machine, but CCNetLive was failing the test!

So, what was happening?

The code was parsing a date/time in a string and then checking to see if it was in a valid date/time range. The string included the time zone (2009-06-13 10:37:42 +0000), which was UTC+0.

Since the time zone was UTC+0, he generated a date using a UTC date/time kind – new DateTime(2009, 06, 13, 10, 00, 00, DateTimeKind.Utc). This date was the lower bound, while the upper bound was DateTime.Now.

Here is where things got interesting – he assumed, and I did also, that since the string contained the time zone that it would be a UTC date/time. Therefore, the UTC date/time would work nicely. And it did – on any machine that was ahead of UTC. On CCNetLive, which was behind UTC, it was failing!!!

Why?

DateTime.Parse generates a Local date/time, no matter what the incoming string has. If the string contains the time zone, it uses this to generate a date/time and then moves it to the local date/time. So, the string that was being parsed was being converted to 5:36:42am, instead of 10:36:42am. This was then being compared to 10:00:00am and naturally failing.

This is where it got us – the 10:00:00am date/time was UTC, and the 5:36:42am was Local. Shouldn’t the .NET date/times automatically convert to the same type in order to perform the comparison?

It turns out, they don’t. They just literally compare the date and time components, without taking into consideration the different date kinds.

So, I don’t know whether this is a bug or an oversight (or even deliberate), but it is worth while making sure you are comparing the same date/time kinds when doing a date/time comparison. Otherwise, like us, you’ll end up wondering why things aren’t working in different places around the world.

So what was the resolution to our issue – we converted the UTC date/time to a local date/time using .ToLocal(). After this, the test worked beautifully!

3 Responses leave one →
  1. 2009 June 27
    Daniel Irvine permalink

    Hi Craig, just found our blog – great to read about the internals of CCNet!

    I’m not sure that this will completely solve your problem, but .NET 3.5 introduced the new DateTimeOffset type (http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx) which was designed to handle UTC times. Though I guess that only helps if you’re already building on .NET 3.5…

    • 2009 June 27
      Craig Sutherland permalink

      Thanks Daniel,

      It’s good to know about this – unfortunately as you mentioned we need .NET 3.5 – CruiseControl.NET is still .NET 2.0 :-(

      Craig

  2. 2009 June 18
    Daniel Hommel permalink

    I had the same problem with the CVS sourcecontrol… We should all use UTC or something. :-D

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS