我正在使用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以及如何处理此类错误?
答案 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