Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 30, 2026

Description

This PR fixes a consistency issue where DateOnly.TryParse/TryParseExact and TimeOnly.TryParse/TryParseExact methods were returning false for invalid DateTimeStyles parameters instead of throwing an ArgumentException, which is inconsistent with other TryParse APIs in .NET.

Additionally, this PR ensures that Argument_BadFormatSpecifier errors from the underlying DateTimeParse.TryParseExact are properly detected and returned immediately, rather than being masked as format errors or deferred until after all formats are tried.

Changes Made

  • Modified DateOnly.TryParse and all DateOnly.TryParseExact overloads to throw ArgumentException for invalid DateTimeStyles
  • Modified TimeOnly.TryParse and all TimeOnly.TryParseExact overloads to throw ArgumentException for invalid DateTimeStyles
  • Updated existing tests to expect exceptions instead of false returns
  • Added comprehensive tests for all TryParseExact variants with invalid styles
  • All tests use AssertExtensions.Throws with the "style" parameter name for consistency
  • Removed unnecessary Argument_BadFormatSpecifier check from TryParse methods (only needed in TryParseExact)
  • Fixed TryParseExactInternal methods to check dtResult.failure and return immediately when Argument_BadFormatSpecifier is encountered from DateTimeParse.TryParseExact
  • Added tests for invalid format specifiers (null/empty formats in format arrays)
  • All 69,639 tests passing (0 failures, 0 errors)

Breaking Change

Yes. This is a breaking change as code that previously received false will now throw an exception. However, this aligns with the behavior of other TryParse APIs and improves consistency. The scenarios affected are those that could never succeed (invalid argument combinations), so the impact should be minimal.

Examples:

// Before: returned false
DateOnly.TryParseExact("2064-07-01", "yyyy-MM-dd", null, DateTimeStyles.AssumeUniversal, out var result);

// After: throws ArgumentException with ParamName = "style"

// Before: returned false  
DateOnly.TryParseExact("2064-07-01", new[] { "", "yyyy-MM-dd" }, null, DateTimeStyles.None, out var result);

// After: throws FormatException

Files Modified

  • src/libraries/System.Private.CoreLib/src/System/DateOnly.cs - Implementation changes
  • src/libraries/System.Private.CoreLib/src/System/TimeOnly.cs - Implementation changes
  • src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateOnlyTests.cs - Test updates
  • src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeOnlyTests.cs - Test updates
Original prompt

This section details on the original issue you should resolve

<issue_title>DateOnly TryParseExact fails to parse basic ISO-8601 input</issue_title>
<issue_description>### Description

Ive had to hunt down a bug, where I swapped a DateTime.TryParseExact with a DateOnly.TryParseExact and had to find out, DateOnly refuses to work with DateTimeStyles.AssumeUniversal.

DateOnly.TryParseExact behaves inconsistently compared to DateTime and DateTimeOffset when parsing the same ISO-8601 formatted date string and DateTimeStyles.AssumeUniversal is supplied.

This is either a bug, or a highly misleading API, since (as far as I could find) nothing in the documentation indicates that DateTimeStyles.AssumeUniversal is invalid or unsupported for DateOnly.

Reproduction Steps

using System;
using System.Globalization;

Console.WriteLine("DateTime:");
Console.WriteLine(DateTime.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out _));
Console.WriteLine(DateTime.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _));
		
Console.WriteLine("\nDateTimeOffset:");
Console.WriteLine(DateTimeOffset.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out _));
Console.WriteLine(DateTimeOffset.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _));
		
Console.WriteLine("\nDateOnly:");
Console.WriteLine(DateOnly.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out _));
Console.WriteLine(DateOnly.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _));

// Output:
// DateTime:
// True
// True

// DateTimeOffset:
// True
// True

// DateOnly:
// False
// True

Expected behavior

Return true, parsing the input correctly without failure.
Or alternatively, as others suggested, throw a clear exception.

Actual behavior

Return false, whereas similar (if not under the hood identical) APIs for DateTime and DateTimeOffset return true.

Regression?

No response

Known Workarounds

Use DateTimeStyles.None instead

Configuration

Target Framework: NET 10
SDK: 10.0.102
Arch.: x64

Other information

No response</issue_description>

<agent_instructions>We need to fix all DateOnly and TimeOnly TryParse and TryParseExact methods to throw exception when passing invalid DateTimeStyle parameter instead of just return false. Ensure adding a new tests cover the fix and if possible, file a new breading change issue in https://github.com/dotnet/docs/issues using the breaking change template.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@tarekgh This is not a bug. `DateOnly` and `TimeOnly` are intentionally designed to be independent of time zones. They represent abstract date and time values that are not associated with any region or time zone.

The official documentation clearly explains this behavior:

https://learn.microsoft.com/en-us/dotnet/standard/datetime/how-to-use-dateonly-timeonly#the-dateonly-structure

The DateTime structure may roll into the previous or next day when adjusted for a time zone. DateOnly cannot be offset by a time zone and always represents the exact date that was set.

