From f01ef48439fb2937917a2fa60d62e39d0135f7d5 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 27 Mar 2017 12:50:36 -0500 Subject: [PATCH] Binary Search in TimeZoneInfo.GetAdjustmentRuleForTime Since Unix uses IANA tzdata files, there can be hundreds of adjustment rules for each time zone. To make the search for a given rule faster, use a binary search since the rules are guaranteed to be in chronological order. See ValidateTimeZoneInfo. Fix dotnet/coreclr#5716 Commit migrated from https://github.com/dotnet/coreclr/commit/8db6c57bc9768b0387cb045b19afee3c721ea348 --- .../src/mscorlib/src/System/TimeZoneInfo.cs | 34 +++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/coreclr/src/mscorlib/src/System/TimeZoneInfo.cs b/src/coreclr/src/mscorlib/src/System/TimeZoneInfo.cs index c37d81b..3dd0aec 100644 --- a/src/coreclr/src/mscorlib/src/System/TimeZoneInfo.cs +++ b/src/coreclr/src/mscorlib/src/System/TimeZoneInfo.cs @@ -1062,14 +1062,29 @@ namespace System (dateTime + BaseUtcOffset).Date : dateTime.Date; - for (int i = 0; i < _adjustmentRules.Length; i++) + int low = 0; + int high = _adjustmentRules.Length - 1; + + while (low <= high) { - AdjustmentRule rule = _adjustmentRules[i]; - AdjustmentRule previousRule = i > 0 ? _adjustmentRules[i - 1] : rule; - if (IsAdjustmentRuleValid(rule, previousRule, dateTime, date, dateTimeisUtc)) + int median = low + ((high - low) >> 1); + + AdjustmentRule rule = _adjustmentRules[median]; + AdjustmentRule previousRule = median > 0 ? _adjustmentRules[median - 1] : rule; + + int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc); + if (compareResult == 0) { return rule; } + else if (compareResult < 0) + { + low = median + 1; + } + else + { + high = median - 1; + } } return null; @@ -1078,7 +1093,12 @@ namespace System /// /// Determines if 'rule' is the correct AdjustmentRule for the given dateTime. /// - private bool IsAdjustmentRuleValid(AdjustmentRule rule, AdjustmentRule previousRule, + /// + /// A value less than zero if rule is for times before dateTime. + /// Zero if rule is correct for dateTime. + /// A value greater than zero if rule is for times after dateTime. + /// + private int CompareAdjustmentRuleToDateTime(AdjustmentRule rule, AdjustmentRule previousRule, DateTime dateTime, DateTime dateOnly, bool dateTimeisUtc) { bool isAfterStart; @@ -1100,7 +1120,7 @@ namespace System if (!isAfterStart) { - return false; + return 1; } bool isBeforeEnd; @@ -1118,7 +1138,7 @@ namespace System isBeforeEnd = dateOnly <= rule.DateEnd; } - return isBeforeEnd; + return isBeforeEnd ? 0 : -1; } /// -- 2.7.4