C# C中比较不同时区时间的代码示例#

C# C中比较不同时区时间的代码示例#,c#,.net,.net-core,C#,.net,.net Core,有人能解释一下为什么使用如下逻辑计算comparisonTime变量,尤其是使用以下行: local.GetAdjustmentRules()[local.GetAdjustmentRules().Length-1].DaylightDelta 及 TimeSpan comparisonTime=time+(offset-tz.BaseUtcOffset).Negate()+(delta-storeDelta.Negate() 使用系统; 公共结构存储信息 { 公共字符串存储; 公共时区信息;

有人能解释一下为什么使用如下逻辑计算
comparisonTime
变量,尤其是使用以下行:

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

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

使用系统;
公共结构存储信息
{
公共字符串存储;
公共时区信息;
公共时间跨度开放;
公共时间间隔关闭;
公共图书馆
{
返回IsOpenAt(DateTime.Now.TimeOfDay);
}
公共bool IsOpenAt(时间跨度时间)
{
TimeZoneInfo local=TimeZoneInfo.local;
TimeSpan offset=TimeZoneInfo.Local.BaseUtcOffset;
//这家商店在同一时区吗?
如果(tz等于(局部)){
return time>=open&time=open&comparisonTime返回一个对象数组,每个对象标识夏令时的时间调整。这包括开始和结束日期以及时钟调整的时间量以及这些规则何时生效(例如,规则改变了,美国过去的周期是4月到10月,现在是3月到11月)。规则通常按最早到最新的顺序排列

相关代码错误地(请参见下文)查找列表中的最后一条规则(
local.GetAdjustmentRules()[local.GetAdjustmentRules().Length-1]
),并计算出该规则更改了多少时间(
DaylightDelta
——在美国,这通常是一小时,但世界部分地区可能会根据其他值(如30分钟)进行调整)

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

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

  • 它假设调整规则是订购的。MSDN文档称它们是“一般订购的”,但不作任何保证

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

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

  • 类似地,对于一家时间超过午夜的商店,如果时间落在DST边界,则夏令时计算可能更加不准确

  • TimeZoneInfo.Local
    可以通过系统设置进行操作。事实上,这取决于是否“自动调整夏令时”在控制面板中选中时,本地时区信息始终可以为
    isDaylightSaves
    返回
    false
    ,为
    local.GetAdjustmentRules
    返回零长度数组。这意味着即使两台计算机并排运行,在两台计算机上运行的相同代码也可能返回不同的结果

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

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


我不会试图给你提供固定的代码。我倾向于把任何与时间和DST计算有关的东西留给专家。我强烈建议你去图书馆找类似的计算。它完全是关于主题的,时区规则也会定期更新。他们的页面会列出一些我认为正如库作者Jon Skeet所写的那样。

以防万一,您是否尝试过使用DateTimeOffset?它是一种除了日期+时间信息之外还包含时区的类型。因此它通常可以为您完成大部分工作。@Arcord这是不正确的。它包含的偏移量与时区类似实际上完全不同。OP:假设这不是唯一一个有这种逻辑的地方,我建议不要使用任何内置的.NET时区/翻译实用程序,而是使用类似nodatime的工具。(事实上,考虑到时区计算很容易出错,尤其是在.NET中,我甚至可能会主张只使用一次Nodatime)稍后你会为此感谢你自己的。你说得对。但是你可以从时区提取偏移量?还要注意,
TimeZoneInfo.Local
可以通过系统设置进行操作。事实上,这取决于是否“自动调整夏令时”如果在控制面板中选中,则本地时区信息对于
isDaylightSaves
总是会返回
false
,对于
local.GetAdjustmentRules
则会返回零长度数组。因此,除非您完全控制了系统,否则我建议您在使用上述信息时要小心(并再次建议使用第三方库)@pinkfloydx33请您推荐一个第三方库好吗?
 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;
          }
       }
    }