Skip to content

Commit

Permalink
Stop throwing exception in TimeZoneInfo POSIX parsing (#458)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
eerhardt authored Dec 3, 2019
1 parent 1bf3be8 commit 42394ce
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 33 deletions.
3 changes: 0 additions & 3 deletions src/coreclr/src/System.Private.CoreLib/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2644,9 +2644,6 @@
<data name="InvalidTimeZone_InvalidJulianDay" xml:space="preserve">
<value>Invalid Julian day in POSIX strings.</value>
</data>
<data name="InvalidTimeZone_NJulianDayNotSupported" xml:space="preserve">
<value>Julian n day in POSIX strings is not supported.</value>
</data>
<data name="InvalidTimeZone_NoTTInfoStructures" xml:space="preserve">
<value>There are no ttinfo structures in the tzfile. At least one ttinfo structure is required in order to construct a TimeZoneInfo object.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -981,21 +981,11 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
// 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

Expand All @@ -1004,22 +994,22 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
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++;
Expand Down Expand Up @@ -1111,15 +1101,20 @@ private static TZifType TZif_GetEarlyDateTransitionType(TZifType[] transitionTyp
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);
}
Expand Down Expand Up @@ -1210,11 +1205,11 @@ private static DateTime ParseTimeOfDay(ReadOnlySpan<char> time)
return timeOfDay;
}

private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpan<char> date, ReadOnlySpan<char> time)
private static TransitionTime? TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpan<char> date, ReadOnlySpan<char> time)
{
if (date.IsEmpty)
{
return default;
return null;
}

if (date[0] == 'M')
Expand Down Expand Up @@ -1260,7 +1255,8 @@ private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpa
//
// 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
Expand Down

0 comments on commit 42394ce

Please sign in to comment.