当前位置: 首页 > 知识库问答 >
问题:

为什么减去两个本地DateTime值似乎不考虑夏时制?

伏建修
2023-03-14

我正在使用一些C#代码,试图了解C#中减去DateTime对象是如何与夏时制相关联的。

根据谷歌和其他消息来源,2017年东部标准时区的夏令时“Spring来临”活动是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个小时。

TimeZoneInfo easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

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

TimeSpan difference = (fourAm - oneAm);

Console.WriteLine(oneAm);
Console.WriteLine(fourAm);
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(oneAm));
Console.WriteLine(TimeZoneInfo.Local.IsDaylightSavingTime(fourAm));
Console.WriteLine(difference);

在我的PC上,这将生成:

2017-03-12 01:00:00.000 -5
2017-03-12 04:00:00.000 -4
False
True
03:00:00

所有的输出都和预期的一样--除了3小时的最终值,正如我上面提到的,我希望改为2小时。

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

共有1个答案

景震博
2023-03-14

观察:

// These are just plain unspecified DateTimes
DateTime dtOneAm = new DateTime(2017, 03, 12, 01, 00, 00);
DateTime dtFourAm = new DateTime(2017, 03, 12, 04, 00, 00);

// The difference is not going to do anything other than 4-1=3
TimeSpan difference1 = dtFourAm - dtOneAm;

// ... but we have a time zone to consider!
TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

// Use that time zone to get DateTimeOffset values.
// The GetUtcOffset method has what we need.
DateTimeOffset dtoOneAmEastern = new DateTimeOffset(dtOneAm, eastern.GetUtcOffset(dtOneAm));
DateTimeOffset dtoFourAmEastern = new DateTimeOffset(dtFourAm, eastern.GetUtcOffset(dtFourAm));

// Subtracting these will take the offset into account!
// It essentially does this: [4-(-4)]-[1-(-5)] = 8-6 = 2
TimeSpan difference2 = dtoFourAmEastern - dtoOneAmEastern;

// Let's see the results
Console.WriteLine("dtOneAm: {0:o} (Kind: {1})", dtOneAm, dtOneAm.Kind);
Console.WriteLine("dtFourAm: {0:o} (Kind: {1})", dtFourAm, dtOneAm.Kind);
Console.WriteLine("difference1: {0}", difference1);

Console.WriteLine("dtoOneAmEastern: {0:o})", dtoOneAmEastern);
Console.WriteLine("dtoFourAmEastern: {0:o})", dtoFourAmEastern);
Console.WriteLine("difference2: {0}", difference2);

结果:

dtOneAm: 2017-03-12T01:00:00.0000000 (Kind: Unspecified)
dtFourAm: 2017-03-12T04:00:00.0000000 (Kind: Unspecified)
difference1: 03:00:00

dtoOneAmEastern: 2017-03-12T01:00:00.0000000-05:00)
dtoFourAmEastern: 2017-03-12T04:00:00.0000000-04:00)
difference2: 02:00:00

请注意,datetime在其kind属性中携带datetimekind,默认情况下为unspecifiated。它不属于任何特定的时区。DateTimeOffset没有类型,它有offset,它告诉您本地时间与UTC的偏移程度。这两个都没有给你时区。这就是TimeZoneInfo对象正在做的事情。请参阅时区标签维基中的“时区!=偏移量”。

using NodaTime;

...

// Start with just the local values.
// They are local to *somewhere*, who knows where?  We didn't say.
LocalDateTime ldtOneAm = new LocalDateTime(2017, 3, 12, 1, 0, 0);
LocalDateTime ldtFourAm = new LocalDateTime(2017, 3, 12, 4, 0, 0);

// The following won't compile, because LocalDateTime does not reference
// a linear time scale!
// Duration difference = ldtFourAm - ldtOneAm;

// We can get the 3 hour period, but what does that really tell us?
Period period = Period.Between(ldtOneAm, ldtFourAm, PeriodUnits.Hours);

// But now lets introduce a time zone
DateTimeZone eastern = DateTimeZoneProviders.Tzdb["America/New_York"];

// And apply the zone to our local values.
// We'll choose to be lenient about DST gaps & overlaps.
ZonedDateTime zdtOneAmEastern = ldtOneAm.InZoneLeniently(eastern);
ZonedDateTime zdtFourAmEastern = ldtFourAm.InZoneLeniently(eastern);

// Now we can get the difference as an exact elapsed amount of time
Duration difference = zdtFourAmEastern - zdtOneAmEastern;


// Dump the output
Console.WriteLine("ldtOneAm: {0}", ldtOneAm);
Console.WriteLine("ldtFourAm: {0}", ldtFourAm);
Console.WriteLine("period: {0}", period);

Console.WriteLine("zdtOneAmEastern: {0}", zdtOneAmEastern);
Console.WriteLine("zdtFourAmEastern: {0}", zdtFourAmEastern);
Console.WriteLine("difference: {0}", difference);
ldtOneAm: 3/12/2017 1:00:00 AM
ldtFourAm: 3/12/2017 4:00:00 AM
period: PT3H

zdtOneAmEastern: 2017-03-12T01:00:00 America/New_York (-05)
zdtFourAmEastern: 2017-03-12T04:00:00 America/New_York (-04)
difference: 0:02:00:00
    null
DateTime oneAm = TimeZoneInfo.ConvertTime(new DateTime(2017, 03, 12, 01, 00, 00), easternStandardTime);
 类似资料:
  • 有没有一个时区,我可以使用,以考虑到夏令时?我知道'EDT'是指夏令时,而'EST'不是。是否有一个时区我可以使用,将自动检测日期时间是否是夏令时?“ET”或“America/New_York”能行吗? 编辑:: 抱歉应该更清楚。我想取一个日期并将其转换为东部时区,但我希望它考虑到东部时区的日期是否为夏令时。

  • 问题内容: 我正在使用以下查询: 令人惊讶的是,该语句不包含错误值为NULL的行。我的意图是仅筛选错误值为连接错误’‘的行。我需要提供其他条件(或错误为NULL)以检索正确的结果。 为什么MYSQL会滤除带有NULL值的结果?我以为IN关键字会返回一个布尔结果(1/0),现在我知道某些MYSQL关键字不返回布尔值,它也可能会返回NULL ....但是为什么将NULL当作特殊值呢? 问题答案: 这个

  • 问题内容: 我的活动课在这里: 和相机预览类在这里: 但是,当我测试该类时,似乎首先调用onResume(),然后在1或2秒后再次调用。因此,相机必须再次刷新。如果我根本没有onResume(),则摄像头预览稳定,但是如果我从主屏幕或其他某个应用再次切换到该应用,则会崩溃。我发现onPause()不会影响任何一个。我的代码正确吗?我应该添加/删除哪些内容以使其不会再次刷新并且在应用切换后仍然不会崩

  • 问题内容: 我正在使用JDBC连接到MySQL服务器(我认为没有连接池)。在连接网址中,我有 但是我的连接仍然超时。我什至检查了它的错误。但是,当我尝试使用连接时,出现以下异常。 我知道在Java 1.6中可以使用它来检查连接,但是我正在使用Java 1.5 有没有办法确保它不会超时?还是我必须升级到Java 1.6? 问题答案: 我有同样的问题,这绝对令人发疯。这是文档在MySQL网站上的内容(

  • 问题内容: 为什么联接不好或“慢”。我知道我再听一次。我找到了这句话 问题在于联接相对较慢,尤其是在非常大的数据集上,如果联接较慢,则您的网站也很慢。从磁盘上获取所有这些单独的信​​息位并再次将它们重新组合在一起需要花费很长时间。 来源 我一直以为他们很快,尤其是在查找PK时。他们为什么“慢”? 问题答案: 可伸缩性是关于预计算(缓存),扩展或将重复的工作缩减为基本要件的全部目的,以最大程度地减少

  • 我在用 使用G1垃圾收集器。JVM参数是 然而,我在没有任何明显原因的情况下经历了完整的GC扫描,如何摆脱它们? GC日志,带有前面事件的一些尾部: 其他类似的: 其他类似问题报告: http://grokbase.com/t/openjdk/hotspot-gc-use/1192sy84j5/g1c-strange-full-gc-behaviorhttp://grokbase.com/p/op