When I started working with Time Zones I tough was an easy task, but the more I dag into the topic and the more I found myself lost. In Stack Overflow there are already dozens of similar questions, mainly attempting to solve specific problems but none of them (answers included) helped me to understand the topic as I wanted. On top of that, as others asked, from time to time it looks like some time zone changes, and Microsoft has to rush updates distributed via Windows Update to cope with it.
In my case I noticed that at least 2 TZs are incorrect:
Because as I mentioned above the TZ are taken from the local system I tried to search for updates, but I have none. So either I am really missing something important, or Microsoft doesn't care about this two time zones.
For Daylight Saving Time, Microsoft has a clear policy and states:
Microsoft makes an effort to incorporate these changes to Windows, and publishes an update through Windows Update (WU). Each DST/TZ update released through WU will have the latest time data and will also supersede any previously issued DST/TZ update
The recent updates can be found in the dedicated Microsoft Tech Community site
To help myself understand, I created a simple console application (see the code below), problem is that this has not been enough.
private static ConsoleColor DefaultColor;
static void Main(string[] args)
{
DefaultColor = Console.ForegroundColor;
foreach (var timeZoneInfo in TimeZoneInfo.GetSystemTimeZones().OrderBy(tz => tz.Id))
{
var firstQuart = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var secondQuart = new DateTime(2019, 4, 1, 0, 0, 0, DateTimeKind.Utc);
var thirdQuart = new DateTime(2019, 7, 1, 0, 0, 0, DateTimeKind.Utc);
var lastQuart = new DateTime(2019, 10, 1, 0, 0, 0, DateTimeKind.Utc);
if (timeZoneInfo.Id == "Altai Standard Time" ||
timeZoneInfo.Id == "Argentina Standard Time" ||
timeZoneInfo.Id == "GMT Standard Time"
)
{
Log($"{timeZoneInfo.DisplayName} (ID: {timeZoneInfo.Id})", ConsoleColor.Yellow);
Log($"StandardName: {timeZoneInfo.StandardName}");
Log($"DST: {timeZoneInfo.SupportsDaylightSavingTime}");
Log($"Daylight Name: {timeZoneInfo.DaylightName}");
Log();
Log($"UTC Offset: {timeZoneInfo.BaseUtcOffset}");
Log($"Dates for each quarter in this year");
var convertedFirstQuart = TimeZoneInfo.ConvertTimeFromUtc(firstQuart, timeZoneInfo);
var convertedSecondQuart = TimeZoneInfo.ConvertTimeFromUtc(secondQuart, timeZoneInfo);
var convertedThirdQuart = TimeZoneInfo.ConvertTimeFromUtc(thirdQuart, timeZoneInfo);
var convertedLastQuart = TimeZoneInfo.ConvertTimeFromUtc(lastQuart, timeZoneInfo);
Log();
Log($"First quarter: {TimeZoneInfo.ConvertTimeFromUtc(firstQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedFirstQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedFirstQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedFirstQuart)}/{timeZoneInfo.IsInvalidTime(convertedFirstQuart)}");
Log();
Log($"Second quarter: {TimeZoneInfo.ConvertTimeFromUtc(secondQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedSecondQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedSecondQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedSecondQuart)}/{timeZoneInfo.IsInvalidTime(convertedSecondQuart)}");
Log();
Log($"Third quarter: {TimeZoneInfo.ConvertTimeFromUtc(thirdQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedThirdQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedThirdQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedThirdQuart)}/{timeZoneInfo.IsInvalidTime(convertedThirdQuart)}");
Log();
Log($"Last quarter: {TimeZoneInfo.ConvertTimeFromUtc(lastQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedLastQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedLastQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedLastQuart)}/{timeZoneInfo.IsInvalidTime(convertedLastQuart)}");
Log("==============================================================");
Log();
}
}
Console.ReadKey();
}
private static void Log(string message = "", ConsoleColor? color = null)
{
if(color.HasValue)
Console.ForegroundColor = color.Value;
Console.WriteLine(message);
Console.ForegroundColor = DefaultColor;
}
}
Given that my local TZ is GMT, and we use DST, the output is the following:
TimeZoneInfo.SupportsDaylightSavingTime(): Official Documentation
The following example retrieves a collection of all time zones that are available on a local system and displays the names of those that do not support daylight saving time.
var zones = TimeZoneInfo.GetSystemTimeZones();
foreach(TimeZoneInfo zone in zones)
{
if (! zone.SupportsDaylightSavingTime)
Console.WriteLine(zone.DisplayName);
}
TimezoneInfo.IsDaylightSavingTime(DateTime): Official Documentation
Indicates whether a specified date and time falls in the range of daylight saving time for the time zone of the current TimeZoneInfo object.
DateTime.IsDaylightSavingTime(): Official Documentation
Indicates whether this instance of DateTime is within the daylight saving time range for the current time zone.
It is important to understand (I didn't at first), that the method IsDaylightSavingTime on an instance of DateTime, always returns the information requested taking in consideration the Local System Time Zone.
Focusing on the Argentina Standard Time, we can see that the TimeZoneInfo.SupportsDaylightSavingTime, return true, this is an incorrect information because everywhere I searched for it, I found the opposite result.
Even tough the support for DST seems to be incorrect, converting a UTC DateTime to the ART TZ, using C#, always produces the correct result.
What makes me think that I still don't understand the whole picture here, is that the TimeInfo.IsDaylightSavingTime(DateTime) return false, which is what I would expect.
According to wikipedia https://en.wikipedia.org/wiki/Daylight_saving_time A move to "permanent daylight saving time" (staying on summer hours all year with no time shifts) is sometimes advocated and is currently implemented in some jurisdictions such as Argentina, Belarus,[78]Canada (e.g. Saskatchewan), Iceland, Kyrgyzstan, Malaysia, Morocco, Namibia, Singapore, Turkey, Turkmenistan and Uzbekistan.[164]It could be a result of following the timezone of a neighbouring region, political will, or other causes.
Short Answer
TimeZoneInfo.SupportsDaylightSavingTime
considers all time zone data available on the system, not just that of the current year. Both Argentina Standard Time
and Altai Standard Time
have periods where DST was in effect, within the periods of time that Windows is tracking for them.
Longer Answer
The documentation for TimeZoneInfo.SupportsDaylightSavingTime
(which you linked to in your question already) explains:
Gets a value indicating whether the time zone has any daylight saving time rules.
What it's a little less clear about is that it is referring specifically to TimeZoneInfo.AdjustmentRule
objects, as returned by the TimeZoneInfo.GetAdjustmentRules
method, and that these are all rules on the system, not just the ones for the current year.
Microsoft policy states that Windows keeps track of all changes from 2010 forward. However, some time zones (such as for Argentina) were already tracking changes before the policy was written so in some cases you will see earlier data.
In the Windows registry, you can find all of the time zone data that the system knows about at the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
Each of the TimeZoneInfo.Id
values corresponds to a subkey under that one, and adjustment rules (if any) will be under Dynamic DST
under that.
For Argentina Standard Time\Dynamic DST
, we find data from 2006 through 2010.
Without even decoding the data, we can see that there were variations between the years. Looking on timeanddate.com here gives us the detail:
It appears that daylight saving time was in effect for the 2007-08 and 2008-09 summer seasons. (Argentina, being in the southern hemisphere, has its summers split across two years.)
Indeed, we can see this from .NET:
var tz = TimeZoneInfo.FindSystemTimeZoneById("Argentina Standard Time");
var dt = new DateTime(2008, 1, 1);
var dst = tz.IsDaylightSavingTime(dt); // True
Thus, it is appropriate for TimeZoneInfo.SupportsDaylightSavingTime
to return True
because there are indeed valid dates that were in DST for this time zone.
The same can be found for Altai. Windows is tracking data from 2010 forward, and DST existed in 2010 there.
Notice that it also has changes to its standard time in 2014 and again in 2016. This is another reason that an adjustment rule might exist. Unfortunately, Windows doesn't have a way to model this without using transitions that are marked as either "start of DST" or "end of DST". Thus, some part of these years will return True
from IsDaylightSavingTime
, even though neither side of the transition was considered to be daylight saving time. This is a known issue with time zones on Windows. It is a compromise that ensures that the correct UTC offset is used, even if the transition is for a change to standard time instead of for daylight saving time.
If you absolutely need to know if a transition was related to DST or not, then you can use IANA time zone data instead, via the Noda Time library. The ZoneInterval.Savings
property will tell you that. However, that gets to your point about "permanent daylight saving time". Even in the IANA database, those are usually treated as changes to standard time, rather than true daylight saving time. So, you will probably find cases where someone might say "We've been on permanent DST for years", but the data disagrees.
Regarding your last question:
How can I make sure that I have the latest DST/TZ updates from Microsoft, beside what I explained above?
It is sufficient to simply ensure you are running Windows Update. All the DST/TZ updates listed on the community site are deployed with regular updates to all supported versions of Windows, regardless of what time zone you are in.