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

make DateTime.UtcNow 5% faster to minimize the leap second performance impact #26046

Merged
merged 2 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions src/System.Private.CoreLib/shared/System/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -641,32 +641,38 @@ public int CompareTo(DateTime value)

// Returns the tick count corresponding to the given year, month, and day.
// Will check the if the parameters are valid.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long DateToTicks(int year, int month, int day)
{
if (year >= 1 && year <= 9999 && month >= 1 && month <= 12)
if (year < 1 || year > 9999 || month < 1 || month > 12 || day < 1)
{
int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365;
if (day >= 1 && day <= days[month] - days[month - 1])
{
int y = year - 1;
int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
return n * TicksPerDay;
}
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
}

int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365;
if (day > days[month] - days[month - 1])
{
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
}
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);

int y = year - 1;
int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
return n * TicksPerDay;
}

// Return the tick count corresponding to the given hour, minute, second.
// Will check the if the parameters are valid.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long TimeToTicks(int hour, int minute, int second)
{
//TimeSpan.TimeToTicks is a family access function which does no error checking, so
//we need to put some error checking out here.
if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60)
{
return (TimeSpan.TimeToTicks(hour, minute, second));
ThrowHelper.ThrowArgumentOutOfRange_BadHourMinuteSecond();
}
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);

return (TimeSpan.TimeToTicks(hour, minute, second));
}

// Returns the number of days in the month given by the year and
Expand Down Expand Up @@ -1182,11 +1188,12 @@ public int Year
// Checks whether a given year is a leap year. This method returns true if
// year is a leap year, or false if not.
//
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsLeapYear(int year)
{
if (year < 1 || year > 9999)
{
throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_Year);
ThrowHelper.ThrowArgumentOutOfRange_Year();
}
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
Expand Down
31 changes: 31 additions & 0 deletions src/System.Private.CoreLib/shared/System/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,31 @@ internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
ExceptionResource.ArgumentOutOfRange_Count);
}

[DoesNotReturn]
internal static void ThrowArgumentOutOfRange_Year()
{
throw GetArgumentOutOfRangeException(ExceptionArgument.year,
ExceptionResource.ArgumentOutOfRange_Year);
}

[DoesNotReturn]
internal static void ThrowArgumentOutOfRange_BadYearMonthDay()
{
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay);
}

[DoesNotReturn]
internal static void ThrowArgumentOutOfRange_BadHourMinuteSecond()
{
throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
}

[DoesNotReturn]
internal static void ThrowArgumentOutOfRange_TimeSpanTooLong()
{
throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong);
}

[DoesNotReturn]
internal static void ThrowWrongKeyTypeArgumentException<T>(T key, Type targetType)
{
Expand Down Expand Up @@ -657,6 +682,8 @@ private static string GetArgumentName(ExceptionArgument argument)
return "elementType";
case ExceptionArgument.arrayIndex:
return "arrayIndex";
case ExceptionArgument.year:
return "year";
default:
Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum.");
return "";
Expand Down Expand Up @@ -687,6 +714,8 @@ private static string GetResourceString(ExceptionResource resource)
return SR.ArgumentOutOfRange_IndexCountBuffer;
case ExceptionResource.ArgumentOutOfRange_Count:
return SR.ArgumentOutOfRange_Count;
case ExceptionResource.ArgumentOutOfRange_Year:
return SR.ArgumentOutOfRange_Year;
case ExceptionResource.Arg_ArrayPlusOffTooSmall:
return SR.Arg_ArrayPlusOffTooSmall;
case ExceptionResource.NotSupported_ReadOnlyCollection:
Expand Down Expand Up @@ -901,6 +930,7 @@ internal enum ExceptionArgument
endIndex,
elementType,
arrayIndex,
year,
}

//
Expand All @@ -912,6 +942,7 @@ internal enum ExceptionResource
ArgumentOutOfRange_IndexCount,
ArgumentOutOfRange_IndexCountBuffer,
ArgumentOutOfRange_Count,
ArgumentOutOfRange_Year,
Arg_ArrayPlusOffTooSmall,
NotSupported_ReadOnlyCollection,
Arg_RankMultiDimNotSupported,
Expand Down
4 changes: 3 additions & 1 deletion src/System.Private.CoreLib/shared/System/TimeSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Globalization;
using System.Runtime.CompilerServices;

namespace System
{
Expand Down Expand Up @@ -288,13 +289,14 @@ public static TimeSpan FromTicks(long value)
return new TimeSpan(value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static long TimeToTicks(int hour, int minute, int second)
{
// totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31,
// which is less than 2^44, meaning we won't overflow totalSeconds.
long totalSeconds = (long)hour * 3600 + (long)minute * 60 + (long)second;
if (totalSeconds > MaxSeconds || totalSeconds < MinSeconds)
throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong);
ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong();
return totalSeconds * TicksPerSecond;
}

Expand Down