Christian
Christian

Reputation: 1735

Use TimeZoneInfo class to account for time change in daylight savings time

I have some outdated code that attempts to account for the change in time caused by daylight savings that looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 31; i++)
            {
                DateTime dt = new DateTime(1960, 3, i, 0, 0, 0);
                Console.WriteLine(dt.ToUniversalTime());
            }

            Console.WriteLine();

            for (int i = 1; i <= 30; i++)
            {
                DateTime dt = new DateTime(1960, 4, i, 0, 0, 0);
                Console.WriteLine(dt.ToUniversalTime());
            }

            Console.ReadKey();
        }
    }
}

This code iterates through the days in March and April in 1960 and prints the datetime. However, this does not correctly account for the time change in 1960, I believe because the date of the time change was different then. I attempted to fix this using the TimeZoneInfo class. I changed the code to the following:

class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 31; i++)
            {
                DateTime dt = new DateTime(1960, 3, i, 0, 0, 0);
                var tz = TimeZoneInfo.Local;
                var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
                //use timeZoneInfo class to account for dlst offset
                Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));
            }

            Console.WriteLine();

            for (int i = 1; i <= 30; i++)
            {
                DateTime dt = new DateTime(1960, 4, i, 0, 0, 0);
                var tz = TimeZoneInfo.Local;
                var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
                //use timeZoneInfo class to account for dlst offset
                Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));

            }

            Console.ReadKey();
        }
    }

Unfortunately, this is printing out: enter image description here

which shows that daylight savings is changing on April 3rd at 4 p.m., while it should be switching over at April 24th at 2:00 a.m. What am I missing to correctly account for daylight savings?

EDIT: My current time zone is eastern.

Upvotes: 3

Views: 1652

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1500505

It looks like the Windows time zone information doesn't match what I'd have expected via TZDB. Here's a program using Noda Time to show all the transitions between ~1960 and 1965 with both the BCL TimeZoneInfo (wrapped) and the TZDB 2012i data:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        var bcl = DateTimeZoneProviders.Bcl["Eastern Standard Time"];
        var tzdb = DateTimeZoneProviders.Tzdb["America/New_York"];

        ShowTransitions(bcl);
        ShowTransitions(tzdb);
    }

    static void ShowTransitions(DateTimeZone zone)
    {
        Console.WriteLine("Transitions for {0}", zone.Id);
        Instant start = Instant.FromUtc(1960, 1, 1, 0, 0);
        Instant end = Instant.FromUtc(1965, 1, 1, 0, 0);
        var interval = zone.GetZoneInterval(start);
        while (interval.Start < end)
        {
            Console.WriteLine(interval.Start);
            interval = zone.GetZoneInterval(interval.End);
        }
        Console.WriteLine();
    }
}

Output:

Transitions for Eastern Standard Time
1959-10-25T06:00:00Z
1960-04-03T07:00:00Z
1960-10-30T06:00:00Z
1961-04-02T07:00:00Z
1961-10-29T06:00:00Z
1962-04-01T07:00:00Z
1962-10-28T06:00:00Z
1963-04-07T07:00:00Z
1963-10-27T06:00:00Z
1964-04-05T07:00:00Z
1964-10-25T06:00:00Z

Transitions for America/Toronto
1959-10-25T06:00:00Z
1960-04-24T07:00:00Z
1960-10-30T06:00:00Z
1961-04-30T07:00:00Z
1961-10-29T06:00:00Z
1962-04-29T07:00:00Z
1962-10-28T06:00:00Z
1963-04-28T07:00:00Z
1963-10-27T06:00:00Z
1964-04-26T07:00:00Z
1964-10-25T06:00:00Z

There are other time zone IDs which map to "Eastern Standard Time", but I haven't found any which match the Windows behaviour.

I don't think this is a TimeZoneInfo bug - I believe it's a potential problem in the underlying Windows time zone data.

If you want to match TZDB data, of course, you can just use Noda Time :)

Upvotes: 2

paparazzo
paparazzo

Reputation: 45096

There is a dt.IsDaylightSavingTime(). And it changes on 4/4 for me (one day later than yours) in 1960 but I am CST. For 2012 it is correct on my system. It may be a bug. It may just be that year or all years up to X.

I think this explains it:

Daylight Saving Time

"In the early 1960s, observance of Daylight Saving Time was quite inconsistent, with a hodgepodge of time observances, and no agreement about when to change clocks."

"The Uniform Time Act of 1966 established a system of uniform (within each time zone) Daylight Saving Time throughout the U.S."

Upvotes: 1

Related Questions