Skip to content
Merged
57 changes: 50 additions & 7 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,19 @@ public static DateOnly ParseExact(string s, [StringSyntax(StringSyntaxAttribute.
/// <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) == ParseFailureKind.None;
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
ParseFailureKind failureKind = TryParseInternal(s, provider, style, out result);
if (failureKind != ParseFailureKind.None)
Comment thread
tannergooding marked this conversation as resolved.
Outdated
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles)
{
Comment thread
tarekgh marked this conversation as resolved.
Outdated
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}

private static ParseFailureKind TryParseInternal(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
Expand Down Expand Up @@ -482,8 +494,19 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan<char> s, IFormatPr
/// <param name="style">A bitwise combination of one or more enumeration values that indicate the permitted format of s.</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 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, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) =>
TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None;
public static bool TryParseExact(ReadOnlySpan<char> s, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
ParseFailureKind failureKind = TryParseExactInternal(s, format, provider, style, out result);
if (failureKind != ParseFailureKind.None)
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles || failureKind == ParseFailureKind.Argument_BadFormatSpecifier)
{
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}
private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0)
Expand Down Expand Up @@ -514,7 +537,9 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, Read
if (!DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult))
{
result = default;
return ParseFailureKind.Format_BadDateOnly;
return dtResult.failure == ParseFailureKind.Argument_BadFormatSpecifier
? ParseFailureKind.Argument_BadFormatSpecifier
: ParseFailureKind.Format_BadDateOnly;
}

if ((dtResult.flags & ParseFlagsDateMask) != 0)
Expand Down Expand Up @@ -546,8 +571,19 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, Read
/// <param name="style">A bitwise combination of enumeration values that defines how to interpret the parsed date. 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, 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, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result) =>
TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None;
public static bool TryParseExact(ReadOnlySpan<char> s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
ParseFailureKind failureKind = TryParseExactInternal(s, formats, provider, style, out result);
if (failureKind != ParseFailureKind.None)
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles || failureKind == ParseFailureKind.Argument_BadFormatSpecifier)
{
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}

private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateOnly result)
{
Expand All @@ -558,6 +594,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, stri
}

DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
ParseFailureKind lastFailure = ParseFailureKind.Format_BadDateOnly;

for (int i = 0; i < formats.Length; i++)
{
Expand Down Expand Up @@ -594,10 +631,16 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, stri
result = new DateOnly(DayNumberFromDateTime(dtResult.parsedDate));
return ParseFailureKind.None;
}

// Preserve Argument_BadFormatSpecifier if encountered
if (dtResult.failure == ParseFailureKind.Argument_BadFormatSpecifier)
Comment thread
tarekgh marked this conversation as resolved.
{
lastFailure = ParseFailureKind.Argument_BadFormatSpecifier;
}
}

result = default;
return ParseFailureKind.Format_BadDateOnly;
return lastFailure;
}

/// <summary>
Expand Down
58 changes: 50 additions & 8 deletions src/libraries/System.Private.CoreLib/src/System/TimeOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,19 @@ public static TimeOnly ParseExact(string s, [StringSyntax(StringSyntaxAttribute.
/// <param name="result">When this method returns, contains the TimeOnly value equivalent to the time 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>
/// <inheritdoc cref="ISpanParsable{TSelf}.TryParse(ReadOnlySpan{char}, IFormatProvider?, out TSelf)" />
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) =>
TryParseInternal(s, provider, style, out result) == ParseFailureKind.None;
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
ParseFailureKind failureKind = TryParseInternal(s, provider, style, out result);
if (failureKind != ParseFailureKind.None)
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles)
{
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}
private static ParseFailureKind TryParseInternal(ReadOnlySpan<char> s, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
if ((style & ~DateTimeStyles.AllowWhiteSpaces) != 0)
Expand Down Expand Up @@ -652,8 +663,19 @@ private static ParseFailureKind TryParseInternal(ReadOnlySpan<char> s, IFormatPr
/// <param name="style">A bitwise combination of one or more enumeration values that indicate the permitted format of s.</param>
/// <param name="result">When this method returns, contains the TimeOnly value equivalent to the time 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 time 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, [StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) =>
TryParseExactInternal(s, format, provider, style, out result) == ParseFailureKind.None;
public static bool TryParseExact(ReadOnlySpan<char> s, [StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
ParseFailureKind failureKind = TryParseExactInternal(s, format, provider, style, out result);
if (failureKind != ParseFailureKind.None)
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles || failureKind == ParseFailureKind.Argument_BadFormatSpecifier)
{
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}

private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
Expand Down Expand Up @@ -685,7 +707,9 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, Read
if (!DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, ref dtResult))
{
result = default;
return ParseFailureKind.Format_BadTimeOnly;
return dtResult.failure == ParseFailureKind.Argument_BadFormatSpecifier
? ParseFailureKind.Argument_BadFormatSpecifier
: ParseFailureKind.Format_BadTimeOnly;
}

if ((dtResult.flags & ParseFlagsTimeMask) != 0)
Expand Down Expand Up @@ -716,8 +740,19 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, Read
/// <param name="style">A bitwise combination of enumeration values that defines how to interpret the parsed time. A typical value to specify is None.</param>
/// <param name="result">When this method returns, contains the TimeOnly value equivalent to the time 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 time. 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, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result) =>
TryParseExactInternal(s, formats, provider, style, out result) == ParseFailureKind.None;
public static bool TryParseExact(ReadOnlySpan<char> s, [NotNullWhen(true), StringSyntax(StringSyntaxAttribute.TimeOnlyFormat)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
ParseFailureKind failureKind = TryParseExactInternal(s, formats, provider, style, out result);
if (failureKind != ParseFailureKind.None)
{
if (failureKind == ParseFailureKind.Argument_InvalidDateStyles || failureKind == ParseFailureKind.Argument_BadFormatSpecifier)
{
ThrowOnError(failureKind, s);
}
return false;
}
return true;
}

private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out TimeOnly result)
{
Expand All @@ -728,6 +763,7 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, stri
}

DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
ParseFailureKind lastFailure = ParseFailureKind.Format_BadTimeOnly;

for (int i = 0; i < formats.Length; i++)
{
Expand Down Expand Up @@ -764,10 +800,16 @@ private static ParseFailureKind TryParseExactInternal(ReadOnlySpan<char> s, stri
result = FromDateTime(dtResult.parsedDate);
return ParseFailureKind.None;
}

// Preserve Argument_BadFormatSpecifier if encountered
if (dtResult.failure == ParseFailureKind.Argument_BadFormatSpecifier)
{
lastFailure = ParseFailureKind.Argument_BadFormatSpecifier;
Comment thread
tarekgh marked this conversation as resolved.
Outdated
}
}

result = default;
return ParseFailureKind.Format_BadTimeOnly;
return lastFailure;
}

/// <summary>
Expand Down
Loading