From 42394ce6c616c8e449f9c280451d2bf59fe86468 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 2 Dec 2019 23:01:59 -0600 Subject: [PATCH] Stop throwing exception in TimeZoneInfo POSIX parsing (#458) IsDaylightSavingTime_CasablancaMultiYearDaylightSavings fails on rhel.8 When parsing the tzdata POSIX string that contains an 'n' Julian date, we are currently throwing an exception, and then falling back to a TimeZoneInfo without DST enabled. However, this is a mistake because there are other DST transitions that were read from the tzdata file that are valid and usable. We shouldn't be throwing that information away. So instead, we now skip the POSIX string if we detect an unsupported 'n' Julian date, and just use the last transition as the AdjustmentRule for all the DateTimes in the future. This way we can still make DST determinations correctly for some DateTimes. Fix https://github.com/dotnet/corefx/issues/42192 --- .../System.Private.CoreLib/Resources/Strings.resx | 3 -- .../src/System/TimeZoneInfo.Unix.cs | 56 ++++++++++------------ 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx b/src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx index f1a5053..37b49a1 100644 --- a/src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx +++ b/src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx @@ -2644,9 +2644,6 @@ Invalid Julian day in POSIX strings. - - Julian n day in POSIX strings is not supported. - There are no ttinfo structures in the tzfile. At least one ttinfo structure is required in order to construct a TimeZoneInfo object. diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 6d18ec4..5b5b795 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -981,21 +981,11 @@ namespace System // NOTE: index == dts.Length DateTime startTransitionDate = dts[index - 1]; - if (!string.IsNullOrEmpty(futureTransitionsPosixFormat)) - { - AdjustmentRule? r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset); - - if (r != null) - { - if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r)) - { - NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r); - } + AdjustmentRule? r = !string.IsNullOrEmpty(futureTransitionsPosixFormat) ? + TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset) : + null; - rulesList.Add(r); - } - } - else + if (r == null) { // just use the last transition as the rule which will be used until the end of time @@ -1004,22 +994,22 @@ namespace System TimeSpan daylightDelta = transitionType.IsDst ? transitionOffset : TimeSpan.Zero; TimeSpan baseUtcDelta = transitionType.IsDst ? TimeSpan.Zero : transitionOffset; - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule( + r = AdjustmentRule.CreateAdjustmentRule( startTransitionDate, DateTime.MaxValue, daylightDelta, - default(TransitionTime), - default(TransitionTime), + default, + default, baseUtcDelta, noDaylightTransitions: true); + } - if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r)) - { - NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r); - } - - rulesList.Add(r); + if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r)) + { + NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r); } + + rulesList.Add(r); } index++; @@ -1111,15 +1101,20 @@ namespace System daylightSavingsTimeSpan = TZif_CalculateTransitionOffsetFromBase(daylightSavingsTimeSpan, baseOffset); } - TransitionTime dstStart = TZif_CreateTransitionTimeFromPosixRule(start, startTime); - TransitionTime dstEnd = TZif_CreateTransitionTimeFromPosixRule(end, endTime); + TransitionTime? dstStart = TZif_CreateTransitionTimeFromPosixRule(start, startTime); + TransitionTime? dstEnd = TZif_CreateTransitionTimeFromPosixRule(end, endTime); + + if (dstStart == null || dstEnd == null) + { + return null; + } return AdjustmentRule.CreateAdjustmentRule( startTransitionDate, DateTime.MaxValue, daylightSavingsTimeSpan, - dstStart, - dstEnd, + dstStart.GetValueOrDefault(), + dstEnd.GetValueOrDefault(), baseOffset, noDaylightTransitions: false); } @@ -1210,11 +1205,11 @@ namespace System return timeOfDay; } - private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpan date, ReadOnlySpan time) + private static TransitionTime? TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpan date, ReadOnlySpan time) { if (date.IsEmpty) { - return default; + return null; } if (date[0] == 'M') @@ -1260,7 +1255,8 @@ namespace System // // If we need to support n format, we'll have to have a floating adjustment rule support this case. - throw new InvalidTimeZoneException(SR.InvalidTimeZone_NJulianDayNotSupported); + // Since we can't support this rule, return null to indicate to skip the POSIX rule. + return null; } // Julian day -- 2.7.4