Reputation: 171
I would expect
TimeZoneInfo.GetSystemTimeZones().Single(x => x.Id == anId)
to always give the same result as
TimeZoneInfo.FindSystemTimeZoneById(anId)
where anId is the same ID string in both cases. However, this is not the case as demonstrated by the following code example.
using System;
using System.Linq;
namespace Utc
{
public static class Program
{
public static void Main()
{
// Outputs (UTC) Coordinated Universal Time
Console.WriteLine(TimeZoneInfo.GetSystemTimeZones().Single(x => x.Id == "UTC").DisplayName);
// Outputs UTC
Console.WriteLine(TimeZoneInfo.FindSystemTimeZoneById("UTC").DisplayName);
Console.WriteLine(TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.GetSystemTimeZones().Single(x => x.Id == "UTC").Id).DisplayName);
Console.ReadKey();
}
}
}
Why is this?
Note that this result was generated with C# version 4.7.2, and gave the same result in Visual Studio 2017 and 2019.
Upvotes: 3
Views: 1999
Reputation: 131
This code was written long ago and during that time the assumption is Utc was not enumerated on the machine and will not be stored in the local dictionary. I agree this is not the case now. Although I am not seeing this can cause a real problem here as both Utc created object will behave correctly, but I think it would be better to fix that and ensure we use one Utc object.
@Ian Kemp, thanks for opening the issue in corefx repo. We'll take care with the issue in the future releases of .NET Core.
Upvotes: 0
Reputation: 29839
The answer is found in the reference source for FindSystemTimeZoneById
:
// Special case for Utc as it will not exist in the dictionary with the rest
// of the system time zones. There is no need to do this check for Local.Id
// since Local is a real time zone that exists in the dictionary cache
if (String.Compare(id, c_utcId, StringComparison.OrdinalIgnoreCase) == 0) {
return TimeZoneInfo.Utc;
}
The dictionary it's referring to is populated from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
, and is what GetSystemTimeZones
returns.
However, I don't believe the comment and logic are correct, because my Windows 10 build 1803 machine has a "UTC" entry at the aforementioned registry path (presumably your computer has the same). It looks like this may have been true in earlier versions of Windows, but perhaps not anymore - have filed a bug in the corefx repo to get clarity.
Upvotes: 0
Reputation: 12619
You are two different results because as per the TimeZoneInfo.cs
implementation of GetSystemTimeZones() will try to lookup into Registry.LocalMachine
and collect timezones data.
In case of FindSystemTimeZoneById it has condition like below. If it doesn't match then it will retrieve from Registry.LocalMachine
.
if (String.Compare(id, c_utcId, StringComparison.OrdinalIgnoreCase) == 0) {
return TimeZoneInfo.Utc;
}
Upvotes: 1