Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect trailing TimeZoneInfo.AdjustmentRule on Unix #20624

Closed
eerhardt opened this issue Mar 14, 2017 · 4 comments
Closed

Incorrect trailing TimeZoneInfo.AdjustmentRule on Unix #20624

eerhardt opened this issue Mar 14, 2017 · 4 comments

Comments

@eerhardt
Copy link
Member

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()}");
        }
    }
@eerhardt
Copy link
Member Author

/cc @tarekgh

@tarekgh
Copy link
Member

tarekgh commented Mar 14, 2017

Thanks @eerhardt for logging the issue.

@jskeet
Copy link

jskeet commented May 25, 2018

This is one of the issues I've run into when getting TimeZoneInfo working in .NET Core in Noda Time. See nodatime/nodatime#1142

(It's possible that all the problems I've found are already reported; I'm going to check though.)

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@joperezr joperezr removed the untriaged New issue has not been triaged by the area owner label Jul 1, 2020
@tarekgh tarekgh modified the milestones: Future, 6.0.0 Mar 20, 2021
@tarekgh
Copy link
Member

tarekgh commented Mar 20, 2021

Fixed by the PR #49733

@tarekgh tarekgh closed this as completed Mar 20, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants