Intl.DateTimeFormat issue with "2-digit" option on hour, minute and second
Categories
(Core :: JavaScript: Internationalization API, defect, P5)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox91 | --- | fixed |
People
(Reporter: toxicbuzzer, Assigned: anba)
References
()
Details
(Keywords: intl)
Attachments
(1 file)
Comment 1•9 years ago
|
||
Comment 2•9 years ago
|
||
| Assignee | ||
Comment 3•9 years ago
|
||
Updated•8 years ago
|
| Comment hidden (me-too) |
Comment 6•7 years ago
|
||
This got reported upstream in this ECMAScript issue: https://github.com/tc39/ecma402/issues/283
I filed a ticket against CLDR. Peter Edberg quickly replied with:
DateTimePatternGenerator has a version of getBestPattern that takes options:
UnicodeString icu::DateTimePatternGenerator::getBestPattern (const
UnicodeString &skeleton,
UDateTimePatternMatchOptions options, UErrorCode & status);and one of those options is
UDATPG_MATCH_HOUR_FIELD_LENGTH
Frank Tang added that flag to Chromium and was able to fix the issue:
https://bugs.chromium.org/p/chromium/issues/detail?id=527926#c14
Perhaps the same fix can be done in SpiderMonkey.
| Assignee | ||
Comment 7•7 years ago
|
||
(In reply to Shane Carr from comment #6)
Perhaps the same fix can be done in SpiderMonkey.
Comment #0 is similar, but not the same as https://github.com/tc39/ecma402/issues/283 ("second" vs. "hour" field). ICU also has UDATPG_MATCH_ALL_FIELDS_LENGTH, but I don't know if just enabling it is the correct choice for all possible skeleton combinations (comment #3).
Comment 8•7 years ago
|
||
Is there an example where UDATPG_MATCH_ALL_FIELDS_LENGTH doesn't do the right thing?
Does answering that question just require a careful reading of the spec?
| Assignee | ||
Comment 9•7 years ago
|
||
I haven't tried it yet, so I can't really tell. In the worst case, every possible field combination in Intl.DateTimeFormat for all supported locales needs to be compared when UDATPG_MATCH_ALL_FIELDS_LENGTH is used resp. not used, and then the output needs to be checked if it's still valid for each locale to avoid returning bogus results.
| Assignee | ||
Comment 10•6 years ago
|
||
After reading the relevant ICU source code, I come to the conclusion that always using UDATPG_MATCH_ALL_FIELDS_LENGTH is okay to do and should also match the CLDR "automatic expansion" requirements from https://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems.
Basically the default behaviour when calling udatpg_getBestPattern resp. udatpg_getBestPatternWithOptions with UDATPG_MATCH_NO_OPTIONS is to adjust all fields except for "hour", "minute", and "second". And only when UDATPG_MATCH_ALL_FIELDS_LENGTH is used, the "hour", "minute", and "second" fields also get the "automatic expansion" feature described in CLDR.
Example for "automatic expansion" (basically repeating the example from CLDR):
common/main/en.xml has this entry:
<dateFormatItem id="yMMMd">MMM d, y</dateFormatItem>
There is no "yMMMMd" entry, so a request for the skeleton "yMMMMd" returns the best-match result "yMMMd" with its pattern "MMM d, y". This best-match pattern is then expanded to "MMMM d, y" and we get the expected result:
js> new Intl.DateTimeFormat("en", {year: "numeric", month: "long", day: "numeric"}).format(new Date("2019-08-06T00:00:00"))
"August 6, 2019"
And using the shell we can also verify the expected pattern is computed:
js> getSelfHostedValue("intl_patternForSkeleton")("en", "yMMMMd")
"MMMM d, y"
| Assignee | ||
Comment 11•6 years ago
|
||
And to address my concerns at comment #3, comment #7, and comment #9:
I was concerned UDATPG_MATCH_ALL_FIELDS_LENGTH means invalid length adjustments are performed, similar to the example in https://unicode.org/reports/tr35/tr35-dates.html#Matching_Skeletons where it's made clear that the pattern "y年M月" should not be expanded to "y年MMMM月" when the input skeleton was "yMMMM".
| Assignee | ||
Comment 12•6 years ago
|
||
Hmm, I don't think we can make this change unless we also request a spec change. When UDATPG_MATCH_ALL_FIELDS_LENGTH is used, the following test case uses "numeric" representation for "minute" and "second", but I guess most would expect to see "2-digit" there.
js> new Date("2019-08-01T01:02:03").toLocaleString("en", {timeZoneName: "long"})
"8/1/2019, 1:2:3 AM Pacific Daylight Time"
This is caused by ToDateTimeOptions defaulting "minute" and "second" to "numeric" in step 7.
| Assignee | ||
Comment 13•6 years ago
|
||
Maybe that's just an ICU bug? The example in comment #12 should use the skeleton "jmszzzz", which, when replacing "j" with the preferred hour symbol "h", should result in finding the following pattern from en.xml:
<dateFormatItem id="hmsv">h:mm:ss a v</dateFormatItem>
The "hms" in "hmsv" matches the fields in the input skeleton "hmszzzz", so only "v" should get automatic expansion to "zzzz". Therefore I'd expect the final pattern to be "h:mm:ss a zzzz". My first guess is that the "v" and "z" mismatch is causing this issue:
js> getSelfHostedValue("intl_patternForSkeleton")("en", "hmsv")
"h:mm:ss a v"
js> getSelfHostedValue("intl_patternForSkeleton")("en", "hmsvvvv")
"h:mm:ss a vvvv"
js> getSelfHostedValue("intl_patternForSkeleton")("en", "hmszzzz")
"h:m:s a zzzz"
| Assignee | ||
Comment 14•6 years ago
|
||
Yes, it is an ICU bug resp. limitation. When DateTimePatternGenerator::adjustFieldTypes adjust the field lengths, it normally takes the original input skeleton into account, except for the case when no skeleton is present. A skeleton may not be present when the pattern was added through DateTimePatternGenerator::addICUPatterns, because that function ends up calling addPatternWithSkeleton with skeletonToUse = nullptr.
One of the ICU patterns added in addICUPatterns is "h:mm:ss a zzzz", which is the one used when requesting "hmszzzz". So we request "hmszzzz" and ICU finds "h:mm:ss a zzzz" as the best match. But "h:mm:ss a zzzz" has no skeleton attached to it, so adjustFieldTypes can't compare the input skeleton with the skeleton of the best-match pattern and instead will adjust all fields, resulting in the final pattern "h:m:s a zzzz".
| Assignee | ||
Comment 15•4 years ago
|
||
Change DateTimePatternGenerator::GetBestPattern() to call udatpg_getBestPatternWithOptions(),
so we can adjust the computed pattern to use 2-digit representation when it was requested by the
user.
Updated•4 years ago
|
Comment 17•4 years ago
|
||
Comment 18•4 years ago
|
||
| bugherder | ||
Description
•