Description
While working on another fix, I noticed unexpected spec text and polyfill behavior for toLocaleString
's calendar
and timeZone
options.
From js-temporal/temporal-polyfill#118:
the spec and the polyfill also accept a ZDT-like property bag too, per tc39/proposal-temporal#925. Specifically, they accept any object with a
timeZone
property and will use that property's value as the time zone, with one exception: per tc39/proposal-temporal#925 (comment), recursive bags like{timeZone: {timeZone: 'Asia/Tokyo'}}
are disallowed.
The above is also true for calendars.
Update 2022-02-13: looks like the same spec text also breaks using ISO strings like "2020-04-25[Europe/Paris][u-ca=islamic]"
for the calendar
or timeZone
options.
Update 2023-05-12: property bag forms of these options are no longer supported. So this issue is now scoped to just Temporal objects and ISO strings.
But AFAICT, a timezone-like or calendar-like object is currently accepted in all places where a TimeZone instance and timezone/calendar ID string are accepted... except toLocaleString
methods (and the Temporal-aware Intl.DateTimeFormat
constructor). The spec text for these operations coerce the timeZone
or calendar
option to a string, and then use that string. But if the option is an ISO string or a ZonedDateTime or Plain* instance, then InitializeDateTimeFormat will throw because coercing the option to a string yields something that will never be a timezone nor calendar ID.
I'm assuming that this is a spec bug, because AFAIK our intent was that all places where a calendar or time zone is required will either accept a Temporal.Calendar
/Temporal.TimeZone
instance, a string ID, an ISO string like 2020-01-01T00:00Z[America/Los_Angeles][u-ca=chinese]
or an object like Temporal.ZonedDateTime.
Repro:
zdt = Temporal.ZonedDateTime.from('2000-01-01[Asia/Tokyo][u-ca=japanese]');
// => 2000-01-01T00:00:00+09:00[Asia/Tokyo][u-ca=japanese]
zdt2 = Temporal.ZonedDateTime.from({ year: 2000, month: 1, day: 1, calendar: zdt, timeZone: zdt });
// => Temporal.ZonedDateTime <2000-01-01T00:00:00+09:00[Asia/Tokyo][u-ca=japanese]
zdt.toLocaleString('ja-JP', { calendar: zdt, timeZone: zdt });
// => Uncaught RangeError: Invalid calendar : 2000-01-01T00:00:00+09:00[Asia/Tokyo][u-ca=japanese]
The problematic spec text is here:
### for calendars
6. Let calendar be ? GetOption(options, "calendar", "string", undefined, undefined).
7. If calendar is not undefined, then
a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
### for time zones
32. Else,
a. Let timeZone be ? ToString(timeZone).
b. If the result of IsValidTimeZoneName(timeZone) is false, then
i. Throw a RangeError exception.