Skip to content

Incorrect trailing TimeZoneInfo.AdjustmentRule on Unix #20624

@eerhardt

Description

@eerhardt

On Unix, time zone data is retrieved from tzfiles. See https://linux.die.net/man/5/tzfile.

The transition times of each time zone are stored in this file. Every time the offset from UTC changes, an entry is made. In practice, they are "forecasted" out until about 2037.

In V2 of the tzfile, the time transitions after this "last" transition date are represented by a "POSIX" style string that represents when DST starts and ends each year.

These POSIX-TZ-environment-variable-style strings are documented http://man7.org/linux/man-pages/man3/tzset.3.html.

Here is an example for New Zealand, where the standard time (NZST) is
12 hours ahead of UTC, and daylight saving time (NZDT), 13 hours
ahead of UTC, runs from the first Sunday in October to the third
Sunday in March, and the changeovers happen at the default time of
02:00:00:
TZ="NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0"

However, our GetAdjustmentRules() method is not translating this information correctly.

Here is an example of using the America/Los_Angeles time zone and printing out the AdjustmentRules. Notice the top row says to start daylight transitions on the November 1 of each year, and to end it on December 31. Also notice that there is no DaylightDelta during this time, when it should be 1 hour.

DateStart       DateEnd         DaylightDelta   DaylightTransitionStart DaylightTransitionEnd
11/01/2037      12/31/9999      00:00:00        M11.w1.d1 1:00 AM       M12.w1.d31 11:59 PM
03/08/2037      11/01/2037      01:00:00        M3.w1.d8 3:00 AM        M11.w1.d1 1:59 AM
11/02/2036      03/08/2037      00:00:00        M11.w1.d2 1:00 AM       M3.w1.d8 1:59 AM
03/09/2036      11/02/2036      01:00:00        M3.w1.d9 3:00 AM        M11.w1.d2 1:59 AM
11/04/2035      03/09/2036      00:00:00        M11.w1.d4 1:00 AM       M3.w1.d9 1:59 AM

Code to print the above table

    class Program
    {
        static void Main(string[] args)
        {
            TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");

            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();
            foreach (var rule in rules.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()}");
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions