I was writing tests in Swift for a time parsing function, and on the way to getting it right, I saw some very confusing error output, as per the screenshot above. In that screenshot I’ve deliberately broken the test (the times don’t match) to invoke the red error text, but what’s interesting is that the error reports 04:02:15 and 04:03:15 instead of the times I actually used – 04:01 and 04:02 respectively.
When you’re testing time-parsing code, the last thing you want is the test failures giving confusing/misleading figures so I had to get to the bottom of it.
It turns out that GMT and “Europe/London” timezones diverge through history (ignoring daylight savings). In fact, in the year 0 AD they were one minute and fifteen seconds different, and it’s this discrepancy that was showing up in my tests. Note that it doesn’t affect the test results themselves – only the display of NSDate values when there’s a test failure.
I was constructing test times from NSDateComponents and only specifying day, hour and minute, as that was all that was relevant to the tests. However that left the year defaulting to zero. I was also specifying timezone as NSTimeZone(name: “Europe/London”). The error messages from XCode only have an NSDate to work with however, which doesn’t have any notion of timezone, so XCode used UTC/GMT to format for display. And being year zero dates, the time comes out differently. The simple fix for me was to set the year in the NSDateComponents to 2015 to get everything into line.
What would happen if I ran the tests in the summer, when daylight savings is in the effect here in the UK? I’m not sure, but I might end up with times an hour out, for the same reason.
Here’s some code you can dump into a playground to demonstrate. The results are even weirder if you use “Europe/Paris” as the timezone, giving “”0001-01-01 10:35:39 +0000” as the output, just nine minutes and twenty-one seconds earlier, rather than the whole hour earlier that one might expect (and that you get if you use 2015).
// Demonstrate GMT/UTC != "Europe/London" in year zero. let ukTimeZone = NSTimeZone(name: "Europe/London")! let ukCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) ukCalendar?.timeZone = ukTimeZone
let dateComponents = NSDateComponents() // Reinstate this to fix things. //dateComponents.year = 2015 dateComponents.hour = 10 dateComponents.minute = 45 dateComponents.timeZone = ukTimeZone
let date = ukCalendar?.dateFromComponents(dateComponents) date?.debugDescription // "0001-01-01 10:46:15 +0000"