diff --git a/doc/articles/uno-community-toolkit-v8.md b/doc/articles/uno-community-toolkit-v8.md
index a628bba775e7..f19ac1211aee 100644
--- a/doc/articles/uno-community-toolkit-v8.md
+++ b/doc/articles/uno-community-toolkit-v8.md
@@ -184,6 +184,97 @@ You can set the `Header`, `HeaderIcon`, `Description`, and `Content` properties
A complete working sample, along with additional examples, is available on GitHub: [Uno Windows Community Toolkit SettingsCard Sample](https://github.com/unoplatform/Uno.Samples/tree/master/UI/WindowsCommunityToolkit/Version-8.x/UnoWCTSettingsCardSample)
+## Using Non-UI Elements from the CommunityToolkit: Converters
+
+The CommunityToolkit is providing some ready-to-use Converters for e.g. x:Bind in Xaml, whithout having to write already existing basic Converters yourself.
+[List of CommunityToolkit Converters | Windows Toolkit Documentation](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/windows/converters/)
+
+The implementation of those are quite similar to the example of the SettingsControl above, but there are small adjustments to be done to use them:
+
+1. Import of the Package
+
+ Change this:
+
+
+ ```CommunityToolkit.WinUI.Controls.SettingsControls```
+
+ to Converters namespace:
+
+ ```CommunityToolkit.WinUI.Converters```
+
+ while the Version will stay the same as above.
+
+1. Add the related needed namespace(s)
+
+ > [!NOTE]
+ > In WCT version 8.x, the namespaces between UWP and WinAppSDK were merged.
+
+ ### WinUI / WinAppSDK / UWP
+
+ In XAML:
+ ```xmlns:converters="using:CommunityToolkit.WinUI.Converters"```
+
+ In C#:
+ ```using CommunityToolkit.WinUI.Converters;```
+
+ In case you are developing a App that's using C# Markup and you want to use the Converters, you can now switch to [C#-Markup Converters](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Markup/Converters.html) Documentation for future Usage Guide, the general Import is done from here on.
+
+1. Xaml Definition
+
+Important Difference to the previous seen SettingsCard Control Example, a Non-UI Converter has to be imported to the Page.Ressources Section to StaticRessources like this for using it, since there is no single Namespace per Converter like on the Controls:
+
+### [Example StringToVisibilityConverter](#tab/string-visible-conv)
+
+StringToVisibilityConverter is a Converter that has to be bound to a String typed Property and will return a Visibility State.
+
+```xml
+
+
+
+```
+
+Somewhere in your Page Content:
+
+```xml
+
+
+```
+
+### [Example BoolToObjectConverter](#tab/bool-obj-conv)
+
+BoolToObjectConverter is a Converter that has to be bound to a Boolean typed Property and can return any Object you will give to it.
+You only have to tell it what to return on True or False. If you would like to use it for switching color on validation:
+
+```xml
+BoolToObjectConverter x:Key="BoolToColorConverter" TrueValue="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
+ FalseValue="{ThemeResource SystemFillColorCriticalBackgroundBrush}"/>
+```
+
+> [!NOTE]
+> The used ThemeResource Brushes can be found in the WinUI Gallery for example.
+> Feel free to use your own Colors e.g. from ColorPaletteOverrides
+
+Somewhere in your Page Content:
+
+```xml
+
+```
+
---
[!include[getting-help](includes/getting-help.md)]
diff --git a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs
index bc00ca60796a..a8ed7c91b438 100644
--- a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs
+++ b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeFormatter.cs
@@ -18,14 +18,15 @@ public sealed partial class DateTimeFormatter
{
private readonly CultureInfo _firstCulture;
- private readonly PatternRootNode _patternRootNode;
+ private readonly TemplateRootNode? _templateRootNode;
+ private readonly PatternRootNode? _patternRootNode;
///
/// Creates a DateTimeFormatter object that is initialized by a format template string.
///
///
- /// A format template string that specifies the requested components.
- /// The order of the components is irrelevant.
+ /// A format template string that specifies the requested components.
+ /// The order of the components is irrelevant.
/// This can also be a format pattern.
///
public DateTimeFormatter(string formatTemplate)
@@ -37,8 +38,8 @@ public DateTimeFormatter(string formatTemplate)
/// Creates a DateTimeFormatter object that is initialized by a format template string.
///
///
- /// A format template string that specifies the requested components.
- /// The order of the components is irrelevant.
+ /// A format template string that specifies the requested components.
+ /// The order of the components is irrelevant.
/// This can also be a format pattern.
///
///
@@ -51,59 +52,43 @@ public DateTimeFormatter(
{
ArgumentNullException.ThrowIfNull(formatTemplate);
- if (languages != null)
- {
- Languages = languages.Distinct().ToArray();
- }
-
- _firstCulture = new CultureInfo(Languages[0]);
-
try
{
// Template example:
// "year month day dayofweek hour timezone" (that's just an example)
var templateParser = new TemplateParser(formatTemplate);
- templateParser.Parse();
- IncludeYear = templateParser.Info.IncludeYear;
- IncludeMonth = templateParser.Info.IncludeMonth;
- IncludeDay = templateParser.Info.IncludeDay;
- IncludeDayOfWeek = templateParser.Info.IncludeDayOfWeek;
- IncludeHour = templateParser.Info.IncludeHour;
- IncludeMinute = templateParser.Info.IncludeMinute;
- IncludeSecond = templateParser.Info.IncludeSecond;
- IncludeTimeZone = templateParser.Info.IncludeTimeZone;
- IsShortDate = templateParser.Info.IsShortDate;
- IsLongDate = templateParser.Info.IsLongDate;
- IsShortTime = templateParser.Info.IsShortTime;
- IsShortDate = templateParser.Info.IsShortDate;
-
- // NOTE: We intentionally don't set the user provided template.
- // Instead, we parse and re-build the template string.
- // That's how WinUI works.
- // Basically, the order of tokens in the template string does NOT matter.
- // So, this kinda normalizes the order the right way.
+ _templateRootNode = templateParser.Parse();
+ IncludeYear = templateParser.IncludeYear;
+ IncludeMonth = templateParser.IncludeMonth;
+ IncludeDay = templateParser.IncludeDay;
+ IncludeDayOfWeek = templateParser.IncludeDayOfWeek;
+ IncludeHour = templateParser.IncludeHour;
+ IncludeMinute = templateParser.IncludeMinute;
+ IncludeSecond = templateParser.IncludeSecond;
+ IncludeTimeZone = templateParser.IncludeTimeZone;
+ IsShortDate = templateParser.IsShortDate;
+ IsLongDate = templateParser.IsLongDate;
+ IsShortTime = templateParser.IsShortTime;
+ IsShortDate = templateParser.IsShortDate;
Template = BuildTemplate();
-
- string patternBuiltFromTemplate = BuildPattern();
- Patterns = [patternBuiltFromTemplate];
- _patternRootNode = new PatternParser(patternBuiltFromTemplate).Parse();
}
- catch (Exception ex)
+ catch (Exception)
{
- try
- {
- // Pattern example:
- // "Hello {year.full} Hello2 {month.full}" (that's just an example)
- _patternRootNode = new PatternParser(formatTemplate).Parse();
- Template = formatTemplate;
- Patterns = [formatTemplate];
- }
- catch (Exception ex2)
- {
- throw new AggregateException(ex, ex2);
- }
+ // Pattern example:
+ // "Hello {year.full} Hello2 {month.full}" (that's just an example)
+ _patternRootNode = new PatternParser(formatTemplate).Parse();
+ Template = formatTemplate;
+ }
+
+ Patterns = [formatTemplate];
+ if (languages != null)
+ {
+ Languages = languages.Distinct().ToArray();
}
+ _firstCulture = new CultureInfo(Languages[0]);
+
+
var calendar = new Calendar(Languages);
Calendar = calendar.GetCalendarSystem();
Clock = calendar.GetClock();
@@ -136,9 +121,7 @@ public DateTimeFormatter(
IncludeDay = dayFormat;
IncludeDayOfWeek = dayOfWeekFormat;
Template = BuildTemplate();
- string patternBuiltFromTemplate = BuildPattern();
- Patterns = [patternBuiltFromTemplate];
- _patternRootNode = new PatternParser(patternBuiltFromTemplate).Parse();
+ Patterns = [Template];
_firstCulture = new CultureInfo(Languages[0]);
// TODO:MZ:
@@ -156,9 +139,7 @@ public DateTimeFormatter(
IncludeMinute = minuteFormat;
IncludeSecond = secondFormat;
Template = BuildTemplate();
- string patternBuiltFromTemplate = BuildPattern();
- Patterns = [patternBuiltFromTemplate];
- _patternRootNode = new PatternParser(patternBuiltFromTemplate).Parse();
+ Patterns = [Template];
_firstCulture = new CultureInfo(Languages[0]);
// TODO:MZ:
@@ -186,9 +167,7 @@ public DateTimeFormatter(
IncludeSecond = secondFormat;
Languages = languages.ToArray();
Template = BuildTemplate();
- string patternBuiltFromTemplate = BuildPattern();
- Patterns = [patternBuiltFromTemplate];
- _patternRootNode = new PatternParser(patternBuiltFromTemplate).Parse();
+ Patterns = [Template];
_firstCulture = new CultureInfo(Languages[0]);
// TODO:MZ:
@@ -222,9 +201,7 @@ public DateTimeFormatter(
Calendar = calendar;
Clock = clock;
Template = BuildTemplate();
- string patternBuiltFromTemplate = BuildPattern();
- Patterns = [patternBuiltFromTemplate];
- _patternRootNode = new PatternParser(patternBuiltFromTemplate).Parse();
+ Patterns = [Template];
_firstCulture = new CultureInfo(Languages[0]);
}
@@ -288,6 +265,16 @@ public DateTimeFormatter(
internal bool IsLongDate { get; }
+ internal TimeZoneFormat IncludeTimeZone { get; }
+
+ internal bool IsShortTime { get; }
+
+ internal bool IsLongTime { get; }
+
+ internal bool IsShortDate { get; }
+
+ internal bool IsLongDate { get; }
+
///
/// Gets the priority list of language identifiers that is used when formatting dates and times.
///
@@ -342,7 +329,129 @@ public string Format(DateTimeOffset value)
{
try
{
- return _patternRootNode.Format(value, _firstCulture, isTwentyFourHours: Clock == ClockIdentifiers.TwentyFourHour);
+ if (_templateRootNode is not null)
+ {
+ string date;
+ if (IsLongDate)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.LongDatePattern, _firstCulture);
+ }
+ else if (IsShortDate)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.ShortDatePattern, _firstCulture);
+ }
+ else
+ {
+ // NOTE: The original order that was specified in the template string does NOT matter.
+ // That's why all we need to care about is the values of the mentioned properties.
+ // However, we should actually be checking the actual enum value and not just being "None" or not.
+ // But the actual correct implementation that will 100% match WinUI isn't yet clear.
+ // This is a best effort approach.
+ bool hasYear = IncludeYear != YearFormat.None;
+ bool hasMonth = IncludeMonth != MonthFormat.None;
+ bool hasDay = IncludeDay != DayFormat.None;
+ bool hasDayOfWeek = IncludeDayOfWeek != DayOfWeekFormat.None;
+
+ if (hasYear && hasMonth && hasDay && hasDayOfWeek)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.LongDatePattern, _firstCulture);
+ }
+ else if (hasYear && hasMonth && hasDay)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.ShortDatePattern, _firstCulture);
+ }
+ else if (hasYear && hasMonth && !hasDayOfWeek)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.YearMonthPattern, _firstCulture);
+ }
+ else if (hasYear && !hasMonth && !hasDay && !hasDayOfWeek)
+ {
+ date = value.ToString("yyyy", _firstCulture);
+ }
+ else if (hasMonth && hasDay && !hasYear && !hasDayOfWeek)
+ {
+ date = value.ToString(_firstCulture.DateTimeFormat.MonthDayPattern, _firstCulture);
+ }
+ else
+ {
+ // Fallback case.
+ // Add more cases as they arise.
+ date = value.ToString(_firstCulture.DateTimeFormat.LongDatePattern, _firstCulture);
+ }
+ }
+
+ string time;
+ if (IsLongTime)
+ {
+ time = value.ToString(_firstCulture.DateTimeFormat.LongTimePattern, _firstCulture);
+ }
+ else if (IsShortTime)
+ {
+ time = value.ToString(_firstCulture.DateTimeFormat.ShortTimePattern, _firstCulture);
+ }
+ else
+ {
+ // NOTE: The original order that was specified in the template string does NOT matter.
+ // That's why all we need to care about is the values of the mentioned properties.
+ bool hasHour = IncludeHour != HourFormat.None;
+ bool hasMinute = IncludeMinute != MinuteFormat.None;
+ bool hasSecond = IncludeSecond != SecondFormat.None;
+ bool hasTimeZone = IncludeTimeZone != TimeZoneFormat.None;
+
+ if (hasHour && hasMinute && hasSecond)
+ {
+ time = value.ToString(_firstCulture.DateTimeFormat.LongTimePattern, _firstCulture);
+ }
+ else if (hasHour && hasMinute)
+ {
+ time = value.ToString(_firstCulture.DateTimeFormat.ShortTimePattern, _firstCulture);
+ }
+ else if (hasHour)
+ {
+ time = value.ToString("%H", _firstCulture);
+ }
+ else if (!hasHour && !hasMinute && !hasSecond)
+ {
+ time = string.Empty;
+ }
+ else
+ {
+ // Shouldn't really be reachable. But a fallback in place just in case.
+ time = value.ToString(_firstCulture.DateTimeFormat.LongTimePattern, _firstCulture);
+ }
+
+ if (hasTimeZone)
+ {
+ if (time.Length == 0)
+ {
+ time = $"GMT+{TimeZoneInfo.Local.BaseUtcOffset.TotalHours}";
+ }
+ else
+ {
+ time = $"{time} GMT+{TimeZoneInfo.Local.BaseUtcOffset.TotalHours}";
+ }
+ }
+ }
+
+ if (date.Length > 0 && time.Length > 0)
+ {
+ return $"{date} {time}";
+ }
+ else if (date.Length > 0)
+ {
+ return date;
+ }
+ else
+ {
+ return time;
+ }
+ }
+ else if (_patternRootNode is not null)
+ {
+ return _patternRootNode.Format(value, _firstCulture);
+ }
+
+ throw new InvalidOperationException("This cannot happen. The constructor sets either _templateRootNode or _patternRootNode to non-null.");
}
catch (Exception e)
{
@@ -432,39 +541,18 @@ private static string ToTemplateString(TimeZoneFormat timeZoneFormat)
private string BuildTemplate()
{
var templateBuilder = new StringBuilder();
- if (IsLongDate)
- Append("longdate");
- else if (IsShortDate)
- Append("shortdate");
- else
- {
- Append(ToTemplateString(IncludeYear));
- Append(ToTemplateString(IncludeMonth));
- Append(ToTemplateString(IncludeDay));
- Append(ToTemplateString(IncludeDayOfWeek));
- }
-
- if (IsLongTime)
- Append("longtime");
- else if (IsShortTime)
- Append("shorttime");
- else
- {
- Append(ToTemplateString(IncludeHour));
- Append(ToTemplateString(IncludeMinute));
- Append(ToTemplateString(IncludeSecond));
- Append(ToTemplateString(IncludeTimeZone));
- }
-
+ Append(ToTemplateString(IncludeYear));
+ Append(ToTemplateString(IncludeMonth));
+ Append(ToTemplateString(IncludeDay));
+ Append(ToTemplateString(IncludeDayOfWeek));
+ Append(ToTemplateString(IncludeHour));
+ Append(ToTemplateString(IncludeMinute));
+ Append(ToTemplateString(IncludeSecond));
+ Append(ToTemplateString(IncludeTimeZone));
return templateBuilder.ToString();
void Append(string value)
{
- if (value.Length == 0)
- {
- return;
- }
-
if (templateBuilder.Length != 0)
{
templateBuilder.Append(' ');
@@ -473,347 +561,4 @@ void Append(string value)
templateBuilder.Append(value);
}
}
-
- private string BuildPattern()
- {
- string datePattern;
- if (IsLongDate)
- {
- datePattern = _firstCulture.DateTimeFormat.LongDatePattern;
- }
- else if (IsShortDate)
- {
- datePattern = _firstCulture.DateTimeFormat.ShortDatePattern;
- }
- else
- {
- // NOTE: The original order that was specified in the template string does NOT matter.
- // That's why all we need to care about is the values of the mentioned properties.
- // However, we should actually be checking the actual enum value and not just being "None" or not.
- // But the actual correct implementation that will 100% match WinUI isn't yet clear.
- // This is a best effort approach.
- bool hasYear = IncludeYear != YearFormat.None;
- bool hasMonth = IncludeMonth != MonthFormat.None;
- bool hasDay = IncludeDay != DayFormat.None;
- bool hasDayOfWeek = IncludeDayOfWeek != DayOfWeekFormat.None;
-
- if (hasYear && hasMonth && hasDay && hasDayOfWeek)
- {
- datePattern = _firstCulture.DateTimeFormat.LongDatePattern;
- }
- else if (hasYear && hasMonth && hasDay)
- {
- datePattern = _firstCulture.DateTimeFormat.ShortDatePattern;
- }
- else if (hasYear && hasMonth && !hasDayOfWeek)
- {
- datePattern = _firstCulture.DateTimeFormat.YearMonthPattern;
- }
- else if (hasYear && !hasMonth && !hasDay && !hasDayOfWeek)
- {
- datePattern = "yyyy";
- }
- else if (hasMonth && hasDay && !hasYear && !hasDayOfWeek)
- {
- datePattern = _firstCulture.DateTimeFormat.MonthDayPattern;
- }
- else
- {
- // Fallback case.
- // Add more cases as they arise.
- datePattern = _firstCulture.DateTimeFormat.LongDatePattern;
- }
- }
-
- string timePattern;
- if (IsLongTime)
- {
- timePattern = _firstCulture.DateTimeFormat.LongTimePattern;
- }
- else if (IsShortTime)
- {
- timePattern = _firstCulture.DateTimeFormat.ShortTimePattern;
- }
- else
- {
- // NOTE: The original order that was specified in the template string does NOT matter.
- // That's why all we need to care about is the values of the mentioned properties.
- bool hasHour = IncludeHour != HourFormat.None;
- bool hasMinute = IncludeMinute != MinuteFormat.None;
- bool hasSecond = IncludeSecond != SecondFormat.None;
- bool hasTimeZone = IncludeTimeZone != TimeZoneFormat.None;
-
- if (hasHour && hasMinute && hasSecond)
- {
- timePattern = _firstCulture.DateTimeFormat.LongTimePattern;
- }
- else if (hasHour && hasMinute)
- {
- timePattern = _firstCulture.DateTimeFormat.ShortTimePattern;
- }
- else if (hasHour)
- {
- timePattern = "h";
- }
- else if (!hasHour && !hasMinute && !hasSecond)
- {
- timePattern = string.Empty;
- }
- else
- {
- // Shouldn't really be reachable. But a fallback in place just in case.
- timePattern = _firstCulture.DateTimeFormat.LongTimePattern;
- }
-
- if (hasTimeZone)
- {
- if (timePattern.Length == 0)
- {
- timePattern = "zzz";
- }
- else
- {
- timePattern = $"{timePattern} zzz";
- }
- }
- }
-
- string finalSystemFormat;
- if (datePattern.Length > 0 && timePattern.Length > 0)
- {
- finalSystemFormat = $"{datePattern} {timePattern}";
- }
- else if (datePattern.Length > 0)
- {
- finalSystemFormat = datePattern;
- }
- else
- {
- finalSystemFormat = timePattern;
- }
-
- return ConstructPattern(finalSystemFormat);
-
- void AddToBuilder(StringBuilder builder, char lastChar, int count)
- {
- // Best effort implementation.
- switch (lastChar)
- {
- case 'g':
- while (count >= 2)
- {
- builder.Append("{era.abbreviated}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{era.abbreviated}");
- count -= 1;
- }
-
- break;
-
- case 'y':
- while (count >= 5)
- {
- builder.Append("{year.full(5)}");
- count -= 5;
- }
-
- while (count >= 4)
- {
- builder.Append("{year.full}");
- count -= 4;
- }
-
- while (count >= 3)
- {
- builder.Append("{year.full(3)}");
- count -= 3;
- }
-
- while (count >= 2)
- {
- builder.Append("{year.full(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{year.full(1)}");
- count -= 1;
- }
-
- break;
-
- case 'M':
- while (count >= 4)
- {
- builder.Append("{month.full}");
- count -= 4;
- }
-
- while (count >= 3)
- {
- builder.Append("{month.abbreviated}");
- count -= 3;
- }
-
- while (count >= 2)
- {
- builder.Append("{month.integer(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{month.integer}");
- count -= 1;
- }
-
- break;
-
- case 'd':
- while (count >= 4)
- {
- builder.Append("{dayofweek.full}");
- count -= 4;
- }
-
- while (count >= 3)
- {
- builder.Append("{dayofweek.abbreviated}");
- count -= 3;
- }
-
- while (count >= 2)
- {
- builder.Append("{day.integer(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{day.integer}");
- count -= 1;
- }
-
- break;
-
- case 't':
- while (count >= 2)
- {
- builder.Append("{period.abbreviated(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{period.abbreviated(1)}");
- count -= 1;
- }
-
- break;
-
- case 'h' or 'H':
-
- while (count >= 2)
- {
- builder.Append("{hour.integer(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{hour.integer(1)}");
- count -= 1;
- }
-
- break;
-
- case 'm':
-
- while (count >= 2)
- {
- builder.Append("{minute.integer(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{minute.integer(1)}");
- count -= 1;
- }
-
- break;
-
- case 's':
-
- while (count >= 2)
- {
- builder.Append("{second.integer(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{second.integer(1)}");
- count -= 1;
- }
-
- break;
-
- case 'z':
- while (count >= 3)
- {
- builder.Append("{timezone.full}");
- count -= 3;
- }
-
- while (count >= 2)
- {
- builder.Append("{timezone.abbreviated(2)}");
- count -= 2;
- }
-
- while (count >= 1)
- {
- builder.Append("{timezone.abbreviated(1)}");
- count -= 1;
- }
-
- break;
-
- default:
- builder.Append(lastChar, count);
- break;
- }
- }
-
- string ConstructPattern(string str)
- {
- var builder = new StringBuilder();
- char lastChar = str[0];
- int count = 1;
- for (int i = 1; i < str.Length; i++)
- {
- if (lastChar != str[i])
- {
- AddToBuilder(builder, lastChar, count);
-
- lastChar = str[i];
- count = 1;
- }
- else
- {
- count++;
- }
- }
-
- AddToBuilder(builder, lastChar, count);
- return builder.ToString();
- }
- }
-
}
diff --git a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternNodes.cs b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternNodes.cs
index a2c3cf8d6557..146eea3e6a11 100644
--- a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternNodes.cs
+++ b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternNodes.cs
@@ -38,19 +38,19 @@ public PatternRootNode(
public PatternLiteralTextNode? OptionalSuffixLiteralText { get; }
public PatternRootNode? OptionalSuffixPattern { get; }
- internal string Format(DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal string Format(DateTimeOffset dateTime, CultureInfo culture)
{
var builder = new StringBuilder();
- Format(builder, dateTime, culture, isTwentyFourHours);
+ Format(builder, dateTime, culture);
return builder.ToString();
}
- internal void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
- OptionalPrefixLiteralText?.Format(builder, dateTime, culture, isTwentyFourHours);
- DateTimeNode.Format(builder, dateTime, culture, isTwentyFourHours);
- OptionalSuffixLiteralText?.Format(builder, dateTime, culture, isTwentyFourHours);
- OptionalSuffixPattern?.Format(builder, dateTime, culture, isTwentyFourHours);
+ OptionalPrefixLiteralText?.Format(builder, dateTime, culture);
+ DateTimeNode.Format(builder, dateTime, culture);
+ OptionalSuffixLiteralText?.Format(builder, dateTime, culture);
+ OptionalSuffixPattern?.Format(builder, dateTime, culture);
}
}
@@ -65,7 +65,7 @@ public PatternLiteralTextNode(string text)
public string Text { get; }
- internal void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
=> builder.Append(Text);
}
@@ -73,7 +73,7 @@ internal void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo
// | | | |
internal abstract class PatternDateTimeNode
{
- internal abstract void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours);
+ internal abstract void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture);
}
// ::= "{era.abbreviated" [] "}"
@@ -87,7 +87,7 @@ public PatternEraNode(int? idealLength)
// Era is always "era.abbreviated", so no need to distinguish.
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
// C# can't represent negative dates (i.e, before christ).
// So, looks like Era will always be "AD" (Anno Domini).
@@ -114,7 +114,7 @@ public PatternYearNode(YearKind kind, int? idealLength)
public YearKind Kind { get; }
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
if (Kind == YearKind.Full)
{
@@ -170,42 +170,28 @@ public PatternMonthNode(MonthKind kind, int? idealLength = null)
// Always null for full and solo.full
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
+ // TODO
if (Kind == MonthKind.Full)
{
- builder.Append(dateTime.ToString("MMMM", culture));
+
}
else if (Kind == MonthKind.SoloFull)
{
- builder.Append(dateTime.ToString("MMMM", culture));
+
}
else if (Kind == MonthKind.Abbreviated)
{
- builder.Append(dateTime.ToString("MMM", culture));
+
}
else if (Kind == MonthKind.SoloAbbreviated)
{
- builder.Append(dateTime.ToString("MMM", culture));
+
}
else if (Kind == MonthKind.Integer)
{
- if (IdealLength.HasValue)
- {
- var idealLength = IdealLength.Value;
- if (idealLength >= 2)
- {
- builder.Append(dateTime.ToString("MM", culture));
- }
- else
- {
- builder.Append(dateTime.Month);
- }
- }
- else
- {
- builder.Append(dateTime.Month);
- }
+
}
}
}
@@ -235,23 +221,24 @@ public PatternDayOfWeekNode(DayOfWeekKind kind, int? idealLength = null)
// Always null for full and solo.full
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
+ // TODO
if (Kind == DayOfWeekKind.Full)
{
- builder.Append(dateTime.ToString("dddd", culture));
+
}
else if (Kind == DayOfWeekKind.SoloFull)
{
- builder.Append(dateTime.ToString("dddd", culture));
+
}
else if (Kind == DayOfWeekKind.Abbreviated)
{
- builder.Append(dateTime.ToString("ddd", culture));
+
}
else if (Kind == DayOfWeekKind.SoloAbbreviated)
{
- builder.Append(dateTime.ToString("ddd", culture));
+
}
}
}
@@ -266,7 +253,7 @@ public PatternDayNode(int? idealLength)
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
if (IdealLength.HasValue)
{
@@ -289,13 +276,8 @@ public PatternPeriodNode(int? idealLength)
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
- if (isTwentyFourHours)
- {
- return;
- }
-
string period = dateTime.ToString("tt", culture);
if (IdealLength.HasValue && IdealLength.Value < period.Length)
{
@@ -318,21 +300,15 @@ public PatternHourNode(int? idealLength)
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
- int hour = dateTime.Hour;
- if (!isTwentyFourHours && hour > 12)
- {
- hour = hour - 12;
- }
-
if (IdealLength.HasValue)
{
- builder.Append(hour.ToString(new string('0', IdealLength.Value), culture));
+ builder.Append(dateTime.Hour.ToString(new string('0', IdealLength.Value), culture));
}
else
{
- builder.Append(hour);
+ builder.Append(dateTime.Hour);
}
}
}
@@ -347,7 +323,7 @@ public PatternMinuteNode(int? idealLength)
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
if (IdealLength.HasValue)
{
@@ -370,7 +346,7 @@ public PatternSecondNode(int? idealLength)
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
if (IdealLength.HasValue)
{
@@ -404,7 +380,7 @@ public PatternTimeZoneNode(TimeZoneKind kind, int? idealLength = null)
// Always null for full
public int? IdealLength { get; }
- internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture, bool isTwentyFourHours)
+ internal override void Format(StringBuilder builder, DateTimeOffset dateTime, CultureInfo culture)
{
// Important: dateTime parameter shouldn't be used here.
// WinUI uses the local time zone info.
diff --git a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternParser.cs b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternParser.cs
index f5c33414fbcc..eb3fc4167be7 100644
--- a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternParser.cs
+++ b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimePatternParser/PatternParser.cs
@@ -76,11 +76,6 @@ public PatternRootNode Parse()
// | | | |
private PatternDateTimeNode ParseDateTimePattern()
{
- if (Completed)
- {
- throw new ArgumentException($"Failed to parse date time pattern. Already reached the end of the pattern '{_pattern}'.");
- }
-
if (TryParseEra(out var era))
{
return era;
@@ -425,7 +420,7 @@ private void ExpectCharacterAndAdvance(char c)
{
if (_pattern[_index] != '(' ||
_index + 2 >= _pattern.Length ||
- _pattern[_index + 2] != ')')
+ _pattern[_index + 2] != '(')
{
return null;
}
diff --git a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeTemplateParser/TemplateNodes.cs b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeTemplateParser/TemplateNodes.cs
index 2a020273afb5..760860a3671b 100644
--- a/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeTemplateParser/TemplateNodes.cs
+++ b/src/Uno.UWP/Globalization/DateTimeFormatting/DateTimeTemplateParser/TemplateNodes.cs
@@ -1,40 +1,11 @@
#nullable enable
-using System;
using System.Collections.Immutable;
namespace Windows.Globalization.DateTimeFormatting;
-internal sealed class DateTimeTemplateInfo
-{
- public YearFormat IncludeYear { get; set; }
-
- public MonthFormat IncludeMonth { get; set; }
-
- public DayFormat IncludeDay { get; set; }
-
- public DayOfWeekFormat IncludeDayOfWeek { get; set; }
-
- public HourFormat IncludeHour { get; set; }
-
- public MinuteFormat IncludeMinute { get; set; }
-
- public SecondFormat IncludeSecond { get; set; }
-
- public TimeZoneFormat IncludeTimeZone { get; set; }
-
- public bool IsLongTime { get; set; }
-
- public bool IsShortTime { get; set; }
-
- public bool IsLongDate { get; set; }
-
- public bool IsShortDate { get; set; }
-}
-
internal abstract class TemplateNode
{
- internal abstract void Traverse(DateTimeTemplateInfo state);
}
// ::= |
@@ -65,11 +36,6 @@ public TemplateRootNode(TemplateNode first, TemplateNode? second = null)
public TemplateNode First { get; }
public TemplateNode? Second { get; }
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- First.Traverse(state);
- Second?.Traverse(state);
- }
}
// ::= | | | | |
@@ -100,12 +66,6 @@ public TemplateMonthDayNode(TemplateDateNode left, TemplateDateNode right)
public TemplateDateNode Left { get; }
public TemplateDateNode Right { get; }
-
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- Left.Traverse(state);
- Right.Traverse(state);
- }
}
// ::= |
@@ -126,13 +86,6 @@ public TemplateRelativeLongDateNode(TemplateDateNode left, TemplateDateNode midd
public TemplateDateNode Left { get; }
public TemplateDateNode Middle { get; }
public TemplateDateNode Right { get; }
-
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- Left.Traverse(state);
- Middle.Traverse(state);
- Right.Traverse(state);
- }
}
// ::= |
@@ -147,12 +100,6 @@ public TemplateMonthYearNode(TemplateNode left, TemplateNode right)
public TemplateNode Left { get; }
public TemplateNode Right { get; }
-
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- Left.Traverse(state);
- Right.Traverse(state);
- }
}
// ::= "shortdate" |
@@ -176,20 +123,6 @@ public TemplateShortDateNode(TemplateDateNode? left, TemplateDateNode? middle, T
public TemplateDateNode? Left { get; }
public TemplateDateNode? Middle { get; }
public TemplateDateNode? Right { get; }
-
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- if (ReferenceEquals(this, DefaultShortDateInstance))
- {
- state.IsShortDate = true;
- }
- else
- {
- Left!.Traverse(state);
- Middle!.Traverse(state);
- Right!.Traverse(state);
- }
- }
}
// ::= "longdate" |
@@ -233,21 +166,6 @@ public TemplateLongDateNode(TemplateDateNode? first, TemplateDateNode? second, T
public TemplateDateNode? Second { get; }
public TemplateDateNode? Third { get; }
public TemplateDateNode? Forth { get; }
-
- internal override void Traverse(DateTimeTemplateInfo state)
- {
- if (ReferenceEquals(this, DefaultLongDateInstance))
- {
- state.IsLongDate = true;
- }
- else
- {
- First!.Traverse(state);
- Second!.Traverse(state);
- Third!.Traverse(state);
- Forth!.Traverse(state);
- }
- }
}
//