Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit c1c7291

Browse files
authored
Skip old time zones adjustments with offsets higher than 14h (#18305) (#18874)
* Skip old time zones with offsets higher than 14h * apply offline feedback * fix braces
1 parent f738f1b commit c1c7291

File tree

2 files changed

+104
-13
lines changed

2 files changed

+104
-13
lines changed

src/mscorlib/shared/System/TimeZoneInfo.Unix.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,14 +595,14 @@ private static TimeZoneInfo GetTimeZoneFromTzData(byte[] rawData, string id)
595595
}
596596
catch (ArgumentException) { }
597597
catch (InvalidTimeZoneException) { }
598+
598599
try
599600
{
600601
return new TimeZoneInfo(rawData, id, dstDisabled: true); // create a TimeZoneInfo instance from the TZif data w/o DST support
601602
}
602603
catch (ArgumentException) { }
603604
catch (InvalidTimeZoneException) { }
604605
}
605-
606606
return null;
607607
}
608608

@@ -866,7 +866,7 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
866866
index++;
867867
}
868868

869-
if (index == 0)
869+
if (rulesList.Count == 0 && index < dts.Length)
870870
{
871871
TZifType transitionType = TZif_GetEarlyDateTransitionType(transitionTypes);
872872
DateTime endTransitionDate = dts[index];
@@ -883,6 +883,12 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
883883
default(TransitionTime),
884884
baseUtcDelta,
885885
noDaylightTransitions: true);
886+
887+
if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
888+
{
889+
NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
890+
}
891+
886892
rulesList.Add(r);
887893
}
888894
else if (index < dts.Length)
@@ -920,6 +926,12 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
920926
default(TransitionTime),
921927
baseUtcDelta,
922928
noDaylightTransitions: true);
929+
930+
if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
931+
{
932+
NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
933+
}
934+
923935
rulesList.Add(r);
924936
}
925937
else
@@ -932,8 +944,14 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
932944
if (!string.IsNullOrEmpty(futureTransitionsPosixFormat))
933945
{
934946
AdjustmentRule r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset);
947+
935948
if (r != null)
936949
{
950+
if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
951+
{
952+
NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
953+
}
954+
937955
rulesList.Add(r);
938956
}
939957
}
@@ -954,6 +972,12 @@ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZone
954972
default(TransitionTime),
955973
baseUtcDelta,
956974
noDaylightTransitions: true);
975+
976+
if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
977+
{
978+
NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
979+
}
980+
957981
rulesList.Add(r);
958982
}
959983
}

src/mscorlib/shared/System/TimeZoneInfo.cs

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,12 +1917,6 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool
19171917
return result;
19181918
}
19191919

1920-
/// <summary>
1921-
/// Helper function that validates the TimeSpan is within +/- 14.0 hours
1922-
/// </summary>
1923-
internal static bool UtcOffsetOutOfRange(TimeSpan offset) =>
1924-
offset.TotalHours < -14.0 || offset.TotalHours > 14.0;
1925-
19261920
/// <summary>
19271921
/// Helper function that performs all of the validation checks for the
19281922
/// factory methods and deserialization callback.
@@ -1972,11 +1966,7 @@ private static void ValidateTimeZoneInfo(string id, TimeSpan baseUtcOffset, Adju
19721966
throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesNoNulls);
19731967
}
19741968

