Bug 26008

Summary: Wrong DST when TimeZoneInfo has floating date rules.
Product: [Mono] Class Libraries Reporter: marcos.henrich
Component: System.CoreAssignee: marcos.henrich
Status: RESOLVED FIXED    
Severity: normal CC: mono-bugs+mono
Priority: ---    
Version: unspecified   
Target Milestone: Untriaged   
Hardware: PC   
OS: Mac OS   
Tags: Is this bug a regression?: ---
Last known good build:

Description marcos.henrich 2015-01-14 06:22:44 UTC
The following bug, test case and possible fix has been reported by nachocove.com

The Mono runtime has a bug in how it calculates the daylight saving transition dates when the time zone uses a floating rule (e.g. 2nd Sunday of the month).  In some cases, the transition to or from daylight saving time will happen a week earlier than it is supposed to.

Here is a function that will check for the presence of the bug.  It creates a custom time zone where daylight saving time starts on the 2nd Sunday in March, and then checks whether Friday, March 7, 2014 (which is in between the first and second Sundays) is reported as being daylight saving time.

        /// <summary>
        /// Mono has a bug in its daylight saving code, where a transition to or from
        /// daylight saving time might happen a week early.  This function tests whether
        /// or not the runtime in use has this particular bug.
        /// </summary>
        /// <returns><c>true</c>, if the runtime is correct, <c>false</c> if the runtime has the bug.</returns>
        /// <remarks>
        /// The bug happens when (1) the transition is a floating rule rather than a
        /// fixed rule, (2) the transition happens in a week other than the first week,
        /// and (3) the day of the week of the first day of the month is later in the
        /// week than the day of the week that the transition happens on.  (Since most
        /// transitions happen on Sundays, which is the first day of the week, condition
        /// #3 almost always applies.)
        /// </remarks>
        private static bool DaylightSavingCorrectnessCheck ()
        {
            // Construct a custom time zone where daylight saving time starts on the
            // 2nd Sunday in March.
            var transitionToDaylight = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (
                new DateTime (1, 1, 1, 2, 0, 0), 3, 2, DayOfWeek.Sunday);
            var transitionToStandard = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (
                new DateTime (1, 1, 1, 2, 0, 0), 11, 1, DayOfWeek.Sunday);
            var adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
                DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1, 0, 0),
                transitionToDaylight, transitionToStandard);
            var timeZone = TimeZoneInfo.CreateCustomTimeZone (
                "BugCheck", new TimeSpan (-8, 0, 0), "Testing", "Testing Standard", "Testing Daylight",
                new TimeZoneInfo.AdjustmentRule[] { adjustment });
            // See if March 7, 2014 is listed as being during daylight saving time.
            // If it is DST, then the runtime has the bug that we are looking for.
            return !timeZone.IsDaylightSavingTime (new DateTime (2014, 3, 7, 12, 0, 0, DateTimeKind.Unspecified));
        }

Looking at the code for class TimeZoneInfo at https://github.com/mono/mono/blob/master/mcs/class/System.Core/System/TimeZoneInfo.cs , the buggy code appears to be in TimeZoneInfo.TransitionPoint(), line 1089:
    int day = 1 + (transition.Week - 1) * 7 + (transition.DayOfWeek - first) % 7;
That line should be:
    int day = 1 + (transition.Week - 1) * 7 + ((transition.DayOfWeek - first) + 7) % 7;
Comment 1 marcos.henrich 2015-01-14 09:53:04 UTC
The following pull request fixes the issue:
https://github.com/mono/mono/pull/1505
Comment 2 marcos.henrich 2015-01-15 06:45:24 UTC
Fixed in mono master bc6ea9d725bddb937306b0a28ee4fad77bccd96a.
https://github.com/mono/mono/commit/bc6ea9d725bddb937306b0a28ee4fad77bccd96a