首页 > 解决方案 > C#中比较不同时区时间的代码示例

问题描述

任何人都可以解释为什么comparisonTime使用下面的逻辑计算变量,尤其是使用下面的行:

local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1].DaylightDelta;

TimeSpan comparisonTime = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate();

时间跨度结构

 using System;
    
    public struct StoreInfo
    {
       public String store;
       public TimeZoneInfo tz;
       public TimeSpan open;
       public TimeSpan close;
    
       public bool IsOpenNow()
       {
          return IsOpenAt(DateTime.Now.TimeOfDay);
       }
    
       public bool IsOpenAt(TimeSpan time)
       {
          TimeZoneInfo local = TimeZoneInfo.Local;
          TimeSpan offset = TimeZoneInfo.Local.BaseUtcOffset;
    
          // Is the store in the same time zone?
          if (tz.Equals(local)) {
             return time >= open & time <= close;
          }
          else {
             TimeSpan delta = TimeSpan.Zero;
             TimeSpan storeDelta = TimeSpan.Zero;
    
             // Is it daylight saving time in either time zone?
             if (local.IsDaylightSavingTime(DateTime.Now.Date + time))
                delta = local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1].DaylightDelta;
    
             if (tz.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(DateTime.Now.Date + time, local, tz)))
                storeDelta = tz.GetAdjustmentRules()[tz.GetAdjustmentRules().Length - 1].DaylightDelta;
    
             TimeSpan comparisonTime = time + (offset - tz.BaseUtcOffset).Negate() + (delta - storeDelta).Negate();
             return comparisonTime >= open & comparisonTime <= close;
          }
       }
    }

标签: c#.net.net-core

解决方案


TimeZoneInfo.GetAdjustmentRules返回一个对象数组AdjustmentRule,每个对象都标识为夏令时所做的时间调整。这包括开始和结束日期以及时钟调整的时间量以及这些规则何时生效(规则发生变化,例如美国曾经有一个 4 月至 10 月的周期,但现在是 3 月至 11 月)。规则通常按从旧到新排序。

有问题的代码错误地(见下文)找到列表中的最后一条规则(local.GetAdjustmentRules()[local.GetAdjustmentRules().Length - 1])并计算出该规则改变了多少时间(DaylightDelta--在美国这通常是一小时,但世界部分地区可能会调整按其他值(例如 30 分钟)

如果任一/两个区域当前都遵守夏令时,您查询的第二段代码会尝试规范化传递的时间。它通过添加两者的差异DaylightDelta(时钟向前/向后移动的数量)和两者BaseUtcOffset(该区域与 UTC 的非 DST 差异)来实现这一点。然后它将其添加到原始时间并改为使用它进行比较。

代码不正确有几个原因(这可能并不详尽):

  • 它假定调整规则是有序的。MSDN 文档说它们是“一般订购的”,但不做任何保证

  • 它假定最后一个调整规则是当前规则。如上所述,它们没有被订购。但它们也可能包含尚未生效的未来规则

  • 它不考虑接近午夜的时间,并且可能会滚动到第二天。这适用于代码的两个分支。虽然商店可能不太可能在午夜后营业,但这是绝对可能的(我不知道您的业务规则)。如果商店从早上 8 点营业到凌晨 2 点,测试将在凌晨 1 点失败,而该测试应该成功

  • 同样,对于营业时间超过午夜的商店,如果时间落在 DST 边界,则夏令时计算可能会更加不准确

  • TimeZoneInfo.Local可以通过系统设置进行操作。事实上,取决于是否在控制面板中检查了“自动调整夏令时”,本地时区信息总是可以返回falseIsDaylightSavingslocal.GetAdjustmentRules. 这意味着在两台计算机上运行的相同代码可能会返回不同的结果,即使它们彼此相邻!

  • 它假定系统是最新的。根据您在世界的哪个位置,夏令时规则可能会经常更改。在这种情况下,操作系统通常不包含所有最新信息。

处理时区和夏令时很困难。规则一直在变化,框架中的工具非常笨重且难以使用(假设您可以理解它们)。更糟糕的是,它们并不总是最新的!

我不会尝试为您提供固定代码。我倾向于将与时间和夏令时计算相关的任何事情留给专家。我强烈建议查看NodaTime库以进行此类计算。它完全专注于主题,时区规则会定期更新。他们的我们为什么存在页面调用了我上面提到的一些事情,正如图书馆的一位作者 Jon Skeet 所写的这篇博客文章一样。


推荐阅读