什么是“转型期的来源时间”。异常来自TZ4NET .NET时区库

时间:2013-10-30 16:04:35

标签: c# timezone tz4net

我正在使用TZ4Net库 http://www.babiej.demon.nl/Tz4Net/main.htm 为了在ASP.NET中使用准确的时区

我最近开始获得“过渡时期的来源时间。”

从代码的这一部分

static DateTime Convert(DateTime srcTime, string srcName, string dstName)
{
  if (OlsonTimeZone.LookupName(srcName) == null)
{
  throw new ArgumentException("Unknown source timezone name.");
}
if (OlsonTimeZone.LookupName(dstName) == null)
{
  throw new ArgumentException("Unknown destintation timezone name.");
}
OlsonTimeZone srcZone = OlsonTimeZone.GetInstance(srcName);
TimeCheckResult srcCheckRes = srcZone.CheckLocalTime(srcTime);
switch (srcCheckRes)
{
case TimeCheckResult.Valid :
{
  OlsonTimeZone dstZone = OlsonTimeZone.GetInstance(dstName);
  DateTime dstTime = dstZone.ToLocalTime(srcZone.ToUniversalTime(srcTime));
  return dstTime;
}
case TimeCheckResult.InSpringForwardGap :
case TimeCheckResult.InFallBackRange :
{
  throw new ArgumentException("Source time in transition period."); // THIS PART HERE
}
default :
{
  throw new ArgumentException("Source time out of range.");
}
}
}

什么是TimeCheckResult.InFallBackRange以及如何处理此类错误?

3 个答案:

答案 0 :(得分:1)

术语“Spring Forward”和“Fall Back”是指夏令时的变化。您可以在the DST tag wiki中阅读更多内容。

在“春季前进”过渡期间,存在当地时间不存在的间隙值。例如,在美国,大多数时区从3月的第二个星期日的1:59:59跳到3:00:00。因此,2:00:00的时间将无效,因为它在差距中。

在“后退”过渡期间,当地时间内存在两次的一系列值。例如,在美国,大多数时区从11月59日59:00回到11月的第一个星期日的1:00:00。因此,1:00:00的时间存在两次,因此它可以引用的两个时刻中的哪一个是模棱两可的。

当你尝试从过渡期的当地时间转换时,你应该做什么:

  • 对于落入“春季前进”过渡所造成的差距的时间,这根本不是一个有效的时间。

    • 您可能应该向用户显示错误消息,以便他们输入有效时间。

    • 或者,如果您想假设他们忘记调整DST,您可能希望将时间提前一个保存金额(通常为1小时)。这通常用于每天重复的事件。

  • 由于它属于“后退”过渡而导致模糊不清的时间,您需要确定实际想要使用的两种可能性中的哪一种。

    • 在许多情况下,您应该提示您的用户选择这两个选项,以便他们决定。问一个问题,“您的意思是美国东部时间下午1点(-0400)还是美国东部时间1点(-0500)?”

    • 有时您会想要挑选它们。您可以根据需要选择第一次出现或第二次出现。

TZ4Net是一个很棒的图书馆,作者(Zbigniew Babiej)多年来一直很友善。但它最初是在.NET 2.0时编写的,因此它不处理DateTimeOffset值。它也不考虑使用的任何.Kind值的DateTime属性。尽管在{。} 2.0中引入了DateTimeKind,但它似乎并没有被纳入TZ4Net。因此,您必须非常小心,以正确的值提供其功能。

如果您想继续使用Olson时区,可以继续使用TZ4Net,但我也建议您尝试使用Noda Time。它是一个社区开发的开源项目(而不是单个作者),其主要开发人员是Jon Skeet。您对DST转换也会有同样的疑虑,但Noda Time的API会强制您先处理这些问题,而不是在部署应用程序后找出答案。

如果您只想保留今天所拥有的内容,可以按照以下方式修改上述功能以处理后退过渡:

  • 假设第一个(日光)实例:

    case TimeCheckResult.InFallBackRange:
    {
        OlsonTimeZone dstZone = OlsonTimeZone.GetInstance(dstName);
        DateTime dstTime = dstZone.ToLocalTime(srcZone.ToUniversalTime(srcTime.AddHours(-1)).AddHours(1));
        return dstTime;
    }
    
  • 假设第二个(标准)实例:

    case TimeCheckResult.InFallBackRange:
    {
        OlsonTimeZone dstZone = OlsonTimeZone.GetInstance(dstName);
        DateTime dstTime = dstZone.ToLocalTime(srcZone.ToUniversalTime(srcTime.AddHours(1)).AddHours(-1));
        return dstTime;
    }
    

对于Spring Forward过渡:

  • 你应该保留这个:

    case TimeCheckResult.InSpringForwardGap:
        throw new ArgumentException("Source time in transition period.");
    
  • 但是如果你想假设用户只是忘了推进他们的时钟,你可以这样做以在转换中推进它:

    case TimeCheckResult.InSpringForwardGap:
    {
        OlsonTimeZone dstZone = OlsonTimeZone.GetInstance(dstName);
        DateTime dstTime = dstZone.ToLocalTime(srcZone.ToUniversalTime(srcTime.AddHours(1)));
        return dstTime;
    }
    

答案 1 :(得分:0)

case TimeCheckResult.InSpringForwardGap :
case TimeCheckResult.InFallBackRange :

表示时钟在您尝试计算的时间段内向前或向后移动。可能没有定义如何在不同的时间段内处理这个问题。它每年只发生两次;)。处理它实际上取决于你计算时区差异的原因。

答案 2 :(得分:0)

TZ4NET作者的回应

嗨马修,

这意味着11/3/2013 1:26:00在源时区中是一个模糊的时间。例如,在2013年3月13日02:00在America / New_York,时间将被设置回01:00。这意味着时间01:26将在当天发生两次,因此在转换期间,您不清楚是否引用第一次出现或第二次出现,因为它们将对应于不同的UTC时间。 我认为最好是检测到这一点,并要求用户详细说明他/她所指的时间。如果这不是交互式过程,最简单的方法是检测它并将源时间加1小时,然后从目标时间减去1小时。

我希望这能回答你的问题, 问候, ZB