Martin Staufcik
Martin Staufcik

Reputation: 9492

C# DateTime conversion when time changes from winter to summer time

I am getting this error:

The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid

when I try to convert time 2020-03-29 02:30 from Eastern European Time (GMT+2) to UTC time.

According to this site the clock should change at 03:00 for Finland, which means that time 02:30 should be possible to convert to UTC.

But when I run the following code, an exception is thrown.

var timezoneMap = TimeZoneInfo.GetSystemTimeZones().ToDictionary(x => x.Id, x => x);
var timezoneInfo = timezoneMap["E. Europe Standard Time"]; 

var localTime1 = DateTime.SpecifyKind(new DateTime(2020, 12, 15, 0, 0, 0), DateTimeKind.Unspecified);
var localTime2 = DateTime.SpecifyKind(new DateTime(2020, 3, 29, 2, 30, 0), DateTimeKind.Unspecified);

var utc1 = TimeZoneInfo.ConvertTimeToUtc(localTime1, timezoneInfo); // 2020-12-14 22:00 correct
var utc2 = TimeZoneInfo.ConvertTimeToUtc(localTime2, timezoneInfo); // throws exception

What is wrong with the second conversion, why is there an exception?

Upvotes: 3

Views: 1057

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1503080

The site you're looking at uses the IANA time zone data, which I believe to be accurate.

But your code uses the Windows time zone database, which in this case looks like it has a discrepancy... it seems to think that the transition is at midnight UTC rather than 1am UTC. Here's code to demonstrate that:

using System;
using System.Globalization;

class Program
{
    static void Main()
    {
        var zone = TimeZoneInfo.FindSystemTimeZoneById("E. Europe Standard Time");

        // Start at 2020-03-28T23:00Z - definitely before the transition
        var utc = new DateTime(2020, 3, 28, 23, 0, 0, DateTimeKind.Utc);
        for (int i = 0; i < 8; i++)
        {
            var local = TimeZoneInfo.ConvertTime(utc, zone);
            Console.WriteLine($"{utc:yyyy-MM-dd HH:mm} UTC => {local:yyyy-MM-dd HH:mm} local");
            utc = utc.AddMinutes(30);
        }
    }
}

Output (annotated):

2020-03-28 23:00 UTC => 2020-03-29 01:00 local
2020-03-28 23:30 UTC => 2020-03-29 01:30 local
2020-03-29 00:00 UTC => 2020-03-29 03:00 local  <= Note the change here, at midnight UTC
2020-03-29 00:30 UTC => 2020-03-29 03:30 local
2020-03-29 01:00 UTC => 2020-03-29 04:00 local
2020-03-29 01:30 UTC => 2020-03-29 04:30 local
2020-03-29 02:00 UTC => 2020-03-29 05:00 local
2020-03-29 02:30 UTC => 2020-03-29 05:30 local

The current IANA data definitely does say 1am UTC, as shown in this line of the rules. So I believe the web site is correctly interpreting the data, and it's just a matter of the Windows time zone database being "different" (and, I suspect, incorrect).

Upvotes: 4

Related Questions