Fix fr-CA culture time formatting and parsing (#56443)
authorTarek Mahmoud Sayed <tarekms@microsoft.com>
Wed, 28 Jul 2021 20:02:39 +0000 (13:02 -0700)
committerGitHub <noreply@github.com>
Wed, 28 Jul 2021 20:02:39 +0000 (13:02 -0700)
src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs

index 3139852..d429460 100644 (file)
@@ -210,5 +210,17 @@ namespace System.Globalization.Tests
                 Assert.Equal(i + 1, ci.DateTimeFormat.GetEra(eraNames[i]));
             }
         }
+
+        [Fact]
+        public void TestFrenchCanadaTimeFormat()
+        {
+            CultureInfo ci = CultureInfo.GetCultureInfo("fr-CA");
+            Assert.Equal(":", ci.DateTimeFormat.TimeSeparator);
+
+            DateTime time = new DateTime(2021, 10, 1, 5, 36, 50);
+            string formattedTime = time.ToString("HH 'h' mm 'min' ss 's'", ci);
+            DateTime dt = DateTime.Parse(formattedTime, ci);
+            Assert.Equal(time.TimeOfDay, dt.TimeOfDay);
+        }
     }
 }
index 43e0cfe..5766096 100644 (file)
@@ -1936,14 +1936,23 @@ namespace System.Globalization
             {
                 if (_sTimeSeparator == null && !GlobalizationMode.Invariant)
                 {
-                    string? longTimeFormat = ShouldUseUserOverrideNlsData ? NlsGetTimeFormatString() : IcuGetTimeFormatString();
-                    if (string.IsNullOrEmpty(longTimeFormat))
+                    // fr-CA culture uses time format as "HH 'h' mm 'min' ss 's'" which we cannot derive the time separator from such pattern.
+                    // We special case such culture and force ':' as time separator.
+                    if (_sName == "fr-CA")
                     {
-                        longTimeFormat = LongTimes[0];
+                        _sTimeSeparator = ":";
                     }
+                    else
+                    {
+                        string? longTimeFormat = ShouldUseUserOverrideNlsData ? NlsGetTimeFormatString() : IcuGetTimeFormatString();
+                        if (string.IsNullOrEmpty(longTimeFormat))
+                        {
+                            longTimeFormat = LongTimes[0];
+                        }
 
-                    // Compute STIME from time format
-                    _sTimeSeparator = GetTimeSeparator(longTimeFormat);
+                        // Compute STIME from time format
+                        _sTimeSeparator = GetTimeSeparator(longTimeFormat);
+                    }
                 }
                 return _sTimeSeparator!;
             }
@@ -1966,7 +1975,7 @@ namespace System.Globalization
                 // changing the default pattern is likely will happen in the near future which can easily break formatting
                 // and parsing.
                 // We are forcing here the date separator to '/' to ensure the parsing is not going to break when changing
-                // the default short date pattern. The application still can override this in the code by DateTimeFormatInfo.DateSeparartor.
+                // the default short date pattern. The application still can override this in the code by DateTimeFormatInfo.DateSeparator.
                 return "/";
             }
 
index e862e03..c0870e1 100644 (file)
@@ -282,7 +282,7 @@ namespace System.Globalization
         }
 
         /// <summary>
-        /// Return a specific culture. A tad irrelevent now since we always
+        /// Return a specific culture. A tad irrelevant now since we always
         /// return valid data for neutral locales.
         ///
         /// Note that there's interesting behavior that tries to find a
index a7b603e..b4c44b8 100644 (file)
@@ -2054,6 +2054,16 @@ namespace System.Globalization
                     InsertHash(temp, TimeSeparator, TokenType.SEP_Time, 0);
                 }
 
+                if (_name == "fr-CA")
+                {
+                    InsertHash(temp, " h", TokenType.SEP_HourSuff, 0);
+                    InsertHash(temp, " h ", TokenType.SEP_HourSuff, 0);
+                    InsertHash(temp, " min", TokenType.SEP_MinuteSuff, 0);
+                    InsertHash(temp, " min ", TokenType.SEP_MinuteSuff, 0);
+                    InsertHash(temp, " s", TokenType.SEP_SecondSuff, 0);
+                    InsertHash(temp, " s ", TokenType.SEP_SecondSuff, 0);
+                }
+
                 InsertHash(temp, AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
                 InsertHash(temp, PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);