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

时区和夏令时节省。NET往返服务器

茹航
2023-03-14

我们在应用程序中遇到了一个问题,即在特定时区的特定日期中,在从服务器到客户端然后从客户端到服务器的往返过程中,没有保留DateTime的值。这是在巴西利亚时区(“南美洲标准时间”)中观察到的,并且DateTime值为“1984-11-04 00:00:00”。

我用以下代码重现了这个问题:

DateTime d = new DateTime(1984, 11, 4, 0, 0, 0, DateTimeKind.Local);
var dUtc = d.ToUniversalTime();
var dRtLocal = dUtc.ToLocalTime();

dUTC的最终值为“1984-11-04 03:00:00”(正确),dRtLocal为“1984-11-04 01:00:00”(不太正确)。

我发现,虽然巴西的夏时制始于1985年,但Windows对从0001-01-01到2006-12-31的日期有相同的规则,根据这一规则,夏季时间将从这个确切的日期(1984-11-04 00:00:00)开始,将时钟向前移动1小时。

除了这个时区的DST规则是错误的之外,我还发现了其他一些奇怪的行为,以及来自timezone和TimeZoneInfo类(GetUtcOffset、Isambiguustime、IsInvalidTime)的方法的不一致的结果。

例如(我的电脑的当前时区设置为“E.南美标准时间”):

    TimeZone.CurrentTimeZone.GetUtcOffset(new DateTime(1984,11,03,23,00,00, DateTimeKind.Local))
    returns -02:00

    TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time").GetUtcOffset(new DateTime(1984,11,03,23,00,00, DateTimeKind.Local)) 
    returns -03:00

在第一种情况下,它似乎正在使用当年的DST规则,并将其应用于1984年(2015年夏季时间将从2015年10月18日开始)。第二个似乎是在Windows中为这个时区应用DST规则。

除了在UTC中使用和存储所有日期之外,还有什么解决方法可以避免这些问题吗?. NET将DST规则应用于过去的日期,其中DST规则与当前年份的不同?

更新@matt johnson answer之后我做了更多测试,发现更多与无效日期时间相关的不一致行为。正如马特指出的,这个日期是无效的(根据windows规则)。但是,如果运行:

var isInvalid = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time").IsInvalidTime(new DateTime(1984, 11, 4, 0, 0, 0, DateTimeKind.Local))

结果为false,即使Windows DST规则应被视为无效。但如果运行:

var isInvalid2 = TimeZoneInfo.Local.IsInvalidTime(new DateTime(1984, 11, 4, 0, 0, 0, DateTimeKind.Local))

结果现在是真的。请注意,我当前的时区是“E.南美标准时间”(TimeZoneInfo.FindSystemTimeZoneById(“E.南美标准时间”)。StandardName==TimeZoneInfo。地方的标准名称是正确的)。

正在尝试使用TimeZoneInfo将日期时间转换为UTC。ConvertTimeToUtc抛出了Matt指出的异常

共有1个答案

厍浩广
2023-03-14

您在时区类中发现的行为(使用当前规则,而不是正确的适用规则)在MSDN上有很好的记录:

时区类仅支持本地时区的单一夏令时调整规则。因此,时区类可以准确地报告夏时制信息,或仅在最新调整规则生效的时间段内,在UTC和当地时间之间进行转换。相比之下,TimeZoneInfo类支持多种调整规则,这使得处理历史时区数据成为可能。

您应该考虑弃用TimeZone类,并且仅使用TimeZoneInfo类。

关于转换不匹配,当您在DateTime上调用ToUniversalTime时,实际上会导致错误。您在d中提供的值正好在向前Spring转换的时刻(就Windows而言)。这意味着从00:00:0000:59:59.9999999的值在该日期无效。一天从凌晨1点开始,而不是午夜。

考虑一下,您可能已经编写了以下代码,而不是调用ToUniversalTime

var dUtc = TimeZoneInfo.ConvertTimeToUtc(d, TimeZoneInfo.Local);

您可能认为这是等效的,但此代码会引发异常,因为d中提供的输入已被DST转换跳过。DateTime不会发生这种情况。ToUniversalTime因为传递了一个名为TimeZoneInfoOptions的内部标志。NoThrowOnInvalidTime,您可以在参考来源中看到。同样有趣的是,NoThrowOnInvalidTime的行为在. NET 3.5和. NET 4.0之间发生了变化。在您的示例案例中,它将在. NET 3.5下返回02:00 UTC,在. NET 4. x下返回03:00 UTC。我不确定我是否同意此更改,但这是往返不匹配的根本原因。

最后,正如你所指出的,巴西1984年的时区与2006年最早的时区html" target="_blank">数据窗口所包含的时区不同。一般来说,Windows时区不是历史信息的好来源。相反,您应该考虑使用TZDB时区,它至少有1970年的历史,在许多情况下更早。在里面NET,你可以使用野田佳彦时间库来实现这一点。等效区域为“美国/圣保罗”

然而,仍然要意识到,即使有野田佳彦的时间,你也不能往返于一个无效的本地日期/时间。如果它在本地时区无效,那么从utc到本地的转换永远不会产生这样的结果。

 类似资料:
  • 有没有一个时区,我可以使用,以考虑到夏令时?我知道'EDT'是指夏令时,而'EST'不是。是否有一个时区我可以使用,将自动检测日期时间是否是夏令时?“ET”或“America/New_York”能行吗? 编辑:: 抱歉应该更清楚。我想取一个日期并将其转换为东部时区,但我希望它考虑到东部时区的日期是否为夏令时。

  • 问题内容: 只是为了验证这一点:我有这种la脚和脑死法,可以计算当前位置的时区偏移量。我想知道是否在需要调整“夏令时”时需要进行调整(目前,我所在的位置为CET时区,所以是“冬季时间”,因此很难验证)。 感谢您的任何提示。 问题答案: 通常,Joda时间会自己照顾DST,因此您不必担心。但是,我注意到您正在传递给getOffset()。鉴于时区偏移量取决于日期,因此您确实应该传递计算偏移量的日期/

  • 轻触方格启用设定,即可将夏令时反映于时间显示中。

  • 问题内容: 如何检查夏令时是否有效? 问题答案: 您可以使用并查看返回值中的标志。 使用,您可以在任意时间问相同的问题,以了解DST在当前时区是否有效。

  • 夏令时间 选择[标准]或[夏令时间]。

  • 从“GMT夏令时”或任何其他可用的Windows时区信息有什么方法可以到达BST吗?