1975-
// FUTURE: check to see if this rule supports Daylight Saving Time
1976-
// adjustmentRulesSupportDst = adjustmentRulesSupportDst || current.SupportsDaylightSavingTime;
1977-
// FUTURE: test baseUtcOffset + current.StandardDelta
1978-
1979-
if (UtcOffsetOutOfRange(baseUtcOffset + current.DaylightDelta))
1969+
if (!IsValidAdjustmentRuleOffest(baseUtcOffset, current))
19801970
{
19811971
throw new InvalidTimeZoneException(SR.ArgumentOutOfRange_UtcOffsetAndDaylightDelta);
19821972
}
@@ -1989,5 +1979,82 @@ private static void ValidateTimeZoneInfo(string id, TimeSpan baseUtcOffset, Adju
19891979
}
19901980
}
19911981
}
1982+
1983+
private static readonly TimeSpan MaxOffset = TimeSpan.FromHours(14.0);
1984+
private static readonly TimeSpan MinOffset = -MaxOffset;
1985+
1986+
/// <summary>
1987+
/// Helper function that validates the TimeSpan is within +/- 14.0 hours
1988+
/// </summary>
1989+
internal static bool UtcOffsetOutOfRange(TimeSpan offset) =>
1990+
offset < MinOffset || offset > MaxOffset;
1991+
1992+
private static TimeSpan GetUtcOffset(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule)
1993+
{
1994+
return baseUtcOffset
1995+
+ adjustmentRule.BaseUtcOffsetDelta
1996+
+ (adjustmentRule.HasDaylightSaving ? adjustmentRule.DaylightDelta : TimeSpan.Zero);
1997+
}
1998+
1999+
/// <summary>
2000+
/// Helper function that performs adjustment rule validation
2001+
/// </summary>
2002+
private static bool IsValidAdjustmentRuleOffest(TimeSpan baseUtcOffset, AdjustmentRule adjustmentRule)
2003+
{
2004+
TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule);
2005+
return !UtcOffsetOutOfRange(utcOffset);
2006+
}
2007+
2008+
/// <summary>
2009+
/// Normalize adjustment rule offset so that it is within valid range
2010+
/// This method should not be called at all but is here in case something changes in the future
2011+
/// or if really old time zones are present on the OS (no combination is known at the moment)
2012+
/// </summary>
2013+
private static void NormalizeAdjustmentRuleOffset(TimeSpan baseUtcOffset, ref AdjustmentRule adjustmentRule)
2014+
{
2015+
// Certain time zones such as:
2016+
// Time Zone start date end date offset
2017+
// -----------------------------------------------------
2018+
// America/Yakutat 0001-01-01 1867-10-18 14:41:00
2019+
// America/Yakutat 1867-10-18 1900-08-20 14:41:00
2020+
// America/Sitka 0001-01-01 1867-10-18 14:58:00
2021+
// America/Sitka 1867-10-18 1900-08-20 14:58:00
2022+
// Asia/Manila 0001-01-01 1844-12-31 -15:56:00
2023+
// Pacific/Guam 0001-01-01 1845-01-01 -14:21:00
2024+
// Pacific/Saipan 0001-01-01 1845-01-01 -14:21:00
2025+
//
2026+
// have larger offset than currently supported by framework.
2027+
// If for whatever reason we find that time zone exceeding max
2028+
// offset of 14h this function will truncate it to the max valid offset.
2029+
// Updating max offset may cause problems with interacting with SQL server
2030+
// which uses SQL DATETIMEOFFSET field type which was originally designed to be
2031+
// bit-for-bit compatible with DateTimeOffset.
2032+
2033+
TimeSpan utcOffset = GetUtcOffset(baseUtcOffset, adjustmentRule);
2034+
2035+
// utc base offset delta increment
2036+
TimeSpan adjustment = TimeSpan.Zero;
2037+
2038+
if (utcOffset > MaxOffset)
2039+
{
2040+
adjustment = MaxOffset - utcOffset;
2041+
}
2042+
else if (utcOffset < MinOffset)
2043+
{
2044+
adjustment = MinOffset - utcOffset;
2045+
}
2046+
2047+
if (adjustment != TimeSpan.Zero)
2048+
{
2049+
adjustmentRule = AdjustmentRule.CreateAdjustmentRule(
2050+
adjustmentRule.DateStart,
2051+
adjustmentRule.DateEnd,
2052+
adjustmentRule.DaylightDelta,
2053+
adjustmentRule.DaylightTransitionStart,
2054+
adjustmentRule.DaylightTransitionEnd,
2055+
adjustmentRule.BaseUtcOffsetDelta + adjustment,
2056+
adjustmentRule.NoDaylightTransitions);
2057+
}
2058+
}
19922059
}
19932060
}

0 commit comments

Comments
 (0)