Skip to content
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
44 changes: 22 additions & 22 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ public readonly struct DateOnly
ISpanParsable<DateOnly>,
IUtf8SpanFormattable
{
private readonly int _dayNumber;
private readonly uint _dayNumber;

// Maps to Jan 1st year 1
private const int MinDayNumber = 0;

// Maps to December 31 year 9999.
private const int MaxDayNumber = DateTime.DaysTo10000 - 1;

private static int DayNumberFromDateTime(DateTime dt) => (int)((ulong)dt.Ticks / TimeSpan.TicksPerDay);
private static uint DayNumberFromDateTime(DateTime dt) => (uint)((ulong)dt.Ticks / TimeSpan.TicksPerDay);

internal DateTime GetEquivalentDateTime() => DateTime.UnsafeCreate(_dayNumber * TimeSpan.TicksPerDay);

private DateOnly(int dayNumber)
private DateOnly(uint dayNumber)
{
Debug.Assert((uint)dayNumber <= MaxDayNumber);
Debug.Assert(dayNumber <= MaxDayNumber);
_dayNumber = dayNumber;
}

Expand Down Expand Up @@ -77,7 +77,7 @@ public static DateOnly FromDayNumber(int dayNumber)
ThrowHelper.ThrowArgumentOutOfRange_DayNumber(dayNumber);
}

return new DateOnly(dayNumber);
return new DateOnly((uint)dayNumber);
}

/// <summary>
Expand All @@ -98,7 +98,7 @@ public static DateOnly FromDayNumber(int dayNumber)
/// <summary>
/// Gets the day of the week represented by this instance.
/// </summary>
public DayOfWeek DayOfWeek => (DayOfWeek)(((uint)_dayNumber + 1) % 7);
public DayOfWeek DayOfWeek => (DayOfWeek)((_dayNumber + 1) % 7);

/// <summary>
/// Gets the day of the year represented by this instance.
Expand All @@ -108,7 +108,7 @@ public static DateOnly FromDayNumber(int dayNumber)
/// <summary>
/// Gets the number of days since January 1, 0001 in the Proleptic Gregorian calendar represented by this instance.
/// </summary>
public int DayNumber => _dayNumber;
public int DayNumber => (int)_dayNumber;

/// <summary>
/// Adds the specified number of days to the value of this instance.
Expand All @@ -120,8 +120,8 @@ public static DateOnly FromDayNumber(int dayNumber)
/// </exception>
public DateOnly AddDays(int value)
{
int newDayNumber = _dayNumber + value;
if ((uint)newDayNumber > MaxDayNumber)
uint newDayNumber = _dayNumber + (uint)value;
if (newDayNumber > MaxDayNumber)
{
ThrowOutOfRange();
}
Expand Down Expand Up @@ -214,15 +214,15 @@ public void Deconstruct(out int year, out int month, out int day)
/// </summary>
/// <param name="time">The time of the day.</param>
/// <returns>The DateTime instance composed of the date of the current DateOnly instance and the time specified by the input time.</returns>
public DateTime ToDateTime(TimeOnly time) => new DateTime(_dayNumber * TimeSpan.TicksPerDay + time.Ticks);
public DateTime ToDateTime(TimeOnly time) => DateTime.UnsafeCreate(_dayNumber * TimeSpan.TicksPerDay + time.Ticks);

/// <summary>
/// Returns a DateTime instance with the specified input kind that is set to the date of this DateOnly instance and the time of specified input time.
/// </summary>
/// <param name="time">The time of the day.</param>
/// <param name="kind">One of the enumeration values that indicates whether ticks specifies a local time, Coordinated Universal Time (UTC), or neither.</param>
/// <returns>The DateTime instance composed of the date of the current DateOnly instance and the time specified by the input time.</returns>
public DateTime ToDateTime(TimeOnly time, DateTimeKind kind) => new DateTime(_dayNumber * TimeSpan.TicksPerDay + time.Ticks, kind);
public DateTime ToDateTime(TimeOnly time, DateTimeKind kind) => DateTime.SpecifyKind(ToDateTime(time), kind);

/// <summary>
/// Returns a DateOnly instance that is set to the date part of the specified dateTime.
Expand Down Expand Up @@ -272,7 +272,7 @@ public int CompareTo(object? value)
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer hash code.</returns>
public override int GetHashCode() => _dayNumber;
public override int GetHashCode() => (int)_dayNumber;

private const ParseFlags ParseFlagsDateMask = ParseFlags.HaveHour | ParseFlags.HaveMinute | ParseFlags.HaveSecond | ParseFlags.HaveTime | ParseFlags.TimeZoneUsed |
ParseFlags.TimeZoneUtc | ParseFlags.CaptureOffset | ParseFlags.UtcSortPattern;
Expand Down Expand Up @@ -498,12 +498,12 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, Read
{
case 'o':
format = OFormat;
provider = CultureInfo.InvariantCulture.DateTimeFormat;
provider = DateTimeFormat.InvariantFormatInfo;
break;

case 'r':
format = RFormat;
provider = CultureInfo.InvariantCulture.DateTimeFormat;
provider = DateTimeFormat.InvariantFormatInfo;
break;
}
}
Expand Down Expand Up @@ -575,12 +575,12 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, stri
{
case 'o':
format = OFormat;
dtfiToUse = CultureInfo.InvariantCulture.DateTimeFormat;
dtfiToUse = DateTimeFormat.InvariantFormatInfo;
break;

case 'r':
format = RFormat;
dtfiToUse = CultureInfo.InvariantCulture.DateTimeFormat;
dtfiToUse = DateTimeFormat.InvariantFormatInfo;
break;
}
}
Expand Down Expand Up @@ -718,7 +718,7 @@ private static void ThrowOnError(ParseFailureKind result, ReadOnlySpan<char> s)
/// The DateOnly object will be formatted in short form.
/// </summary>
/// <returns>A string that contains the short date string representation of the current DateOnly object.</returns>
public override string ToString() => ToString("d");
public override string ToString() => DateTimeFormat.Format(GetEquivalentDateTime(), "d", null);

