ecma402 icon indicating copy to clipboard operation
ecma402 copied to clipboard

How to show different language time formats in different countries

Open qcyblm opened this issue 3 years ago • 15 comments

Such as new Date().toLocaleString()

new Date().toLocaleString("zh",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"});
2022年8月9日 中国标准时间 09:37:52
new Date().toLocaleString("zh-u-ca-chinese-nu-hanidec", {year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"});
二〇二二壬寅年七月一二 中国标准时间 〇九:三七:五二
new Date().toLocaleString("en",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"});
August 9, 2022 at 9:37:52 AM China Standard Time
new Date().toLocaleString("ja",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"});
2022年8月9日 9時37分52秒 中国標準時

qcyblm avatar Aug 09 '22 01:08 qcyblm

When you specify a calendar, you can only see the actual calendar time if you write out the parameters separately

const data = Temporal.Now.zonedDateTimeISO('Asia/Shanghai').withCalendar("chinese")
console.log(data.toString());
// 2022-08-09T09:49:41.945660009+08:00[Asia/Shanghai][u-ca=chinese]
console.log( data.year,data.month,data.day );
// 2022 7 12
``` js

qcyblm avatar Aug 09 '22 01:08 qcyblm

You can also use toLocaleString() on any Temporal object. The parameters are the same as Date.prototype.toLocaleString. Example:

zdt = Temporal.Now.zonedDateTime('chinese', 'Asia/Shanghai');
zdt.toLocaleString(
  "zh-u-ca-chinese-nu-hanidec",
  {year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"});
// '七月一二日 中国标准时间 一一:五二:一四'

justingrant avatar Aug 09 '22 03:08 justingrant

@justingrant The lack of year

qcyblm avatar Aug 09 '22 04:08 qcyblm

@qcyblm The root cause is of the problem is that the Intl.DateTimeFormat.prototype.resolvedOptions() method drops the year. We rely on that method in the polyfill. Because the output is the same in Chrome and Firefox, I suspect that the problem is in the upstream CLDR data that Intl.DateTimeFormat uses to power its behavior.

@sffc, is this a CLDR bug, and if so could we get your help to file an issue in the right place(s) to fix it?

locale = 'zh-u-ca-chinese-nu-hanidec';
formattingProps = {year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"long"};
date = new Date('2020-01-01T00:00:00Z');
dtf = new Intl.DateTimeFormat(locale, formattingProps);
original = dtf.format(date);
ro = dtf.resolvedOptions();
// {"locale":"zh-u-ca-chinese-nu-hanidec","calendar":"chinese","numberingSystem":"hanidec","timeZone":"America/Los_Angeles","hourCycle":"h23","hour12":false,"month":"long","day":"numeric","hour":"numeric","minute":"2-digit","second":"2-digit","timeZoneName":"long"}
// note that `ro.year` is missing, which causes the unexpected behavior below
dtfNew = new Intl.DateTimeFormat(locale, ro);
usingResolvedOptions = dtfNew.format(date);
console.log(JSON.stringify({original, usingResolvedOptions}));
// expected: both strings are the same
// actual: 
// {
//   "original":   "二〇一九己亥年腊月六 北美太平洋标准时间 一六:〇〇:〇〇",
//   "usingResolvedOptions": "腊月六日 北美太平洋标准时间 一六:〇〇:〇〇"
// }
``

justingrant avatar Aug 18 '22 16:08 justingrant

In Temporal: .year returns the arithmetic year; .eraYear returns the year within the era.

In CLDR: Formatting of the chinese calendar uses the cyclic year field in CLDR patterns.

Does it work as expected if the DTF option is { dateStyle: "full" }? If it only breaks when { year: "numeric", month: "long", day: "numeric" } is used, then this would be (yet another) bug in the components bag resolution in either ICU or ECMA-402.

sffc avatar Aug 18 '22 16:08 sffc

@qcyblm: Please post a test case with the expected result (a line of code that does not behave as expected, with how you expect it to behave).

sffc avatar Aug 18 '22 16:08 sffc

Does it work as expected if the DTF option is { dateStyle: "full" }?

The output using { dateStyle: "full" } is below. Both strings are different from the output when each component is listed separately in https://github.com/tc39/ecma402/issues/703.

{
  "original":            "二〇一九己亥年腊月初六星期二",
  "usingResolvedOptions":"二〇一九己亥年腊月初六星期二"
}

@qcyblm: Please post a test case with the expected result (a line of code that does not behave as expected, with how you expect it to behave).

Note that the code in the test case should not use Temporal but should use Intl.DateTimeFormat.prototype.format because that seems to be the underlying issue here. Using Temporal would just distract from the real bug.

justingrant avatar Aug 18 '22 16:08 justingrant

This sounds similar to https://bugzilla.mozilla.org/show_bug.cgi?id=1298794 (upstream: https://unicode-org.atlassian.net/browse/ICU-13518). But in addition to that round tripping issue, we also have a "related year" component here. I know that the SpiderMonkey implementation doesn't map the Date Field Symbol r when computing the resolved options, but I can't remember anymore if that's intentional or just an oversight.

anba avatar Aug 19 '22 07:08 anba

Okay, I've just tested this. Handling r fixes the output, now I have to somehow verify that that's actually spec-compliant and won't introduce any other bugs...

anba avatar Aug 19 '22 08:08 anba

Yes, if the issue is only that resolvedOptions doesn't round-trip, then the bug is probably around failing to match alternative year fields in the resolved pattern. There are 5 year fields listed in UTS 35: YyUur. https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-year

sffc avatar Aug 19 '22 08:08 sffc

I transferred the issue to the ECMA-402 repository. I think we should at least add a test for the behavior, if not clarify the spec.

sffc avatar Aug 19 '22 08:08 sffc

There are 5 year fields listed in UTS 35: YyUur.

I wonder how to map standalone U, because the year property for resolvedOptions() can only be either "2-digit" or "numeric".

js> new Intl.DateTimeFormat("de-u-ca-chinese", {year:"numeric"}).format()
"ren-yin"
js> new Intl.DateTimeFormat("de-u-ca-chinese", {year:"numeric"}).resolvedOptions()
Object { locale: "de-u-ca-chinese", calendar: "chinese", numberingSystem: "latn", timeZone: "Europe/Berlin" }

anba avatar Aug 22 '22 07:08 anba

2024-03-28 TG2 notes: https://github.com/tc39/ecma402/blob/main/meetings/notes-2024-03-28.md#how-to-show-different-language-time-formats-in-different-countries-703

sffc avatar Mar 30 '24 06:03 sffc