Why doesn't C# detect that 1970/1/1 was under

2019-03-03 10:02发布

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

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

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);

The above code will still print 5AM.

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. Why does it behave this way?
  2. How do I workaround this? Our app needs to work across any TimeZone (i.e. hard coding timezone isn't an option - we basically use the Windows local timezone).

3条回答
Viruses.
2楼-- · 2019-03-03 10:37

I think the code is working correctly. BSt starts from last sunday of march until last sunday of october where the clock moves one hour forward . That is UTC+1. Since you are looking at a date in jan, london time will be same as UTC.that is utc+0 Check the wikipedia for timezone details https://en.m.wikipedia.org/wiki/British_Summer_Time

查看更多
成全新的幸福
3楼-- · 2019-03-03 10:49

Have you looked at creating a custom time zone adjustment for the historical period(s) that are in question?

https://msdn.microsoft.com/en-us/library/bb397784(v=vs.110).aspx

which can be used in the case of:

The time zone does not have accurate information about time zone adjustments for a particular historic period.

查看更多
【Aperson】
4楼-- · 2019-03-03 10:58

When you use the TimeZoneInfo class 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 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).

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.

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.

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

See also the timezone tag wiki.

查看更多
登录 后发表回答