-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
On Unix, we are trying to populate the "DaylightTransitionStart" and "DaylightTransitionEnd" values for the AdjustmentRules. However, this design is flawed and leads to incorrect data being reported by the API.
See https://github.com/dotnet/corefx/issues/2465#issuecomment-127645308 and the whole issue for discussion on how the Windows-centric TimeZoneInfo.AdjustmentRule API was modified to fit the information that is available on Unix.
We are trying to hydrate the DaylightTransition Start and End data here https://github.com/dotnet/coreclr/blob/c2b5d5a707e3bb037df847e17b4e55e19fd5bfa8/src/mscorlib/src/System/TimeZoneInfo.Unix.cs#L124-L158. However, this data is incorrect on Unix. Take the Africa/Casablanca time zone from 1940-1945:
From our tests
// Africa/Casablanca had DST from
// 1940-02-25T00:00:00.0000000Z {+01:00:00 DST=True}
// 1945-11-17T23:00:00.0000000Z { 00:00:00 DST=False}
Printing the AdjustmentRules from around that time:
Baseoffset: 00:00:00
DateStart DateEnd DaylightDelta DaylightTransitionStart DaylightTransitionEnd
11/17/1945 06/10/1950 00:00:00 M11.w1.d17 11:00 PM M6.w1.d10 11:59 PM
02/25/1940 11/17/1945 01:00:00 M2.w1.d25 1:00 AM M11.w1.d17 11:59 PM
11/18/1939 02/24/1940 00:00:00 M11.w1.d18 11:00 PM M2.w1.d24 11:59 PM
09/12/1939 11/18/1939 01:00:00 M9.w1.d12 1:00 AM M11.w1.d18 11:59 PM
10/26/1913 09/11/1939 00:00:00 M10.w1.d26 12:30 AM M9.w1.d11 11:59 PM
Specifically, look at this row:
DateStart DateEnd DaylightDelta DaylightTransitionStart DaylightTransitionEnd
02/25/1940 11/17/1945 01:00:00 M2.w1.d25 1:00 AM M11.w1.d17 11:59 PM
What this says is that for times in this time zone between 02/25/1940 and 11/17/1945, Daylight Savings Time starts on the 25th day of February and ends on the 17th day of November of every year. So from Nov 17 to Feb 25 every year, the time zone should not be in daylight savings time, which is incorrect because the time zone was in DST all year round those 5 years.
I don't think we should be populating these Daylight TransitionTime values at all when giving the AdjustmentRules to public consumers. Anyone who wants to consume this information is going to be broken trying to use it. This is just going to lead to incorrect information being displayed to their users.
Code to print the above table
class Program
{
static void Main(string[] args)
{
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Africa/Casablanca");
System.Console.WriteLine($"Baseoffset: {tz.BaseUtcOffset}");
StringBuilder builder = new StringBuilder();
builder.Append("DateStart");
builder.Append("\t");
builder.Append("DateEnd");
builder.Append("\t");
builder.Append("\t");
builder.Append("DaylightDelta");
builder.Append("\t");
builder.Append("DaylightTransitionStart");
builder.Append("\t");
builder.Append("DaylightTransitionEnd");
System.Console.WriteLine(builder);
var rules = tz.GetAdjustmentRules();
DateTime startDate = new DateTime(1945, 12, 31);
//DateTime startDate = DateTime.Now;
foreach (var rule in rules.Where(r => r.DateStart < startDate).Reverse().Take(5))
{
builder = new StringBuilder();
builder.Append(rule.DateStart.ToString("MM/dd/yyyy"));
builder.Append("\t");
builder.Append(rule.DateEnd.ToString("MM/dd/yyyy"));
builder.Append("\t");
builder.Append(rule.DaylightDelta);
builder.Append("\t");
PrintTransition(rule.DaylightTransitionStart, builder);
builder.Append("\t");
PrintTransition(rule.DaylightTransitionEnd, builder);
System.Console.WriteLine(builder);
}
}
private static void PrintTransition(TimeZoneInfo.TransitionTime transition, StringBuilder builder)
{
builder.Append($"M{transition.Month}.w{transition.Week}.d{transition.Day} {transition.TimeOfDay.ToShortTimeString()}");
}
}