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 1ada31201cb99d..08cf57024e5dd9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -4457,16 +4457,14 @@ private static bool ParseByFormat( case '.': if (!str.Match(ch)) { - if (format.GetNext()) + // If we encounter the pattern ".F", and the dot is not present, it is an optional + // second fraction and we can skip this format. + if (format.Match('F')) { - // If we encounter the pattern ".F", and the dot is not present, it is an optional - // second fraction and we can skip this format. - if (format.Match('F')) - { - format.GetRepeatCount(); - break; - } + format.GetRepeatCount(); + break; } + result.SetBadDateTimeFailure(); return false; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs index 8eca865c38f95f..716b4df993a6d3 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DateTimeTests.cs @@ -2763,8 +2763,8 @@ public void TestTimeSynchronizationWithTheSystem() DateTime dt = DateTime.UtcNow; GetSystemTime(out st1); - DateTime systemDateTimeNow1 = new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMillisecond, DateTimeKind.Utc); - DateTime systemDateTimeNow2 = new DateTime(st1.wYear, st1.wMonth, st1.wDay, st1.wHour, st1.wMinute, st1.wSecond, st1.wMillisecond, DateTimeKind.Utc); + DateTime systemDateTimeNow1 = new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMillisecond, DateTimeKind.Utc); + DateTime systemDateTimeNow2 = new DateTime(st1.wYear, st1.wMonth, st1.wDay, st1.wHour, st1.wMinute, st1.wSecond, st1.wMillisecond, DateTimeKind.Utc); // Usually GetSystemTime and DateTime.UtcNow calls doesn't take one second to execute, if this is not the case then // the thread was sleeping for awhile and we cannot test reliably on that case. @@ -2777,6 +2777,44 @@ public void TestTimeSynchronizationWithTheSystem() } } + [Fact] + public void TestFractionSpecifier() + { + DateTime date = new DateTime(2008, 8, 29, 7, 27, 15, 18); + CultureInfo ci = CultureInfo.InvariantCulture; + + // Test using .F format https://learn.microsoft.com/dotnet/standard/base-types/custom-date-and-time-format-strings#F_Specifier + string pattern = "yyyy-MM-ddThh:mm:ss.F"; + string formatted = date.ToString(pattern, ci); + Assert.Equal("2008-08-29T07:27:15", formatted); + Assert.True(DateTime.TryParseExact(formatted, pattern, ci, DateTimeStyles.None, out DateTime parsedDate)); + Assert.Equal(date, parsedDate.AddTicks((long)(TimeSpan.TicksPerMillisecond * 18))); // 18 milliseconds fraction difference + pattern = "yyyy-MM-ddThh:mm.F:ss"; + formatted = date.ToString(pattern, ci); + Assert.True(DateTime.TryParseExact(formatted, "yyyy-MM-ddThh:mm.F:ss", ci, DateTimeStyles.None, out parsedDate)); + Assert.Equal(date, parsedDate.AddTicks((long)(TimeSpan.TicksPerMillisecond * 18))); // 18 milliseconds fraction difference + + pattern = "yyyy-MM-ddThh:mm:ss.FF"; + formatted = date.ToString(pattern, ci); + Assert.Equal("2008-08-29T07:27:15.01", formatted); + Assert.True(DateTime.TryParseExact(formatted, pattern, ci, DateTimeStyles.None, out parsedDate), $"Failed to parse '{formatted}' using the pattern '{pattern}'."); + Assert.Equal(date, parsedDate.AddTicks((long)(TimeSpan.TicksPerMillisecond * 8))); // 8 milliseconds fraction difference + pattern = "yyyy-MM-ddThh.FF:mm:ss"; + formatted = date.ToString(pattern, ci); + Assert.True(DateTime.TryParseExact(formatted, pattern, ci, DateTimeStyles.None, out parsedDate), $"Failed to parse '{formatted}' using the pattern '{pattern}'."); + Assert.Equal(date, parsedDate.AddTicks((long)(TimeSpan.TicksPerMillisecond * 8))); // 8 milliseconds fraction difference + + pattern = "yyyy-MM-ddThh:mm:ss.FFF"; + formatted = date.ToString(pattern, ci); + Assert.Equal("2008-08-29T07:27:15.018", formatted); + Assert.True(DateTime.TryParseExact(formatted, pattern, ci, DateTimeStyles.None, out parsedDate), $"Failed to parse '{formatted}' using the pattern '{pattern}'."); + Assert.Equal(date, parsedDate); + pattern = "yyyy-MM-ddThh.FFF:mm:ss"; + formatted = date.ToString(pattern, ci); + Assert.True(DateTime.TryParseExact(formatted, pattern, ci, DateTimeStyles.None, out parsedDate), $"Failed to parse '{formatted}' using the pattern '{pattern}'."); + Assert.Equal(date, parsedDate); + } + [DllImport("Kernel32.dll")] internal static extern void GetSystemTime(out SYSTEMTIME lpSystemTime);