I noticed something odd when trying to determine if a given datetimeoffset occurred on the beginning or end of a timezoneadjustment (daylight savings). And I'm not sure if I'm going about this the wrong way or not.
Take the following code for example:
class Program
{
static void Main(string[] args)
{
// Note: this is done on a swedish computer.
int year = 2015;
DateTimeOffset dateTimeJustBeforeOffsetChanges = new DateTime(year, 10, 25, 1, 59, 59);
DateTimeOffset dateTimeRightWhenOffsetChanges = new DateTime(year, 10, 25, 2, 0, 0); // 2015-10-25 02:00:00. This is how we set our offset. We let the implicit conversion do all the work :)
var daylightSavings = TimeZone.CurrentTimeZone.GetDaylightChanges(year);
Console.WriteLine(dateTimeJustBeforeOffsetChanges); // Prints out 2015-10-25 01:59:59 +02:00
Console.WriteLine(dateTimeRightWhenOffsetChanges); // Prints out 2015-10-25 02:00:00 +01:00 This is the exact time when the datetimeoffset starts using offset +02 instead of +01
Console.WriteLine(daylightSavings.End.ToString()); // Prints out 2015-10-25 03:00:00
Console.ReadLine();
}
}
As you can see from the above code, the offset changes from +1 hour to +2 hours on October 25:th at 2 o'clock in the morning when using the implicit conversion from a datetime to a datetimeoffset. However, when analyzing the current daylightsavings with the GetDaylightChanges method whe are told that the change should occur at 3 o'clock on October 25:th.
In my head the offset should change to +2 at 3 o'clock, not 2 o'clock, or am I wrong?
PS: This code is run on a Swedish machine with Swedish timezonesettings.
Firstly, GetDaylightChanges
is accurate - the clocks did go back in Sweden at 3am local time.
Secondly, that doesn't mean that you've shown a bug anywhere in the BCL. The problem is simply that 02:00:00 occurs twice - once before the clocks go back, and once after. In other words, it occurs at 2015-10-25 02:00:00 +02:00 and 2015-10-25 02:00:00 +01:00. How do you expect the implicit conversion to tell which one you meant? Both are valid results, and it happens to be picking the later one, although that behaviour is unfortunately unspecified, at least in both the implicit conversion documentation and the DateTimeOffset
constructor documentation.
This sort of thing is why in my Noda Time library, when you map from a LocalDateTime
to a ZonedDateTime
(by applying a time zone) you have to say what you want to happen if the value is ambiguous or skipped - so in this case, you could choose for it to resolve to either the later or the earlier occurrence of 2015-10-25 02:00:00.
Basically this is something you should think about, and decide how you want your application to behave... then you should specify the behaviour you want, using whatever API you're using. That's easier in some APIs than in others :)
See more on this question at Stackoverflow