使用TimeZoneInfo类来考虑夏令时时间更改。

3

我有一些过时的代码,试图考虑夏令时引起的时间变化,看起来像这样:

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();
        }
    }
}

这段代码迭代了1960年3月和4月中的每一天,并打印出日期时间。然而,由于1960年的夏令时日期不同,所以这并没有正确地计算出时间变化。为了解决这个问题,我尝试使用TimeZoneInfo类进行修复。我将代码修改为以下内容:

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();
        }
    }
很不幸,打印出来的是: enter image description here

这显示夏令时将于4月3日下午4点更改,而应该在4月24日凌晨2:00切换。 我漏掉了哪些内容以正确考虑夏令时? 编辑: 我的当前时区是东部。

3
不知道你指的是哪个时区,所以很难回答。此外,请记住,Windows 对时区的定义并不总是与 TZDB(例如)相同。 - Jon Skeet
我的时区是东部,但这会影响1960年夏令时的应用日期吗? - Christian
1
@Christian,是的,夏令时规则因时区而异。甚至有一些时区的规则是没有规则,只是任意选择的日期。 - Alexei Levenkov
抱歉,问题出在夏令时而不是时区上,我已经修改了含糊不清的措辞。 - Christian
@Christian:夏令时是时区的一部分,这就是问题所在。我认为即使是“东部”也是含糊不清的,因为不同的地方改变时间的时间是不同的。你的TimeZoneInfo ID是什么? - Jon Skeet
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

看起来Windows的时区信息与我通过TZDB预期的不符。这里有一个使用Noda Time编写的程序,显示了1960年至1965年之间使用BCL TimeZoneInfo(封装)和TZDB 2012i数据的所有转换:

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();
    }
}

输出:

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

还有其他时区ID与“Eastern Standard Time”相对应,但我没有找到任何与Windows行为匹配的。

我不认为这是TimeZoneInfo的bug - 我认为这是潜在的Windows时区数据问题。

如果您想匹配TZDB数据,当然可以使用Noda Time :)


DateTimeZoneProviders.Tzdb["America/New York"] 对我来说不存在(抛出异常;实际上在您的输出中有“America/Toronto”),但是是否有一个将城市映射到适当时区的列表? - Paul Westcott
实际上,“America/New_York”带有下划线是存在的,但是是否有某个列表呢?比如将“拉斯维加斯”映射到它所在的时区... - Paul Westcott
@PaulWestcott:已修正,谢谢。对于映射列表,我恐怕不了解有哪些好的选择。 - Jon Skeet

1

有一个dt.IsDaylightSavingTime()。对于我来说,它在1960年的4/4更改(比你晚一天),但我是CST。对于2012年,我的系统是正确的。这可能是一个错误。它可能只是那一年或所有年份直到X。

我认为这解释了:

夏令时

“在20世纪60年代初,夏令时的观察非常不一致,时间观察杂乱无章,没有关于何时更改时钟的协议。”

“1966年的统一时间法案在美国全境内建立了一个统一的(每个时区内)夏令时系统。”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,