From 484fac780cf16b48e216c98804eb2e0d9d73e3b8 Mon Sep 17 00:00:00 2001 From: Dominik Titl <78549750+morning4coffe-dev@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:46:14 +0100 Subject: [PATCH 1/2] fix: Improve DateTimeFormatter template matching and mappings --- .../DateTimeFormatting/DateTimeFormatter.cs | 100 +++++++++++++----- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs index 9c4f25831e95..3f2ffa32422f 100644 --- a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs +++ b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs @@ -303,43 +303,90 @@ private IDictionary BuildLookup(string language) var info = new CultureInfo(language).DateTimeFormat; map = new Dictionary - { + { + // Predefined patterns { "longdate" , info.LongDatePattern } , { "shortdate" , info.ShortDatePattern } , { "longtime" , info.LongTimePattern } , { "shorttime" , info.ShortTimePattern } , + + // Compound patterns { "dayofweek day month year" , info.FullDateTimePattern } , { "dayofweek day month" , "D" } , { "day month year" , info.ShortDatePattern } , { "day month.full year" , info.ShortDatePattern } , { "day month" , info.MonthDayPattern } , { "month year" , info.YearMonthPattern } , - { "dayofweek.full" , "dddd" } , - { "dayofweek.abbreviated" , "ddd" } , - { "month.full" , "MMMM" } , - { "month.abbreviated" , "MMM" } , - { "month.numeric" , "%M" } , - { "year.abbreviated" , "yy" } , - { "year.full" , "yyyy" } , { "hour minute second" , info.LongTimePattern }, { "hour minute" , info.ShortTimePattern }, - { "timezone.abbreviated" , "zz" }, - { "timezone.full" , "zzz" }, + //{ "year month day hour" , "" }, + + // Day of week formats { "dayofweek" , "dddd" } , - { "day.integer" , "d" }, + { "dayofweek.full" , "dddd" } , + { "dayofweek.abbreviated" , "ddd" } , + { "dayofweek.abbreviated(1)" , "dd" } , + { "dayofweek.abbreviated(2)" , "ddd" } , + { "dayofweek.solo.full" , "dddd" } , + { "dayofweek.solo.abbreviated" , "ddd" } , + + // Day formats { "day" , "%d" } , - { "month.integer" , "M" }, + { "day.integer" , "%d" }, + { "day.integer(1)" , "%d" }, + { "day.integer(2)" , "dd" }, + + // Month formats { "month" , "MMMM" } , + { "month.full" , "MMMM" } , + { "month.abbreviated" , "MMM" } , + { "month.abbreviated(1)" , "%M" } , + { "month.abbreviated(2)" , "MMM" } , + { "month.numeric" , "%M" } , + { "month.integer" , "%M" } , + { "month.integer(1)" , "%M" } , + { "month.integer(2)" , "MM" } , + { "month.solo.full" , "MMMM" } , + { "month.solo.abbreviated" , "MMM" } , + + // Year formats { "year" , "yyyy" } , - { "hour.integer(1)" , "%h" }, - { "hour" , "H tt" } , - { "minute.integer(2)" , "mm" }, - { "minute.integer" , "%m" }, - { "minute" , "%m" }, - { "second" , "%s" }, - { "timezone" , "%z" }, - { "period.abbreviated(2)" , "tt" }, - // { "year month day hour" , "" } , + { "year.full" , "yyyy" } , + { "year.abbreviated" , "yy" } , + { "year.abbreviated(1)" , "%y" } , + { "year.abbreviated(2)" , "yy" } , + + // Hour formats + { "hour" , "%H" } , + { "hour.integer" , "%H" } , + { "hour.integer(1)" , "%h" } , + { "hour.integer(2)" , "HH" } , + + // Period (AM/PM) formats + { "period" , "tt" } , + { "period.full" , "tt" } , + { "period.abbreviated" , "tt" } , + { "period.abbreviated(1)" , "t" } , + { "period.abbreviated(2)" , "tt" } , + + // Minute formats + { "minute" , "%m" } , + { "minute.integer" , "%m" } , + { "minute.integer(1)" , "%m" } , + { "minute.integer(2)" , "mm" } , + + // Second formats + { "second" , "%s" } , + { "second.integer" , "%s" } , + { "second.integer(1)" , "%s" } , + { "second.integer(2)" , "ss" } , + + // Timezone formats + { "timezone" , "%z" } , + { "timezone.full" , "zzz" } , + { "timezone.abbreviated" , "zz" } , + { "timezone.abbreviated(1)" , "%z" } , + { "timezone.abbreviated(2)" , "zz" } }; return _mapCache[language] = map; @@ -370,16 +417,21 @@ private string GetSystemTemplate() var map = _maps![0]; - foreach (var p in map) - { - result = result.Replace(p.Key, p.Value); + var sortedKeys = map.Keys.OrderByDescending(k => k.Length); + foreach (var key in sortedKeys) + { + result = result.Replace(key, map[key]); } if (result.Contains("h") && Clock == ClockIdentifiers.TwentyFourHour) { result = result.Replace("h", "H"); } + else if (result.Contains("H") && Clock == ClockIdentifiers.TwelveHour) + { + result = result.Replace("H", "h"); + } return result; } From 0e9220e57e0d22ab7e9e3972c40013317e0ff750 Mon Sep 17 00:00:00 2001 From: Dominik Titl <78549750+morning4coffe-dev@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:46:46 +0100 Subject: [PATCH 2/2] chore: Add runtime test for Time format --- .../Given_DateTimeFormatter.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_Globalization/Given_DateTimeFormatter.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_Globalization/Given_DateTimeFormatter.cs index 557870ff2c19..54ebd37a74cc 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_Globalization/Given_DateTimeFormatter.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_Globalization/Given_DateTimeFormatter.cs @@ -104,19 +104,18 @@ public void When_FormattingDateVariants_ShouldProduceExpectedFormats() } } - // TODO(DT): Currently is throwing unexpected results on WinUI as well, can't compare the expected results - /* [TestMethod] + [TestMethod] public void When_FormattingTimeVariants_ShouldProduceExpectedFormats() { var expectedResults = new Dictionary { { "{hour.integer}:{minute.integer}", "14:30" }, - { "{hour.integer}:{minute.integer}:{second.integer}", "14:30:00" }, + { "{hour.integer}:{minute.integer}:{second.integer(2)}", "14:30:00" }, { "{hour.integer}:{minute.integer} {period.abbreviated(2)}", "2:30 PM" }, - { "{hour.integer}:{minute.integer}:{second.integer} {period.abbreviated(2)}", "2:30:00 PM" }, - { "{minute.integer}:{second.integer}", "30:00" }, + { "{hour.integer}:{minute.integer}:{second.integer} {period.abbreviated(2)}", "2:30:0 PM" }, + { "{minute.integer}:{second.integer}", "30:0" }, { "{second.integer}", "0" }, - { "{hour.integer}:{minute.integer}:{second.integer} UTC", "14:30:00 UTC" } + { "{hour.integer}:{minute.integer}:{second.integer(2)} UTC", "14:30:00 UTC" } }; foreach (var kvp in expectedResults) @@ -124,11 +123,12 @@ public void When_FormattingTimeVariants_ShouldProduceExpectedFormats() var template = kvp.Key; var expected = kvp.Value; - var formatter = new DateTimeFormatter(template); - var formattedTime = formatter.Format(_testDate); + var clock = template.Contains("period") ? ClockIdentifiers.TwelveHour : ClockIdentifiers.TwentyFourHour; + + var formatter = new DateTimeFormatter(template, ["en-US"], "US", CalendarIdentifiers.Gregorian, clock); + var formattedTime = formatter.Format(new DateTime(2024, 6, 17, 14, 30, 0)); Assert.AreEqual(expected, formattedTime, $"Mismatch for template: {template}"); - Console.WriteLine($"Template: {template}, Result: {formattedTime}"); } - }*/ + } }