diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs index 9fe6ff109653c..8b518113018c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -13,6 +13,10 @@ internal static class DateTimeParse { internal const int MaxDateTimeNumberDigits = 8; + internal const char TimeDelimiter = ':'; + internal const char TimeFractionDelimiterComma = ','; + internal const char TimeFractionDelimiterDot = '.'; + internal static DateTime ParseExact(ReadOnlySpan s, ReadOnlySpan format, DateTimeFormatInfo dtfi, DateTimeStyles style) { DateTimeResult result = default; // The buffer to store the parsing result. @@ -521,7 +525,7 @@ private static bool ParseTimeZone(ref __DTString str, scoped ref TimeSpan result str.ConsumeSubString(sub); // See if we have minutes sub = str.GetSubString(); - if (sub.length == 1 && sub[0] == ':') + if (sub.length == 1 && sub[0] == TimeDelimiter) { // Parsing "+8:00" or "+08:00" str.ConsumeSubString(sub); @@ -642,7 +646,8 @@ private static bool Lex(DS dps, ref __DTString str, scoped ref DateTimeToken dto if (str.Index < str.Length - 1) { char nextCh = str.Value[str.Index]; - if (nextCh == '.') + if ((nextCh == TimeFractionDelimiterDot) + || (nextCh == TimeFractionDelimiterComma)) { // While ParseFraction can fail, it just means that there were no digits after // the dot. In this case ParseFraction just removes the dot. This is actually @@ -2961,7 +2966,7 @@ private static bool ParseISO8601(scoped ref DateTimeRawInfo raw, ref __DTString return false; } str.SkipWhiteSpaces(); - if (!str.Match(':')) + if (!str.Match(TimeDelimiter)) { result.SetBadDateTimeFailure(); return false; @@ -2973,7 +2978,7 @@ private static bool ParseISO8601(scoped ref DateTimeRawInfo raw, ref __DTString return false; } str.SkipWhiteSpaces(); - if (str.Match(':')) + if (str.Match(TimeDelimiter)) { str.SkipWhiteSpaces(); if (!ParseDigits(ref str, 2, out second)) @@ -2981,7 +2986,8 @@ private static bool ParseISO8601(scoped ref DateTimeRawInfo raw, ref __DTString result.SetBadDateTimeFailure(); return false; } - if (str.Match('.')) + if ((str.Match(TimeFractionDelimiterDot)) + || (str.Match(TimeFractionDelimiterComma))) { if (!ParseFraction(ref str, out partSecond)) { diff --git a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs index 2e2ff83a504f9..f0d5dc2120b2e 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs @@ -856,14 +856,18 @@ public static void Compare(DateTimeOffset dateTimeOffset1, DateTimeOffset dateTi } } - [Fact] - public static void Parse_String() + public static IEnumerable Parse_TestData() { - DateTimeOffset expected = DateTimeOffset.MaxValue; - string expectedString = expected.ToString(); + yield return new object[] { "2021-04-23T13:04:17,307642270+02:00", new DateTimeOffset(637547798573076423, new TimeSpan(2, 0, 0)) }; + yield return new object[] { DateTimeOffset.MaxValue.ToString("O"), DateTimeOffset.MaxValue }; + } - DateTimeOffset result = DateTimeOffset.Parse(expectedString); - Assert.Equal(expectedString, result.ToString()); + [Theory] + [MemberData(nameof(Parse_TestData))] + public static void Parse_String(string valueForParse, DateTimeOffset expectedValue) + { + DateTimeOffset actualValue = DateTimeOffset.Parse(valueForParse); + Assert.Equal(expectedValue, actualValue); } [Fact]