If you have any suggestions to improve any docs, please feel free to submit issue or a PR in https://github.com/dotnet/dotnet-api-docs. Thanks for your report.

@tannergooding @tarekgh I believe the supposed bug here is that unlike other `TryParse` APIs, `DateOnly` doesn't throw for an invalid style and simply returns `false` making it inconsistent with the general rule that we should only have one mode of failure.

That is, there is no string that would make DateOnly.TryParseExact("2064-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out _) succeed and therefore DateTimeStyles.AssumeUniversal is "invalid" for DateOnly and should be throwing accordingly (as all of our other TryParse APIs behave with invalid styles)</comment_new>
<comment_new>@tarekgh
@tannergooding you are correct regarding that but honestly, I am not sure if this deserve to fix for the sake of consistency while it introduces a breaking change we can avoid. Let me know if you still think we should fix it and we can consider it. Thanks!</comment_new>
<comment_new>@tannergooding
We've got at least one customer report on it already and it is something that creates other potential problems for users, i.e. its a static bug and so any typical "get user input, try to ...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@tarekgh tarekgh added this to the 11.0.0 milestone Jan 30, 2026
@tarekgh tarekgh added breaking-change Issue or PR that represents a breaking API or functional change over a previous release. needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet area-System.DateTime labels Jan 30, 2026
Copilot AI and others added 4 commits January 30, 2026 18:28
…imeStyles

Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
…tency

Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix DateOnly TryParseExact inconsistent behavior with ISO-8601 Fix DateOnly/TimeOnly TryParse to throw on invalid DateTimeStyles Jan 30, 2026
@tarekgh
Copy link
Member

tarekgh commented Jan 30, 2026

@copilot please address all opened feedback

…thods

Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
… for bad format specifiers

Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 30, 2026

        {

@copilot DateTimeParse.TryParseExact can return zero and set the dtResult.failure to ParseFailureKind.Argument_BadFormatSpecifier but the method TryParseExactInternal will return Pa...

Fixed in 492c226. Now checking dtResult.failure and preserving Argument_BadFormatSpecifier if returned by DateTimeParse.TryParseExact.

        {

@copilot my comment on DateOnly file will apply here too.
...

Fixed in 492c226. Applied the same fix for TimeOnly single format overload.

        {

@copilot My comment on DateOnly file apply here too.
...

Fixed in 492c226. Applied the same fix for TimeOnly multiple formats overload.

    }

@copilot This method should preserve ParseFailureKind.Argument_BadFormatSpecifier if it is returned in dtResult.failure
...

Fixed in 492c226. Now tracking and preserving Argument_BadFormatSpecifier across the loop iterations.

@copilot please address all opened feedback

All feedback addressed in commit 492c226. Summary of changes:

  • Fixed all TryParseExactInternal methods to preserve Argument_BadFormatSpecifier from DateTimeParse.TryParseExact
  • Added tests for invalid format specifiers (null/empty formats)
  • All 69,639 tests passing

Copilot AI changed the title Fix DateOnly/TimeOnly TryParse to throw on invalid DateTimeStyles Fix DateOnly/TimeOnly TryParse to throw on invalid DateTimeStyles and format specifiers Jan 30, 2026
Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
@tarekgh
Copy link
Member

tarekgh commented Jan 31, 2026

/asp run runtime

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a consistency issue where DateOnly.TryParse/TryParseExact and TimeOnly.TryParse/TryParseExact methods were returning false for invalid DateTimeStyles parameters instead of throwing an ArgumentException, aligning their behavior with other TryParse APIs in .NET. Additionally, it ensures that invalid format specifiers (null/empty formats in arrays) properly throw FormatException instead of being masked as general format errors.

Changes:

  • Modified all TryParse and TryParseExact overloads in both DateOnly and TimeOnly to throw exceptions for invalid DateTimeStyles values
  • Enhanced TryParseExactInternal methods to detect and immediately return Argument_BadFormatSpecifier errors from underlying DateTimeParse.TryParseExact
  • Updated existing tests to expect exceptions instead of false returns, and added comprehensive new test cases for all variants

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Private.CoreLib/src/System/DateOnly.cs Modified TryParse and all TryParseExact overloads to throw on invalid DateTimeStyles; enhanced TryParseExactInternal to detect bad format specifiers
src/libraries/System.Private.CoreLib/src/System/TimeOnly.cs Modified TryParse and all TryParseExact overloads to throw on invalid DateTimeStyles; enhanced TryParseExactInternal to detect bad format specifiers
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateOnlyTests.cs Updated existing tests to expect exceptions; added comprehensive tests for invalid styles and format specifiers
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/TimeOnlyTests.cs Updated existing tests to expect exceptions; added comprehensive tests for invalid styles and format specifiers

@tarekgh
Copy link
Member

tarekgh commented Feb 1, 2026

CC @stephentoub

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.DateTime breaking-change Issue or PR that represents a breaking API or functional change over a previous release. needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DateOnly TryParseExact fails to parse basic ISO-8601 input

2 participants