diff --git a/polyfill/lib/intl.mjs b/polyfill/lib/intl.mjs index 1dbd877ae..c904425ec 100644 --- a/polyfill/lib/intl.mjs +++ b/polyfill/lib/intl.mjs @@ -75,7 +75,7 @@ function getSlotLazy(obj, slot) { return val; } -function createDateTimeFormat(dtf, locale, options) { +function internalCreateDateTimeFormat(dtf, locale, options, required) { const hasOptions = typeof options !== 'undefined'; if (hasOptions) { // Read all the options in the expected order and copy them to a @@ -173,10 +173,35 @@ function createDateTimeFormat(dtf, locale, options) { SetSlot(dtf, ORIGINAL, original); SetSlot(dtf, TZ_CANONICAL, ro.timeZone); SetSlot(dtf, CAL_ID, ro.calendar); - SetSlot(dtf, DATE, dateAmend); - SetSlot(dtf, YM, yearMonthAmend); - SetSlot(dtf, MD, monthDayAmend); - SetSlot(dtf, TIME_FMT, timeAmend); + + if (options.dateStyle !== undefined || options.timeStyle !== undefined) { + if (options.dateStyle !== undefined) { + if (required === 'time') { + throw new TypeErrorCtor('toLocaleString of Temporal.PlainTime does not support dateStyle option'); + } + SetSlot(dtf, DATE, dateAmend); + SetSlot(dtf, YM, yearMonthAmend); + SetSlot(dtf, MD, monthDayAmend); + } else { + SetSlot(dtf, DATE, null); + SetSlot(dtf, YM, null); + SetSlot(dtf, MD, null); + } + if (options.timeStyle !== undefined) { + if (required === 'date') { + throw new TypeErrorCtor('toLocaleString of a Temporal date type does not support timeStyle option'); + } + SetSlot(dtf, TIME_FMT, timeAmend); + } else { + SetSlot(dtf, TIME_FMT, null); + } + } else { + SetSlot(dtf, DATE, dateAmend); + SetSlot(dtf, YM, yearMonthAmend); + SetSlot(dtf, MD, monthDayAmend); + SetSlot(dtf, TIME_FMT, timeAmend); + } + SetSlot(dtf, DATETIME, datetimeAmend); SetSlot(dtf, INST, instantAmend); @@ -202,7 +227,7 @@ function createDateTimeFormat(dtf, locale, options) { class DateTimeFormatImpl { constructor(locales = undefined, options = undefined) { - createDateTimeFormat(this, locales, options); + internalCreateDateTimeFormat(this, locales, options, 'any'); } get format() { @@ -262,6 +287,17 @@ ObjectDefineProperty(DateTimeFormat, 'prototype', { DateTimeFormat.supportedLocalesOf = IntlDateTimeFormat.supportedLocalesOf; MakeIntrinsicClass(DateTimeFormat, 'Intl.DateTimeFormat'); +// This corresponds to the spec operation CreateDateTimeFormat in that it +// creates a new instance and does all the required initialization on it. +// However, most of the spec operation is in internalCreateDateTimeFormat() so +// that we can call it in the DateTimeFormat constructor, where we already have +// the uninitialized instance. +export function CreateDateTimeFormat(locales, options, required) { + const instance = Object.create(DateTimeFormat.prototype); + internalCreateDateTimeFormat(instance, locales, options, required); + return instance; +} + function resolvedOptions() { const resolved = ES.Call(IntlDateTimeFormatPrototypeResolvedOptions, GetSlot(this, ORIGINAL), []); resolved.timeZone = GetSlot(this, TZ_ORIGINAL); @@ -551,13 +587,7 @@ function hasTimeOptions(options) { } function hasAnyDateTimeOptions(originalOptions) { - return ( - hasDateOptions(originalOptions) || - hasTimeOptions(originalOptions) || - 'dateStyle' in originalOptions || - 'timeStyle' in originalOptions || - 'timeZoneName' in originalOptions - ); + return hasDateOptions(originalOptions) || hasTimeOptions(originalOptions); } function isTemporalObject(obj) { @@ -595,9 +625,11 @@ function extractOverrides(temporalObj, main) { isoDate: { year: 1970, month: 1, day: 1 }, time: GetSlot(temporalObj, TIME) }; + const formatter = getSlotLazy(main, TIME_FMT); + if (!formatter) throw new TypeErrorCtor('cannot format PlainTime with only date options'); return { epochNs: ES.GetEpochNanosecondsFor(GetSlot(main, TZ_CANONICAL), isoDateTime, 'compatible'), - formatter: getSlotLazy(main, TIME_FMT) + formatter }; } @@ -610,9 +642,11 @@ function extractOverrides(temporalObj, main) { ); } const isoDateTime = ES.CombineISODateAndTimeRecord(GetSlot(temporalObj, ISO_DATE), ES.NoonTimeRecord()); + const formatter = getSlotLazy(main, YM); + if (!formatter) throw new TypeErrorCtor('cannot format PlainYearMonth with only time options'); return { epochNs: ES.GetEpochNanosecondsFor(GetSlot(main, TZ_CANONICAL), isoDateTime, 'compatible'), - formatter: getSlotLazy(main, YM) + formatter }; } @@ -625,9 +659,11 @@ function extractOverrides(temporalObj, main) { ); } const isoDateTime = ES.CombineISODateAndTimeRecord(GetSlot(temporalObj, ISO_DATE), ES.NoonTimeRecord()); + const formatter = getSlotLazy(main, MD); + if (!formatter) throw new TypeErrorCtor('cannot format PlainMonthDay with only time options'); return { epochNs: ES.GetEpochNanosecondsFor(GetSlot(main, TZ_CANONICAL), isoDateTime, 'compatible'), - formatter: getSlotLazy(main, MD) + formatter }; } @@ -640,9 +676,11 @@ function extractOverrides(temporalObj, main) { ); } const isoDateTime = ES.CombineISODateAndTimeRecord(GetSlot(temporalObj, ISO_DATE), ES.NoonTimeRecord()); + const formatter = getSlotLazy(main, DATE); + if (!formatter) throw new TypeErrorCtor('cannot format PlainDate with only time options'); return { epochNs: ES.GetEpochNanosecondsFor(GetSlot(main, TZ_CANONICAL), isoDateTime, 'compatible'), - formatter: getSlotLazy(main, DATE) + formatter }; } diff --git a/polyfill/lib/plaindate.mjs b/polyfill/lib/plaindate.mjs index 9a7869e0c..9c4d0c57d 100644 --- a/polyfill/lib/plaindate.mjs +++ b/polyfill/lib/plaindate.mjs @@ -1,7 +1,7 @@ import { TypeError as TypeErrorCtor } from './primordials.mjs'; import * as ES from './ecmascript.mjs'; -import { DateTimeFormat } from './intl.mjs'; +import { CreateDateTimeFormat } from './intl.mjs'; import { MakeIntrinsicClass } from './intrinsicclass.mjs'; import { CALENDAR, GetSlot, ISO_DATE, TIME } from './slots.mjs'; @@ -159,7 +159,7 @@ export class PlainDate { } toLocaleString(locales = undefined, options = undefined) { if (!ES.IsTemporalDate(this)) throw new TypeErrorCtor('invalid receiver'); - return new DateTimeFormat(locales, options).format(this); + return CreateDateTimeFormat(locales, options, 'date').format(this); } valueOf() { ES.ValueOfThrows('PlainDate'); diff --git a/polyfill/lib/plainmonthday.mjs b/polyfill/lib/plainmonthday.mjs index 9b01aa45e..f563672b9 100644 --- a/polyfill/lib/plainmonthday.mjs +++ b/polyfill/lib/plainmonthday.mjs @@ -1,7 +1,7 @@ import { TypeError as TypeErrorCtor } from './primordials.mjs'; import * as ES from './ecmascript.mjs'; -import { DateTimeFormat } from './intl.mjs'; +import { CreateDateTimeFormat } from './intl.mjs'; import { MakeIntrinsicClass } from './intrinsicclass.mjs'; import { CALENDAR, GetSlot, ISO_DATE } from './slots.mjs'; @@ -72,7 +72,7 @@ export class PlainMonthDay { } toLocaleString(locales = undefined, options = undefined) { if (!ES.IsTemporalMonthDay(this)) throw new TypeErrorCtor('invalid receiver'); - return new DateTimeFormat(locales, options).format(this); + return CreateDateTimeFormat(locales, options, 'date').format(this); } valueOf() { ES.ValueOfThrows('PlainMonthDay'); diff --git a/polyfill/lib/plaintime.mjs b/polyfill/lib/plaintime.mjs index e31853808..2182c64ba 100644 --- a/polyfill/lib/plaintime.mjs +++ b/polyfill/lib/plaintime.mjs @@ -9,7 +9,7 @@ import { } from './primordials.mjs'; import * as ES from './ecmascript.mjs'; -import { DateTimeFormat } from './intl.mjs'; +import { CreateDateTimeFormat } from './intl.mjs'; import { MakeIntrinsicClass } from './intrinsicclass.mjs'; import { GetSlot, TIME } from './slots.mjs'; @@ -144,7 +144,7 @@ export class PlainTime { } toLocaleString(locales = undefined, options = undefined) { if (!ES.IsTemporalTime(this)) throw new TypeErrorCtor('invalid receiver'); - return new DateTimeFormat(locales, options).format(this); + return CreateDateTimeFormat(locales, options, 'time').format(this); } valueOf() { ES.ValueOfThrows('PlainTime'); diff --git a/polyfill/lib/plainyearmonth.mjs b/polyfill/lib/plainyearmonth.mjs index bce1d4d8e..56da50f47 100644 --- a/polyfill/lib/plainyearmonth.mjs +++ b/polyfill/lib/plainyearmonth.mjs @@ -1,7 +1,7 @@ import { TypeError as TypeErrorCtor } from './primordials.mjs'; import * as ES from './ecmascript.mjs'; -import { DateTimeFormat } from './intl.mjs'; +import { CreateDateTimeFormat } from './intl.mjs'; import { MakeIntrinsicClass } from './intrinsicclass.mjs'; import { CALENDAR, GetSlot, ISO_DATE } from './slots.mjs'; @@ -121,7 +121,7 @@ export class PlainYearMonth { } toLocaleString(locales = undefined, options = undefined) { if (!ES.IsTemporalYearMonth(this)) throw new TypeErrorCtor('invalid receiver'); - return new DateTimeFormat(locales, options).format(this); + return CreateDateTimeFormat(locales, options, 'date').format(this); } valueOf() { ES.ValueOfThrows('PlainYearMonth'); diff --git a/polyfill/test262 b/polyfill/test262 index 249ef0e4b..e85173bc2 160000 --- a/polyfill/test262 +++ b/polyfill/test262 @@ -1 +1 @@ -Subproject commit 249ef0e4b5ee86c0440e4ce383f12d5811eb5eaa +Subproject commit e85173bc211eb110477de3279ec1dcd36d9a8a58