C# 为什么';t减去两个本地日期时间值似乎可以解释夏令时?

C# 为什么';t减去两个本地日期时间值似乎可以解释夏令时?,c#,datetime,dst,C#,Datetime,Dst,我正在玩一些C#代码,试图了解在C#中减去DateTime对象如何与夏令时相关 根据谷歌和其他消息来源,2017年东部标准时区的夏时制“春天来临”活动发生在3月12日凌晨2:00。因此,当天的前几个小时是: 12:00am - 1:00am 1:00am - 2:00am (There was no 2:00am - 3:00am hour due to the "spring ahead") 3:00am - 4:00am 因此,如果我要计算当天该时区凌晨1:00

我正在玩一些C#代码,试图了解在C#中减去DateTime对象如何与夏令时相关

根据谷歌和其他消息来源,2017年东部标准时区的夏时制“春天来临”活动发生在3月12日凌晨2:00。因此,当天的前几个小时是:

   12:00am - 1:00am
    1:00am - 2:00am
   (There was no 2:00am - 3:00am hour due to the "spring ahead")
    3:00am - 4:00am
因此,如果我要计算当天该时区凌晨1:00和凌晨4:00之间的时差,我希望结果是2小时

然而,我为模拟这个问题而编写的代码返回了3小时的时间跨度

代码:

在我的电脑上,这会生成:

2017-03-12 01:00:00.000 -5
2017-03-12 04:00:00.000 -4
False
True
03:00:00
所有的输出都和预期的一样——除了3小时的最终值,正如我上面提到的,我希望是2小时


显然,我的代码没有正确模拟我所想的情况。缺陷是什么?

因此在文档中对此进行了说明

基本上,当从一个日期减去另一个日期时,应该使用
DateTimeOffset.Subtract()
,而不是这里的算术减法

TimeSpan difference = fourAm.Subtract(oneAm);

产生预期的2小时时差。

好的,所以我对代码做了一些小改动。不确定这是否是你想要实现的,但这会给你想要的

static void Main() {
        TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        TimeZone timeZone = TimeZone.CurrentTimeZone;

        DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
        DateTime fourAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 04, 00, 00), easternStandardTime);

        DaylightTime time = timeZone.GetDaylightChanges(fourAm.Year);

        TimeSpan difference = ((fourAm - time.Delta) - oneAm);

        Console.WriteLine(oneAm);
        Console.WriteLine(fourAm);
        Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(oneAm));
        Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(fourAm));
        Console.WriteLine(difference);
        Console.ReadLine();
    }
注意:

//这些只是普通的未指定日期时间
DateTime dtOneAm=新的日期时间(2017,03,12,01,00,00);
DateTime dtFourAm=新的日期时间(2017,03,12,04,00,00);
//除了4-1=3之外,差不会做任何事情
时间跨度差1=dtFourAm-dtOneAm;
// ... 但我们有一个时区要考虑!
TimeZoneInfo东部=TimeZoneInfo.FindSystemTimeZoneById(“东部标准时间”);
//使用该时区获取DateTimeOffset值。
//GetUtcOffset方法具有我们需要的功能。
DateTimeOffset dtoOneAmEastern=新的DateTimeOffset(dtOneAm,eastern.GetUtcOffset(dtOneAm));
DateTimeOffset dtoFourAmEastern=新的DateTimeOffset(dtFourAm,eastern.GetUtcOffset(dtFourAm));
//减去这些将考虑偏移量!
//它基本上是这样做的:[4-(-4)]-[1-(-5)]=8-6=2
时间跨度差2=乌拉米斯特恩-乌拉米斯特恩;
//让我们看看结果
WriteLine(“dtOneAm:{0:o}(种类:{1})”,dtOneAm,dtOneAm.Kind;
WriteLine(“dtFourAm:{0:o}(种类:{1})”,dtFourAm,dtOneAm.Kind;
WriteLine(“difference1:{0}”,difference1);
WriteLine(“dtoOneAmEastern:{0:o})”,dtoOneAmEastern);
Console.WriteLine(“dtoFourAmEastern:{0:o})”,dtoFourAmEastern;
WriteLine(“difference2:{0}”,difference2);
结果:

dtOneAm:2017-03-12T01:00:00.0000000(种类:未指定)
dtFourAm:2017-03-12T04:00:00.0000000(种类:未指定)
差异1:03:00:00
东区:2017-03-12T01:00:00.0000000-05:00)
日期:2017-03-12T04:00:00.0000000-04:00)
差异2:02:00:00
请注意,
DateTime
在其
Kind
属性中携带一个
DateTimeKind
,默认情况下该属性为
Unspecified
。它不属于任何特定的时区
DateTimeOffset
没有种类,它有一个
Offset
,它告诉您本地时间与UTC的偏移量有多远。这两个都没有给你时区。这就是
TimeZoneInfo
对象正在做的事情。请参见中的“时区!=偏移”

