diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs index 7c4a2e342d895..884fdebf8d2fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs @@ -41,47 +41,49 @@ private static bool TryFormatDateTimeG(DateTime value, TimeSpan offset, Span destination, o return false; } + value.GetDate(out int year, out int month, out int day); + value.GetTime(out int hour, out int minute, out int second); + uint dayAbbrev = s_dayAbbreviationsLowercase[(int)value.DayOfWeek]; destination[0] = (byte)dayAbbrev; @@ -32,10 +35,10 @@ private static bool TryFormatDateTimeL(DateTime value, Span destination, o destination[3] = Utf8Constants.Comma; destination[4] = Utf8Constants.Space; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 5); + FormattingHelpers.WriteTwoDecimalDigits((uint)day, destination, 5); destination[7] = Utf8Constants.Space; - uint monthAbbrev = s_monthAbbreviationsLowercase[value.Month - 1]; + uint monthAbbrev = s_monthAbbreviationsLowercase[month - 1]; destination[8] = (byte)monthAbbrev; monthAbbrev >>= 8; destination[9] = (byte)monthAbbrev; @@ -43,16 +46,16 @@ private static bool TryFormatDateTimeL(DateTime value, Span destination, o destination[10] = (byte)monthAbbrev; destination[11] = Utf8Constants.Space; - FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 12); + FormattingHelpers.WriteFourDecimalDigits((uint)year, destination, 12); destination[16] = Utf8Constants.Space; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 17); + FormattingHelpers.WriteTwoDecimalDigits((uint)hour, destination, 17); destination[19] = Utf8Constants.Colon; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 20); + FormattingHelpers.WriteTwoDecimalDigits((uint)minute, destination, 20); destination[22] = Utf8Constants.Colon; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 23); + FormattingHelpers.WriteTwoDecimalDigits((uint)second, destination, 23); destination[25] = Utf8Constants.Space; destination[26] = GMT1Lowercase; diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs index 2bbfcaaee8a57..29b9c2cb3cbb0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs @@ -51,46 +51,52 @@ private static bool TryFormatDateTimeO(DateTime value, TimeSpan offset, Span destination, o return false; } + value.GetDate(out int year, out int month, out int day); + value.GetTime(out int hour, out int minute, out int second); + uint dayAbbrev = s_dayAbbreviations[(int)value.DayOfWeek]; destination[0] = (byte)dayAbbrev; @@ -32,10 +35,10 @@ private static bool TryFormatDateTimeR(DateTime value, Span destination, o destination[3] = Utf8Constants.Comma; destination[4] = Utf8Constants.Space; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 5); + FormattingHelpers.WriteTwoDecimalDigits((uint)day, destination, 5); destination[7] = Utf8Constants.Space; - uint monthAbbrev = s_monthAbbreviations[value.Month - 1]; + uint monthAbbrev = s_monthAbbreviations[month - 1]; destination[8] = (byte)monthAbbrev; monthAbbrev >>= 8; destination[9] = (byte)monthAbbrev; @@ -43,16 +46,16 @@ private static bool TryFormatDateTimeR(DateTime value, Span destination, o destination[10] = (byte)monthAbbrev; destination[11] = Utf8Constants.Space; - FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 12); + FormattingHelpers.WriteFourDecimalDigits((uint)year, destination, 12); destination[16] = Utf8Constants.Space; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 17); + FormattingHelpers.WriteTwoDecimalDigits((uint)hour, destination, 17); destination[19] = Utf8Constants.Colon; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 20); + FormattingHelpers.WriteTwoDecimalDigits((uint)minute, destination, 20); destination[22] = Utf8Constants.Colon; - FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 23); + FormattingHelpers.WriteTwoDecimalDigits((uint)second, destination, 23); destination[25] = Utf8Constants.Space; destination[26] = GMT1; diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs index 134e83697e0e8..fdd37e347039e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs @@ -97,17 +97,17 @@ internal FullSystemTime(long ticks) { DateTime dt = new DateTime(ticks); - int year, month, day; - dt.GetDatePart(out year, out month, out day); + dt.GetDate(out int year, out int month, out int day); + dt.GetTime(out int hour, out int minute, out int second, out int millisecond); systemTime.Year = (ushort)year; systemTime.Month = (ushort)month; systemTime.DayOfWeek = (ushort)dt.DayOfWeek; systemTime.Day = (ushort)day; - systemTime.Hour = (ushort)dt.Hour; - systemTime.Minute = (ushort)dt.Minute; - systemTime.Second = (ushort)dt.Second; - systemTime.Milliseconds = (ushort)dt.Millisecond; + systemTime.Hour = (ushort)hour; + systemTime.Minute = (ushort)minute; + systemTime.Second = (ushort)second; + systemTime.Milliseconds = (ushort)millisecond; hundredNanoSecond = 0; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs index 8452e89c071ef..a03da9563f8b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs @@ -509,7 +509,7 @@ public DateTime AddMinutes(double value) public DateTime AddMonths(int months) { if (months < -120000 || months > 120000) throw new ArgumentOutOfRangeException(nameof(months), SR.ArgumentOutOfRange_DateTimeBadMonths); - GetDatePart(out int y, out int m, out int d); + GetDate(out int y, out int m, out int d); int i = m - 1 + months; if (i >= 0) { @@ -935,10 +935,10 @@ private int GetDatePart(int part) return n - days[m - 1] + 1; } - // Exactly the same as GetDatePart(int part), except computing all of - // year/month/day rather than just one of them. Used when all three + // Exactly the same as GetDatePart, except computing all of + // year/month/day rather than just one of them. Used when all three // are needed rather than redoing the computations for each. - internal void GetDatePart(out int year, out int month, out int day) + internal void GetDate(out int year, out int month, out int day) { long ticks = InternalTicks; // n = number of days since 1/1/0001 @@ -980,6 +980,42 @@ internal void GetDatePart(out int year, out int month, out int day) day = n - days[m - 1] + 1; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void GetTime(out int hour, out int minute, out int second) + { + long n = InternalTicks / TicksPerSecond; + n = Math.DivRem(n, 60, out long m); + second = (int)m; + n = Math.DivRem(n, 60, out m); + minute = (int)m; + hour = (int)(n % 24); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void GetTime(out int hour, out int minute, out int second, out int millisecond) + { + long n = InternalTicks / TicksPerMillisecond; + n = Math.DivRem(n, 1000, out long m); + millisecond = (int)m; + n = Math.DivRem(n, 60, out m); + second = (int)m; + n = Math.DivRem(n, 60, out m); + minute = (int)m; + hour = (int)(n % 24); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void GetTimePrecise(out int hour, out int minute, out int second, out int tick) + { + long n = Math.DivRem(InternalTicks, TicksPerSecond, out long m); + tick = (int)m; + n = Math.DivRem(n, 60, out m); + second = (int)m; + n = Math.DivRem(n, 60, out m); + minute = (int)m; + hour = (int)(n % 24); + } + // Returns the day-of-month part of this DateTime. The returned // value is an integer between 1 and 31. // diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs index 8f8944bba2ff5..1941e75117592 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs @@ -1154,38 +1154,45 @@ private static bool TryFormatO(DateTime dateTime, TimeSpan offset, Span de // Hoist most of the bounds checks on destination. { _ = destination[MinimumBytesNeeded - 1]; } - WriteFourDecimalDigits((uint)dateTime.Year, destination, 0); + dateTime.GetDate(out int year, out int month, out int day); + dateTime.GetTimePrecise(out int hour, out int minute, out int second, out int tick); + + WriteFourDecimalDigits((uint)year, destination, 0); destination[4] = '-'; - WriteTwoDecimalDigits((uint)dateTime.Month, destination, 5); + WriteTwoDecimalDigits((uint)month, destination, 5); destination[7] = '-'; - WriteTwoDecimalDigits((uint)dateTime.Day, destination, 8); + WriteTwoDecimalDigits((uint)day, destination, 8); destination[10] = 'T'; - WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 11); + WriteTwoDecimalDigits((uint)hour, destination, 11); destination[13] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 14); + WriteTwoDecimalDigits((uint)minute, destination, 14); destination[16] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Second, destination, 17); + WriteTwoDecimalDigits((uint)second, destination, 17); destination[19] = '.'; - WriteDigits((uint)((ulong)dateTime.Ticks % (ulong)TimeSpan.TicksPerSecond), destination.Slice(20, 7)); + WriteDigits((uint)tick, destination.Slice(20, 7)); if (kind == DateTimeKind.Local) { + int offsetTotalMinutes = (int)(offset.Ticks / TimeSpan.TicksPerMinute); + char sign; - if (offset < default(TimeSpan) /* a "const" version of TimeSpan.Zero */) + if (offsetTotalMinutes < 0) { sign = '-'; - offset = TimeSpan.FromTicks(-offset.Ticks); + offsetTotalMinutes = -offsetTotalMinutes; } else { sign = '+'; } + int offsetHours = Math.DivRem(offsetTotalMinutes, 60, out int offsetMinutes); + // Writing the value backward allows the JIT to optimize by // performing a single bounds check against buffer. - WriteTwoDecimalDigits((uint)offset.Minutes, destination, 31); + WriteTwoDecimalDigits((uint)offsetMinutes, destination, 31); destination[30] = ':'; - WriteTwoDecimalDigits((uint)offset.Hours, destination, 28); + WriteTwoDecimalDigits((uint)offsetHours, destination, 28); destination[27] = sign; } else if (kind == DateTimeKind.Utc) @@ -1216,7 +1223,8 @@ private static bool TryFormatR(DateTime dateTime, TimeSpan offset, Span de dateTime -= offset; } - dateTime.GetDatePart(out int year, out int month, out int day); + dateTime.GetDate(out int year, out int month, out int day); + dateTime.GetTime(out int hour, out int minute, out int second); string dayAbbrev = InvariantAbbreviatedDayNames[(int)dateTime.DayOfWeek]; Debug.Assert(dayAbbrev.Length == 3); @@ -1237,11 +1245,11 @@ private static bool TryFormatR(DateTime dateTime, TimeSpan offset, Span de destination[11] = ' '; WriteFourDecimalDigits((uint)year, destination, 12); destination[16] = ' '; - WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 17); + WriteTwoDecimalDigits((uint)hour, destination, 17); destination[19] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 20); + WriteTwoDecimalDigits((uint)minute, destination, 20); destination[22] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Second, destination, 23); + WriteTwoDecimalDigits((uint)second, destination, 23); destination[25] = ' '; destination[26] = 'G'; destination[27] = 'M'; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs index 113fec1a7d6c2..459f4a74022f1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs @@ -400,7 +400,8 @@ private bool LunarToGregorian(int lunarYear, int lunarMonth, int lunarDate, out private DateTime LunarToTime(DateTime time, int year, int month, int day) { LunarToGregorian(year, month, day, out int gy, out int gm, out int gd); - return GregorianCalendar.GetDefaultInstance().ToDateTime(gy, gm, gd, time.Hour, time.Minute, time.Second, time.Millisecond); + time.GetTime(out int hour, out int minute, out int second, out int millisecond); + return GregorianCalendar.GetDefaultInstance().ToDateTime(gy, gm, gd, hour, minute, second, millisecond); } private void TimeToLunar(DateTime time, out int year, out int month, out int day) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs index 6767b9a26a293..d0b83ccec812f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs @@ -145,7 +145,7 @@ public override DateTime AddMonths(DateTime time, int months) SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); } - time.GetDatePart(out int y, out int m, out int d); + time.GetDate(out int y, out int m, out int d); int i = m - 1 + months; if (i >= 0) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/HebrewCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/HebrewCalendar.cs index 477c1ed8d93c9..e2d8e72140e28 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/HebrewCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/HebrewCalendar.cs @@ -449,7 +449,7 @@ internal virtual int GetDatePart(long ticks, int part) DateTime time = new DateTime(ticks); // Save the Gregorian date values. - time.GetDatePart(out gregorianYear, out gregorianMonth, out gregorianDay); + time.GetDate(out gregorianYear, out gregorianMonth, out gregorianDay); DateBuffer lunarDate = new DateBuffer(); // lunar month and day for Jan 1 diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/UmAlQuraCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/UmAlQuraCalendar.cs index ae5820841e48c..05e258faafd3a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/UmAlQuraCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/UmAlQuraCalendar.cs @@ -282,7 +282,7 @@ private static void ConvertHijriToGregorian(int HijriYear, int HijriMonth, int H } dt = dt.AddDays(nDays); - dt.GetDatePart(out yg, out mg, out dg); + dt.GetDate(out yg, out mg, out dg); } private static long GetAbsoluteDateUmAlQura(int year, int month, int day) diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs index 7365549e97524..df3d3ce5060f2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.AdjustmentRule.cs @@ -119,8 +119,8 @@ internal static AdjustmentRule CreateAdjustmentRule( // internal bool IsStartDateMarkerForBeginningOfYear() => !NoDaylightTransitions && - DaylightTransitionStart.Month == 1 && DaylightTransitionStart.Day == 1 && DaylightTransitionStart.TimeOfDay.Hour == 0 && - DaylightTransitionStart.TimeOfDay.Minute == 0 && DaylightTransitionStart.TimeOfDay.Second == 0 && + DaylightTransitionStart.Month == 1 && DaylightTransitionStart.Day == 1 && + DaylightTransitionStart.TimeOfDay.TimeOfDay.Ticks < TimeSpan.TicksPerSecond && // < 12:00:01 AM _dateStart.Year == _dateEnd.Year; // @@ -129,8 +129,8 @@ internal bool IsStartDateMarkerForBeginningOfYear() => // internal bool IsEndDateMarkerForEndOfYear() => !NoDaylightTransitions && - DaylightTransitionEnd.Month == 1 && DaylightTransitionEnd.Day == 1 && DaylightTransitionEnd.TimeOfDay.Hour == 0 && - DaylightTransitionEnd.TimeOfDay.Minute == 0 && DaylightTransitionEnd.TimeOfDay.Second == 0 && + DaylightTransitionEnd.Month == 1 && DaylightTransitionEnd.Day == 1 && + DaylightTransitionEnd.TimeOfDay.TimeOfDay.Ticks < TimeSpan.TicksPerSecond && // < 12:00:01 AM _dateStart.Year == _dateEnd.Year; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.TransitionTime.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.TransitionTime.cs index 141b621f5cfa8..4d1a93e7ce4e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.TransitionTime.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.TransitionTime.cs @@ -99,7 +99,7 @@ private static void ValidateTransitionTime(DateTime timeOfDay, int month, int we throw new ArgumentOutOfRangeException(nameof(dayOfWeek), SR.ArgumentOutOfRange_DayOfWeek); } - timeOfDay.GetDatePart(out int timeOfDayYear, out int timeOfDayMonth, out int timeOfDayDay); + timeOfDay.GetDate(out int timeOfDayYear, out int timeOfDayMonth, out int timeOfDayDay); if (timeOfDayYear != 1 || timeOfDayMonth != 1 || timeOfDayDay != 1 || (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0)) { throw new ArgumentException(SR.Argument_DateTimeHasTicks, nameof(timeOfDay)); diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs index 9aad352304dc3..af68566a1964b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs @@ -1751,17 +1751,24 @@ internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, o internal static DateTime TransitionTimeToDateTime(int year, TransitionTime transitionTime) { DateTime value; - DateTime timeOfDay = transitionTime.TimeOfDay; + TimeSpan timeOfDay = transitionTime.TimeOfDay.TimeOfDay; if (transitionTime.IsFixedDateRule) { // create a DateTime from the passed in year and the properties on the transitionTime + int day = transitionTime.Day; // if the day is out of range for the month then use the last day of the month - int day = DateTime.DaysInMonth(year, transitionTime.Month); + if (day > 28) + { + int daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); + if (day > daysInMonth) + { + day = daysInMonth; + } + } - value = new DateTime(year, transitionTime.Month, (day < transitionTime.Day) ? day : transitionTime.Day, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + value = new DateTime(year, transitionTime.Month, day) + timeOfDay; } else { @@ -1770,8 +1777,7 @@ internal static DateTime TransitionTimeToDateTime(int year, TransitionTime trans // // Get the (transitionTime.Week)th Sunday. // - value = new DateTime(year, transitionTime.Month, 1, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + value = new DateTime(year, transitionTime.Month, 1) + timeOfDay; int dayOfWeek = (int)value.DayOfWeek; int delta = (int)transitionTime.DayOfWeek - dayOfWeek; @@ -1792,8 +1798,7 @@ internal static DateTime TransitionTimeToDateTime(int year, TransitionTime trans // If TransitionWeek is greater than 4, we will get the last week. // int daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); - value = new DateTime(year, transitionTime.Month, daysInMonth, - timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + value = new DateTime(year, transitionTime.Month, daysInMonth) + timeOfDay; // This is the day of week for the last day of the month. int dayOfWeek = (int)value.DayOfWeek;