From e2f2f9248605906d818d90b26cd0ac8de8466ed0 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Thu, 3 Oct 2024 17:20:14 -0700 Subject: [PATCH] Temporal: Add tests for formatting with no overlap between DTF options and Temporal object See tc39/proposal-temporal#2795. When attempting to format a Temporal object, if the DateTimeFormat has options that do not overlap with the data model of the Temporal object, toLocaleString() and format() are supposed to throw a TypeError. --- ...emporal-objects-not-overlapping-options.js | 83 +++++++++++++++++++ ...emporal-objects-not-overlapping-options.js | 83 +++++++++++++++++++ ...emporal-objects-not-overlapping-options.js | 83 +++++++++++++++++++ ...emporal-objects-not-overlapping-options.js | 83 +++++++++++++++++++ 4 files changed, 332 insertions(+) create mode 100644 test/intl402/DateTimeFormat/prototype/format/temporal-objects-not-overlapping-options.js create mode 100644 test/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-not-overlapping-options.js create mode 100644 test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-not-overlapping-options.js create mode 100644 test/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-not-overlapping-options.js diff --git a/test/intl402/DateTimeFormat/prototype/format/temporal-objects-not-overlapping-options.js b/test/intl402/DateTimeFormat/prototype/format/temporal-objects-not-overlapping-options.js new file mode 100644 index 0000000000..a889160b9b --- /dev/null +++ b/test/intl402/DateTimeFormat/prototype/format/temporal-objects-not-overlapping-options.js @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: > + Temporal objects cannot be formatted if there is no overlap between the + provided options and the data model of the object +features: [Temporal] +---*/ + +const sampleEpochMs = 1726773817847; /* 2024-09-19T19:23:37.847Z */ +const sampleEpochNs = BigInt(sampleEpochMs) * 1_000_000n; +const legacyDate = new Date(sampleEpochMs); +const instant = new Temporal.Instant(sampleEpochNs); +const plainDateTime = new Temporal.PlainDateTime(2024, 9, 19, 12, 23, 37, 847); +const plainDate = new Temporal.PlainDate(2024, 9, 19); +const plainYearMonth = new Temporal.PlainYearMonth(2024, 9); +const plainMonthDay = new Temporal.PlainMonthDay(9, 19); +const plainTime = new Temporal.PlainTime(12, 23, 37, 847); + +const dateStyleFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "short", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dateStyleResult = dateStyleFormatter.format(legacyDate); + +assert.sameValue(dateStyleFormatter.format(instant), dateStyleResult, "Instant with dateStyle"); +assert.sameValue(dateStyleFormatter.format(plainDateTime), dateStyleResult, "PlainDateTime with dateStyle"); +assert.sameValue(dateStyleFormatter.format(plainDate), dateStyleResult, "PlainDate with dateStyle"); +assert.notSameValue(dateStyleFormatter.format(plainYearMonth), dateStyleResult, "PlainYearMonth with dateStyle should not throw but day is omitted"); +assert.notSameValue(dateStyleFormatter.format(plainMonthDay), dateStyleResult, "PlainMonthDay with dateStyle should not throw but year is omitted"); +assert.throws(TypeError, () => dateStyleFormatter.format(plainTime), "no overlap between dateStyle and PlainTime"); + +const yearFormatter = new Intl.DateTimeFormat(undefined, { year: "numeric", calendar: "iso8601", timeZone: "America/Vancouver" }); +const yearResult = yearFormatter.format(legacyDate); + +assert.sameValue(yearFormatter.format(instant), yearResult, "Instant with year"); +assert.sameValue(yearFormatter.format(plainDateTime), yearResult, "PlainDateTime with year"); +assert.sameValue(yearFormatter.format(plainDate), yearResult, "PlainDate with year"); +assert.sameValue(yearFormatter.format(plainYearMonth), yearResult, "PlainYearMonth with year"); +assert.throws(TypeError, () => yearFormatter.format(plainMonthDay), "no overlap between year and PlainMonthDay"); +assert.throws(TypeError, () => yearFormatter.format(plainTime), "no overlap between year and PlainTime"); + +const dayFormatter = new Intl.DateTimeFormat(undefined, { day: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dayResult = dayFormatter.format(legacyDate); + +assert.sameValue(dayFormatter.format(instant), dayResult, "Instant with day"); +assert.sameValue(dayFormatter.format(plainDateTime), dayResult, "PlainDateTime with day"); +assert.sameValue(dayFormatter.format(plainDate), dayResult, "PlainDate with day"); +assert.throws(TypeError, () => dayFormatter.format(plainYearMonth), "no overlap between day and PlainYearMonth"); +assert.sameValue(dayFormatter.format(plainMonthDay), dayResult, "PlainMonthDay with day"); +assert.throws(TypeError, () => dayFormatter.format(plainTime), "no overlap between day and PlainTime"); + +const timeStyleFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "long", calendar: "iso8601", timeZone: "America/Vancouver" }); +const timeStyleResult = timeStyleFormatter.format(legacyDate); + +assert.sameValue(timeStyleFormatter.format(instant), timeStyleResult, "Instant with timeStyle"); +const timeStylePlainDateTimeResult = timeStyleFormatter.format(plainDateTime); +assert.notSameValue(timeStylePlainDateTimeResult, timeStyleResult, "PlainDateTime with timeStyle should not throw but time zone is omitted"); +assert.throws(TypeError, () => timeStyleFormatter.format(plainDate), "no overlap between PlainDate and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.format(plainYearMonth), "no overlap between PlainYearMonth and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.format(plainMonthDay), "no overlap between PlainMonthDay and timeStyle"); +assert.sameValue(timeStyleFormatter.format(plainTime), timeStylePlainDateTimeResult, "PlainTime with timeStyle should be the same as PlainDateTime"); + +const hourFormatter = new Intl.DateTimeFormat(undefined, { hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const hourResult = hourFormatter.format(legacyDate); + +assert.sameValue(hourFormatter.format(instant), hourResult, "Instant with hour"); +assert.sameValue(hourFormatter.format(plainDateTime), hourResult, "PlainDateTime with hour"); +assert.throws(TypeError, () => hourFormatter.format(plainDate), "no overlap between PlainDate and hour"); +assert.throws(TypeError, () => hourFormatter.format(plainYearMonth), "no overlap between PlainYearMonth and hour"); +assert.throws(TypeError, () => hourFormatter.format(plainMonthDay), "no overlap between PlainMonthDay and hour"); +assert.sameValue(hourFormatter.format(plainTime), hourResult, "PlainTime with hour"); + +const monthFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthResult = monthFormatter.format(legacyDate); +const monthHourFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthHourResult = monthHourFormatter.format(legacyDate); + +assert.sameValue(monthHourFormatter.format(instant), monthHourResult, "Instant with month+hour"); +assert.sameValue(monthHourFormatter.format(plainDateTime), monthHourResult, "PlainDateTime with month+hour"); +assert.sameValue(monthHourFormatter.format(plainDate), monthResult, "PlainDate with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.format(plainYearMonth), monthResult, "PlainYearMonth with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.format(plainMonthDay), monthResult, "PlainMonthDay with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.format(plainTime), hourResult, "PlainTime with month+hour behaves the same as hour"); diff --git a/test/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-not-overlapping-options.js b/test/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-not-overlapping-options.js new file mode 100644 index 0000000000..1efd64f136 --- /dev/null +++ b/test/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-not-overlapping-options.js @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: > + Temporal objects cannot be formatted if there is no overlap between the + provided options and the data model of the object +features: [Temporal] +---*/ + +const sampleEpochMs = 1726773817847; /* 2024-09-19T19:23:37.847Z */ +const sampleEpochNs = BigInt(sampleEpochMs) * 1_000_000n; +const legacyDate = new Date(sampleEpochMs); +const instant = new Temporal.Instant(sampleEpochNs); +const plainDateTime = new Temporal.PlainDateTime(2024, 9, 19, 12, 23, 37, 847); +const plainDate = new Temporal.PlainDate(2024, 9, 19); +const plainYearMonth = new Temporal.PlainYearMonth(2024, 9); +const plainMonthDay = new Temporal.PlainMonthDay(9, 19); +const plainTime = new Temporal.PlainTime(12, 23, 37, 847); + +const dateStyleFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "short", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dateStyleResult = dateStyleFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(dateStyleFormatter.formatRange(instant, instant), dateStyleResult, "Instant with dateStyle"); +assert.sameValue(dateStyleFormatter.formatRange(plainDateTime, plainDateTime), dateStyleResult, "PlainDateTime with dateStyle"); +assert.sameValue(dateStyleFormatter.formatRange(plainDate, plainDate), dateStyleResult, "PlainDate with dateStyle"); +assert.notSameValue(dateStyleFormatter.formatRange(plainYearMonth, plainYearMonth), dateStyleResult, "PlainYearMonth with dateStyle should not throw but day is omitted"); +assert.notSameValue(dateStyleFormatter.formatRange(plainMonthDay, plainMonthDay), dateStyleResult, "PlainMonthDay with dateStyle should not throw but year is omitted"); +assert.throws(TypeError, () => dateStyleFormatter.formatRange(plainTime, plainTime), "no overlap between dateStyle and PlainTime"); + +const yearFormatter = new Intl.DateTimeFormat(undefined, { year: "numeric", calendar: "iso8601", timeZone: "America/Vancouver" }); +const yearResult = yearFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(yearFormatter.formatRange(instant, instant), yearResult, "Instant with year"); +assert.sameValue(yearFormatter.formatRange(plainDateTime, plainDateTime), yearResult, "PlainDateTime with year"); +assert.sameValue(yearFormatter.formatRange(plainDate, plainDate), yearResult, "PlainDate with year"); +assert.sameValue(yearFormatter.formatRange(plainYearMonth, plainYearMonth), yearResult, "PlainYearMonth with year"); +assert.throws(TypeError, () => yearFormatter.formatRange(plainMonthDay, plainMonthDay), "no overlap between year and PlainMonthDay"); +assert.throws(TypeError, () => yearFormatter.formatRange(plainTime, plainTime), "no overlap between year and PlainTime"); + +const dayFormatter = new Intl.DateTimeFormat(undefined, { day: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dayResult = dayFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(dayFormatter.formatRange(instant, instant), dayResult, "Instant with day"); +assert.sameValue(dayFormatter.formatRange(plainDateTime, plainDateTime), dayResult, "PlainDateTime with day"); +assert.sameValue(dayFormatter.formatRange(plainDate, plainDate), dayResult, "PlainDate with day"); +assert.throws(TypeError, () => dayFormatter.formatRange(plainYearMonth, plainYearMonth), "no overlap between day and PlainYearMonth"); +assert.sameValue(dayFormatter.formatRange(plainMonthDay, plainMonthDay), dayResult, "PlainMonthDay with day"); +assert.throws(TypeError, () => dayFormatter.formatRange(plainTime, plainTime), "no overlap between day and PlainTime"); + +const timeStyleFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "long", calendar: "iso8601", timeZone: "America/Vancouver" }); +const timeStyleResult = timeStyleFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(timeStyleFormatter.formatRange(instant, instant), timeStyleResult, "Instant with timeStyle"); +const timeStylePlainDateTimeResult = timeStyleFormatter.formatRange(plainDateTime, plainDateTime); +assert.notSameValue(timeStylePlainDateTimeResult, timeStyleResult, "PlainDateTime with timeStyle should not throw but time zone is omitted"); +assert.throws(TypeError, () => timeStyleFormatter.formatRange(plainDate, plainDate), "no overlap between PlainDate and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatRange(plainYearMonth, plainYearMonth), "no overlap between PlainYearMonth and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatRange(plainMonthDay, plainMonthDay), "no overlap between PlainMonthDay and timeStyle"); +assert.sameValue(timeStyleFormatter.formatRange(plainTime, plainTime), timeStylePlainDateTimeResult, "PlainTime with timeStyle should be the same as PlainDateTime"); + +const hourFormatter = new Intl.DateTimeFormat(undefined, { hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const hourResult = hourFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(hourFormatter.formatRange(instant, instant), hourResult, "Instant with hour"); +assert.sameValue(hourFormatter.formatRange(plainDateTime, plainDateTime), hourResult, "PlainDateTime with hour"); +assert.throws(TypeError, () => hourFormatter.formatRange(plainDate, plainDate), "no overlap between PlainDate and hour"); +assert.throws(TypeError, () => hourFormatter.formatRange(plainYearMonth, plainYearMonth), "no overlap between PlainYearMonth and hour"); +assert.throws(TypeError, () => hourFormatter.formatRange(plainMonthDay, plainMonthDay), "no overlap between PlainMonthDay and hour"); +assert.sameValue(hourFormatter.formatRange(plainTime, plainTime), hourResult, "PlainTime with hour"); + +const monthFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthResult = monthFormatter.formatRange(legacyDate, legacyDate); +const monthHourFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthHourResult = monthHourFormatter.formatRange(legacyDate, legacyDate); + +assert.sameValue(monthHourFormatter.formatRange(instant, instant), monthHourResult, "Instant with month+hour"); +assert.sameValue(monthHourFormatter.formatRange(plainDateTime, plainDateTime), monthHourResult, "PlainDateTime with month+hour"); +assert.sameValue(monthHourFormatter.formatRange(plainDate, plainDate), monthResult, "PlainDate with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.formatRange(plainYearMonth, plainYearMonth), monthResult, "PlainYearMonth with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.formatRange(plainMonthDay, plainMonthDay), monthResult, "PlainMonthDay with month+hour behaves the same as month"); +assert.sameValue(monthHourFormatter.formatRange(plainTime, plainTime), hourResult, "PlainTime with month+hour behaves the same as hour"); diff --git a/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-not-overlapping-options.js b/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-not-overlapping-options.js new file mode 100644 index 0000000000..a5d450d2fd --- /dev/null +++ b/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-not-overlapping-options.js @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: > + Temporal objects cannot be formatted if there is no overlap between the + provided options and the data model of the object +features: [Temporal] +---*/ + +const sampleEpochMs = 1726773817847; /* 2024-09-19T19:23:37.847Z */ +const sampleEpochNs = BigInt(sampleEpochMs) * 1_000_000n; +const legacyDate = new Date(sampleEpochMs); +const instant = new Temporal.Instant(sampleEpochNs); +const plainDateTime = new Temporal.PlainDateTime(2024, 9, 19, 12, 23, 37, 847); +const plainDate = new Temporal.PlainDate(2024, 9, 19); +const plainYearMonth = new Temporal.PlainYearMonth(2024, 9); +const plainMonthDay = new Temporal.PlainMonthDay(9, 19); +const plainTime = new Temporal.PlainTime(12, 23, 37, 847); + +const dateStyleFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "short", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dateStyleResult = JSON.stringify(dateStyleFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(dateStyleFormatter.formatRangeToParts(instant, instant)), dateStyleResult, "Instant with dateStyle"); +assert.sameValue(JSON.stringify(dateStyleFormatter.formatRangeToParts(plainDateTime, plainDateTime)), dateStyleResult, "PlainDateTime with dateStyle"); +assert.sameValue(JSON.stringify(dateStyleFormatter.formatRangeToParts(plainDate, plainDate)), dateStyleResult, "PlainDate with dateStyle"); +assert.notSameValue(JSON.stringify(dateStyleFormatter.formatRangeToParts(plainYearMonth, plainYearMonth)), dateStyleResult, "PlainYearMonth with dateStyle should not throw but day is omitted"); +assert.notSameValue(JSON.stringify(dateStyleFormatter.formatRangeToParts(plainMonthDay, plainMonthDay)), dateStyleResult, "PlainMonthDay with dateStyle should not throw but year is omitted"); +assert.throws(TypeError, () => dateStyleFormatter.formatRangeToParts(plainTime, plainTime), "no overlap between dateStyle and PlainTime"); + +const yearFormatter = new Intl.DateTimeFormat(undefined, { year: "numeric", calendar: "iso8601", timeZone: "America/Vancouver" }); +const yearResult = JSON.stringify(yearFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(yearFormatter.formatRangeToParts(instant, instant)), yearResult, "Instant with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatRangeToParts(plainDateTime, plainDateTime)), yearResult, "PlainDateTime with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatRangeToParts(plainDate, plainDate)), yearResult, "PlainDate with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatRangeToParts(plainYearMonth, plainYearMonth)), yearResult, "PlainYearMonth with year"); +assert.throws(TypeError, () => yearFormatter.formatRangeToParts(plainMonthDay, plainMonthDay), "no overlap between year and PlainMonthDay"); +assert.throws(TypeError, () => yearFormatter.formatRangeToParts(plainTime, plainTime), "no overlap between year and PlainTime"); + +const dayFormatter = new Intl.DateTimeFormat(undefined, { day: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dayResult = JSON.stringify(dayFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(dayFormatter.formatRangeToParts(instant, instant)), dayResult, "Instant with day"); +assert.sameValue(JSON.stringify(dayFormatter.formatRangeToParts(plainDateTime, plainDateTime)), dayResult, "PlainDateTime with day"); +assert.sameValue(JSON.stringify(dayFormatter.formatRangeToParts(plainDate, plainDate)), dayResult, "PlainDate with day"); +assert.throws(TypeError, () => dayFormatter.formatRangeToParts(plainYearMonth, plainYearMonth), "no overlap between day and PlainYearMonth"); +assert.sameValue(JSON.stringify(dayFormatter.formatRangeToParts(plainMonthDay, plainMonthDay)), dayResult, "PlainMonthDay with day"); +assert.throws(TypeError, () => dayFormatter.formatRangeToParts(plainTime, plainTime), "no overlap between day and PlainTime"); + +const timeStyleFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "long", calendar: "iso8601", timeZone: "America/Vancouver" }); +const timeStyleResult = JSON.stringify(timeStyleFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(timeStyleFormatter.formatRangeToParts(instant, instant)), timeStyleResult, "Instant with timeStyle"); +const timeStylePlainDateTimeResult = JSON.stringify(timeStyleFormatter.formatRangeToParts(plainDateTime, plainDateTime)); +assert.notSameValue(timeStylePlainDateTimeResult, timeStyleResult, "PlainDateTime with timeStyle should not throw but time zone is omitted"); +assert.throws(TypeError, () => timeStyleFormatter.formatRangeToParts(plainDate, plainDate), "no overlap between PlainDate and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatRangeToParts(plainYearMonth, plainYearMonth), "no overlap between PlainYearMonth and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatRangeToParts(plainMonthDay, plainMonthDay), "no overlap between PlainMonthDay and timeStyle"); +assert.sameValue(JSON.stringify(timeStyleFormatter.formatRangeToParts(plainTime, plainTime)), timeStylePlainDateTimeResult, "PlainTime with timeStyle should be the same as PlainDateTime"); + +const hourFormatter = new Intl.DateTimeFormat(undefined, { hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const hourResult = JSON.stringify(hourFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(hourFormatter.formatRangeToParts(instant, instant)), hourResult, "Instant with hour"); +assert.sameValue(JSON.stringify(hourFormatter.formatRangeToParts(plainDateTime, plainDateTime)), hourResult, "PlainDateTime with hour"); +assert.throws(TypeError, () => hourFormatter.formatRangeToParts(plainDate, plainDate), "no overlap between PlainDate and hour"); +assert.throws(TypeError, () => hourFormatter.formatRangeToParts(plainYearMonth, plainYearMonth), "no overlap between PlainYearMonth and hour"); +assert.throws(TypeError, () => hourFormatter.formatRangeToParts(plainMonthDay, plainMonthDay), "no overlap between PlainMonthDay and hour"); +assert.sameValue(JSON.stringify(hourFormatter.formatRangeToParts(plainTime, plainTime)), hourResult, "PlainTime with hour"); + +const monthFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthResult = JSON.stringify(monthFormatter.formatRangeToParts(legacyDate, legacyDate)); +const monthHourFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthHourResult = JSON.stringify(monthHourFormatter.formatRangeToParts(legacyDate, legacyDate)); + +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(instant, instant)), monthHourResult, "Instant with month+hour"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(plainDateTime, plainDateTime)), monthHourResult, "PlainDateTime with month+hour"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(plainDate, plainDate)), monthResult, "PlainDate with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(plainYearMonth, plainYearMonth)), monthResult, "PlainYearMonth with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(plainMonthDay, plainMonthDay)), monthResult, "PlainMonthDay with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatRangeToParts(plainTime, plainTime)), hourResult, "PlainTime with month+hour behaves the same as hour"); diff --git a/test/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-not-overlapping-options.js b/test/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-not-overlapping-options.js new file mode 100644 index 0000000000..be02fc31f1 --- /dev/null +++ b/test/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-not-overlapping-options.js @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-datetime-format-functions +description: > + Temporal objects cannot be formatted if there is no overlap between the + provided options and the data model of the object +features: [Temporal] +---*/ + +const sampleEpochMs = 1726773817847; /* 2024-09-19T19:23:37.847Z */ +const sampleEpochNs = BigInt(sampleEpochMs) * 1_000_000n; +const legacyDate = new Date(sampleEpochMs); +const instant = new Temporal.Instant(sampleEpochNs); +const plainDateTime = new Temporal.PlainDateTime(2024, 9, 19, 12, 23, 37, 847); +const plainDate = new Temporal.PlainDate(2024, 9, 19); +const plainYearMonth = new Temporal.PlainYearMonth(2024, 9); +const plainMonthDay = new Temporal.PlainMonthDay(9, 19); +const plainTime = new Temporal.PlainTime(12, 23, 37, 847); + +const dateStyleFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "short", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dateStyleResult = JSON.stringify(dateStyleFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(dateStyleFormatter.formatToParts(instant)), dateStyleResult, "Instant with dateStyle"); +assert.sameValue(JSON.stringify(dateStyleFormatter.formatToParts(plainDateTime)), dateStyleResult, "PlainDateTime with dateStyle"); +assert.sameValue(JSON.stringify(dateStyleFormatter.formatToParts(plainDate)), dateStyleResult, "PlainDate with dateStyle"); +assert.notSameValue(JSON.stringify(dateStyleFormatter.formatToParts(plainYearMonth)), dateStyleResult, "PlainYearMonth with dateStyle should not throw but day is omitted"); +assert.notSameValue(JSON.stringify(dateStyleFormatter.formatToParts(plainMonthDay)), dateStyleResult, "PlainMonthDay with dateStyle should not throw but year is omitted"); +assert.throws(TypeError, () => dateStyleFormatter.formatToParts(plainTime), "no overlap between dateStyle and PlainTime"); + +const yearFormatter = new Intl.DateTimeFormat(undefined, { year: "numeric", calendar: "iso8601", timeZone: "America/Vancouver" }); +const yearResult = JSON.stringify(yearFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(yearFormatter.formatToParts(instant)), yearResult, "Instant with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatToParts(plainDateTime)), yearResult, "PlainDateTime with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatToParts(plainDate)), yearResult, "PlainDate with year"); +assert.sameValue(JSON.stringify(yearFormatter.formatToParts(plainYearMonth)), yearResult, "PlainYearMonth with year"); +assert.throws(TypeError, () => yearFormatter.formatToParts(plainMonthDay), "no overlap between year and PlainMonthDay"); +assert.throws(TypeError, () => yearFormatter.formatToParts(plainTime), "no overlap between year and PlainTime"); + +const dayFormatter = new Intl.DateTimeFormat(undefined, { day: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const dayResult = JSON.stringify(dayFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(dayFormatter.formatToParts(instant)), dayResult, "Instant with day"); +assert.sameValue(JSON.stringify(dayFormatter.formatToParts(plainDateTime)), dayResult, "PlainDateTime with day"); +assert.sameValue(JSON.stringify(dayFormatter.formatToParts(plainDate)), dayResult, "PlainDate with day"); +assert.throws(TypeError, () => dayFormatter.formatToParts(plainYearMonth), "no overlap between day and PlainYearMonth"); +assert.sameValue(JSON.stringify(dayFormatter.formatToParts(plainMonthDay)), dayResult, "PlainMonthDay with day"); +assert.throws(TypeError, () => dayFormatter.formatToParts(plainTime), "no overlap between day and PlainTime"); + +const timeStyleFormatter = new Intl.DateTimeFormat(undefined, { timeStyle: "long", calendar: "iso8601", timeZone: "America/Vancouver" }); +const timeStyleResult = JSON.stringify(timeStyleFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(timeStyleFormatter.formatToParts(instant)), timeStyleResult, "Instant with timeStyle"); +const timeStylePlainDateTimeResult = JSON.stringify(timeStyleFormatter.formatToParts(plainDateTime)); +assert.notSameValue(timeStylePlainDateTimeResult, timeStyleResult, "PlainDateTime with timeStyle should not throw but time zone is omitted"); +assert.throws(TypeError, () => timeStyleFormatter.formatToParts(plainDate), "no overlap between PlainDate and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatToParts(plainYearMonth), "no overlap between PlainYearMonth and timeStyle"); +assert.throws(TypeError, () => timeStyleFormatter.formatToParts(plainMonthDay), "no overlap between PlainMonthDay and timeStyle"); +assert.sameValue(JSON.stringify(timeStyleFormatter.formatToParts(plainTime)), timeStylePlainDateTimeResult, "PlainTime with timeStyle should be the same as PlainDateTime"); + +const hourFormatter = new Intl.DateTimeFormat(undefined, { hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const hourResult = JSON.stringify(hourFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(hourFormatter.formatToParts(instant)), hourResult, "Instant with hour"); +assert.sameValue(JSON.stringify(hourFormatter.formatToParts(plainDateTime)), hourResult, "PlainDateTime with hour"); +assert.throws(TypeError, () => hourFormatter.formatToParts(plainDate), "no overlap between PlainDate and hour"); +assert.throws(TypeError, () => hourFormatter.formatToParts(plainYearMonth), "no overlap between PlainYearMonth and hour"); +assert.throws(TypeError, () => hourFormatter.formatToParts(plainMonthDay), "no overlap between PlainMonthDay and hour"); +assert.sameValue(JSON.stringify(hourFormatter.formatToParts(plainTime)), hourResult, "PlainTime with hour"); + +const monthFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthResult = JSON.stringify(monthFormatter.formatToParts(legacyDate)); +const monthHourFormatter = new Intl.DateTimeFormat(undefined, { month: "2-digit", hour: "2-digit", calendar: "iso8601", timeZone: "America/Vancouver" }); +const monthHourResult = JSON.stringify(monthHourFormatter.formatToParts(legacyDate)); + +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(instant)), monthHourResult, "Instant with month+hour"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(plainDateTime)), monthHourResult, "PlainDateTime with month+hour"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(plainDate)), monthResult, "PlainDate with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(plainYearMonth)), monthResult, "PlainYearMonth with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(plainMonthDay)), monthResult, "PlainMonthDay with month+hour behaves the same as month"); +assert.sameValue(JSON.stringify(monthHourFormatter.formatToParts(plainTime)), hourResult, "PlainTime with month+hour behaves the same as hour");