From 2457e2b3831d73ff5178961a62f7a6fcc332eceb Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 12 Nov 2016 07:51:08 -0500 Subject: [PATCH] Avoid allocations in DateTime.Now Every call to DateTime.Now ends up allocating a DaylightTime as it computes the offset from UtcNow. DaylightTime is just a plain old object that stores two DateTimes and a Timespan. Ideally we could just change it to be a struct, but it's public. Instead, this commit adds an internal DaylightTimeStruct, which is the same as DaylightTime except as a value type, and changes some of the internal uses of DaylightTime to instead use DaylightTime. As a result, DateTime.Now is allocation-free. --- .../src/System/Globalization/DaylightTime.cs | 23 ++++++++++++++--- src/mscorlib/src/System/TimeZoneInfo.cs | 30 +++++++++++----------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/mscorlib/src/System/Globalization/DaylightTime.cs b/src/mscorlib/src/System/Globalization/DaylightTime.cs index 037d9ff..a164867 100644 --- a/src/mscorlib/src/System/Globalization/DaylightTime.cs +++ b/src/mscorlib/src/System/Globalization/DaylightTime.cs @@ -2,12 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace System.Globalization { - - using System; +using System.Runtime.InteropServices; + +namespace System.Globalization +{ // This class represents a starting/ending time for a period of daylight saving time. [Serializable] - [System.Runtime.InteropServices.ComVisible(true)] + [ComVisible(true)] public class DaylightTime { internal DateTime m_start; @@ -46,4 +47,18 @@ namespace System.Globalization { } + // Value type version of DaylightTime + internal struct DaylightTimeStruct + { + public DaylightTimeStruct(DateTime start, DateTime end, TimeSpan delta) + { + Start = start; + End = end; + Delta = delta; + } + + public DateTime Start { get; } + public DateTime End { get; } + public TimeSpan Delta { get; } + } } diff --git a/src/mscorlib/src/System/TimeZoneInfo.cs b/src/mscorlib/src/System/TimeZoneInfo.cs index e41c0bd..85f28ca 100644 --- a/src/mscorlib/src/System/TimeZoneInfo.cs +++ b/src/mscorlib/src/System/TimeZoneInfo.cs @@ -388,7 +388,7 @@ namespace System { Boolean isAmbiguous = false; AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime); if (rule != null && rule.HasDaylightSaving) { - DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } @@ -436,7 +436,7 @@ namespace System { Boolean isAmbiguous = false; AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime); if (rule != null && rule.HasDaylightSaving) { - DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } @@ -600,7 +600,7 @@ namespace System { AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); if (rule != null && rule.HasDaylightSaving) { - DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); return GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } return false; @@ -678,7 +678,7 @@ namespace System { // AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); if (rule != null && rule.HasDaylightSaving) { - DaylightTime daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags); } else { @@ -702,7 +702,7 @@ namespace System { AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime); if (rule != null && rule.HasDaylightSaving) { - DaylightTime daylightTime = GetDaylightTime(dateTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule); isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime); } else { @@ -855,7 +855,7 @@ namespace System { sourceOffset = sourceOffset + sourceRule.BaseUtcOffsetDelta; if (sourceRule.HasDaylightSaving) { Boolean sourceIsDaylightSavings = false; - DaylightTime sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule); + DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule); // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule // period that supports DST @@ -1749,7 +1749,7 @@ namespace System { // // Helper function that returns a DaylightTime from a year and AdjustmentRule // - private DaylightTime GetDaylightTime(Int32 year, AdjustmentRule rule) { + private DaylightTimeStruct GetDaylightTime(Int32 year, AdjustmentRule rule) { TimeSpan delta = rule.DaylightDelta; DateTime startTime; DateTime endTime; @@ -1770,7 +1770,7 @@ namespace System { startTime = TransitionTimeToDateTime(year, rule.DaylightTransitionStart); endTime = TransitionTimeToDateTime(year, rule.DaylightTransitionEnd); } - return new DaylightTime(startTime, endTime, delta); + return new DaylightTimeStruct(startTime, endTime, delta); } // @@ -1779,7 +1779,7 @@ namespace System { // Helper function that checks if a given dateTime is in Daylight Saving Time (DST) // This function assumes the dateTime and AdjustmentRule are both in the same time zone // - static private Boolean GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTime daylightTime, TimeZoneInfoOptions flags) { + static private Boolean GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime, TimeZoneInfoOptions flags) { if (rule == null) { return false; } @@ -1874,7 +1874,7 @@ namespace System { // Get the daylight changes for the year of the specified time. - DaylightTime daylightTime = zone.GetDaylightTime(Year, rule); + DaylightTimeStruct daylightTime = zone.GetDaylightTime(Year, rule); // The start and end times represent the range of universal times that are in DST for that year. // Within that there is an ambiguous hour, usually right at the end, but at the beginning in @@ -1893,7 +1893,7 @@ namespace System { if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) { AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime(new DateTime(daylightTime.Start.Year - 1, 12, 31)); if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) { - DaylightTime previousDaylightTime = zone.GetDaylightTime(daylightTime.Start.Year - 1, previousYearRule); + DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime(daylightTime.Start.Year - 1, previousYearRule); startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta; ignoreYearAdjustment = true; } else { @@ -1911,7 +1911,7 @@ namespace System { if (nextYearRule.IsEndDateMarkerForEndOfYear()) {// next year end with daylight saving on too endTime = new DateTime(daylightTime.End.Year + 1, 12, 31) - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; } else { - DaylightTime nextdaylightTime = zone.GetDaylightTime(daylightTime.End.Year + 1, nextYearRule); + DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime(daylightTime.End.Year + 1, nextYearRule); endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; } ignoreYearAdjustment = true; @@ -2017,7 +2017,7 @@ namespace System { // In this example, any DateTime values that fall into the [1AM - 1:59:59AM] range // are ambiguous; as it is unclear if these times are in Daylight Saving Time. // - static private Boolean GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTime daylightTime) { + static private Boolean GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) { Boolean isAmbiguous = false; if (rule == null || rule.DaylightDelta == TimeSpan.Zero) { return isAmbiguous; @@ -2081,7 +2081,7 @@ namespace System { // A "time hole" is not limited to only occurring at the start of DST, and may occur at // the end of DST as well. // - static private Boolean GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTime daylightTime) { + static private Boolean GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) { Boolean isInvalid = false; if (rule == null || rule.DaylightDelta == TimeSpan.Zero) { return isInvalid; @@ -2684,7 +2684,7 @@ namespace System { if (rule != null) { baseOffset = baseOffset + rule.BaseUtcOffsetDelta; if (rule.HasDaylightSaving) { - DaylightTime daylightTime = zone.GetDaylightTime(time.Year, rule); + DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule); Boolean isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); } -- 2.7.4