我认为您可能会感到失望的部分是,由于一些历史原因,
DateTime
对象在进行数学运算时永远无法理解时区,即使您可能有
DateTimeKind.Local
。它本来可以用来观察当地时区的变化,但不是这样做的

您可能还对它感兴趣,它以一种更加明智和有目的的方式为.NET中的日期和时间提供了一个非常不同的API

使用NodaTime;
...
//从局部值开始。
//他们在某地,谁知道在哪里?我们没有说。
LocalDateTime ldtOneAm=新的LocalDateTime(2017,3,12,1,0,0);
LocalDateTime ldtFourAm=新的LocalDateTime(2017,3,12,4,0,0);
//由于LocalDateTime不引用
//线性时间刻度!
//持续时间差=ldtFourAm-ldtOneAm;
//我们可以得到3个小时的周期,但这到底告诉了我们什么?
时段=时段之间(ldtOneAm、ldtFourAm、PeriodUnits.Hours);
//现在让我们来介绍一个时区
DateTimeZone eastern=DateTimeZoneProviders.Tzdb[“美国/纽约”];
//并将区域应用于我们的本地值。
//我们将选择宽容对待DST的差距和重叠。
ZonedDateTime zdtOneAmEastern=ldtOneAm.inZoneleNely(东部);
ZonedDateTime zdtFourAmEastern=ldtFourAm.inZoneleNely(东部);
//现在我们可以得到精确的时间差
持续时间差=zdtFourAmEastern-zdtOneAmEastern;
//转储输出
WriteLine(“ldtOneAm:{0}”,ldtOneAm);
WriteLine(“ldtFourAm:{0}”,ldtFourAm);
WriteLine(“句点:{0}”,句点);
Console.WriteLine(“zdtOneAmEastern:{0}”,zdtOneAmEastern);
WriteLine(“zdtFourAmEastern:{0}”,zdtFourAmEastern);
WriteLine(“差异:{0}”,差异);
ldtOneAm:2017年12月3日凌晨1:00:00
伦敦时间:2017年12月3日上午4:00:00
周期:PT3H
zdtOneAmEastern:2017-03-12T01:00:00美国/纽约(-05)
zdtFourAmEastern:2017-03-12T04:00:00美国/纽约(-04)
差异:0:02:00:00
我们可以看到三个小时的时间,但这并不意味着与过去的时间相同。这仅仅意味着两个本地值在时钟上的位置相隔三小时。NodaTime理解这些概念之间的区别,而.Net的内置类型则不理解

为您提供一些后续阅读:

哦,还有一个ot
static void Main() {
        TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        TimeZone timeZone = TimeZone.CurrentTimeZone;

        DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
        DateTime fourAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 04, 00, 00), easternStandardTime);

        DaylightTime time = timeZone.GetDaylightChanges(fourAm.Year);

        TimeSpan difference = ((fourAm - time.Delta) - oneAm);

        Console.WriteLine(oneAm);
        Console.WriteLine(fourAm);
        Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(oneAm));
        Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(fourAm));
        Console.WriteLine(difference);
        Console.ReadLine();
    }
DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);