From 0af7deb209e13667aad950b7cdf9b657bf36ac49 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 3 Dec 2021 15:53:04 -0800 Subject: [PATCH 1/4] Fix Some Date and Time parsing cases --- .../src/System/Globalization/DateTimeParse.cs | 22 +++++++----- .../tests/System/DateTimeTests.cs | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) 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 b4796fd92e63d9..19eedac7aa8f50 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -341,10 +341,10 @@ internal enum DS new DS[] { DS.BEGIN, DS.ERROR, DS.TX_N, DS.N, DS.D_Nd, DS.T_Nt, DS.ERROR, DS.D_M, DS.D_M, DS.D_S, DS.T_S, DS.BEGIN, DS.D_Y, DS.D_Y, DS.ERROR, DS.BEGIN, DS.BEGIN, DS.ERROR }, // DS.N // DS.N -new DS[] { DS.ERROR, DS.DX_NN, DS.ERROR, DS.NN, DS.D_NNd, DS.ERROR, DS.DX_NM, DS.D_NM, DS.D_MNd, DS.D_NDS, DS.ERROR, DS.N, DS.D_YN, DS.D_YNd, DS.DX_YN, DS.N, DS.N, DS.ERROR }, +new DS[] { DS.ERROR, DS.DX_NN, DS.TX_NN, DS.NN, DS.D_NNd, DS.ERROR, DS.DX_NM, DS.D_NM, DS.D_MNd, DS.D_NDS, DS.ERROR, DS.N, DS.D_YN, DS.D_YNd, DS.DX_YN, DS.N, DS.N, DS.ERROR }, // DS.NN // DS.NN -new DS[] { DS.DX_NN, DS.DX_NNN, DS.TX_N, DS.DX_NNN, DS.ERROR, DS.T_Nt, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.ERROR, DS.T_S, DS.NN, DS.DX_NNY, DS.ERROR, DS.DX_NNY, DS.NN, DS.NN, DS.ERROR }, +new DS[] { DS.DX_NN, DS.DX_NNN, DS.TX_NNN, DS.DX_NNN, DS.ERROR, DS.T_Nt, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.ERROR, DS.T_S, DS.NN, DS.DX_NNY, DS.ERROR, DS.DX_NNY, DS.NN, DS.NN, DS.ERROR }, // DS.D_Nd // DS.D_Nd new DS[] { DS.ERROR, DS.DX_NN, DS.ERROR, DS.D_NN, DS.D_NNd, DS.ERROR, DS.DX_NM, DS.D_MN, DS.D_MNd, DS.ERROR, DS.ERROR, DS.D_Nd, DS.D_YN, DS.D_YNd, DS.DX_YN, DS.ERROR, DS.D_Nd, DS.ERROR }, @@ -3192,8 +3192,8 @@ private static bool ParseFractionExact(ref __DTString str, int maxDigitLen, ref /*=================================ParseSign================================== **Action: Parse a positive or a negative sign. - **Returns: true if postive sign. flase if negative sign. - **Arguments: str: a __DTString. The parsing will start from the + **Returns: true if postive sign. false if negative sign. + **Arguments: str: a __DTString. The parsing will start from the ** next character after str.Index. **Exceptions: FormatException if end of string is encountered or a sign ** symbol is not found. @@ -5244,6 +5244,8 @@ private static void Trace(string s) // internal ref struct __DTString { + internal const char RightToLeftMark = '\u200F'; + // // Value property: stores the real string to be parsed. // @@ -5418,7 +5420,7 @@ internal TokenType GetSeparatorToken(DateTimeFormatInfo dtfi, out int indexBefor indexBeforeSeparator = Index; charBeforeSeparator = m_current; TokenType tokenType; - if (!SkipWhiteSpaceCurrent()) + if (!SkipWhiteSpaceAndRtlMarkCurrent()) { // Reach the end of the string. return TokenType.SEP_End; @@ -5672,18 +5674,20 @@ internal void SkipWhiteSpaces() } // - // Skip white spaces from the current position + // Skip white spaces and right-to-left Mark from the current position // + // U+200F is the Unicode right-to-left mark. In some Bidi cultures, this mark gets inserted inside the formatted date or time to have the output displayed in the correct layout. + // This mark does not affect the date or the time component values. Ignoring this mark during parsing wouldn't affect the result but will avoid having the parsing fail. // Return false if end of string is encountered. // - internal bool SkipWhiteSpaceCurrent() + internal bool SkipWhiteSpaceAndRtlMarkCurrent() { if (Index >= Length) { return false; } - if (!char.IsWhiteSpace(m_current)) + if (!char.IsWhiteSpace(m_current) && m_current != RightToLeftMark) { return true; } @@ -5691,7 +5695,7 @@ internal bool SkipWhiteSpaceCurrent() while (++Index < Length) { m_current = Value[Index]; - if (!char.IsWhiteSpace(m_current)) + if (!char.IsWhiteSpace(m_current) && m_current != RightToLeftMark) { return true; } diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs index 1a9a487ecd4849..49f4580bcaae09 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs @@ -1024,6 +1024,41 @@ public static void Parse_Japanese() Assert.Equal(expected, DateTime.Parse(expectedString, cultureInfo)); } + [Theory] + [InlineData("ar")] + [InlineData("ar-EG")] + [InlineData("ar-IQ")] + [InlineData("ar-SA")] + [InlineData("ar-YE")] + public static void DateTimeParsingWithBiDiCultureTest(string cultureName) + { + DateTime dt = new DateTime(2021, 11, 30, 14, 30, 40); + CultureInfo ci = CultureInfo.GetCultureInfo(cultureName); + string formatted = dt.ToString("d", ci); + Assert.Equal(dt.Date, DateTime.Parse(formatted, ci)); + formatted = dt.ToString("g", ci); + DateTime parsed = DateTime.Parse(formatted, ci); + Assert.Equal(dt.Date, parsed.Date); + Assert.Equal(dt.Hour, parsed.Hour); + Assert.Equal(dt.Minute, parsed.Minute); + } + + [Fact] + public static void DateTimeParsingWithSpaceTimeSeparators() + { + DateTime dt = new DateTime(2021, 11, 30, 14, 30, 40); + CultureInfo ci = CultureInfo.GetCultureInfo("en-US"); + // It is possible we find some cultures use such formats. dz-BT is example of that + string formatted = dt.ToString("yyyy/MM/dd hh mm tt", ci); + DateTime parsed = DateTime.Parse(formatted, ci); + Assert.Equal(dt.Hour, parsed.Hour); + Assert.Equal(dt.Minute, parsed.Minute); + + formatted = dt.ToString("yyyy/MM/dd hh mm ss tt", ci); + parsed = DateTime.Parse(formatted, ci); + Assert.Equal(dt, parsed); + } + [Fact] public static void Parse_InvalidArguments_Throws() { From 0fe11c0dc394a3af2a76ec6ab89c156415a7e2a3 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Fri, 3 Dec 2021 17:39:25 -0800 Subject: [PATCH 2/4] Avoid running the new test on Mac --- .../Common/tests/TestUtilities/System/PlatformDetection.Unix.cs | 1 + src/libraries/System.Runtime/tests/System/DateTimeTests.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index 99492706f7ec99..7b886477a9245d 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -35,6 +35,7 @@ public static partial class PlatformDetection // OSX family public static bool IsOSXLike => IsOSX || IsiOS || IstvOS || IsMacCatalyst; + public static bool IsNotOSXLike => !IsOSXLike; public static bool IsOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); public static bool IsNotOSX => !IsOSX; public static bool IsMacOsMojaveOrHigher => IsOSX && Environment.OSVersion.Version >= new Version(10, 14); diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs index 49f4580bcaae09..8a9d4fb2174eb9 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs @@ -1024,7 +1024,7 @@ public static void Parse_Japanese() Assert.Equal(expected, DateTime.Parse(expectedString, cultureInfo)); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotOSXLike))] [InlineData("ar")] [InlineData("ar-EG")] [InlineData("ar-IQ")] From f1a842f7a5df239c28b1c707fc0a17ede90b5b7e Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sat, 4 Dec 2021 17:09:02 -0800 Subject: [PATCH 3/4] Exclude the browser for the new test --- .../tests/TestUtilities/System/PlatformDetection.Unix.cs | 1 - src/libraries/System.Runtime/tests/System/DateTimeTests.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index 7b886477a9245d..99492706f7ec99 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -35,7 +35,6 @@ public static partial class PlatformDetection // OSX family public static bool IsOSXLike => IsOSX || IsiOS || IstvOS || IsMacCatalyst; - public static bool IsNotOSXLike => !IsOSXLike; public static bool IsOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); public static bool IsNotOSX => !IsOSX; public static bool IsMacOsMojaveOrHigher => IsOSX && Environment.OSVersion.Version >= new Version(10, 14); diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs index 8a9d4fb2174eb9..0cbe26a005ede3 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs @@ -1024,7 +1024,9 @@ public static void Parse_Japanese() Assert.Equal(expected, DateTime.Parse(expectedString, cultureInfo)); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotOSXLike))] + private static bool IsNotOSXOrBrowser => !PlatformDetection.IsOSXLike && !PlatformDetection.IsBrowser; + + [ConditionalTheory(nameof(IsNotOSXOrBrowser))] [InlineData("ar")] [InlineData("ar-EG")] [InlineData("ar-IQ")] From 9177e0cd6fdc12b8c7243172ef55a957020cd4ac Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Mon, 6 Dec 2021 14:18:30 -0600 Subject: [PATCH 4/4] Update src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs --- .../src/System/Globalization/DateTimeParse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 19eedac7aa8f50..a7ebe4c496f641 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -3192,7 +3192,7 @@ private static bool ParseFractionExact(ref __DTString str, int maxDigitLen, ref /*=================================ParseSign================================== **Action: Parse a positive or a negative sign. - **Returns: true if postive sign. false if negative sign. + **Returns: true if positive sign. false if negative sign. **Arguments: str: a __DTString. The parsing will start from the ** next character after str.Index. **Exceptions: FormatException if end of string is encountered or a sign