Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
121 changes: 50 additions & 71 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@

namespace System
{
internal enum ParseOperationResult
{
Success,
WrongStyles,
ParseFailure,
WrongParts,
BadFormatSpecifier
}

/// <summary>
/// Represents dates with values ranging from January 1, 0001 Anno Domini (Common Era) through December 31, 9999 A.D. (C.E.) in the Gregorian calendar.
/// </summary>
Expand Down Expand Up @@ -266,17 +257,10 @@ public int CompareTo(object? value)
/// <returns>An object that is equivalent to the date contained in s, as specified by provider and styles.</returns>
public static DateOnly Parse(ReadOnlySpan<char> s, IFormatProvider? provider = default, DateTimeStyles style = DateTimeStyles.None)
{
ParseOperationResult result = TryParseInternal(s, provider, style, out DateOnly dateOnly);
if (result != ParseOperationResult.Success)
ParseFailureKind result = TryParseInternal(s, provider, style, out DateOnly dateOnly);
if (result != ParseFailureKind.None)
{
switch (result)
{
case ParseOperationResult.WrongStyles: throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style));
case ParseOperationResult.ParseFailure: throw new FormatException(SR.Format(SR.Format_BadDateOnly, s.ToString()));
default:
Debug.Assert(result == ParseOperationResult.WrongParts);
throw new FormatException(SR.Format(SR.Format_DateTimeOnlyContainsNoneDateParts, s.ToString(), nameof(DateOnly)));
}
ThrowOnError(result, s);
}

return dateOnly;
Expand All @@ -296,19 +280,11 @@ public static DateOnly Parse(ReadOnlySpan<char> s, IFormatProvider? provider = d
/// <returns>An object that is equivalent to the date contained in s, as specified by format, provider, and style.</returns>
public static DateOnly ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider = default, DateTimeStyles style = DateTimeStyles.None)
{
ParseOperationResult result = TryParseExactInternal(s, format, provider, style, out DateOnly dateOnly);
ParseFailureKind result = TryParseExactInternal(s, format, provider, style, out DateOnly dateOnly);

if (result != ParseOperationResult.Success)
if (result != ParseFailureKind.None)
{
switch (result)
{
case ParseOperationResult.WrongStyles: throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style));
case ParseOperationResult.ParseFailure: throw new FormatException(SR.Format(SR.Format_BadDateOnly, s.ToString()));
default:
Debug.Assert(result == ParseOperationResult.WrongParts);
throw new FormatException(SR.Format(SR.Format_DateTimeOnlyContainsNoneDateParts, s.ToString(), nameof(DateOnly)));

}
ThrowOnError(result, s);
}

return dateOnly;
Expand All @@ -334,17 +310,10 @@ public static DateOnly ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> forma
/// <returns>An object that is equivalent to the date contained in s, as specified by format, provider, and style.</returns>
public static DateOnly ParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider? provider, DateTimeStyles style = DateTimeStyles.None)
{
ParseOperationResult result = TryParseExactInternal(s, formats, provider, style, out DateOnly dateOnly);
if (result != ParseOperationResult.Success)
ParseFailureKind result = TryParseExactInternal(s, formats, provider, style, out DateOnly dateOnly);
if (result != ParseFailureKind.None)
{
switch (result)
{
case ParseOperationResult.WrongStyles: throw new ArgumentException(SR.Argument_InvalidDateStyles, nameof(style));
case ParseOperationResult.ParseFailure: throw new FormatException(SR.Format(SR.Format_BadDateOnly, s.ToString()));
default:
Debug.Assert(result == ParseOperationResult.BadFormatSpecifier);
throw new FormatException(SR.Argument_BadFormatSpecifier);
}
ThrowOnError(result, s);
}

return dateOnly;
Expand Down Expand Up @@ -435,14 +404,14 @@ public static DateOnly ParseExact(string s, string[] formats, IFormatProvider? p
/// <param name="style">A bitwise combination of enumeration values that indicates the permitted format of s. A typical value to specify is None.</param>
/// <param name="result">When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is empty string, or does not contain a valid string representation of a date. This parameter is passed uninitialized.</param>
/// <returns>true if the s parameter was converted successfully; otherwise, false.</returns>
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) => TryParseInternal(s, provider, style, out result) == ParseOperationResult.Success;
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) => TryParseInternal(s, provider, style, out result) == ParseFailureKind.None;

private static ParseOperationResult TryParseInternal(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
private static ParseFailureKind TryParseInternal(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0)
{
result = default;
return ParseOperationResult.WrongStyles;
return ParseFailureKind.FormatWithParameter;
}

DateTimeResult dtResult = default;
Expand All @@ -451,17 +420,17 @@ private static ParseOperationResult TryParseInternal(ReadOnlySpan<char> s, IForm
if (!DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult))
{
result = default;
return ParseOperationResult.ParseFailure;
return ParseFailureKind.FormatWithOriginalDateTime;
}

if ((dtResult.flags & ParseFlagsDateMask) != 0)
{
result = default;
return ParseOperationResult.WrongParts;
return ParseFailureKind.WrongParts;
}

result = new DateOnly(DayNumberFromDateTime(dtResult.parsedDate));
return ParseOperationResult.Success;
return ParseFailureKind.None;
}

