From 5180718423e70d5e18154f0103225ffd05086287 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 6 Apr 2025 08:12:48 -0700 Subject: [PATCH 01/30] Semantic skeletons design This design document contains the proposed design for including semantic skeletons into Unicode MessageFormat's functions. This PR is based on @sffc's [doc](https://docs.google.com/document/d/1s7GeN5V0cnw9B1erfMHTWwmnxz0EJkq2v78ZjzRq2t8/edit) --- exploration/semantic-skeletons.md | 143 ++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 exploration/semantic-skeletons.md diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md new file mode 100644 index 0000000000..19a6407d95 --- /dev/null +++ b/exploration/semantic-skeletons.md @@ -0,0 +1,143 @@ +# Semantic Skeletons Design + +Status: **Proposed** + +
+ Metadata +
+
Contributors
+
@sffc
+
@aphillips
+
First proposed
+
2024-04-06
+
Pull Requests
+
#000
+
+
+ +## Objective + +_What is this proposal trying to achieve?_ + +"Semantic skeletons" are a method introduced in CLDR 46 for programmatically selecting a datetime pattern for formatting. +There is a fixed set of acceptable semantic skeletons. + +Advantages of semantic skeletons over classical skeletons: + +- A smaller set of acceptable options focused on producing outputs that are sensical +- Allows for a more efficient implementation +- Allows for a more clear, ergonomic API +- More future-proof since CLDR recently added them (??) + + + +## Background + +_What context is helpful to understand this proposal?_ + +Semantic skeletons are not the first attempt to provide this functionality. +Previous skeleton mechanisms used +collections of field options (as in `Intl.DateTimeFormat`) +or a microsyntax (as in ICU4J). + +The `Intl.DateTimeFormat` skeletons consist of "option bags" +such as `{ year: "numeric", month: "short", day: "numeric" }` +in which the user specifies the field and its width. +Only fields appearing in the options appear in the formatted date/time value. + +The ICU microsyntax uses strings supplied by the developers. +These strings specify the fields and field lengths that should appear in the formatted value. +See [here](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#date-field-symbol-table) +The system then uses the string to perform date/time pattern generation, +arranging the specified fields in the correct order, +selecting locale-appropriate separators, +and producing a "picture string" that can be consumed by date/time formatters +such as `java.text.SimpleDateFormat`. + +## Use-Cases + +_What use-cases do we see? Ideally, quote concrete examples._ + +As a developer, I want to format date, time, or date/time values to show specific fields +with specific appearance without having to learn a complex microsyntax +or modify my code or formatting directions for each locale. + +As a translator, I want to understand what output a given date/time placeholder will produce +in my language. + +As a translator, I don't want to have to "translate" or modify a date/time placeholder to suit +my language's needs. +I should trust that the placeholder will produce appropriate results for my language. + +## Requirements + +_What properties does the solution have to manifest to enable the use-cases above?_ + +1. It should be possible to format common incremental time types + (e.g. milliseconds since epoch times) +2. It should be possible to format field-based time types + (e.g. those that contain seperate values per field type in a date/time, such as a year-month) +3. It should be possible to format [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values + (e.g. those that are not tied to a specific time zone) +4. Date/time formatters should not permit users to format fields that don't exist in the value + (e.g. the "month" of a time, the "hour" of a date) +5. Date/time formatters should not permit users to format bad combinations of fields + (e.g. `MMMMmm` (month-minute), `yyyyjm` (year-hour-minute), etc.) +6. Date/time formatters should permit users to control or influence the width of indvidual fields + in a manner similar to classical skeletons + (e.g. `yMMd` vs. `yMMMd` vs. `yMMMMd` => 04/06/2025 vs. Apr 6, 2025 vs. April 6, 2025) +7. Developers, translators, and UI designers should only have to learn a single "microsyntax" or set of options for date formatting. + Such a syntax or option set should be easy to understand only from the placeholder. + Such a syntax or option set should not require translators to alter the values in most or all locales. + +## Constraints + +_What prior decisions and existing conditions limit the possible design?_ + +## Proposed Design + +_Describe the proposed solution. Consider syntax, formatting, errors, registry, tooling, interchange._ + +## Alternatives Considered + +_What other solutions are available?_ +_How do they compare against the requirements?_ +_What other properties they have?_ + + +### Design: Use Option Naming + +In this section, we use a scheme similar to `FieldSetBuilder` linked earlier. + +#### DateTime fields + +Options: + +``` +{$date :datetime dateFields="YMD"} +{$date :datetime date="YMD"} +{$date :datetime fields="YMD"} +``` + +#### TimePrecision + +Options: +``` +{$date :datetime timePrecision="minute"} +{$date :datetime time="minute"} +``` +(TODO: Add others) + +### Design: Use Separate Functions + +Some choices: + +1. A single :datetime function + 1. Pro: All in one place + 2. Con: More combinations of options that form invalid skeletons +2. :date, :time, and :datetime + 1. Pro: More tailored and type-safe + 2. Con: Not fully type-safe +3. :date, :time, :datetime, :zoneddatetime, *maybe* :zoneddate, :zonedtime, :timezone + 1. Pro: Most type-safe + 2. Con: Lots of functions From 239b85840bbd9a1de5c5c188f5db2a8da7c9616f Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 6 Apr 2025 08:19:00 -0700 Subject: [PATCH 02/30] Add links --- exploration/semantic-skeletons.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 19a6407d95..ca053ce313 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -29,12 +29,21 @@ Advantages of semantic skeletons over classical skeletons: - Allows for a more clear, ergonomic API - More future-proof since CLDR recently added them (??) +Advantages of semantic skeletons over other mechanisms: + +- Unlike "picture strings" (`MMM dd, yyyy`), does not require translation ## Background _What context is helpful to understand this proposal?_ +Links: +- [Semantic Skeletons Specification](https://unicode.org/reports/tr35/tr35-dates.html#Semantic_Skeletons) +- [ICU4X Field Set Enum \(strongly typed\)](https://unicode-org.github.io/icu4x/rustdoc/icu/datetime/fieldsets/enums/enum.CompositeFieldSet.html) +- [ICU4X Field Set Builder \(more JS-like\)](https://unicode-org.github.io/icu4x/rustdoc/icu/datetime/fieldsets/builder/struct.FieldSetBuilder.html) + + Semantic skeletons are not the first attempt to provide this functionality. Previous skeleton mechanisms used collections of field options (as in `Intl.DateTimeFormat`) From 20f623ae729c170e7ece58a4e045d5e5d2b79df1 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 21 Apr 2025 12:15:30 -0700 Subject: [PATCH 03/30] Explain picture strings better --- exploration/semantic-skeletons.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index ca053ce313..b6b61fdfd6 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -31,7 +31,35 @@ Advantages of semantic skeletons over classical skeletons: Advantages of semantic skeletons over other mechanisms: -- Unlike "picture strings" (`MMM dd, yyyy`), does not require translation +- Unlike "picture strings" (`MMM dd, yyyy`), skeletons do not require translation. + Many date/time formatting regimes provide for "picture strings", which are patterns that + exactly match the expected format of the output. + In a picture string, separators, spaces, and other formatting are explicitly specified. + This provides a lot of power to the devleoper or user experience designer, in terms of specifying formatting. + However, this means that the translator has to modify the string to get localized output. + For example, here are some picture strings with their output vs. the skeleton `MMMddyyyy`: +``` +en-US +MMM dd, yyyy=Apr 21, 2025 +dd MMM, yyyy=21 Apr, 2025 +MM/dd/yyyy=04/21/2025 +dd-MM-yyyy=21-04-2025 +Apr 21, 2025 +--- +fr-FR +MMM dd, yyyy=avr. 21, 2025 +dd MMM, yyyy=21 avr., 2025 +MM/dd/yyyy=04/21/2025 +dd-MM-yyyy=21-04-2025 +21 avr. 2025 +--- +ja-JP +MMM dd, yyyy=4月 21, 2025 +dd MMM, yyyy=21 4月, 2025 +MM/dd/yyyy=04/21/2025 +dd-MM-yyyy=21-04-2025 +2025年4月21日 +``` ## Background From 676f6c9d852c5c53f37bb825e13e4d594381b9ae Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 08:22:18 -0700 Subject: [PATCH 04/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index b6b61fdfd6..721c7d3345 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -11,7 +11,7 @@ Status: **Proposed**
First proposed
2024-04-06
Pull Requests
-
#000
+
#1067
From 289739f843e95536cd74c8ac8a2b88c0057b799d Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 10:12:43 -0700 Subject: [PATCH 05/30] Replace picture output with a table --- exploration/semantic-skeletons.md | 42 +++++++++++++------------------ 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 721c7d3345..9ccd95d159 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -37,31 +37,23 @@ Advantages of semantic skeletons over other mechanisms: In a picture string, separators, spaces, and other formatting are explicitly specified. This provides a lot of power to the devleoper or user experience designer, in terms of specifying formatting. However, this means that the translator has to modify the string to get localized output. - For example, here are some picture strings with their output vs. the skeleton `MMMddyyyy`: -``` -en-US -MMM dd, yyyy=Apr 21, 2025 -dd MMM, yyyy=21 Apr, 2025 -MM/dd/yyyy=04/21/2025 -dd-MM-yyyy=21-04-2025 -Apr 21, 2025 ---- -fr-FR -MMM dd, yyyy=avr. 21, 2025 -dd MMM, yyyy=21 avr., 2025 -MM/dd/yyyy=04/21/2025 -dd-MM-yyyy=21-04-2025 -21 avr. 2025 ---- -ja-JP -MMM dd, yyyy=4月 21, 2025 -dd MMM, yyyy=21 4月, 2025 -MM/dd/yyyy=04/21/2025 -dd-MM-yyyy=21-04-2025 -2025年4月21日 -``` - - + For example, here are some picture strings with their output vs. common skeletons: + +| Picture String | Locale | Output | Skeleton yMMMd | Skeleton yMMd | +|---|---|---|---|---| +|MMM dd, yyyy| en-US | Apr 22, 2025| Apr 22, 2025| 04/22/2025| +| | fr-FR | avr. 22, 2025| 22 avr. 2025| 22/04/2025| +| | ja-JP | 4月 22, 2025| 2025年4月22日| 2025/04/22| +|dd MMM, yyyy| en-US | 22 Apr, 2025| Apr 22, 2025| 04/22/2025| +| | fr-FR | 22 avr., 2025| 22 avr. 2025| 22/04/2025| +| | ja-JP | 22 4月, 2025| 2025年4月22日| 2025/04/22| +|MM/dd/yyyy| en-US | 04/22/2025| Apr 22, 2025| 04/22/2025| +| | fr-FR | 04/22/2025| 22 avr. 2025| 22/04/2025| +| | ja-JP | 04/22/2025| 2025年4月22日| 2025/04/22| +|dd-MM-yyyy| en-US | 22-04-2025| Apr 22, 2025| 04/22/2025| +| | fr-FR | 22-04-2025| 22 avr. 2025| 22/04/2025| +| | ja-JP | 22-04-2025| 2025年4月22日| 2025/04/22| + ## Background _What context is helpful to understand this proposal?_ From e70ad8a6968ef6f02f4d8a1b50cece7381bbeceb Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 10:33:49 -0700 Subject: [PATCH 06/30] Fix objective section --- exploration/semantic-skeletons.md | 46 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 9ccd95d159..b7c10b8ee3 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -19,9 +19,23 @@ Status: **Proposed** _What is this proposal trying to achieve?_ +### Provide support for formatting date/time values using semantic skeletons + "Semantic skeletons" are a method introduced in CLDR 46 for programmatically selecting a datetime pattern for formatting. There is a fixed set of acceptable semantic skeletons. +Previously, ICU MessageFormat provided support for "classical skeletons", +using a microsyntax derived from familiar picture strings (see below) +combined with code in ICU (`DateTimePatternGenerator`) to produce the desired date/time value format. +`Intl.DateTimeFormat` uses "option bags" to provide a similar capability. +A classical skeleton allowed users to express the desired fields and field widths in a formatted date/time value. +The runtime uses locale data to determine minutiae such as +field-order, +separators, +spacing, +field-length, +etc. to produce the desired output. + Advantages of semantic skeletons over classical skeletons: - A smaller set of acceptable options focused on producing outputs that are sensical @@ -29,15 +43,29 @@ Advantages of semantic skeletons over classical skeletons: - Allows for a more clear, ergonomic API - More future-proof since CLDR recently added them (??) -Advantages of semantic skeletons over other mechanisms: -- Unlike "picture strings" (`MMM dd, yyyy`), skeletons do not require translation. - Many date/time formatting regimes provide for "picture strings", which are patterns that - exactly match the expected format of the output. - In a picture string, separators, spaces, and other formatting are explicitly specified. - This provides a lot of power to the devleoper or user experience designer, in terms of specifying formatting. - However, this means that the translator has to modify the string to get localized output. - For example, here are some picture strings with their output vs. common skeletons: +### Avoid 'picture strings' + +The MFWG early on considered including support for "picture strings" in the formatting of date/time values. +There is a Working Group consensus **_not_** to support picture strings in Unicode MessageFormat, if possible. +Many date/time formatting regimes provide for "picture strings". +A "picture string" is a pattern using a microsyntax in which the user (developer, translator, UX designer) +exactly specifies the desired format of the date/time value. +In a picture string, separators, spaces, and other formatting are explicitly specified. +This provides a lot of power to the devleoper or user experience designer, in terms of specifying formatting. +For example: `MMM dd, yyyy` or `yyyy-dd-MM'T'HH:mm:ss` + +Picture strings require translators to interact with and "translate" the picture string +which is embedded into the _placeholder_ in order to get appropriately localized output. +For example, in MF1 you might see: `Today is {myDate,date,MMM dd, yyyy}` + +Translating picture strings can result in non-functional messages. +The exotic microsyntax can be unfamiliar to translators, as it is designed for developers. +Unlike "picture strings", skeletons (classical or semantic) do not require the translator or +developer to alter them for each locale or to know about the specifics, +such as spaces or separators in each locale. + +Here are some picture strings with their output vs. common skeletons: | Picture String | Locale | Output | Skeleton yMMMd | Skeleton yMMd | |---|---|---|---|---| @@ -65,7 +93,7 @@ Links: Semantic skeletons are not the first attempt to provide this functionality. -Previous skeleton mechanisms used +Previous skeleton mechanisms ("classical skeletons") used collections of field options (as in `Intl.DateTimeFormat`) or a microsyntax (as in ICU4J). From c5cf831b7329dc109ef72dc536131c98e455d693 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 10:42:40 -0700 Subject: [PATCH 07/30] Update semantic-skeletons.md --- exploration/semantic-skeletons.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index b7c10b8ee3..a1d26d3bfc 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -38,11 +38,10 @@ etc. to produce the desired output. Advantages of semantic skeletons over classical skeletons: -- A smaller set of acceptable options focused on producing outputs that are sensical -- Allows for a more efficient implementation -- Allows for a more clear, ergonomic API -- More future-proof since CLDR recently added them (??) - +- Provides all and only those combinations that make sense + - Allows for more efficient implementation, since there is no need to support "crazy" combinations like "month-hour" +- Allows for a more clear, ergonomic placeholder syntax, since the number of options can be limited +- Easier for user experience designers to specify, developers to implement, and translators to interpret ### Avoid 'picture strings' @@ -102,7 +101,7 @@ such as `{ year: "numeric", month: "short", day: "numeric" }` in which the user specifies the field and its width. Only fields appearing in the options appear in the formatted date/time value. -The ICU microsyntax uses strings supplied by the developers. +The ICU MessageFormat "classical skeleton" microsyntax uses strings supplied by the developers. These strings specify the fields and field lengths that should appear in the formatted value. See [here](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#date-field-symbol-table) The system then uses the string to perform date/time pattern generation, @@ -130,12 +129,12 @@ I should trust that the placeholder will produce appropriate results for my lang _What properties does the solution have to manifest to enable the use-cases above?_ -1. It should be possible to format common incremental time types - (e.g. milliseconds since epoch times) -2. It should be possible to format field-based time types +1. It should be possible to format operands consisting of common incremental time types + (e.g. milliseconds since epoch times such as `java.util.Date`, `time_t`, JS `Date`, etc.) +2. It should be possible to format operands consisting of field-based time types (e.g. those that contain seperate values per field type in a date/time, such as a year-month) 3. It should be possible to format [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values - (e.g. those that are not tied to a specific time zone) + (e.g. those that are not tied to a specific time zone, variously called local/plain/civil times) 4. Date/time formatters should not permit users to format fields that don't exist in the value (e.g. the "month" of a time, the "hour" of a date) 5. Date/time formatters should not permit users to format bad combinations of fields From 902eab7d24f4abd6af6b8ad9d86d093ba1500461 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 11:05:15 -0700 Subject: [PATCH 08/30] Fix requirements per comments - Put all the time types together in a single requirement about operands --- exploration/semantic-skeletons.md | 38 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index a1d26d3bfc..c619ca6372 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -129,22 +129,32 @@ I should trust that the placeholder will produce appropriate results for my lang _What properties does the solution have to manifest to enable the use-cases above?_ -1. It should be possible to format operands consisting of common incremental time types - (e.g. milliseconds since epoch times such as `java.util.Date`, `time_t`, JS `Date`, etc.) -2. It should be possible to format operands consisting of field-based time types - (e.g. those that contain seperate values per field type in a date/time, such as a year-month) -3. It should be possible to format [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values - (e.g. those that are not tied to a specific time zone, variously called local/plain/civil times) -4. Date/time formatters should not permit users to format fields that don't exist in the value +1. It should be possible to format operands consisting of locally-relevant date/time types, including: + - Temporal values such as `java.time` or JS `Temporal` values, + - incremental time types ("timestamps") + (e.g. milliseconds since epoch times such as `java.util.Date`, `time_t`, JS `Date`, etc.), + - field-based time types + (e.g. those that contain seperate values per field type in a date/time, such as a year-month), + - [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values + (e.g. those that are not tied to a specific time zone, variously called local/plain/civil times), + - or other local exotica (Java `Calendar`, C `tm` struct, etc.) +1. Date/time formatters should not permit users to format fields that don't exist in the value (e.g. the "month" of a time, the "hour" of a date) -5. Date/time formatters should not permit users to format bad combinations of fields +1. Date/time formatters should not permit users to format bad combinations of fields (e.g. `MMMMmm` (month-minute), `yyyyjm` (year-hour-minute), etc.) -6. Date/time formatters should permit users to control or influence the width of indvidual fields - in a manner similar to classical skeletons - (e.g. `yMMd` vs. `yMMMd` vs. `yMMMMd` => 04/06/2025 vs. Apr 6, 2025 vs. April 6, 2025) -7. Developers, translators, and UI designers should only have to learn a single "microsyntax" or set of options for date formatting. - Such a syntax or option set should be easy to understand only from the placeholder. - Such a syntax or option set should not require translators to alter the values in most or all locales. +1. Date/time formatters should permit users to specify the desired width of indvidual fields + in a manner similar to classical skeletons, + while relying on locale data to prevent undesirable results. + For example: + | Classical Skeleton | `en-US` Output | + |---|---| + | `yMd` | 04/06/2025 | + | `yMMMd` | Apr 6, 2025 | + | `yMMMMd` | April 6, 2025 | +1. Developers, translators, and UI designers should not have to learn + multiple new microsyntaxes or multiple different sets of options for date/time value formatting. +1. Any microsyntax or option set specified should be easy to understand only from the placeholder. +1. Any microsyntax or option set specified should not _require_ translators to alter the values in most or all locales. ## Constraints From f5de049414e64835fcae7d67e4af9df1e5be15b5 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 16:00:56 -0700 Subject: [PATCH 09/30] Update semantic-skeletons.md --- exploration/semantic-skeletons.md | 92 ++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index c619ca6372..3bbef76138 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -24,11 +24,27 @@ _What is this proposal trying to achieve?_ "Semantic skeletons" are a method introduced in CLDR 46 for programmatically selecting a datetime pattern for formatting. There is a fixed set of acceptable semantic skeletons. +#### Avoid 'classical skeletons' + Previously, ICU MessageFormat provided support for "classical skeletons", -using a microsyntax derived from familiar picture strings (see below) +using a microsyntax derived from familiar 'picture strings' (see below) combined with code in ICU (`DateTimePatternGenerator`) to produce the desired date/time value format. -`Intl.DateTimeFormat` uses "option bags" to provide a similar capability. -A classical skeleton allowed users to express the desired fields and field widths in a formatted date/time value. + +`Intl.DateTimeFormat` provided options to provide a similar capability. +For example: +```javascript +options = { + hour: "numeric", + minute: "numeric", + second: "numeric", + timeZone: "Australia/Sydney", + timeZoneName: "short", +}; +console.log(new Intl.DateTimeFormat("en-AU", options).format(date)); +// "2:00:00 pm AEDT" +``` + +Classical skeleton solutions allow users to express the desired fields and field widths in a formatted date/time value. The runtime uses locale data to determine minutiae such as field-order, separators, @@ -39,11 +55,12 @@ etc. to produce the desired output. Advantages of semantic skeletons over classical skeletons: - Provides all and only those combinations that make sense - - Allows for more efficient implementation, since there is no need to support "crazy" combinations like "month-hour" + - Allows for more efficient implementation, since there is no need to support combinations like "month-hour" + that are not useful to users - Allows for a more clear, ergonomic placeholder syntax, since the number of options can be limited - Easier for user experience designers to specify, developers to implement, and translators to interpret -### Avoid 'picture strings' +#### Avoid 'picture strings' The MFWG early on considered including support for "picture strings" in the formatting of date/time values. There is a Working Group consensus **_not_** to support picture strings in Unicode MessageFormat, if possible. @@ -129,6 +146,9 @@ I should trust that the placeholder will produce appropriate results for my lang _What properties does the solution have to manifest to enable the use-cases above?_ +Users want the most intuitive formats and outcomes to be the defaults. +They should not have to coerce or convert normal date/time types in order to do simple operations. + 1. It should be possible to format operands consisting of locally-relevant date/time types, including: - Temporal values such as `java.time` or JS `Temporal` values, - incremental time types ("timestamps") @@ -180,17 +200,17 @@ In this section, we use a scheme similar to `FieldSetBuilder` linked earlier. Options: ``` -{$date :datetime dateFields="YMD"} -{$date :datetime date="YMD"} -{$date :datetime fields="YMD"} +{$date :datetime dateFields=YMD} +{$date :datetime date=YMD} +{$date :datetime fields=YMD} ``` #### TimePrecision Options: ``` -{$date :datetime timePrecision="minute"} -{$date :datetime time="minute"} +{$date :datetime timePrecision=minute} +{$date :datetime time=minute} ``` (TODO: Add others) @@ -198,12 +218,46 @@ Options: Some choices: -1. A single :datetime function - 1. Pro: All in one place - 2. Con: More combinations of options that form invalid skeletons -2. :date, :time, and :datetime - 1. Pro: More tailored and type-safe - 2. Con: Not fully type-safe -3. :date, :time, :datetime, :zoneddatetime, *maybe* :zoneddate, :zonedtime, :timezone - 1. Pro: Most type-safe - 2. Con: Lots of functions +#### A single `:datetime` function + +_Pros_ +- Everything is in one place + +_Cons_ +- More combinations of options that can form invalid skeletons +- Can require verbose placeholders + +#### Use separate `:date`, `:time` and `:datetime` functions + +_Pros_ +- More tailored to specific user requirements +- `:date` and `:time` are somewhat self-documenting about the message author's formatting intention + +_Cons_ +- Not fully type-safe. + +#### Use separate semantic functions + +`:date`, `:time`, `:datetime`, `:zoneddatetime`, *maybe* `:zoneddate`, `:zonedtime`, `:timezone` + +Problem: Most users are likely to prefer date/time/datetime to zoneddate/zonedtime/zoneddatetime +as the default formatting functions. +Most "classical" time types are timestamps. +User intentions might not be met by these names. + +Problem: Different platforms cannot agree on what to call a Floating Time Value: HTML and Java use `LocalXXX`, +JavaScript has adopted `PlainXXX`, +some others use different terms, such as `CivilXXX`. + +_Pros_ +- Helps users get the right results +- Could be less verbose +- Better at documenting the message author's intention + +_Cons_ +- _Lots_ of functions + +--- + + + From d2a16a64961e0d07654343e660e17a934512d31f Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 16:31:08 -0700 Subject: [PATCH 10/30] Update exploration/semantic-skeletons.md Co-authored-by: Tim Chevalier --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 3bbef76138..a0fcf38f98 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -154,7 +154,7 @@ They should not have to coerce or convert normal date/time types in order to do - incremental time types ("timestamps") (e.g. milliseconds since epoch times such as `java.util.Date`, `time_t`, JS `Date`, etc.), - field-based time types - (e.g. those that contain seperate values per field type in a date/time, such as a year-month), + (e.g. those that contain separate values per field type in a date/time, such as a year-month), - [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values (e.g. those that are not tied to a specific time zone, variously called local/plain/civil times), - or other local exotica (Java `Calendar`, C `tm` struct, etc.) From 941405bf1dae14cda84ec10457f02a3a737b6841 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 16:31:28 -0700 Subject: [PATCH 11/30] Update exploration/semantic-skeletons.md Co-authored-by: Tim Chevalier --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index a0fcf38f98..040fa8846b 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -68,7 +68,7 @@ Many date/time formatting regimes provide for "picture strings". A "picture string" is a pattern using a microsyntax in which the user (developer, translator, UX designer) exactly specifies the desired format of the date/time value. In a picture string, separators, spaces, and other formatting are explicitly specified. -This provides a lot of power to the devleoper or user experience designer, in terms of specifying formatting. +This provides a lot of power to the developer or user experience designer, in terms of specifying formatting. For example: `MMM dd, yyyy` or `yyyy-dd-MM'T'HH:mm:ss` Picture strings require translators to interact with and "translate" the picture string From 50289722e054a7852e35900196244d5579ff726c Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 16:33:42 -0700 Subject: [PATCH 12/30] Update exploration/semantic-skeletons.md Co-authored-by: Tim Chevalier --- exploration/semantic-skeletons.md | 1 + 1 file changed, 1 insertion(+) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 040fa8846b..c075f3ea3c 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -205,6 +205,7 @@ Options: {$date :datetime fields=YMD} ``` +The names `dateFields`, `date`, and `fields` are candidate names for the option that specifies the semantic skeleton string to be used for formatting the date/time value. #### TimePrecision Options: From 10bb70d17b1dc95d07a30f5c74d2865ddd97af59 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 22 Apr 2025 16:35:56 -0700 Subject: [PATCH 13/30] clarify the picture string table Address @duerst's comment --- exploration/semantic-skeletons.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index c075f3ea3c..6cc85d5406 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -81,7 +81,9 @@ Unlike "picture strings", skeletons (classical or semantic) do not require the t developer to alter them for each locale or to know about the specifics, such as spaces or separators in each locale. -Here are some picture strings with their output vs. common skeletons: +Here are some picture strings with their output vs. common skeletons, +showing how picture strings produce poorly localized output +while skeletons produce localized output: | Picture String | Locale | Output | Skeleton yMMMd | Skeleton yMMd | |---|---|---|---|---| From 108e5f3102f3d3609497378343162eeb2c3e0346 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 23 Apr 2025 08:21:13 -0700 Subject: [PATCH 14/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 6cc85d5406..1e978cbbd1 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -62,14 +62,15 @@ Advantages of semantic skeletons over classical skeletons: #### Avoid 'picture strings' -The MFWG early on considered including support for "picture strings" in the formatting of date/time values. -There is a Working Group consensus **_not_** to support picture strings in Unicode MessageFormat, if possible. Many date/time formatting regimes provide for "picture strings". A "picture string" is a pattern using a microsyntax in which the user (developer, translator, UX designer) exactly specifies the desired format of the date/time value. In a picture string, separators, spaces, and other formatting are explicitly specified. This provides a lot of power to the developer or user experience designer, in terms of specifying formatting. For example: `MMM dd, yyyy` or `yyyy-dd-MM'T'HH:mm:ss` + +The MFWG early on considered including support for "picture strings" in the formatting of date/time values. +There is a Working Group consensus **_not_** to support picture strings in Unicode MessageFormat, if possible. Picture strings require translators to interact with and "translate" the picture string which is embedded into the _placeholder_ in order to get appropriately localized output. From 9d326ece2b98b04cdb76e248080c041b0624f0f9 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 23 Apr 2025 08:27:48 -0700 Subject: [PATCH 15/30] Add FAQ, improve option bag skeleton description --- exploration/semantic-skeletons.md | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 1e978cbbd1..4535e8c0e5 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -31,6 +31,10 @@ using a microsyntax derived from familiar 'picture strings' (see below) combined with code in ICU (`DateTimePatternGenerator`) to produce the desired date/time value format. `Intl.DateTimeFormat` provided options to provide a similar capability. +These weren't "skeletons" from the point of view that they didn't use a dedicated microsyntax +similar to 'picture strings', +but the effect was the same: +user's specified which fields they wanted with which display options (such as width). For example: ```javascript options = { @@ -130,6 +134,47 @@ selecting locale-appropriate separators, and producing a "picture string" that can be consumed by date/time formatters such as `java.text.SimpleDateFormat`. +### FAQ + +This section considers some potential arguments against the design +or captures frequently asked questions about it. + +**What if semantic skeletons doesn't support the format I want? +Unlike picture strings or classical skeletons, semantic skeletons do not allow unrestricted +composition of date/time formats.** + +If there were an overlooked format, it could be added in a future release. +However, the designers of semantic skeletons have considered the breadth of use cases. +If a skeleton is not available, there is probably a good reason for avoiding it. + +**My UX designer wants to specify different separators/presentational details. +I could do that with picture strings, but not with any kind of skeleton. Help!** + +Specialized formats might be constructed using individual fields or by using formatToParts. +In general, such specialized designs rapidly become examples of poor internationalization, +since examples of such adjustments do not consider the breadth of date/time representation. + +**Semantic skeletons are too new. +Implementation experience is limited. +Shouldn't we wait to adopt them?** + +Unicode MessageFormat has a one-time opportunity to avoid "deprecated at birth" date/time formatting +and to provide a robust, internally-consistent mechanism that guides users away from +common date/time formatting pitfalls. + +This is already ample experience with classical skeletons. +The difference with semantic skeletons is that it filters out "mistakes" +such as "11 PM April" (`jjMMMM` or `HHaMMMM`) or "2 2025" (`dyyyy`). + +**What about specialized formats, such as ISO8601?** + +These should be provided via other means that requiring a specialized pattern +and the (optional) `@locale` attribute. Do you really want to support this, +given that it can then be used for other things: +``` +{$now :datetime pattern=|yyyy-MM-dd'T'HH:mm:ss.sssz| @locale=und timezone=UTC} +``` + ## Use-Cases _What use-cases do we see? Ideally, quote concrete examples._ From b8dabd23e9bb6d1265ae0e33cdc3975992ae9b38 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 23 Apr 2025 08:28:34 -0700 Subject: [PATCH 16/30] An apostrophe escaped notice --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 4535e8c0e5..6fd10d5a9f 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -34,7 +34,7 @@ combined with code in ICU (`DateTimePatternGenerator`) to produce the desired da These weren't "skeletons" from the point of view that they didn't use a dedicated microsyntax similar to 'picture strings', but the effect was the same: -user's specified which fields they wanted with which display options (such as width). +users specified which fields they wanted with which display options (such as width). For example: ```javascript options = { From 3ea7e4d77e0628bba6bbd3f12326c6105fff0eec Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 23 Apr 2025 10:15:03 -0700 Subject: [PATCH 17/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 6fd10d5a9f..16e43fcd33 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -221,7 +221,7 @@ They should not have to coerce or convert normal date/time types in order to do | `yMMMMd` | April 6, 2025 | 1. Developers, translators, and UI designers should not have to learn multiple new microsyntaxes or multiple different sets of options for date/time value formatting. -1. Any microsyntax or option set specified should be easy to understand only from the placeholder. +1. Any microsyntax or option set specified should be easy to understand only from the expression. 1. Any microsyntax or option set specified should not _require_ translators to alter the values in most or all locales. ## Constraints From 0f36d02b54d758ae8d32ac584ac99d07b2e2ba66 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 25 Apr 2025 10:17:34 -0700 Subject: [PATCH 18/30] Adding use cases and descriptions of types --- exploration/semantic-skeletons.md | 99 +++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 16e43fcd33..65bbcea3fc 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -175,6 +175,12 @@ given that it can then be used for other things: {$now :datetime pattern=|yyyy-MM-dd'T'HH:mm:ss.sssz| @locale=und timezone=UTC} ``` +**What do we call a [floating time value](https://www.w3.org/TR/timezone/#dfn-floating-time)?** +Different platforms cannot agree on what to call a Floating Time Value: HTML and Java use `LocalXXX`, +JavaScript has adopted `PlainXXX`, +some others use different terms, such as `CivilXXX`. +This could affect what functions or options are named when dealing with floating times. + ## Use-Cases _What use-cases do we see? Ideally, quote concrete examples._ @@ -190,6 +196,90 @@ As a translator, I don't want to have to "translate" or modify a date/time place my language's needs. I should trust that the placeholder will produce appropriate results for my language. +> [!NOTE] +> In the subsections below, we only show the `:datetime` function. +> Readers should assume that `:date` and `:time` also exist. + +### Incremental (timestamp) values +As a developer, I want to format common incremental time values. +Examples of these are `java.util.Date`, JS `Date`, `time_t`, etc. +These are typically measured in millis or seconds in the UNIX epoch. +The UNIX epoch is measured from January 1, 1970 and uses the UTC time zone. +These values are "attached to the timeline", +that is, they are not floating times. +These types are very common and are the only option for representing time in some programming languages. + +Incremental values usually do not include time zone. +They occasionally include a _local time offset_ ("offset"), although most commonly they do not. + +To format a timestamp an offset or a timezone is required. +Options for providing this are: +- Assume UTC +- Assume the runtime's current offset or time zone should be used +- Require offset or time zone be provided (or error) +- Assume the runtime's offset/time zone, but allow user to override + +For the table below +- `$d` is the date value `0` (January 1, 1970 00:00:00 UTC); +- the runtime's time zone is `America/Los_Angeles`; +- the user has a time zone of `Europe/Helsinki` + +| Option | Syntax | Output | +|---|---|---| +| Assume UTC | `{$d :datetime}` | `Jan 1, 1970, 12:00:00 AM UTC` | +| Assume runtime zone | `{$d :datetime}` | `Dec 31, 1969, 4:00:00 PM PST` | +| Require offset | `{$d :datetime offset=\|02:00\|` | `Jan 1, 1970, 2:00:00 AM GMT+2` | +| Require zone... | `{$d :datetime timezone=\|Europe/Helsinki\|}` | `Jan 1, 1970, 2:00:00 AM EET` | +| ... or error | `{$d :datetime}` | `Bad Operand` | +| Assume runtime... | `{$d :datetime}` | `Dec 31, 1969, 4:00:00 PM PST` | +| ...but allow override | `{$d :datetime timezone=\|Europe/Helsinki\|}` | `Jan 1, 1970, 2:00:00 AM EET` | + +> [!NOTE] +> Time zone and offset option values can be specified using variables. + +### Floating Time values +As a developer, I want to format floating time values. +I may need to force an incremental value to "float", since many platforms do not have a type for floating times, +they only have incremental values. +I may need to force a zoned value to "float" by removing the offset or zone. +I may also need to attach a floating value to the timeline by specifying an offset or time zone. + +Floating/unfloating time values is a less-common requirement, +so functions/options might not need to be optimized for these cases. + +For the table below: +- `$f` is a floating time value equivalent to `1970-01-01T00:00:00.00` +- `$d` is a timestamp equivalent to `1970-01-01T00:00:00.00Z` +- `$zoned` is a non-floating value equivalent to `1970-01-01T00:00:00.000Z[America/Los_Angeles]` + (this value might also be represented as `1969-12-31T16:00:00.000-08:00[America/Los_Angeles]`) +- the option `offset` is an example only; the function `:localdatetime` is an example only. + The function `:zoneddatetime` is one of the alternative designs for zoned values, + which might make `:datetime` the equivalent of `:localdatetime`?? + +| Option | Syntax | Output | +|---|---|---| +| Format a floating time | `{$f :datetime}` | `Jan 1, 1970, 12:00:00 AM` | +| Float a timestamp | `{$d :datetime offset=none}` | `Jan 1, 1970, 12:00:00 AM` | +| Float a zoned value | `{$zoned :datetime offset=none}` | `Dec 31, 1969, 4:00:00 PM` | +| ... using floating function | `{$zoned :localdatetime}` | `Dec 31, 1969, 4:00:00 PM` | +| Attach a floating time to timeline | `{$f :datetime timezone=\|Europe/Helsinki\|}` | `Jan 1, 1970, 2:00:00 AM EET` | + +### Zoned or Offset Time values +As a developer, I want to format time values that include an offset or time zone. + +In the preceding subsections, the possibility of allowing time zone or offset +to be provided (in the case of timestamps) +or overridden (in the case of floating times or zoned/offsetted times) +was described. +If such behavior is permitted, it introduces tension between the options for offset/time zone +and the value itself. +That is, given a value `1970-01-01T00:00:00.000Z[UTC]` +and an expression `{$zoned :datetime timezone=\|Europe/Helsinki\|}`, +what is the format? +- `Jan 1, 1970, 12:00:00 AM UTC` (value wins; user cannot adjust) +- `Jan 1, 1970, 2:00:00 AM EET` (option wins; inconsistent with some Temporal behaviors on Java and JS) + + ## Requirements _What properties does the solution have to manifest to enable the use-cases above?_ @@ -223,6 +313,11 @@ They should not have to coerce or convert normal date/time types in order to do multiple new microsyntaxes or multiple different sets of options for date/time value formatting. 1. Any microsyntax or option set specified should be easy to understand only from the expression. 1. Any microsyntax or option set specified should not _require_ translators to alter the values in most or all locales. +1. User's should be able to specify the time zone or local time offset used in formatting + an incremental or timestamp value + because many date/time formatting processes are + running in a different environment/offset/zone from where the value will be seen + or are formatting a value for a specific offset or zone. ## Constraints @@ -294,10 +389,6 @@ as the default formatting functions. Most "classical" time types are timestamps. User intentions might not be met by these names. -Problem: Different platforms cannot agree on what to call a Floating Time Value: HTML and Java use `LocalXXX`, -JavaScript has adopted `PlainXXX`, -some others use different terms, such as `CivilXXX`. - _Pros_ - Helps users get the right results - Could be less verbose From 1fb130b7f13c6a1bff74d1caa9c217f92cf00195 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Sun, 27 Apr 2025 10:55:41 -0700 Subject: [PATCH 19/30] Add an alternative design --- exploration/semantic-skeletons.md | 42 +++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 65bbcea3fc..e07c9ef7d4 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -380,7 +380,7 @@ _Pros_ _Cons_ - Not fully type-safe. -#### Use separate semantic functions +#### Use separate typed functions `:date`, `:time`, `:datetime`, `:zoneddatetime`, *maybe* `:zoneddate`, `:zonedtime`, `:timezone` @@ -395,7 +395,45 @@ _Pros_ - Better at documenting the message author's intention _Cons_ -- _Lots_ of functions +- More functions + + +#### Use separate skeleton functions + +Define functions according to the available "field sets" or fields in the semantic skeletons spec. +Use options to handle field widths. +Such a list might look like: + +- Standalone fields + - `:day`, `:weekday`, `:month`, `:year`, `:hour`, `:minute`, `:second`, `:zone`, `:era` + - plus the common combo `:time` and `:date` +- Date Field Sets + - `:day-weekday`, `:month-day`, `:month-day-weekday`, `:year-month-day`, `:year-month-day-weekday` +- Composite field sets + - `:date-zone`, `:date-time-zone`, `:time-zone` (note: `time-zone` is two fields, not "timezone") + +Examples: +``` +Your package arrived on {$d :date} at {$d :time}. + Your package arrived on Apr 27, 2025 at 10:50 AM. +Your package arrived on {$d :month-day-weekday} at {$d :time-zone}. + Your package arrived on Sunday, April 27th at 10:50 AM PDT. +Your package arrived on {$d :month-day-weekday month=medium weekday=full} at {$d :time-zone display=full zone=short}. + Your package arrive on Sunday, Apr 27th at 10:50 PDT. +``` + + +_Pros_ +- Options focused on field widths +- Self-documenting: obvious what fields are shown +- Reserves options for field width + +_Cons_ +- _Nineteen_ (or so) functions +- Names appear generative, but aren't actually +- Options might be baroque. Some option values might not be compatible with one another. + - Expression-wide options (short/medium/long/full) and field-level options might both be needed together + --- From afd0001b6581cfd1a1e5dd3183eec4cad7d1eedb Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 29 Apr 2025 07:57:53 -0700 Subject: [PATCH 20/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index e07c9ef7d4..5703e211e5 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -296,8 +296,8 @@ They should not have to coerce or convert normal date/time types in order to do - [floating time](https://www.w3.org/TR/timezone/#dfn-floating-time) values (e.g. those that are not tied to a specific time zone, variously called local/plain/civil times), - or other local exotica (Java `Calendar`, C `tm` struct, etc.) -1. Date/time formatters should not permit users to format fields that don't exist in the value - (e.g. the "month" of a time, the "hour" of a date) +1. Date/time formatter options should be able to impose restrictions on acceptable values, + such as formatting a month requiring a date, and formatting an hour requiring a time. 1. Date/time formatters should not permit users to format bad combinations of fields (e.g. `MMMMmm` (month-minute), `yyyyjm` (year-hour-minute), etc.) 1. Date/time formatters should permit users to specify the desired width of indvidual fields From a9440d5f7436a86a5d30afc3bda69be8578914d2 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 29 Apr 2025 07:58:59 -0700 Subject: [PATCH 21/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 5703e211e5..e9ae081e0d 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -139,9 +139,10 @@ such as `java.text.SimpleDateFormat`. This section considers some potential arguments against the design or captures frequently asked questions about it. -**What if semantic skeletons doesn't support the format I want? -Unlike picture strings or classical skeletons, semantic skeletons do not allow unrestricted -composition of date/time formats.** +**What if semantic skeletons don't support the format I want?** + +Unlike picture strings or classical skeletons, +semantic skeletons do not allow unrestricted composition of date/time formats. If there were an overlooked format, it could be added in a future release. However, the designers of semantic skeletons have considered the breadth of use cases. From ff58cc3abcf4bc9597b3370011b5ddc373f4ba65 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 29 Apr 2025 07:59:48 -0700 Subject: [PATCH 22/30] Update exploration/semantic-skeletons.md Co-authored-by: Eemeli Aro --- exploration/semantic-skeletons.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index e9ae081e0d..1c12a76425 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -169,11 +169,12 @@ such as "11 PM April" (`jjMMMM` or `HHaMMMM`) or "2 2025" (`dyyyy`). **What about specialized formats, such as ISO8601?** -These should be provided via other means that requiring a specialized pattern -and the (optional) `@locale` attribute. Do you really want to support this, +These should be provided via other means than requiring a specialized pattern +and the (optional) `u:locale` option. +Do you really want to support this, given that it can then be used for other things: ``` -{$now :datetime pattern=|yyyy-MM-dd'T'HH:mm:ss.sssz| @locale=und timezone=UTC} +{$now :datetime pattern=|yyyy-MM-dd'T'HH:mm:ss.sssz| u:locale=und timezone=UTC} ``` **What do we call a [floating time value](https://www.w3.org/TR/timezone/#dfn-floating-time)?** From 937c04b8fda30cca8b9fc9bb69ff3c5c789c37d8 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 29 Apr 2025 08:02:00 -0700 Subject: [PATCH 23/30] Make `Intl.DateTimeFormat` present tense --- exploration/semantic-skeletons.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 1c12a76425..d8d6c5c901 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -30,11 +30,10 @@ Previously, ICU MessageFormat provided support for "classical skeletons", using a microsyntax derived from familiar 'picture strings' (see below) combined with code in ICU (`DateTimePatternGenerator`) to produce the desired date/time value format. -`Intl.DateTimeFormat` provided options to provide a similar capability. -These weren't "skeletons" from the point of view that they didn't use a dedicated microsyntax -similar to 'picture strings', -but the effect was the same: -users specified which fields they wanted with which display options (such as width). +`Intl.DateTimeFormat` provides options that provide a similar capability. +These aren't "skeletons" from the point of view that they don't use a dedicated microsyntax similar to 'picture strings', +but the effect is the same: +users specify which fields they want with which display options (such as width). For example: ```javascript options = { From 1beea81962de6594a43d1aab456b9968a2ba5a8e Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 2 May 2025 07:25:48 -0700 Subject: [PATCH 24/30] typo --- exploration/semantic-skeletons.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index d8d6c5c901..6df42c2589 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -314,7 +314,7 @@ They should not have to coerce or convert normal date/time types in order to do multiple new microsyntaxes or multiple different sets of options for date/time value formatting. 1. Any microsyntax or option set specified should be easy to understand only from the expression. 1. Any microsyntax or option set specified should not _require_ translators to alter the values in most or all locales. -1. User's should be able to specify the time zone or local time offset used in formatting +1. Users should be able to specify the time zone or local time offset used in formatting an incremental or timestamp value because many date/time formatting processes are running in a different environment/offset/zone from where the value will be seen From be267244ad3b73e31be6e9c4731db23d4f8eaa05 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Fri, 2 May 2025 07:30:04 -0700 Subject: [PATCH 25/30] Add @eemeli's example --- exploration/semantic-skeletons.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 6df42c2589..7c4e44dd59 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -280,6 +280,21 @@ what is the format? - `Jan 1, 1970, 12:00:00 AM UTC` (value wins; user cannot adjust) - `Jan 1, 1970, 2:00:00 AM EET` (option wins; inconsistent with some Temporal behaviors on Java and JS) +### Inflection + +``` +new Intl.DateTimeFormat('fi', { month: 'long' }).format() +// 'toukokuu' + +new Intl.DateTimeFormat('fi', { day: 'numeric', month: 'long' }).format() +// '2. toukokuuta' +``` + +As a developer, I need the formatted values to inflect fields and formats correctly, +depending on the combination chosen for display. +For example, as shown above, +I want the month name to be inflected for standalone when used by itself, +but properly inflected when used in a month-day combination. ## Requirements @@ -407,7 +422,8 @@ Such a list might look like: - Standalone fields - `:day`, `:weekday`, `:month`, `:year`, `:hour`, `:minute`, `:second`, `:zone`, `:era` - - plus the common combo `:time` and `:date` +- Common combinations + - `:time` and `:date` - Date Field Sets - `:day-weekday`, `:month-day`, `:month-day-weekday`, `:year-month-day`, `:year-month-day-weekday` - Composite field sets From 7cf129a2200e47dfd215296ad8064ab7f810bf62 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 5 May 2025 06:49:48 -0700 Subject: [PATCH 26/30] Apply suggestion manually (time zone/offset discussion) --- exploration/semantic-skeletons.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 7c4e44dd59..c1fc5cf3ec 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -329,11 +329,11 @@ They should not have to coerce or convert normal date/time types in order to do multiple new microsyntaxes or multiple different sets of options for date/time value formatting. 1. Any microsyntax or option set specified should be easy to understand only from the expression. 1. Any microsyntax or option set specified should not _require_ translators to alter the values in most or all locales. -1. Users should be able to specify the time zone or local time offset used in formatting - an incremental or timestamp value - because many date/time formatting processes are - running in a different environment/offset/zone from where the value will be seen - or are formatting a value for a specific offset or zone. +1. Message authors and developers should be able to manage + the formatting of date/time values such that + processes running in an environment with a different time zone or local time offset + from that needed to express or format the value + can get the necessary results. ## Constraints From 754c53f394e6824ff25d7e8b8ad9497bfb149f81 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Mon, 5 May 2025 11:01:03 -0700 Subject: [PATCH 27/30] Update exploration/semantic-skeletons.md --- exploration/semantic-skeletons.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index c1fc5cf3ec..638ac51701 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -450,7 +450,15 @@ _Cons_ - Names appear generative, but aren't actually - Options might be baroque. Some option values might not be compatible with one another. - Expression-wide options (short/medium/long/full) and field-level options might both be needed together - +- Providing easy-to-use standalone field functions + could lead to localization failures similar to picture strings, + as naive users might use combinations of standalone functions to concatenate date/time values + that are inappropriate in various other locales and require translator intervention. + > For example, this message hard codes separators, field order, and + > uses standalone representation of the fields: + > ``` + > Today is {$d :month} {$d :day}, {$d :year} and it is {$d :hour}:{$d :minute} o'clock. + >``` --- From 9f84cbab17a25da50767df3c8e73676199eec24c Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Tue, 13 May 2025 11:49:26 -0700 Subject: [PATCH 28/30] Start work on 2025-05-12 discussion Start working on error section, add references to ICU4X field sets, including a table --- exploration/semantic-skeletons.md | 75 +++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 638ac51701..6325edfded 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -7,7 +7,7 @@ Status: **Proposed**
Contributors
@sffc
-
@aphillips
+
@aphillips
First proposed
2024-04-06
Pull Requests
@@ -296,6 +296,31 @@ For example, as shown above, I want the month name to be inflected for standalone when used by itself, but properly inflected when used in a month-day combination. +### Error Conditions and Value Forcing +One challenge with formatting date/time values is +deciding what effect the function has on the resolved value of the operand. +For example, consider a _declaration_ that uses a function `:time`: +>``` +>.local $myTime = {$d :time} +>``` + +Does the variable `$myTime` contain any date information, such as year or month? +What if `$d` (the original value) is an incremental time? Or a datetime value? +Does the declaration strip the visibility of the date fields, assuming that they _were_ previously present? + +On the other hand, many combinations of functions and semantic skeletons seem to imply an implicit conversion. +Implementations that use, for example, `java.time` or JS `Temporal` types +have very specific requirements for some of their types. +Some operations on these types can produce error conditions in the function handler, +even if the _message_ itself is well-formed and other, differently-typed, values do not produce errors. + +As noted elsewhere, many programming languages and operating environments do not have +more-modern temporal-like date/time types. +Incremental values or field-based values in these environments +use calendar and time zone information to compute the displayed field. +Users of these kinds of date/time values sometime can need access to calendar, time zone, and possibly offset controls +in order to achieve effects similar to what temporal types provide. + ## Requirements _What properties does the solution have to manifest to enable the use-cases above?_ @@ -352,11 +377,38 @@ _What other properties they have?_ ### Design: Use Option Naming -In this section, we use a scheme similar to `FieldSetBuilder` linked earlier. +In this design, we use a capability similar to `FieldSetBuilder` (proposed for ICU4X). +These have the following built-in "fieldsets" (see [here](https://unicode-org.github.io/icu4x/rustdoc/icu/datetime/fieldsets/index.html)): + +| Fieldset | Description | +|------------|-------------| +| `Combo` | Struct for combining date/time fields with zone fields. | +| `D` | “17” ⇒ day of month (standalone) | +| `DE` | “17 Friday” ⇒ day of month and weekday | +| `DET` | “17 Friday, 3:47:50 PM” ⇒ day of month and weekday with time | +| `DT` | “17, 3:47:50 PM” ⇒ day of month (standalone) with time | +| `E` | “Friday” ⇒ weekday (standalone) | +| `ET` | “Friday 3:47:50 PM” ⇒ weekday (standalone) with time | +| `M` | “May” ⇒ month (standalone) | +| `MD` | “May 17” ⇒ month and day | +| `MDE` | “Fri, May 17” ⇒ month, day, and weekday | +| `MDET` | “Fri, May 17, 3:47:50 PM” ⇒ month, day, and weekday with time | +| `MDT` | “May 17, 3:47:50 PM” ⇒ month and day with time | +| `T` | “3:47:50 PM” ⇒ time (locale-dependent hour cycle) | +| `Y` | “2024” ⇒ year (standalone) | +| `YM` | “May 2024” ⇒ year and month | +| `YMD` | “5/17/24” ⇒ year, month, and day | +| `YMDE` | “Fri, 5/17/24” ⇒ year, month, day, and weekday | +| `YMDET` | “Fri, 5/17/24, 3:47:50 PM” ⇒ year, month, day, and weekday with time | +| `YMDT` | “5/17/24, 3:47:50 PM” ⇒ year, month, and day with time | + #### DateTime fields +Use the function `:datetime` and use an _option_ to indicate the fieldset. -Options: +The _option_ might have a generic name, such as `fields`, +or it might have sematic names such as `date`/`dateFields`/`time`/`timeFields`. +Option values would be as shown in the table above. ``` {$date :datetime dateFields=YMD} @@ -364,15 +416,21 @@ Options: {$date :datetime fields=YMD} ``` -The names `dateFields`, `date`, and `fields` are candidate names for the option that specifies the semantic skeleton string to be used for formatting the date/time value. #### TimePrecision +Note that in the table above, there is only one fieldset of "time" values. +Use a `timePrecision` option to indicate which subfields of a time are desired. +Time formats within a locale don't generally have field lengths +(although zero- versus non-zero filled hours is a variation) +and thus it is sufficient to say what the "last field to show" would be. -Options: +The name `timePrecision` is a placeholder. +This option might be shortened to just `time`. + +For example: ``` -{$date :datetime timePrecision=minute} -{$date :datetime time=minute} +{$date :datetime timePrecision=minute} ⇒ 11:39 AM +{$date :datetime time=second} ⇒ 11:39:00 AM ``` -(TODO: Add others) ### Design: Use Separate Functions @@ -395,6 +453,7 @@ _Pros_ _Cons_ - Not fully type-safe. +- The `:datetime` function might duplicate functionality #### Use separate typed functions From e29b5e293cfa8123fedda3bae0cbffe75f3a89b1 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 4 Jun 2025 09:05:13 -0700 Subject: [PATCH 29/30] Add materials about field width specification --- exploration/semantic-skeletons.md | 78 ++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index 6325edfded..fad49ead96 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -321,6 +321,72 @@ use calendar and time zone information to compute the displayed field. Users of these kinds of date/time values sometime can need access to calendar, time zone, and possibly offset controls in order to achieve effects similar to what temporal types provide. +### Dealing with Field Widths + +The current design of date/time functions includes "option bags" derived from `Intl.DateTimeFormat`. +These option bags serve as both classical skeletons _and_ as a source for field width. +The current options are specified as: + +- `weekday` + - `long` + - `short` + - `narrow` +- `era` + - `long` + - `short` + - `narrow` +- `year` + - `numeric` + - `2-digit` +- `month` + - `numeric` + - `2-digit` + - `long` + - `short` + - `narrow` +- `day` + - `numeric` + - `2-digit` +- `hour` + - `numeric` + - `2-digit` +- `minute` + - `numeric` + - `2-digit` +- `second` + - `numeric` + - `2-digit` +- `fractionalSecondDigits` + - `1` + - `2` + - `3` +- `timeZoneName` + - `long` + - `short` + - `shortOffset` + - `longOffset` + - `shortGeneric` + - `longGeneric` + +Notice that each of these options is specifically about field width or presentation. +The "skeleton" functionality in `Intl` is based on the idea that only the fields mentioned are formatted. +If a separate option specifies which fields to use, +then the above options could be used independently to control field presentation. + +> Examples. +> ``` +> {{{$d :datetime fields=YMDE month=short} prints Wednesday, Jun 4, 2025}} +> {{{$d :datetime fields=YMDE month=short weekday=short} prints Wed, Jun 4, 2025}} +> {{{$d :datetime fields=T timePrecision=minutes} prints 9:53 AM}} +> {{{$d :datetime fields=T timePrecision=seconds hour=2-digit} prints 09:53:00 AM}} +> {{{$d :datetime fields=T timePrecision=fractionalSeconds hour=2-digit fractionalSecondDigits=2} prints 09:53:00.17 AM}} +> ``` + +In the above design, it would be an error to specify a field width for a field that is not in the skeleton: +``` +{{{$d :datetime fields=T month=short} is an error.}} +``` + ## Requirements _What properties does the solution have to manifest to enable the use-cases above?_ @@ -432,6 +498,15 @@ For example: {$date :datetime time=second} ⇒ 11:39:00 AM ``` +Pros: +- Reduces the number of skeleton strings and associated alphabet soup + for message authors (developers, translators) to memorize + +Cons: +- Different mechanism from that used for the date portion. + Greater learning curve/cognitive burden for users? + + ### Design: Use Separate Functions Some choices: @@ -505,7 +580,7 @@ _Pros_ - Reserves options for field width _Cons_ -- _Nineteen_ (or so) functions +- _Eighteen_ (or so) functions - Names appear generative, but aren't actually - Options might be baroque. Some option values might not be compatible with one another. - Expression-wide options (short/medium/long/full) and field-level options might both be needed together @@ -522,4 +597,3 @@ _Cons_ --- - From 8f41b5fdb251d181e3fd8c887a51547a61ab9590 Mon Sep 17 00:00:00 2001 From: Addison Phillips Date: Wed, 4 Jun 2025 09:29:36 -0700 Subject: [PATCH 30/30] Add design from @sffc's comment --- exploration/semantic-skeletons.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/exploration/semantic-skeletons.md b/exploration/semantic-skeletons.md index fad49ead96..2c105f6b83 100644 --- a/exploration/semantic-skeletons.md +++ b/exploration/semantic-skeletons.md @@ -506,6 +506,27 @@ Cons: - Different mechanism from that used for the date portion. Greater learning curve/cognitive burden for users? +#### Mixing the Above Solutions + +Use `dateFields`, `timePrecisions` and `zoneStyle` to separately control the date, time, and zone +portions of a placeholder. + +> A date formatter +>``` +> {$d :datetime dateFields=YMD} +>``` +> A time formatter +>``` +> {$d :datetime timePrecision=minute} +>``` +> A datetime formatter +>``` +> {$d :datetime dateFields=YMD timePrecision=minute} +>``` +> A zoned datetime formatter +>``` +> {$d :datetime dateFields=YMD timePrecision=minute zoneStyle=generic} +>``` ### Design: Use Separate Functions