/// <summary>
/// Converts the value of the current DateOnly object to its equivalent string representation using the specified format and the formatting conventions of the current culture.
Expand All @@ -732,7 +732,7 @@ private static void ThrowOnError(ParseFailureKind result, ReadOnlySpan<char> s)
/// </summary>
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
/// <returns>A string representation of value of the current DateOnly object as specified by provider.</returns>
public string ToString(IFormatProvider? provider) => ToString("d", provider);
public string ToString(IFormatProvider? provider) => DateTimeFormat.Format(GetEquivalentDateTime(), "d", provider);

/// <summary>
/// Converts the value of the current DateOnly object to its equivalent string representation using the specified culture-specific format information.
Expand All @@ -753,13 +753,13 @@ public string ToString([StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] stri
{
'o' => string.Create(10, this, (destination, value) =>
{
DateTimeFormat.TryFormatDateOnlyO(value.Year, value.Month, value.Day, destination, out int charsWritten);
DateTimeFormat.TryFormatDateOnlyO(value, destination, out int charsWritten);
Debug.Assert(charsWritten == destination.Length);
}),

'r' => string.Create(16, this, (destination, value) =>
{
DateTimeFormat.TryFormatDateOnlyR(value.DayOfWeek, value.Year, value.Month, value.Day, destination, out int charsWritten);
DateTimeFormat.TryFormatDateOnlyR(value, destination, out int charsWritten);
Debug.Assert(charsWritten == destination.Length);
}),

Expand Down Expand Up @@ -801,10 +801,10 @@ private bool TryFormatCore<TChar>(Span<TChar> destination, out int charsWritten,
switch (format[0] | 0x20)
{
case 'o':
return DateTimeFormat.TryFormatDateOnlyO(Year, Month, Day, destination, out charsWritten);
return DateTimeFormat.TryFormatDateOnlyO(this, destination, out charsWritten);

case 'r':
return DateTimeFormat.TryFormatDateOnlyR(DayOfWeek, Year, Month, Day, destination, out charsWritten);
return DateTimeFormat.TryFormatDateOnlyR(this, destination, out charsWritten);

case 'm':
case 'd':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ private static ulong DateToTicks(int year, int month, int day)
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
}

ReadOnlySpan<uint> days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
ReadOnlySpan<uint> days = month > 1 && IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
if ((uint)day > days[month] - days[month - 1])
{
ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,7 @@ public static DateTimeOffset FromUnixTimeSeconds(long seconds)
{
if (seconds < UnixMinSeconds || seconds > UnixMaxSeconds)
{
throw new ArgumentOutOfRangeException(nameof(seconds),
SR.Format(SR.ArgumentOutOfRange_Range, UnixMinSeconds, UnixMaxSeconds));
ThrowHelper.ThrowArgumentOutOfRange_Range(nameof(seconds), seconds, UnixMinSeconds, UnixMaxSeconds);
}

long ticks = seconds * TimeSpan.TicksPerSecond + DateTime.UnixEpochTicks;
Expand All @@ -602,8 +601,7 @@ public static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)

if (milliseconds < MinMilliseconds || milliseconds > MaxMilliseconds)
{
throw new ArgumentOutOfRangeException(nameof(milliseconds),
SR.Format(SR.ArgumentOutOfRange_Range, MinMilliseconds, MaxMilliseconds));
ThrowHelper.ThrowArgumentOutOfRange_Range(nameof(milliseconds), milliseconds, MinMilliseconds, MaxMilliseconds);
}

long ticks = milliseconds * TimeSpan.TicksPerMillisecond + DateTime.UnixEpochTicks;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ internal static bool IsValidCustomTimeOnlyFormat(ReadOnlySpan<char> format, bool
// 012345678901234567890123456789012
// ---------------------------------
// 05:30:45.7680000
internal static unsafe bool TryFormatTimeOnlyO<TChar>(int hour, int minute, int second, long fraction, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
internal static unsafe bool TryFormatTimeOnlyO<TChar>(TimeOnly value, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
{
if (destination.Length < 16)
{
Expand All @@ -1322,6 +1322,7 @@ internal static unsafe bool TryFormatTimeOnlyO<TChar>(int hour, int minute, int
}

charsWritten = 16;
value.ToDateTime().GetTimePrecise(out int hour, out int minute, out int second, out int fraction);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1340,7 +1341,7 @@ internal static unsafe bool TryFormatTimeOnlyO<TChar>(int hour, int minute, int
// 012345678901234567890123456789012
// ---------------------------------
// 05:30:45
internal static unsafe bool TryFormatTimeOnlyR<TChar>(int hour, int minute, int second, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
internal static unsafe bool TryFormatTimeOnlyR<TChar>(TimeOnly value, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
{
if (destination.Length < 8)
{
Expand All @@ -1349,6 +1350,7 @@ internal static unsafe bool TryFormatTimeOnlyR<TChar>(int hour, int minute, int
}

charsWritten = 8;
value.ToDateTime().GetTime(out int hour, out int minute, out int second);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1366,7 +1368,7 @@ internal static unsafe bool TryFormatTimeOnlyR<TChar>(int hour, int minute, int
// 012345678901234567890123456789012
// ---------------------------------
// 2017-06-12
internal static unsafe bool TryFormatDateOnlyO<TChar>(int year, int month, int day, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
internal static unsafe bool TryFormatDateOnlyO<TChar>(DateOnly value, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
{
if (destination.Length < 10)
{
Expand All @@ -1375,6 +1377,7 @@ internal static unsafe bool TryFormatDateOnlyO<TChar>(int year, int month, int d
}

charsWritten = 10;
(int year, int month, int day) = value;

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1392,7 +1395,7 @@ internal static unsafe bool TryFormatDateOnlyO<TChar>(int year, int month, int d
// 01234567890123456789012345678
// -----------------------------
// Tue, 03 Jan 2017
internal static unsafe bool TryFormatDateOnlyR<TChar>(DayOfWeek dayOfWeek, int year, int month, int day, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
internal static unsafe bool TryFormatDateOnlyR<TChar>(DateOnly value, Span<TChar> destination, out int charsWritten) where TChar : unmanaged, IUtfChar<TChar>
{
if (destination.Length < 16)
{
Expand All @@ -1401,9 +1404,9 @@ internal static unsafe bool TryFormatDateOnlyR<TChar>(DayOfWeek dayOfWeek, int y
}

charsWritten = 16;
(int year, int month, int day) = value;

Debug.Assert((uint)dayOfWeek < 7);
string dayAbbrev = s_invariantAbbreviatedDayNames[(int)dayOfWeek];
string dayAbbrev = s_invariantAbbreviatedDayNames[(int)value.DayOfWeek];
Debug.Assert(dayAbbrev.Length == 3);

string monthAbbrev = s_invariantAbbreviatedMonthNames[month - 1];
Expand Down Expand Up @@ -1467,7 +1470,6 @@ internal static unsafe bool TryFormatO<TChar>(DateTime dateTime, TimeSpan offset
charsWritten = charsRequired;

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);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1477,6 +1479,7 @@ internal static unsafe bool TryFormatO<TChar>(DateTime dateTime, TimeSpan offset
dest[7] = TChar.CastFrom('-');
Number.WriteTwoDigits((uint)day, dest + 8);
dest[10] = TChar.CastFrom('T');
dateTime.GetTimePrecise(out int hour, out int minute, out int second, out int tick);
Number.WriteTwoDigits((uint)hour, dest + 11);
dest[13] = TChar.CastFrom(':');
Number.WriteTwoDigits((uint)minute, dest + 14);
Expand Down Expand Up @@ -1527,7 +1530,6 @@ internal static unsafe bool TryFormatS<TChar>(DateTime dateTime, Span<TChar> des
charsWritten = FormatSLength;

dateTime.GetDate(out int year, out int month, out int day);
dateTime.GetTime(out int hour, out int minute, out int second);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1537,6 +1539,7 @@ internal static unsafe bool TryFormatS<TChar>(DateTime dateTime, Span<TChar> des
dest[7] = TChar.CastFrom('-');
Number.WriteTwoDigits((uint)day, dest + 8);
dest[10] = TChar.CastFrom('T');
dateTime.GetTime(out int hour, out int minute, out int second);
Number.WriteTwoDigits((uint)hour, dest + 11);
dest[13] = TChar.CastFrom(':');
Number.WriteTwoDigits((uint)minute, dest + 14);
Expand Down Expand Up @@ -1567,7 +1570,6 @@ internal static unsafe bool TryFormatu<TChar>(DateTime dateTime, TimeSpan offset
}

dateTime.GetDate(out int year, out int month, out int day);
dateTime.GetTime(out int hour, out int minute, out int second);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1577,6 +1579,7 @@ internal static unsafe bool TryFormatu<TChar>(DateTime dateTime, TimeSpan offset
dest[7] = TChar.CastFrom('-');
Number.WriteTwoDigits((uint)day, dest + 8);
dest[10] = TChar.CastFrom(' ');
dateTime.GetTime(out int hour, out int minute, out int second);
Number.WriteTwoDigits((uint)hour, dest + 11);
dest[13] = TChar.CastFrom(':');
Number.WriteTwoDigits((uint)minute, dest + 14);
Expand Down Expand Up @@ -1609,7 +1612,6 @@ internal static unsafe bool TryFormatR<TChar>(DateTime dateTime, TimeSpan offset
}

dateTime.GetDate(out int year, out int month, out int day);
dateTime.GetTime(out int hour, out int minute, out int second);

string dayAbbrev = s_invariantAbbreviatedDayNames[(int)dateTime.DayOfWeek];
Debug.Assert(dayAbbrev.Length == 3);
Expand All @@ -1634,6 +1636,7 @@ internal static unsafe bool TryFormatR<TChar>(DateTime dateTime, TimeSpan offset
dest[11] = TChar.CastFrom(' ');
Number.WriteFourDigits((uint)year, dest + 12);
dest[16] = TChar.CastFrom(' ');
dateTime.GetTime(out int hour, out int minute, out int second);
Number.WriteTwoDigits((uint)hour, dest + 17);
dest[19] = TChar.CastFrom(':');
Number.WriteTwoDigits((uint)minute, dest + 20);
Expand Down Expand Up @@ -1674,7 +1677,6 @@ internal static unsafe bool TryFormatInvariantG<TChar>(DateTime value, TimeSpan
bytesWritten = bytesRequired;

value.GetDate(out int year, out int month, out int day);
value.GetTime(out int hour, out int minute, out int second);

fixed (TChar* dest = &MemoryMarshal.GetReference(destination))
{
Expand All @@ -1685,6 +1687,7 @@ internal static unsafe bool TryFormatInvariantG<TChar>(DateTime value, TimeSpan
Number.WriteFourDigits((uint)year, dest + 6);
dest[10] = TChar.CastFrom(' ');

value.GetTime(out int hour, out int minute, out int second);
Number.WriteTwoDigits((uint)hour, dest + 11);
dest[13] = TChar.CastFrom(':');
Number.WriteTwoDigits((uint)minute, dest + 14);
Expand Down
Loading
Loading