/// <summary>
Expand All @@ -485,13 +454,13 @@ private static ParseOperationResult TryParseInternal(ReadOnlySpan<char> s, IForm
/// <param name="result">When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s is empty string, or does not contain a date that correspond to the pattern specified in format. This parameter is passed uninitialized.</param>
/// <returns>true if s was converted successfully; otherwise, false.</returns>
public static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) =>
TryParseExactInternal(s, format, provider, style, out result) == ParseOperationResult.Success;
private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None;
private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0)
{
result = default;
return ParseOperationResult.WrongStyles;
return ParseFailureKind.FormatWithParameter;
}

if (format.Length == 1)
Expand All @@ -518,18 +487,18 @@ private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s,
if (!DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult))
{
result = default;
return ParseOperationResult.ParseFailure;
return ParseFailureKind.FormatWithOriginalDateTime;
}

if ((dtResult.flags & ParseFlagsDateMask) != 0)
{
result = default;
return ParseOperationResult.WrongParts;
return ParseFailureKind.WrongParts;
}

result = new DateOnly(DayNumberFromDateTime(dtResult.parsedDate));

return ParseOperationResult.Success;
return ParseFailureKind.None;
}

/// <summary>
Expand All @@ -551,14 +520,14 @@ private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s,
/// <param name="result">When this method returns, contains the DateOnly value equivalent to the date contained in s, if the conversion succeeded, or MinValue if the conversion failed. The conversion fails if the s parameter is Empty, or does not contain a valid string representation of a date. This parameter is passed uninitialized.</param>
/// <returns>true if the s parameter was converted successfully; otherwise, false.</returns>
public static bool TryParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) =>
TryParseExactInternal(s, formats, provider, style, out result) == ParseOperationResult.Success;
TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None;

private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s, string[] formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, string[] formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0 || formats == null)
{
result = default;
return ParseOperationResult.WrongStyles;
return ParseFailureKind.FormatWithParameter;
}

DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
Expand All @@ -570,7 +539,7 @@ private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s,
if (string.IsNullOrEmpty(format))
{
result = default;
return ParseOperationResult.BadFormatSpecifier;
return ParseFailureKind.FormatWithFormatSpecifier;
}

if (format.Length == 1)
Expand Down Expand Up @@ -598,12 +567,12 @@ private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s,
if (DateTimeParse.TryParseExact(s, format, dtfiToUse, style, ref dtResult) && ((dtResult.flags & ParseFlagsDateMask) == 0))
{
result = new DateOnly(DayNumberFromDateTime(dtResult.parsedDate));
return ParseOperationResult.Success;
return ParseFailureKind.None;
}
}

result = default;
return ParseOperationResult.ParseFailure;
return ParseFailureKind.FormatWithOriginalDateTime;
}

/// <summary>
Expand All @@ -624,9 +593,9 @@ private static ParseOperationResult TryParseExactInternal(ReadOnlySpan<char> s,
/// <returns>true if the s parameter was converted successfully; otherwise, false.</returns>
public static bool TryParse(string s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
result = default;
if (s == null)
{
result = default;
return false;
}

Expand Down Expand Up @@ -693,6 +662,20 @@ public static bool TryParseExact(string s, string[] formats, IFormatProvider? pr
return TryParseExact(s.AsSpan(), formats, provider, style, out result);
}

private static void ThrowOnError(ParseFailureKind result, ReadOnlySpan<char> s)
{
Debug.Assert(result != ParseFailureKind.None);
switch (result)
{
case ParseFailureKind.FormatWithParameter: throw new ArgumentException(SR.Argument_InvalidDateStyles, "style");
case ParseFailureKind.FormatWithOriginalDateTime: throw new FormatException(SR.Format(SR.Format_BadDateOnly, s.ToString()));
case ParseFailureKind.FormatWithFormatSpecifier: throw new FormatException(SR.Argument_BadFormatSpecifier);
default:
Debug.Assert(result == ParseFailureKind.WrongParts);
throw new FormatException(SR.Format(SR.Format_DateTimeOnlyContainsNoneDateParts, s.ToString(), nameof(DateOnly)));
}
}

/// <summary>
/// Converts the value of the current DateOnly object to its equivalent long date string representation.
/// </summary>
Expand Down Expand Up @@ -745,23 +728,19 @@ public string ToString(string? format, IFormatProvider? provider)
{
case 'o':
case 'O':
return string.Create(10, this, (destination, value) =>
{
return string.Create(10, this, (destination, value) =>
{
bool b = DateTimeFormat.TryFormatDateOnlyO(value.Year, value.Month, value.Day, destination);
Debug.Assert(b);
});
}
bool b = DateTimeFormat.TryFormatDateOnlyO(value.Year, value.Month, value.Day, destination);
Debug.Assert(b);
});

case 'r':
case 'R':
return string.Create(16, this, (destination, value) =>
{
return string.Create(16, this, (destination, value) =>
{
bool b = DateTimeFormat.TryFormatDateOnlyR(value.DayOfWeek, value.Year, value.Month, value.Day, destination);
Debug.Assert(b);
});
}
bool b = DateTimeFormat.TryFormatDateOnlyR(value.DayOfWeek, value.Year, value.Month, value.Day, destination);
Debug.Assert(b);
});

case 'm':
case 'M':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5903,6 +5903,7 @@ internal enum ParseFailureKind
FormatWithFormatSpecifier = 5,
FormatWithOriginalDateTimeAndParameter = 6,
FormatBadDateTimeCalendar = 7, // FormatException when ArgumentOutOfRange is thrown by a Calendar.TryToDateTime().
WrongParts = 8, // DateOnly and TimeOnly specific value. Unrelated date parts when parsing DateOnly or Unrelated time parts when parsing TimeOnly
}

[Flags]
Expand Down
Loading