为什么C#无法检测到1970/1/1在BST下? [英] Why doesn't C# detect that 1970/1/1 was under BST?

查看:81
本文介绍了为什么C#无法检测到1970/1/1在BST下?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个第三方API,该API返回每日时间值作为DateTime值,并将1970年1月1日作为日期部分。因此对于5AM,它将返回类似 1969-12-31T21:03:00.000-08:00

I'm working with a 3rd party API that returns Time of Day values as DateTime values filling in Jan 1, 1970 as the date part. So for 5AM, it will return something like 1969-12-31T21:03:00.000-08:00

问题是,如果用户在伦敦时间,C#将无法应用1970-01-01的BST调整。
例如,UTC中的 1970-01-01 5AM 的UTC应该为 1970-01-01 6AM 伦敦。
看到转化

The problem is that, when if the user was on London time, C# fails to apply BST adjustment for 1970-01-01. For example, 1970-01-01 5AM in UTC should be 1970-01-01 6AM in London. See conversion

但是,C#似乎没有应用此转换:

But, C# doesn't seem to apply this conversion:

var utcTime = new DateTime(1970, 1, 1, 5, 0, 0, DateTimeKind.Utc);
var britishZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var ukTime = TimeZoneInfo.ConvertTime(utcTime, britishZone);
Console.WriteLine(ukTime);

上面的代码仍会打印5AM。

The above code will still print 5AM.

但是,如果我将其设置为BST生效的最近日期(例如2016年10月1日),则相同的代码可以在6AM正确打印。

However, if I set it to a more recent date that BST was effective such as Oct 1st, 2016, the same code works correctly printing 6AM.


  1. 为什么会这样?

  2. 我该如何解决?我们的应用程序需要跨任何TimeZone(即,硬编码时区不是选项-我们基本上使用Windows本地时区)。


推荐答案

在Windows上使用 TimeZoneInfo 类在系统时区( GMT标准时间 ),您需要从Windows操作系统中获取时区数据,该数据存储在注册表中:

When you use the TimeZoneInfo class on Windows to work with a system time zone ("GMT Standard Time" in this case), you are asking for time zone data from the Windows operating system, which is stored in the registry at:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

Windows根本无法将历史数据返回那么远。对于 GMT标准时间 (伦敦的格林尼治标准时间和BST之间交替的时区),它只知道一组规则-当前有效的规则。在此之前,它什么都不知道(它最后一次更改是在1996年)。

Windows simply does not carry historical data back that far. For "GMT Standard Time", which is the time zone in London that alternates between GMT and BST, it only knows about one set of rules - the current ones that are in effect. It does not know about anything before that (it last changed in 1996).

请注意,根据Microsoft的 DST / TZ支持政策,只有从2010年开始的更改才能得到记录。 Windows历史上曾发生过一些较旧的更改(例如US 2007 DST更改等),这些更改的确有效,但是从全球范围来看,日期可能不会在2010年之前获得最佳效果。

Note that per Microsoft's DST/TZ Support Policy, only changes from 2010 forward are guaranteed to be recorded. There are several older changes that have historically been in Windows (such as the US 2007 DST change and others), which do indeed work, but from a global perspective you may not get the best results with dates before 2010.

为此,您需要完整实现 IANA TZ数据库,在.NET中,最好的方法之一是使用 Noda Time 库。

For that, you'll need a full implementation of the IANA TZ Database, and in .NET, one of the best ways to do that is with the Noda Time library.

您的代码,音译为Noda Time:

Your code, transliterated to Noda Time:

var utcTime = Instant.FromUtc(1970, 1, 1, 5, 0, 0);
var britishZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var ukTime = utcTime.InZone(britishZone);
Console.WriteLine(ukTime.ToDateTimeUnspecified()); // just for equivalent output

// Prints:  1/1/1970 6:00:00 AM

还请注意,如果您在Linux或OSX上运行.NET Core,则时区确实是IANA时区,因此您的原始代码仅需使用IANA标识符即可工作

Also note that if you are running .NET Core on Linux or OSX, then the time zones are indeed the IANA ones, thus your original code would work by just using the IANA identifer

var britishZone = TimeZoneInfo.FindSystemTimeZoneById("Europe/London");

另请参见时区标签Wiki

这篇关于为什么C#无法检测到1970/1/1在BST下?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