diff --git a/src/System.Private.CoreLib/shared/System/DateTime.cs b/src/System.Private.CoreLib/shared/System/DateTime.cs index 2317221b5a78..cc621dae21a8 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.cs @@ -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 ((uint)hour >= 24 || (uint)minute >= 60 || (uint)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 @@ -1182,13 +1188,14 @@ 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); + return (year & 3) == 0 && ((year & 15) == 0 || (year % 25) != 0); } // Constructs a DateTime from a string. The string must specify a diff --git a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs index e79b785e66e3..c8ccd4fb93e8 100644 --- a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -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 key, Type targetType) { @@ -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 ""; @@ -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: @@ -901,6 +930,7 @@ internal enum ExceptionArgument endIndex, elementType, arrayIndex, + year, } // @@ -912,6 +942,7 @@ internal enum ExceptionResource ArgumentOutOfRange_IndexCount, ArgumentOutOfRange_IndexCountBuffer, ArgumentOutOfRange_Count, + ArgumentOutOfRange_Year, Arg_ArrayPlusOffTooSmall, NotSupported_ReadOnlyCollection, Arg_RankMultiDimNotSupported, diff --git a/src/System.Private.CoreLib/shared/System/TimeSpan.cs b/src/System.Private.CoreLib/shared/System/TimeSpan.cs index f08b9048d750..5d5af9a93ba1 100644 --- a/src/System.Private.CoreLib/shared/System/TimeSpan.cs +++ b/src/System.Private.CoreLib/shared/System/TimeSpan.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Globalization; +using System.Runtime.CompilerServices; namespace System { @@ -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; }