summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/intl402/DateTimeFormat
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/intl402/DateTimeFormat
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/intl402/DateTimeFormat')
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/builtin.js21
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js46
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js51
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js42
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js31
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js36
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js44
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js51
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js41
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js52
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js68
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js127
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js111
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js47
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js26
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js26
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js31
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js31
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js40
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js106
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js22
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js19
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js34
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js20
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js21
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/length.js34
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/name.js29
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js69
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js60
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js14
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js95
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js95
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js95
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js31
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js28
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js34
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js36
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js31
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js29
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js20
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js55
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js52
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js20
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js20
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js114
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js41
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js41
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js56
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js32
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js72
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js63
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js44
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js35
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js45
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js42
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js23
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js55
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js58
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js21
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js28
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js41
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js56
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js56
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js32
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js71
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js78
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js43
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js208
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js160
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js40
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js23
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js384
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js117
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js21
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js28
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js49
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js35
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js35
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js108
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js108
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js108
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js21
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js69
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js15
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js76
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js15
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js35
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js23
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js44
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js360
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js107
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js20
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js19
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js40
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js39
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js43
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js19
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js53
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js93
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js47
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js89
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js102
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js34
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js29
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js35
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js38
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js36
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js42
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js50
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js88
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js24
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js17
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js28
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js24
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js26
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js48
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/shell.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/subclassing.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js25
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js0
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js34
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js29
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js33
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js24
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js18
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js17
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js13
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js16
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js13
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js37
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js638
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js28
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js30
-rw-r--r--js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js21
195 files changed, 8932 insertions, 0 deletions
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/builtin.js
new file mode 100644
index 0000000000..abffae0582
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/builtin.js
@@ -0,0 +1,21 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.1_L15
+description: >
+ Tests that Intl.DateTimeFormat meets the requirements for
+ built-in objects defined by the introduction of chapter 17 of the
+ ECMAScript Language Specification.
+author: Norbert Lindenberg
+---*/
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(Intl.DateTimeFormat), "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat), Function.prototype);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js b/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js
new file mode 100644
index 0000000000..15ae3a5e14
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/casing-numbering-system-calendar-options.js
@@ -0,0 +1,46 @@
+// Copyright 2020 Google Inc, Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that the options numberingSystem and calendar are mapped
+ to lower case properly.
+author: Caio Lima
+features: [Array.prototype.includes]
+---*/
+
+let defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale;
+
+let supportedNumberingSystems = ["latn", "arab"].filter(nu =>
+ new Intl.DateTimeFormat(defaultLocale + "-u-nu-" + nu)
+ .resolvedOptions().numberingSystem === nu
+);
+
+if (supportedNumberingSystems.includes("latn")) {
+ let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-nu-lATn");
+ assert.sameValue(dateTimeFormat.resolvedOptions().numberingSystem, "latn", "Numbering system option should be in lower case");
+}
+
+if (supportedNumberingSystems.includes("arab")) {
+ let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-nu-Arab");
+ assert.sameValue(dateTimeFormat.resolvedOptions().numberingSystem, "arab", "Numbering system option should be in lower case");
+}
+
+let supportedCalendars = ["gregory", "chinese"].filter(ca =>
+ new Intl.DateTimeFormat(defaultLocale + "-u-ca-" + ca)
+ .resolvedOptions().calendar === ca
+);
+
+if (supportedCalendars.includes("gregory")) {
+ let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-ca-Gregory");
+ assert.sameValue(dateTimeFormat.resolvedOptions().calendar, "gregory", "Calendar option should be in lower case");
+}
+
+if (supportedCalendars.includes("chinese")) {
+ let dateTimeFormat = new Intl.DateTimeFormat(defaultLocale + "-u-ca-CHINESE");
+ assert.sameValue(dateTimeFormat.resolvedOptions().calendar, "chinese", "Calendar option should be in lower case");
+}
+
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js
new file mode 100644
index 0000000000..f7cecd54e7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-calendar-numberingSystem-order.js
@@ -0,0 +1,51 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks the order of getting "calendar" and "numberingSystem" options in the
+ DateTimeFormat is between "localeMatcher" and "hour12" options.
+info: |
+ 5. Let _matcher_ be ? GetOption(_options_, `"localeMatcher"`, ~string~, &laquo; `"lookup"`, `"best fit"` &raquo;, `"best fit"`).
+ ...
+ 7. Let _calendar_ be ? GetOption(_options_, `"calendar"`, ~string~ , ~empty~, *undefined*).
+ ...
+ 10. Let _numberingSystem_ be ? GetOption(_options_, `"numberingSystem"`, ~string~, ~empty~, *undefined*).
+ ...
+ 13. Let _hour12_ be ? GetOption(_options_, `"hour12"`, ~boolean~, ~empty~, *undefined*).
+includes: [compareArray.js]
+---*/
+
+const actual = [];
+
+const options = {
+ get localeMatcher() {
+ actual.push("localeMatcher");
+ return undefined;
+ },
+ get calendar() {
+ actual.push("calendar");
+ return undefined;
+ },
+ get numberingSystem() {
+ actual.push("numberingSystem");
+ return undefined;
+ },
+ get hour12() {
+ actual.push("hour12");
+ return undefined;
+ },
+};
+
+const expected = [
+ "localeMatcher",
+ "calendar",
+ "numberingSystem",
+ "hour12"
+];
+
+let df = new Intl.DateTimeFormat(undefined, options);
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js
new file mode 100644
index 0000000000..2cfcab904e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-default-value.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 Ujjwal Sharma. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that the constructor for Intl.DateTimeFormat uses appropriate default
+ values for its arguments (locales and options).
+---*/
+
+const actual = new Intl.DateTimeFormat().resolvedOptions();
+const expected = new Intl.DateTimeFormat(
+ [],
+ Object.create(null)
+).resolvedOptions();
+
+assert.sameValue(actual.locale, expected.locale);
+assert.sameValue(actual.calendar, expected.calendar);
+assert.sameValue(actual.day, expected.day);
+assert.sameValue(actual.month, expected.month);
+assert.sameValue(actual.year, expected.year);
+assert.sameValue(actual.numberingSystem, expected.numberingSystem);
+assert.sameValue(actual.timeZone, expected.timeZone);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js
new file mode 100644
index 0000000000..d999f188a8
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-invalid-offset-timezone.js
@@ -0,0 +1,38 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: Tests that invalid offset time zones are rejected.
+---*/
+let invalidOffsetTimeZones = [
+ '+3',
+ '+24',
+ '+23:0',
+ '+130',
+ '+13234',
+ '+135678',
+ '-7',
+ '-10.50',
+ '-10,50',
+ '-24',
+ '-014',
+ '-210',
+ '-2400',
+ '-1:10',
+ '-21:0',
+ '+0:003',
+ '+15:59:00',
+ '+15:59.50',
+ '+15:59,50',
+ '+222700',
+ '-02:3200',
+ '-170100',
+ '-22230',
+];
+invalidOffsetTimeZones.forEach((timeZone) => {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat(undefined, {timeZone});
+ }, timeZone + ":");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js
new file mode 100644
index 0000000000..c2905aa57b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-no-instanceof.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl-datetimeformat-constructor
+description: >
+ Tests that the Intl.DateTimeFormat constructor calls
+ OrdinaryHasInstance instead of the instanceof operator which includes a
+ Symbol.hasInstance lookup and call among other things.
+info: >
+ ChainDateTimeFormat ( dateTimeFormat, newTarget, this )
+ 1. If newTarget is undefined and ? OrdinaryHasInstance(%DateTimeFormat%, this) is true, then
+ a. Perform ? DefinePropertyOrThrow(this, %Intl%.[[FallbackSymbol]], PropertyDescriptor{
+ [[Value]]: dateTimeFormat, [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: false }).
+ b. Return this.
+---*/
+
+Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
+ get() { throw new Test262Error(); }
+});
+
+Intl.DateTimeFormat();
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js
new file mode 100644
index 0000000000..894392f62c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-calendar-invalid.js
@@ -0,0 +1,42 @@
+// Copyright 2020 André Bargull; Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+ 8. If calendar is not undefined, then
+ a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
+---*/
+
+/*
+ alphanum = (ALPHA / DIGIT) ; letters and numbers
+ numberingSystem = (3*8alphanum) *("-" (3*8alphanum))
+*/
+const invalidCalendarOptions = [
+ "",
+ "a",
+ "ab",
+ "abcdefghi",
+ "abc-abcdefghi",
+ "!invalid!",
+ "-gregory-",
+ "gregory-",
+ "gregory--",
+ "gregory-nu",
+ "gregory-nu-",
+ "gregory-nu-latn",
+ "gregoryé",
+ "gregory역법",
+];
+for (const calendar of invalidCalendarOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat('en', {calendar});
+ }, `new Intl.DateTimeFormat("en", {calendar: "${calendar}"}) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js
new file mode 100644
index 0000000000..0aac3d9863
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-invalid.js
@@ -0,0 +1,31 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+ 39. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+
+const invalidOptions = [
+ "",
+ "FULL",
+ " long",
+ "short ",
+ "narrow",
+ "numeric",
+];
+for (const dateStyle of invalidOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat("en", { dateStyle });
+ }, `new Intl.DateTimeFormat("en", { dateStyle: "${dateStyle}" }) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js
new file mode 100644
index 0000000000..0f6dc77f22
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dateStyle-valid.js
@@ -0,0 +1,39 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks handling of the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+ 39. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
+ 40. If dateStyle is not undefined, set dateTimeFormat.[[DateStyle]] to dateStyle.
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+
+const validOptions = [
+ [undefined, undefined],
+ ["full", "full"],
+ ["long", "long"],
+ ["medium", "medium"],
+ ["short", "short"],
+ [{ toString() { return "full"; } }, "full"],
+ [{ valueOf() { return "long"; }, toString: undefined }, "long"],
+];
+for (const [dateStyle, expected] of validOptions) {
+ const dtf = new Intl.DateTimeFormat("en", { dateStyle });
+ const options = dtf.resolvedOptions();
+ assert.sameValue(options.dateStyle, expected);
+ const propdesc = Object.getOwnPropertyDescriptor(options, "dateStyle");
+ if (expected === undefined) {
+ assert.sameValue(propdesc, undefined);
+ } else {
+ assert.sameValue(propdesc.value, expected);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js
new file mode 100644
index 0000000000..f331b357d7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-invalid.js
@@ -0,0 +1,30 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ [[DayPeriod]] `"dayPeriod"` `"narrow"`, `"short"`, `"long"`
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const invalidOptions = [
+ "",
+ "LONG",
+ " long",
+ "short ",
+ "full",
+ "numeric",
+];
+for (const dayPeriod of invalidOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat("en", { dayPeriod });
+ }, `new Intl.DateTimeFormat("en", { dayPeriod: "${dayPeriod}" }) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js
new file mode 100644
index 0000000000..75acac41a1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-dayPeriod-valid.js
@@ -0,0 +1,36 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks handling of the options argument to the DateTimeFormat constructor.
+info: |
+ [[DayPeriod]] `"dayPeriod"` `"narrow"`, `"short"`, `"long"`
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const validOptions = [
+ [undefined, undefined],
+ ["long", "long"],
+ ["short", "short"],
+ ["narrow", "narrow"],
+ [{ toString() { return "narrow"; } }, "narrow"],
+ [{ valueOf() { return "long"; }, toString: undefined }, "long"],
+];
+for (const [dayPeriod, expected] of validOptions) {
+ const dtf = new Intl.DateTimeFormat("en", { dayPeriod });
+ const options = dtf.resolvedOptions();
+ assert.sameValue(options.dayPeriod, expected);
+ const propdesc = Object.getOwnPropertyDescriptor(options, "dayPeriod");
+ if (expected === undefined) {
+ assert.sameValue(propdesc, undefined);
+ } else {
+ assert.sameValue(propdesc.value, expected);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js
new file mode 100644
index 0000000000..cd9bc0a97f
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-invalid.js
@@ -0,0 +1,39 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+ ...
+ 37. For each row of Table 7, except the header row, in table order, do
+ a. Let prop be the name given in the Property column of the row.
+ b. If prop is "fractionalSecondDigits", then
+ i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+
+const invalidOptions = [
+ "LONG",
+ " long",
+ "short ",
+ "full",
+ "numeric",
+ -1,
+ 4,
+ "4",
+ "-1",
+ -0.00001,
+ 3.000001,
+];
+for (const fractionalSecondDigits of invalidOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat("en", { fractionalSecondDigits });
+ },
+ `new Intl.DateTimeFormat("en", { fractionalSecondDigits: "${fractionalSecondDigits}" }) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js
new file mode 100644
index 0000000000..d66e4209cd
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-fractionalSecondDigits-valid.js
@@ -0,0 +1,44 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks handling of the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+ ...
+ 37. For each row of Table 7, except the header row, in table order, do
+ a. Let prop be the name given in the Property column of the row.
+ b. If prop is "fractionalSecondDigits", then
+ i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+
+const validOptions = [
+ [undefined, undefined],
+ [1, 1],
+ ["1", 1],
+ [2, 2],
+ ["2", 2],
+ [3, 3],
+ ["3", 3],
+ [2.9, 2],
+ ["2.9", 2],
+ [1.00001, 1],
+ [{ toString() { return "3"; } }, 3],
+];
+for (const [fractionalSecondDigits, expected] of validOptions) {
+ const dtf = new Intl.DateTimeFormat("en", { fractionalSecondDigits });
+ const options = dtf.resolvedOptions();
+ assert.sameValue(options.fractionalSecondDigits, expected);
+ const propdesc = Object.getOwnPropertyDescriptor(options, "fractionalSecondDigits");
+ if (expected === undefined) {
+ assert.sameValue(propdesc, undefined);
+ } else {
+ assert.sameValue(propdesc.value, expected);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js
new file mode 100644
index 0000000000..c435c211bd
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-invalid-explicit-components.js
@@ -0,0 +1,51 @@
+// Copyright 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Verifies that constructor throws when dateStyle is combined with explicit format components.
+info: |
+ CreateDateTimeFormat ( newTarget, locales, options, required, defaults )
+ ...
+ 39. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined).
+ 40. Set dateTimeFormat.[[DateStyle]] to dateStyle.
+ 41. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined).
+ 42. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
+ 43. If dateStyle is not undefined or timeStyle is not undefined, then
+
+ a. If hasExplicitFormatComponents is true, then
+ i. Throw a TypeError exception.
+---*/
+
+function optionsThrow(options, testName) {
+ assert.throws(TypeError, function() {
+ new Intl.DateTimeFormat(undefined, options);
+ }, testName + ":");
+}
+
+optionsThrow({dateStyle: "full", weekday: "long"}, "dateStyle-weekday");
+optionsThrow({dateStyle: "full", era: "long"}, "dateStyle-era");
+optionsThrow({dateStyle: "full", year: "numeric"}, "dateStyle-year");
+optionsThrow({dateStyle: "full", month: "numeric"}, "dateStyle-month");
+optionsThrow({dateStyle: "full", day: "numeric"}, "dateStyle-day");
+optionsThrow({dateStyle: "full", dayPeriod: "long"}, "dateStyle-dayPeriod");
+optionsThrow({dateStyle: "full", hour: "numeric"}, "dateStyle-hour");
+optionsThrow({dateStyle: "full", minute: "numeric"}, "dateStyle-minute");
+optionsThrow({dateStyle: "full", second: "numeric"}, "dateStyle-second");
+optionsThrow({dateStyle: "full", fractionalSecondDigits: 1}, "dateStyle-fractionalSecondDigits");
+optionsThrow({dateStyle: "full", timeZoneName: "short"}, "dateStyle-timeZoneName");
+
+optionsThrow({timeStyle: "full", weekday: "long"}, "timeStyle-weekday");
+optionsThrow({timeStyle: "full", era: "long"}, "timeStyle-era");
+optionsThrow({timeStyle: "full", year: "numeric"}, "timeStyle-year");
+optionsThrow({timeStyle: "full", month: "numeric"}, "timeStyle-month");
+optionsThrow({timeStyle: "full", day: "numeric"}, "timeStyle-day");
+optionsThrow({timeStyle: "full", dayPeriod: "long"}, "timeStyle-dayPeriod");
+optionsThrow({timeStyle: "full", hour: "numeric"}, "timeStyle-hour");
+optionsThrow({timeStyle: "full", minute: "numeric"}, "timeStyle-minute");
+optionsThrow({timeStyle: "full", second: "numeric"}, "timeStyle-second");
+optionsThrow({timeStyle: "full", fractionalSecondDigits: 1}, "timeStyle-fractionalSecondDigits");
+optionsThrow({timeStyle: "full", timeZoneName: "short"}, "timeStyle-timeZoneName");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js
new file mode 100644
index 0000000000..c1b555c87e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-numberingSystem-invalid.js
@@ -0,0 +1,41 @@
+// Copyright 2020 André Bargull; Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+ ...
+ 27. If numberingSystem is not undefined, then
+ a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
+---*/
+
+/*
+ alphanum = (ALPHA / DIGIT) ; letters and numbers
+ numberingSystem = (3*8alphanum) *("-" (3*8alphanum))
+*/
+const invalidNumberingSystemOptions = [
+ "",
+ "a",
+ "ab",
+ "abcdefghi",
+ "abc-abcdefghi",
+ "!invalid!",
+ "-latn-",
+ "latn-",
+ "latn--",
+ "latn-ca",
+ "latn-ca-",
+ "latn-ca-gregory",
+ "latné",
+ "latn编号",
+];
+for (const numberingSystem of invalidNumberingSystemOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat('en', {numberingSystem});
+ }, `new Intl.DateTimeFormat("en", {numberingSystem: "${numberingSystem}"}) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js
new file mode 100644
index 0000000000..c05bd1bee8
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-dayPeriod.js
@@ -0,0 +1,52 @@
+// Copyright 2019 Googe Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the order of getting options of 'dayPeriod' for the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( newTarget, locales, options, required, defaults )
+ ...
+ 36. For each row of Table 7, except the header row, in table order, do
+ a. Let prop be the name given in the Property column of the row.
+ b. If prop is "fractionalSecondDigits", then
+ i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
+ c. Else,
+ i. Let values be a List whose elements are the strings given in the Values column of the row.
+ ii. Let value be ? GetOption(options, prop, string, values, undefined).
+ d. Set formatOptions.[[<prop>]] to value.
+ ...
+includes: [compareArray.js]
+features: [Intl.DateTimeFormat-dayPeriod]
+
+---*/
+
+// Just need to ensure dayPeriod are get between day and hour.
+const expected = [
+ // CreateDateTimeFormat step 36.
+ "day",
+ "dayPeriod",
+ "hour"
+];
+
+const actual = [];
+
+const options = {
+ get day() {
+ actual.push("day");
+ return "numeric";
+ },
+ get dayPeriod() {
+ actual.push("dayPeriod");
+ return "long";
+ },
+ get hour() {
+ actual.push("hour");
+ return "numeric";
+ },
+};
+
+new Intl.DateTimeFormat("en", options);
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js
new file mode 100644
index 0000000000..8fddf69f91
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js
@@ -0,0 +1,68 @@
+// Copyright 2019 Googe Inc. All rights reserved.
+// Copyright 2020 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the order of getting options of 'fractionalSecondDigits' for the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( newTarget, locales, options, required, defaults )
+ ...
+ 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
+ ...
+ 36. For each row of Table 7, except the header row, in table order, do
+ a. Let prop be the name given in the Property column of the row.
+ b. If prop is "fractionalSecondDigits", then
+ i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
+ c. Else,
+ i. Let values be a List whose elements are the strings given in the Values column of the row.
+ ii. Let value be ? GetOption(options, prop, string, values, undefined).
+ d. Set formatOptions.[[<prop>]] to value.
+ 37. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit").
+ ...
+includes: [compareArray.js]
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+// Just need to ensure fractionalSecondDigits are get
+// between "second" and "timeZoneName".
+const expected = [
+ // CreateDateTimeFormat step 4.
+ "localeMatcher",
+ // CreateDateTimeFormat step 36.
+ "second",
+ "fractionalSecondDigits",
+ "timeZoneName",
+ // CreateDateTimeFormat step 37.
+ "formatMatcher",
+];
+
+const actual = [];
+
+const options = {
+ get second() {
+ actual.push("second");
+ return "numeric";
+ },
+ get fractionalSecondDigits() {
+ actual.push("fractionalSecondDigits");
+ return undefined;
+ },
+ get localeMatcher() {
+ actual.push("localeMatcher");
+ return undefined;
+ },
+ get timeZoneName() {
+ actual.push("timeZoneName");
+ return undefined;
+ },
+ get formatMatcher() {
+ actual.push("formatMatcher");
+ return undefined;
+ },
+};
+
+new Intl.DateTimeFormat("en", options);
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js
new file mode 100644
index 0000000000..34e92ff711
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order-timedate-style.js
@@ -0,0 +1,127 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the order of getting options for the DateTimeFormat constructor.
+includes: [compareArray.js]
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+// To be merged into constructor-options-order.js when the feature is removed.
+
+const expected = [
+ // CreateDateTimeFormat step 4.
+ "localeMatcher",
+ // CreateDateTimeFormat step 12.
+ "hour12",
+ // CreateDateTimeFormat step 13.
+ "hourCycle",
+ // CreateDateTimeFormat step 29.
+ "timeZone",
+ // CreateDateTimeFormat step 36.
+ "weekday",
+ "era",
+ "year",
+ "month",
+ "day",
+ "hour",
+ "minute",
+ "second",
+ "timeZoneName",
+ "formatMatcher",
+ // CreateDateTimeFormat step 38.
+ "dateStyle",
+ // CreateDateTimeFormat step 40.
+ "timeStyle",
+];
+
+const actual = [];
+
+const options = {
+ get dateStyle() {
+ actual.push("dateStyle");
+ return undefined;
+ },
+
+ get day() {
+ actual.push("day");
+ return "numeric";
+ },
+
+ get era() {
+ actual.push("era");
+ return "long";
+ },
+
+ get formatMatcher() {
+ actual.push("formatMatcher");
+ return "best fit";
+ },
+
+ get hour() {
+ actual.push("hour");
+ return "numeric";
+ },
+
+ get hour12() {
+ actual.push("hour12");
+ return true;
+ },
+
+ get hourCycle() {
+ actual.push("hourCycle");
+ return "h24";
+ },
+
+ get localeMatcher() {
+ actual.push("localeMatcher");
+ return "best fit";
+ },
+
+ get minute() {
+ actual.push("minute");
+ return "numeric";
+ },
+
+ get month() {
+ actual.push("month");
+ return "numeric";
+ },
+
+ get second() {
+ actual.push("second");
+ return "numeric";
+ },
+
+ get timeStyle() {
+ actual.push("timeStyle");
+ return undefined;
+ },
+
+ get timeZone() {
+ actual.push("timeZone");
+ return "UTC";
+ },
+
+ get timeZoneName() {
+ actual.push("timeZoneName");
+ return "long";
+ },
+
+ get weekday() {
+ actual.push("weekday");
+ return "long";
+ },
+
+ get year() {
+ actual.push("year");
+ return "numeric";
+ },
+};
+
+new Intl.DateTimeFormat("en", options);
+
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js
new file mode 100644
index 0000000000..1b12975daf
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js
@@ -0,0 +1,111 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the order of getting options for the DateTimeFormat constructor.
+includes: [compareArray.js]
+---*/
+
+const expected = [
+ // CreateDateTimeFormat step 4.
+ "localeMatcher",
+ // CreateDateTimeFormat step 12.
+ "hour12",
+ // CreateDateTimeFormat step 13.
+ "hourCycle",
+ // CreateDateTimeFormat step 29.
+ "timeZone",
+ // CreateDateTimeFormat step 36.
+ "weekday",
+ "era",
+ "year",
+ "month",
+ "day",
+ "hour",
+ "minute",
+ "second",
+ "timeZoneName",
+ // CreateDateTimeFormat step 37.
+ "formatMatcher",
+];
+
+const actual = [];
+
+const options = {
+ get day() {
+ actual.push("day");
+ return "numeric";
+ },
+
+ get era() {
+ actual.push("era");
+ return "long";
+ },
+
+ get formatMatcher() {
+ actual.push("formatMatcher");
+ return "best fit";
+ },
+
+ get hour() {
+ actual.push("hour");
+ return "numeric";
+ },
+
+ get hour12() {
+ actual.push("hour12");
+ return true;
+ },
+
+ get hourCycle() {
+ actual.push("hourCycle");
+ return "h24";
+ },
+
+ get localeMatcher() {
+ actual.push("localeMatcher");
+ return "best fit";
+ },
+
+ get minute() {
+ actual.push("minute");
+ return "numeric";
+ },
+
+ get month() {
+ actual.push("month");
+ return "numeric";
+ },
+
+ get second() {
+ actual.push("second");
+ return "numeric";
+ },
+
+ get timeZone() {
+ actual.push("timeZone");
+ return "UTC";
+ },
+
+ get timeZoneName() {
+ actual.push("timeZoneName");
+ return "long";
+ },
+
+ get weekday() {
+ actual.push("weekday");
+ return "long";
+ },
+
+ get year() {
+ actual.push("year");
+ return "numeric";
+ },
+};
+
+new Intl.DateTimeFormat("en", options);
+
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js
new file mode 100644
index 0000000000..9d8419a8af
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-style-conflict.js
@@ -0,0 +1,47 @@
+// Copyright 2021 Kate Miháliková. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Conflicting properties of dateStyle/timeStyle must be rejected with a TypeError for the options argument to the DateTimeFormat constructor.
+info: |
+ InitializeDateTimeFormat ( dateTimeFormat, locales, options )
+
+ ...
+ 43. If dateStyle is not undefined or timeStyle is not undefined, then
+ a. If hasExplicitFormatComponents is true, then
+ i. Throw a TypeError exception.
+ b. If required is date and timeStyle is not undefined, then
+ i. Throw a TypeError exception.
+ c. If required is time and dateStyle is not undefined, then
+ i. Throw a TypeError exception.
+---*/
+
+
+// Table 4 - Property column + example value from Values column
+const conflictingOptions = [
+ [ "weekday", "short" ],
+ [ "era", "short" ],
+ [ "year", "numeric" ],
+ [ "month", "numeric" ],
+ [ "day", "numeric" ],
+ [ "dayPeriod", "short" ],
+ [ "hour", "numeric" ],
+ [ "minute", "numeric" ],
+ [ "second", "numeric" ],
+ [ "fractionalSecondDigits", 3 ],
+ [ "timeZoneName", "short" ],
+];
+
+for (const [ option, value ] of conflictingOptions) {
+ assert.throws(TypeError, function() {
+ new Intl.DateTimeFormat("en", { [option]: value, dateStyle: "short" });
+ }, `new Intl.DateTimeFormat("en", { ${option}: "${value}", dateStyle: "short" }) throws TypeError`);
+
+ assert.throws(TypeError, function() {
+ new Intl.DateTimeFormat("en", { [option]: value, timeStyle: "short" });
+ }, `new Intl.DateTimeFormat("en", { ${option}: "${value}", timeStyle: "short" }) throws TypeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js
new file mode 100644
index 0000000000..79260c8ef7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-dayPeriod.js
@@ -0,0 +1,26 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor.
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+function CustomError() {}
+
+const options = [
+ "dayPeriod",
+];
+
+for (const option of options) {
+ assert.throws(CustomError, () => {
+ new Intl.DateTimeFormat("en", {
+ get [option]() {
+ throw new CustomError();
+ }
+ });
+ }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js
new file mode 100644
index 0000000000..2ff4078376
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-fractionalSecondDigits.js
@@ -0,0 +1,26 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor.
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+function CustomError() {}
+
+const options = [
+ "fractionalSecondDigits",
+];
+
+for (const option of options) {
+ assert.throws(CustomError, () => {
+ new Intl.DateTimeFormat("en", {
+ get [option]() {
+ throw new CustomError();
+ }
+ });
+ }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js
new file mode 100644
index 0000000000..1e23c09bc2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters-timedate-style.js
@@ -0,0 +1,31 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor.
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+// To be merged into constructor-options-throwing-getters.js when the feature is removed.
+
+function CustomError() {}
+
+const options = [
+ // CreateDateTimeFormat step 39
+ "dateStyle",
+ // CreateDateTimeFormat step 41
+ "timeStyle",
+];
+
+for (const option of options) {
+ assert.throws(CustomError, () => {
+ new Intl.DateTimeFormat("en", {
+ get [option]() {
+ throw new CustomError();
+ }
+ });
+ }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js
new file mode 100644
index 0000000000..2eead83306
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js
@@ -0,0 +1,33 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor.
+---*/
+
+function CustomError() {}
+
+const options = [
+ "weekday", "year", "month", "day",
+ "hour", "minute", "second",
+ "localeMatcher",
+ "hour12",
+ "hourCycle",
+ "timeZone",
+ "era",
+ "timeZoneName",
+ "formatMatcher",
+];
+
+for (const option of options) {
+ assert.throws(CustomError, () => {
+ new Intl.DateTimeFormat("en", {
+ get [option]() {
+ throw new CustomError();
+ }
+ });
+ }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js
new file mode 100644
index 0000000000..0bb3b18afa
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-invalid.js
@@ -0,0 +1,31 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks error cases for the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+
+ ...
+ 41. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined).
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+
+const invalidOptions = [
+ "",
+ "FULL",
+ " long",
+ "short ",
+ "narrow",
+ "numeric",
+];
+for (const timeStyle of invalidOptions) {
+ assert.throws(RangeError, function() {
+ new Intl.DateTimeFormat("en", { timeStyle });
+ }, `new Intl.DateTimeFormat("en", { timeStyle: "${timeStyle}" }) throws RangeError`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js
new file mode 100644
index 0000000000..f8bad0acda
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeStyle-valid.js
@@ -0,0 +1,38 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks handling of the options argument to the DateTimeFormat constructor.
+info: |
+ CreateDateTimeFormat ( dateTimeFormat, locales, options, required, default )
+
+ ...
+ 41. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined).
+ 42. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+const validOptions = [
+ [undefined, undefined],
+ ["full", "full"],
+ ["long", "long"],
+ ["medium", "medium"],
+ ["short", "short"],
+ [{ toString() { return "full"; } }, "full"],
+ [{ valueOf() { return "long"; }, toString: undefined }, "long"],
+];
+for (const [timeStyle, expected] of validOptions) {
+ const dtf = new Intl.DateTimeFormat("en", { timeStyle });
+ const options = dtf.resolvedOptions();
+ assert.sameValue(options.timeStyle, expected);
+ const propdesc = Object.getOwnPropertyDescriptor(options, "timeStyle");
+ if (expected === undefined) {
+ assert.sameValue(propdesc, undefined);
+ } else {
+ assert.sameValue(propdesc.value, expected);
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js
new file mode 100644
index 0000000000..7c37e7c523
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-invalid.js
@@ -0,0 +1,30 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Invalid values for the `timeZoneName` option of the DateTimeFormat constructor
+features: [Intl.DateTimeFormat-extend-timezonename]
+---*/
+
+assert.throws(RangeError, function () {
+ new Intl.DateTimeFormat('en', { timeZoneName: '' });
+}, 'empty string');
+
+assert.throws(RangeError, function () {
+ new Intl.DateTimeFormat('en', { timeZoneName: 'short ' });
+}, '"short "');
+
+assert.throws(RangeError, function () {
+ new Intl.DateTimeFormat('en', { timeZoneName: ' long' });
+}, '" long"');
+
+assert.throws(RangeError, function () {
+ new Intl.DateTimeFormat('en', { timeZoneName: 'offset' });
+}, '"offset"');
+
+assert.throws(RangeError, function () {
+ new Intl.DateTimeFormat('en', { timeZoneName: 'generic' });
+}, '"generic"');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js
new file mode 100644
index 0000000000..cdfc4dcd5c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-timeZoneName-valid.js
@@ -0,0 +1,30 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Valid values for the `timeZoneName` option of the DateTimeFormat constructor
+features: [Intl.DateTimeFormat-extend-timezonename]
+---*/
+
+var dtf;
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'short' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'short');
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'long' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'long');
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'shortOffset' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'shortOffset');
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'longOffset' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'longOffset');
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'shortGeneric' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'shortGeneric');
+
+dtf = new Intl.DateTimeFormat('en', { timeZoneName: 'longGeneric' });
+assert.sameValue(dtf.resolvedOptions().timeZoneName, 'longGeneric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js
new file mode 100644
index 0000000000..6f449b023b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-toobject.js
@@ -0,0 +1,40 @@
+// Copyright (C) 2018 Ujjwal Sharma. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that Intl.DateTimeFormat contructor converts the options argument
+ to an object using `ToObject` (7.1.13).
+
+---*/
+
+const toObjectResults = [
+ [true, new Boolean(true)],
+ [42, new Number(42)],
+ ['foo', new String('foo')],
+ [{}, {}],
+ [Symbol(), Object(Symbol())]
+];
+
+// Test if ToObject is used to convert primitives to Objects.
+toObjectResults.forEach(pair => {
+ const [value, result] = pair;
+
+ const actual = new Intl.DateTimeFormat(['en-US'], value).resolvedOptions();
+ const expected = new Intl.DateTimeFormat(['en-US'], result).resolvedOptions();
+
+ assert.sameValue(actual.locale, expected.locale);
+ assert.sameValue(actual.calendar, expected.calendar);
+ assert.sameValue(actual.day, expected.day);
+ assert.sameValue(actual.month, expected.month);
+ assert.sameValue(actual.year, expected.year);
+ assert.sameValue(actual.numberingSystem, expected.numberingSystem);
+ assert.sameValue(actual.timeZone, expected.timeZone);
+});
+
+// ToObject throws a TypeError for undefined and null, but it's not called
+// when options is undefined.
+assert.throws(TypeError, () => new Intl.DateTimeFormat(['en-US'], null));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js b/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js
new file mode 100644
index 0000000000..bfe57ade97
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/date-time-options.js
@@ -0,0 +1,106 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_TDTO
+description: >
+ Tests that the set of options for the date and time components is
+ processed correctly.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+var locales = [[], ["zh-Hans-CN"], ["hi-IN"], ["en-US"], ["id-ID"]];
+var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))];
+
+function testWithDateTimeFormat(options, expected) {
+ locales.forEach(function (locales) {
+ var format = new Intl.DateTimeFormat(locales, options);
+ var resolvedOptions = format.resolvedOptions();
+ getDateTimeComponents().forEach(function (component) {
+ if (resolvedOptions.hasOwnProperty(component)) {
+ assert(expected.hasOwnProperty(component),
+ "Unrequested component " + component +
+ " added to expected subset " + JSON.stringify(expected) +
+ "; locales " + locales + ", options " +
+ (options ? JSON.stringify(options) : options) + ".");
+ } else {
+ assert.sameValue(expected.hasOwnProperty(component), false,
+ "Missing component " + component +
+ " from expected subset " + JSON.stringify(expected) +
+ "; locales " + locales + ", options " +
+ (options ? JSON.stringify(options) : options) + ".");
+ }
+ });
+ });
+}
+
+function testWithToLocale(f, options, expected) {
+ // expected can be either one subset or an array of possible subsets
+ if (expected.length === undefined) {
+ expected = [expected];
+ }
+ locales.forEach(function (locales) {
+ dates.forEach(function (date) {
+ var formatted = Date.prototype[f].call(date, locales, options);
+ var expectedStrings = [];
+ expected.forEach(function (expected) {
+ var referenceFormat = new Intl.DateTimeFormat(locales, expected);
+ expectedStrings.push(referenceFormat.format(date));
+ });
+ assert.notSameValue(expectedStrings.indexOf(formatted), -1,
+ "Function " + f + " did not return expected string for locales " +
+ locales + ", options " + (options? JSON.stringify(options) : options) +
+ "; expected " +
+ (expectedStrings.length === 1 ? expectedStrings[0] : "one of " + expectedStrings) +
+ ", got " + formatted + ".");
+ });
+ });
+}
+
+// any/date: steps 5a, 6a, 7a
+testWithDateTimeFormat(undefined, {year: "numeric", month: "numeric", day: "numeric"});
+
+// any/date: steps 5a, 6a
+testWithDateTimeFormat({year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"});
+
+// any/date: steps 5a, 6a
+testWithDateTimeFormat({hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"});
+
+// any/all: steps 5a, 6a, 7a, 8a
+testWithToLocale("toLocaleString", undefined, [
+ // the first one is not guaranteed to be supported; the second one is
+ {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"},
+ {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}
+]);
+
+// any/all: steps 5a, 6a
+testWithToLocale("toLocaleString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"});
+
+// any/all: steps 5a, 6a
+testWithToLocale("toLocaleString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"});
+
+// date/date: steps 5a, 7a
+testWithToLocale("toLocaleDateString", undefined, {year: "numeric", month: "numeric", day: "numeric"});
+
+// date/date: steps 5a
+testWithToLocale("toLocaleDateString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"});
+
+// date/date: steps 5a, 7a
+testWithToLocale("toLocaleDateString", {hour: "numeric", minute: "numeric", second: "numeric"}, [
+ // the first one is not guaranteed to be supported; the second one is
+ {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"},
+ {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}
+]);
+
+// time/time: steps 6a, 8a
+testWithToLocale("toLocaleTimeString", undefined, {hour: "numeric", minute: "numeric", second: "numeric"});
+
+// time/time: steps 6a, 8a
+testWithToLocale("toLocaleTimeString", {weekday: "short", year: "numeric", month: "numeric", day: "numeric"},
+ {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"});
+
+// time/time: steps 6a
+testWithToLocale("toLocaleTimeString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js
new file mode 100644
index 0000000000..854e5ff3f1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/default-options-object-prototype.js
@@ -0,0 +1,22 @@
+// Copyright (C) 2017 Daniel Ehrenberg. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-todatetimeoptions
+description: >
+ Monkey-patching Object.prototype does not change the default
+ options for DateTimeFormat as a null prototype is used.
+info: |
+ ToDateTimeOptions ( options, required, defaults )
+
+ 1. If options is undefined, let options be null; otherwise let options be ? ToObject(options).
+ 1. Let options be ObjectCreate(options).
+---*/
+
+let defaultYear = new Intl.DateTimeFormat("en").resolvedOptions().year;
+
+Object.prototype.year = "2-digit";
+let formatter = new Intl.DateTimeFormat("en");
+assert.sameValue(formatter.resolvedOptions().year, defaultYear);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js b/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js
new file mode 100644
index 0000000000..34c9829741
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/ignore-invalid-unicode-ext-values.js
@@ -0,0 +1,39 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.2.3_b
+description: >
+ Tests that Intl.DateTimeFormat does not accept Unicode locale
+ extension keys and values that are not allowed.
+author: Norbert Lindenberg
+---*/
+
+var locales = ["ja-JP", "zh-Hans-CN", "zh-Hant-TW"];
+var input = new Date(Date.parse("1989-11-09T17:57:00Z"));
+
+locales.forEach(function (locale) {
+ var defaultDateTimeFormat = new Intl.DateTimeFormat([locale]);
+ var defaultOptions = defaultDateTimeFormat.resolvedOptions();
+ var defaultOptionsJSON = JSON.stringify(defaultOptions);
+ var defaultLocale = defaultOptions.locale;
+ var defaultFormatted = defaultDateTimeFormat.format(input);
+
+ var keyValues = {
+ "cu": ["USD", "EUR", "JPY", "CNY", "TWD", "invalid"], // DateTimeFormat internally uses NumberFormat
+ "nu": ["native", "traditio", "finance", "invalid"],
+ "tz": ["usnavajo", "utcw01", "aumel", "uslax", "usnyc", "deber", "invalid"]
+ };
+
+ Object.getOwnPropertyNames(keyValues).forEach(function (key) {
+ keyValues[key].forEach(function (value) {
+ var dateTimeFormat = new Intl.DateTimeFormat([locale + "-u-" + key + "-" + value]);
+ var options = dateTimeFormat.resolvedOptions();
+ assert.sameValue(options.locale, defaultLocale, "Locale " + options.locale + " is affected by key " + key + "; value " + value + ".");
+ assert.sameValue(JSON.stringify(options), defaultOptionsJSON, "Resolved options " + JSON.stringify(options) + " are affected by key " + key + "; value " + value + ".");
+ assert.sameValue(dateTimeFormat.format(input), defaultFormatted, "Formatted value " + dateTimeFormat.format(input) + " is affected by key " + key + "; value " + value + ".");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js b/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js
new file mode 100644
index 0000000000..34e6873529
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/instance-proto-and-extensible.js
@@ -0,0 +1,19 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.3
+description: >
+ Tests that objects constructed by Intl.DateTimeFormat have the
+ specified internal properties.
+author: Norbert Lindenberg
+---*/
+
+var obj = new Intl.DateTimeFormat();
+
+var actualPrototype = Object.getPrototypeOf(obj);
+assert.sameValue(actualPrototype, Intl.DateTimeFormat.prototype, "Prototype of object constructed by Intl.DateTimeFormat isn't Intl.DateTimeFormat.prototype.");
+
+assert(Object.isExtensible(obj), "Object constructed by Intl.DateTimeFormat must be extensible.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js
new file mode 100644
index 0000000000..61b9452d9a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol-on-unwrap.js
@@ -0,0 +1,34 @@
+// Copyright 2020 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-unwrapdatetimeformat
+description: >
+ Tests that [[FallbackSymbol]]'s [[Description]] is "IntlLegacyConstructedSymbol" if normative optional is implemented.
+author: Yusuke Suzuki
+features: [intl-normative-optional]
+---*/
+
+let object = new Intl.DateTimeFormat();
+let newObject = Intl.DateTimeFormat.call(object);
+let symbol = null;
+let error = null;
+try {
+ let proxy = new Proxy(newObject, {
+ get(target, property) {
+ symbol = property;
+ return target[property];
+ }
+ });
+ Intl.DateTimeFormat.prototype.resolvedOptions.call(proxy);
+} catch (e) {
+ // If normative optional is not implemented, an error will be thrown.
+ error = e;
+ assert(error instanceof TypeError);
+}
+if (error === null) {
+ assert.sameValue(typeof symbol, "symbol");
+ assert.sameValue(symbol.description, "IntlLegacyConstructedSymbol");
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js
new file mode 100644
index 0000000000..6ca345b44e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/intl-legacy-constructed-symbol.js
@@ -0,0 +1,20 @@
+// Copyright 2020 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat
+description: >
+ Tests that [[FallbackSymbol]]'s [[Description]] is "IntlLegacyConstructedSymbol" if normative optional is implemented.
+author: Yusuke Suzuki
+features: [intl-normative-optional]
+---*/
+
+let object = new Intl.DateTimeFormat();
+let newObject = Intl.DateTimeFormat.call(object);
+let symbols = Object.getOwnPropertySymbols(newObject);
+if (symbols.length !== 0) {
+ assert.sameValue(symbols.length, 1);
+ assert.sameValue(symbols[0].description, "IntlLegacyConstructedSymbol");
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js b/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js
new file mode 100644
index 0000000000..6d44737ef4
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/legacy-regexp-statics-not-modified.js
@@ -0,0 +1,21 @@
+// Copyright 2013 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_a
+description: >
+ Tests that constructing a DateTimeFormat doesn't create or modify
+ unwanted properties on the RegExp constructor.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+testForUnwantedRegExpChanges(function () {
+ new Intl.DateTimeFormat("de-DE-u-ca-gregory");
+});
+
+testForUnwantedRegExpChanges(function () {
+ new Intl.DateTimeFormat("de-DE-u-ca-gregory", {timeZone: "UTC"});
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/length.js b/js/src/tests/test262/intl402/DateTimeFormat/length.js
new file mode 100644
index 0000000000..29563adcd3
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/length.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat
+description: >
+ Intl.DateTimeFormat.length is 0.
+info: |
+ Intl.DateTimeFormat ( [ locales [ , options ] ] )
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every built-in function object, including constructors, has a length
+ property whose value is an integer. Unless otherwise specified, this
+ value is equal to the largest number of named arguments shown in the
+ subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which
+ are shown using the form «...name») are not included in the default
+ argument count.
+ Unless otherwise specified, the length property of a built-in function
+ object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: true }.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/name.js b/js/src/tests/test262/intl402/DateTimeFormat/name.js
new file mode 100644
index 0000000000..fbdc7f6cab
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/name.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat
+description: >
+ Intl.DateTimeFormat.name is "DateTimeFormat".
+info: |
+ 12.2.1 Intl.DateTimeFormat ([ locales [ , options ]])
+
+ 17 ECMAScript Standard Built-in Objects:
+ Every built-in Function object, including constructors, that is not
+ identified as an anonymous function has a name property whose value
+ is a String.
+
+ Unless otherwise specified, the name property of a built-in Function
+ object, if it exists, has the attributes { [[Writable]]: false,
+ [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat, "name", {
+ value: "DateTimeFormat",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js b/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js
new file mode 100644
index 0000000000..baa730596c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/numbering-system-calendar-options.js
@@ -0,0 +1,69 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that the options numberingSystem and calendar can be set through
+ either the locale or the options.
+author: Norbert Lindenberg, Daniel Ehrenberg
+---*/
+
+let defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale;
+
+let supportedNumberingSystems = ["latn", "arab"].filter(nu =>
+ new Intl.DateTimeFormat(defaultLocale + "-u-nu-" + nu)
+ .resolvedOptions().numberingSystem === nu
+);
+
+let supportedCalendars = ["gregory", "chinese"].filter(ca =>
+ new Intl.DateTimeFormat(defaultLocale + "-u-ca-" + ca)
+ .resolvedOptions().calendar === ca
+);
+
+let options = [
+ {key: "nu", property: "numberingSystem", type: "string", values: supportedNumberingSystems},
+ {key: "ca", property: "calendar", type: "string", values: supportedCalendars}
+];
+
+options.forEach(function (option) {
+ let dateTimeFormat, opt, result;
+
+ // find out which values are supported for a property in the default locale
+ let supportedValues = [];
+ option.values.forEach(function (value) {
+ opt = {};
+ opt[option.property] = value;
+ dateTimeFormat = new Intl.DateTimeFormat([defaultLocale], opt);
+ result = dateTimeFormat.resolvedOptions()[option.property];
+ if (result !== undefined && supportedValues.indexOf(result) === -1) {
+ supportedValues.push(result);
+ }
+ });
+
+ // verify that the supported values can also be set through the locale
+ supportedValues.forEach(function (value) {
+ dateTimeFormat = new Intl.DateTimeFormat([defaultLocale + "-u-" + option.key + "-" + value]);
+ result = dateTimeFormat.resolvedOptions()[option.property];
+ assert.sameValue(result, value, "Property " + option.property + " couldn't be set through locale extension key " + option.key + ".");
+ });
+
+ // verify that the options setting overrides the locale setting
+ supportedValues.forEach(function (value) {
+ let otherValue;
+ option.values.forEach(function (possibleValue) {
+ if (possibleValue !== value) {
+ otherValue = possibleValue;
+ }
+ });
+ if (otherValue !== undefined) {
+ opt = {};
+ opt[option.property] = value;
+ dateTimeFormat = new Intl.DateTimeFormat([defaultLocale + "-u-" + option.key + "-" + otherValue], opt);
+ result = dateTimeFormat.resolvedOptions()[option.property];
+ assert.sameValue(result, value, "Options value for property " + option.property + " doesn't override locale extension key " + option.key + ".");
+ }
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js
new file mode 100644
index 0000000000..c2b774815d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prop-desc.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat-intro
+description: >
+ "DateTimeFormat" property of Intl.
+info: |
+ Intl.DateTimeFormat (...)
+
+ 7 Requirements for Standard Built-in ECMAScript Objects
+
+ Unless specified otherwise in this document, the objects, functions, and constructors
+ described in this standard are subject to the generic requirements and restrictions
+ specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+ Specification, 9th edition, clause 17, or successor.
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every other data property described in clauses 18 through 26 and in Annex B.2 has the
+ attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+ unless otherwise specified.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl, "DateTimeFormat", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js b/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js
new file mode 100644
index 0000000000..118fadf545
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/proto-from-ctor-realm.js
@@ -0,0 +1,60 @@
+// Copyright (C) 2019 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat
+description: Default [[Prototype]] value derived from realm of the NewTarget.
+info: |
+ Intl.DateTimeFormat ( [ locales [ , options ] ] )
+
+ 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ 2. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%DateTimeFormatPrototype%", « ... »).
+ ...
+ 6. Return dateTimeFormat.
+
+ OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] )
+
+ ...
+ 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto).
+ 3. Return ObjectCreate(proto, internalSlotsList).
+
+ GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto )
+
+ ...
+ 3. Let proto be ? Get(constructor, 'prototype').
+ 4. If Type(proto) is not Object, then
+ a. Let realm be ? GetFunctionRealm(constructor).
+ b. Set proto to realm's intrinsic object named intrinsicDefaultProto.
+ 5. Return proto.
+features: [cross-realm, Reflect, Symbol]
+---*/
+
+var other = $262.createRealm().global;
+var newTarget = new other.Function();
+var dtf;
+
+newTarget.prototype = undefined;
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is undefined');
+
+newTarget.prototype = null;
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is null');
+
+newTarget.prototype = false;
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Boolean');
+
+newTarget.prototype = 'str';
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a String');
+
+newTarget.prototype = Symbol();
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Symbol');
+
+newTarget.prototype = 1;
+dtf = Reflect.construct(Intl.DateTimeFormat, [], newTarget);
+assert.sameValue(Object.getPrototypeOf(dtf), other.Intl.DateTimeFormat.prototype, 'newTarget.prototype is a Number');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js
new file mode 100644
index 0000000000..dd849faaef
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/builtin.js
@@ -0,0 +1,18 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.3_L15
+description: >
+ Tests that Intl.DateTimeFormat.prototype meets the requirements
+ for built-in objects defined by the introduction of chapter 17 of
+ the ECMAScript Language Specification.
+author: Norbert Lindenberg
+---*/
+
+assert(Object.isExtensible(Intl.DateTimeFormat.prototype), "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.prototype), Object.prototype,
+ "Built-in prototype objects must have Object.prototype as their prototype.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js
new file mode 100644
index 0000000000..6d19563ee2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/prop-desc.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.constructor
+description: >
+ "constructor" property of Intl.DateTimeFormat.prototype.
+info: |
+ Intl.DateTimeFormat.prototype.constructor
+
+ 7 Requirements for Standard Built-in ECMAScript Objects
+
+ Unless specified otherwise in this document, the objects, functions, and constructors
+ described in this standard are subject to the generic requirements and restrictions
+ specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+ Specification, 9th edition, clause 17, or successor.
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every other data property described in clauses 18 through 26 and in Annex B.2 has the
+ attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+ unless otherwise specified.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.prototype, "constructor", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/shell.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js
new file mode 100644
index 0000000000..5092db0768
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/constructor/value.js
@@ -0,0 +1,14 @@
+// Copyright 2012 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3.1
+description: >
+ Tests that Intl.DateTimeFormat.prototype.constructor is the
+ Intl.DateTimeFormat.
+author: Roozbeh Pournader
+---*/
+
+assert.sameValue(Intl.DateTimeFormat.prototype.constructor, Intl.DateTimeFormat, "Intl.DateTimeFormat.prototype.constructor is not the same as Intl.DateTimeFormat");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js
new file mode 100644
index 0000000000..485a7c0720
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/bound-to-datetimeformat-instance.js
@@ -0,0 +1,30 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_1_c
+description: Tests that format function is bound to its Intl.DateTimeFormat.
+author: Norbert Lindenberg
+---*/
+
+var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))];
+var locales = [undefined, ["de"], ["th-u-ca-gregory-nu-thai"], ["en"], ["ja-u-ca-japanese"], ["ar-u-ca-islamicc-nu-arab"]];
+var options = [
+ undefined,
+ {hour12: false},
+ {month: "long", day: "numeric", hour: "2-digit", minute: "2-digit"}
+];
+
+locales.forEach(function (locales) {
+ options.forEach(function (options) {
+ var formatObj = new Intl.DateTimeFormat(locales, options);
+ var formatFunc = formatObj.format;
+ dates.forEach(function (date) {
+ var referenceFormatted = formatObj.format(date);
+ var formatted = formatFunc(date);
+ assert.sameValue(referenceFormatted, formatted, "format function produces different result than format method for locales " + locales + "; options: " + (options ? JSON.stringify(options) : options) + ".");
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js
new file mode 100644
index 0000000000..c4870b0b57
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/builtin.js
@@ -0,0 +1,33 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_L15
+description: >
+ Tests that the getter for Intl.DateTimeFormat.prototype.format
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language
+ Specification.
+author: Norbert Lindenberg
+includes: [isConstructor.js]
+features: [Reflect.construct]
+---*/
+
+var formatFn = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get;
+
+assert.sameValue(Object.prototype.toString.call(formatFn), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(formatFn),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(formatFn), Function.prototype);
+
+assert.sameValue(formatFn.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(formatFn), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js
new file mode 100644
index 0000000000..f13f9425ce
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/date-constructor-not-called.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ The Date constructor is not called to convert the input value.
+info: >
+ 12.1.5 DateTime Format Functions
+
+ ...
+ 3. If date is not provided or is undefined, then
+ ...
+ 4. Else,
+ a. Let x be ? ToNumber(date).
+ 5. Return FormatDateTime(dtf, x).
+
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. ...
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var dateTimeString = "2017-11-10T14:09:00.000Z";
+
+// |dateTimeString| is valid ISO-8601 style date/time string.
+assert.notSameValue(new Date(dateTimeString), NaN);
+
+// Ensure string input values are not converted to time values by calling the
+// Date constructor.
+assert.throws(RangeError, function() {
+ dtf.format(dateTimeString);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js
new file mode 100644
index 0000000000..13b8f374b3
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-long-en.js
@@ -0,0 +1,95 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of dayPeriod, long format.
+features: [Intl.DateTimeFormat-dayPeriod]
+locale: [en-US]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const long = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'long'
+});
+
+assert.sameValue(long.format(d0000), 'at night', '00:00, long format');
+assert.sameValue(long.format(d0100), 'at night', '01:00, long format');
+assert.sameValue(long.format(d0200), 'at night', '02:00, long format');
+assert.sameValue(long.format(d0300), 'at night', '03:00, long format');
+assert.sameValue(long.format(d0400), 'at night', '04:00, long format');
+assert.sameValue(long.format(d0500), 'at night', '05:00, long format');
+assert.sameValue(long.format(d0600), 'in the morning', '06:00, long format');
+assert.sameValue(long.format(d0700), 'in the morning', '07:00, long format');
+assert.sameValue(long.format(d0800), 'in the morning', '08:00, long format');
+assert.sameValue(long.format(d0900), 'in the morning', '09:00, long format');
+assert.sameValue(long.format(d1000), 'in the morning', '10:00, long format');
+assert.sameValue(long.format(d1100), 'in the morning', '11:00, long format');
+assert.sameValue(long.format(d1200), 'noon', '12:00, long format');
+assert.sameValue(long.format(d1300), 'in the afternoon', '13:00, long format');
+assert.sameValue(long.format(d1400), 'in the afternoon', '14:00, long format');
+assert.sameValue(long.format(d1500), 'in the afternoon', '15:00, long format');
+assert.sameValue(long.format(d1600), 'in the afternoon', '16:00, long format');
+assert.sameValue(long.format(d1700), 'in the afternoon', '17:00, long format');
+assert.sameValue(long.format(d1800), 'in the evening', '18:00, long format');
+assert.sameValue(long.format(d1900), 'in the evening', '19:00, long format');
+assert.sameValue(long.format(d2000), 'in the evening', '20:00, long format');
+assert.sameValue(long.format(d2100), 'at night', '21:00, long format');
+assert.sameValue(long.format(d2200), 'at night', '22:00, long format');
+assert.sameValue(long.format(d2300), 'at night', '23:00, long format');
+
+const longNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'long',
+ hour: 'numeric'
+});
+
+assert.sameValue(longNumeric.format(d0000), '12 at night', '00:00, long-numeric');
+assert.sameValue(longNumeric.format(d0100), '1 at night', '01:00, long-numeric');
+assert.sameValue(longNumeric.format(d0200), '2 at night', '02:00, long-numeric');
+assert.sameValue(longNumeric.format(d0300), '3 at night', '03:00, long-numeric');
+assert.sameValue(longNumeric.format(d0400), '4 at night', '04:00, long-numeric');
+assert.sameValue(longNumeric.format(d0500), '5 at night', '05:00, long-numeric');
+assert.sameValue(longNumeric.format(d0600), '6 in the morning', '06:00, long-numeric');
+assert.sameValue(longNumeric.format(d0700), '7 in the morning', '07:00, long-numeric');
+assert.sameValue(longNumeric.format(d0800), '8 in the morning', '08:00, long-numeric');
+assert.sameValue(longNumeric.format(d0900), '9 in the morning', '09:00, long-numeric');
+assert.sameValue(longNumeric.format(d1000), '10 in the morning', '10:00, long-numeric');
+assert.sameValue(longNumeric.format(d1100), '11 in the morning', '11:00, long-numeric');
+assert.sameValue(longNumeric.format(d1200), '12 noon', '12:00, long-numeric');
+assert.sameValue(longNumeric.format(d1300), '1 in the afternoon', '13:00, long-numeric');
+assert.sameValue(longNumeric.format(d1400), '2 in the afternoon', '14:00, long-numeric');
+assert.sameValue(longNumeric.format(d1500), '3 in the afternoon', '15:00, long-numeric');
+assert.sameValue(longNumeric.format(d1600), '4 in the afternoon', '16:00, long-numeric');
+assert.sameValue(longNumeric.format(d1700), '5 in the afternoon', '17:00, long-numeric');
+assert.sameValue(longNumeric.format(d1800), '6 in the evening', '18:00, long-numeric');
+assert.sameValue(longNumeric.format(d1900), '7 in the evening', '19:00, long-numeric');
+assert.sameValue(longNumeric.format(d2000), '8 in the evening', '20:00, long-numeric');
+assert.sameValue(longNumeric.format(d2100), '9 at night', '21:00, long-numeric');
+assert.sameValue(longNumeric.format(d2200), '10 at night', '22:00, long-numeric');
+assert.sameValue(longNumeric.format(d2300), '11 at night', '23:00, long-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js
new file mode 100644
index 0000000000..4d26a5131d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-narrow-en.js
@@ -0,0 +1,95 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of dayPeriod, narrow format.
+features: [Intl.DateTimeFormat-dayPeriod]
+locale: [en-US]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const narrow = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'narrow'
+});
+
+assert.sameValue(narrow.format(d0000), 'at night', '00:00, narrow format');
+assert.sameValue(narrow.format(d0100), 'at night', '01:00, narrow format');
+assert.sameValue(narrow.format(d0200), 'at night', '02:00, narrow format');
+assert.sameValue(narrow.format(d0300), 'at night', '03:00, narrow format');
+assert.sameValue(narrow.format(d0400), 'at night', '04:00, narrow format');
+assert.sameValue(narrow.format(d0500), 'at night', '05:00, narrow format');
+assert.sameValue(narrow.format(d0600), 'in the morning', '06:00, narrow format');
+assert.sameValue(narrow.format(d0700), 'in the morning', '07:00, narrow format');
+assert.sameValue(narrow.format(d0800), 'in the morning', '08:00, narrow format');
+assert.sameValue(narrow.format(d0900), 'in the morning', '09:00, narrow format');
+assert.sameValue(narrow.format(d1000), 'in the morning', '10:00, narrow format');
+assert.sameValue(narrow.format(d1100), 'in the morning', '11:00, narrow format');
+assert.sameValue(narrow.format(d1200), 'n', '12:00, narrow format');
+assert.sameValue(narrow.format(d1300), 'in the afternoon', '13:00, narrow format');
+assert.sameValue(narrow.format(d1400), 'in the afternoon', '14:00, narrow format');
+assert.sameValue(narrow.format(d1500), 'in the afternoon', '15:00, narrow format');
+assert.sameValue(narrow.format(d1600), 'in the afternoon', '16:00, narrow format');
+assert.sameValue(narrow.format(d1700), 'in the afternoon', '17:00, narrow format');
+assert.sameValue(narrow.format(d1800), 'in the evening', '18:00, narrow format');
+assert.sameValue(narrow.format(d1900), 'in the evening', '19:00, narrow format');
+assert.sameValue(narrow.format(d2000), 'in the evening', '20:00, narrow format');
+assert.sameValue(narrow.format(d2100), 'at night', '21:00, narrow format');
+assert.sameValue(narrow.format(d2200), 'at night', '22:00, narrow format');
+assert.sameValue(narrow.format(d2300), 'at night', '23:00, narrow format');
+
+const narrowNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'narrow',
+ hour: 'numeric'
+});
+
+assert.sameValue(narrowNumeric.format(d0000), '12 at night', '00:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0100), '1 at night', '01:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0200), '2 at night', '02:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0300), '3 at night', '03:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0400), '4 at night', '04:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0500), '5 at night', '05:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0600), '6 in the morning', '06:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0700), '7 in the morning', '07:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0800), '8 in the morning', '08:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d0900), '9 in the morning', '09:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1000), '10 in the morning', '10:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1100), '11 in the morning', '11:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1200), '12 n', '12:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1300), '1 in the afternoon', '13:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1400), '2 in the afternoon', '14:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1500), '3 in the afternoon', '15:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1600), '4 in the afternoon', '16:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1700), '5 in the afternoon', '17:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1800), '6 in the evening', '18:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d1900), '7 in the evening', '19:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d2000), '8 in the evening', '20:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d2100), '9 at night', '21:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d2200), '10 at night', '22:00, narrow-numeric');
+assert.sameValue(narrowNumeric.format(d2300), '11 at night', '23:00, narrow-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js
new file mode 100644
index 0000000000..f7b410f24d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/dayPeriod-short-en.js
@@ -0,0 +1,95 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializedatetimeformat
+description: Checks basic handling of dayPeriod, short format.
+features: [Intl.DateTimeFormat-dayPeriod]
+locale: [en-US]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const short = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'short'
+});
+
+assert.sameValue(short.format(d0000), 'at night', '00:00, short format');
+assert.sameValue(short.format(d0100), 'at night', '01:00, short format');
+assert.sameValue(short.format(d0200), 'at night', '02:00, short format');
+assert.sameValue(short.format(d0300), 'at night', '03:00, short format');
+assert.sameValue(short.format(d0400), 'at night', '04:00, short format');
+assert.sameValue(short.format(d0500), 'at night', '05:00, short format');
+assert.sameValue(short.format(d0600), 'in the morning', '06:00, short format');
+assert.sameValue(short.format(d0700), 'in the morning', '07:00, short format');
+assert.sameValue(short.format(d0800), 'in the morning', '08:00, short format');
+assert.sameValue(short.format(d0900), 'in the morning', '09:00, short format');
+assert.sameValue(short.format(d1000), 'in the morning', '10:00, short format');
+assert.sameValue(short.format(d1100), 'in the morning', '11:00, short format');
+assert.sameValue(short.format(d1200), 'noon', '12:00, short format');
+assert.sameValue(short.format(d1300), 'in the afternoon', '13:00, short format');
+assert.sameValue(short.format(d1400), 'in the afternoon', '14:00, short format');
+assert.sameValue(short.format(d1500), 'in the afternoon', '15:00, short format');
+assert.sameValue(short.format(d1600), 'in the afternoon', '16:00, short format');
+assert.sameValue(short.format(d1700), 'in the afternoon', '17:00, short format');
+assert.sameValue(short.format(d1800), 'in the evening', '18:00, short format');
+assert.sameValue(short.format(d1900), 'in the evening', '19:00, short format');
+assert.sameValue(short.format(d2000), 'in the evening', '20:00, short format');
+assert.sameValue(short.format(d2100), 'at night', '21:00, short format');
+assert.sameValue(short.format(d2200), 'at night', '22:00, short format');
+assert.sameValue(short.format(d2300), 'at night', '23:00, short format');
+
+const shortNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'short',
+ hour: 'numeric'
+});
+
+assert.sameValue(shortNumeric.format(d0000), '12 at night', '00:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0100), '1 at night', '01:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0200), '2 at night', '02:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0300), '3 at night', '03:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0400), '4 at night', '04:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0500), '5 at night', '05:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0600), '6 in the morning', '06:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0700), '7 in the morning', '07:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0800), '8 in the morning', '08:00, short-numeric');
+assert.sameValue(shortNumeric.format(d0900), '9 in the morning', '09:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1000), '10 in the morning', '10:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1100), '11 in the morning', '11:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1200), '12 noon', '12:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1300), '1 in the afternoon', '13:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1400), '2 in the afternoon', '14:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1500), '3 in the afternoon', '15:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1600), '4 in the afternoon', '16:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1700), '5 in the afternoon', '17:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1800), '6 in the evening', '18:00, short-numeric');
+assert.sameValue(shortNumeric.format(d1900), '7 in the evening', '19:00, short-numeric');
+assert.sameValue(shortNumeric.format(d2000), '8 in the evening', '20:00, short-numeric');
+assert.sameValue(shortNumeric.format(d2100), '9 at night', '21:00, short-numeric');
+assert.sameValue(shortNumeric.format(d2200), '10 at night', '22:00, short-numeric');
+assert.sameValue(shortNumeric.format(d2300), '11 at night', '23:00, short-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js
new file mode 100644
index 0000000000..d5270e354a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-builtin.js
@@ -0,0 +1,33 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_1_a_L15
+description: >
+ Tests that the function returned by
+ Intl.DateTimeFormat.prototype.format meets the requirements for
+ built-in objects defined by the introduction of chapter 17 of the
+ ECMAScript Language Specification.
+author: Norbert Lindenberg
+includes: [isConstructor.js]
+features: [Reflect.construct]
+---*/
+
+var formatFn = new Intl.DateTimeFormat().format;
+
+assert.sameValue(Object.prototype.toString.call(formatFn), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(formatFn),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(formatFn), Function.prototype);
+
+assert.sameValue(formatFn.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(formatFn), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js
new file mode 100644
index 0000000000..255417c98a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-length.js
@@ -0,0 +1,31 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.format
+description: >
+ The length of the bound DateTime Format function is 1.
+info: |
+ get Intl.DateTimeFormat.prototype.format
+
+ ...
+ 4. If dtf.[[BoundFormat]] is undefined, then
+ a. Let F be a new built-in function object as defined in DateTime Format Functions (12.1.5).
+ b. Let bf be BoundFunctionCreate(F, dft, « »).
+ c. Perform ! DefinePropertyOrThrow(bf, "length", PropertyDescriptor {[[Value]]: 1,
+ [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).
+ ...
+
+includes: [propertyHelper.js]
+---*/
+
+var formatFn = new Intl.DateTimeFormat().format;
+
+verifyProperty(formatFn, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js
new file mode 100644
index 0000000000..73922bca5f
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-name.js
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.format
+description: >
+ The bound DateTimeFormat format function is an anonymous function.
+info: |
+ 12.4.3 get Intl.DateTimeFormat.prototype.compare
+
+ 17 ECMAScript Standard Built-in Objects:
+ Every built-in function object, including constructors, has a `name`
+ property whose value is a String. Functions that are identified as
+ anonymous functions use the empty string as the value of the `name`
+ property.
+ Unless otherwise specified, the `name` property of a built-in function
+ object has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*,
+ [[Configurable]]: *true* }.
+includes: [propertyHelper.js]
+---*/
+
+var formatFn = new Intl.DateTimeFormat().format;
+
+verifyProperty(formatFn, "name", {
+ value: "", writable: false, enumerable: false, configurable: true
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js
new file mode 100644
index 0000000000..78fcf6950b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/format-function-property-order.js
@@ -0,0 +1,18 @@
+// Copyright (C) 2020 ExE Boss. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createbuiltinfunction
+description: DateTimeFormat bound format function property order
+info: |
+ Set order: "length", "name"
+includes: [compareArray.js]
+---*/
+
+var formatFn = new Intl.DateTimeFormat().format;
+
+assert.compareArray(
+ Object.getOwnPropertyNames(formatFn),
+ ['length', 'name']
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js
new file mode 100644
index 0000000000..25af5ada6d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/fractionalSecondDigits.js
@@ -0,0 +1,34 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of fractionalSecondDigits.
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+locale: [en-US]
+---*/
+
+const d1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+const d2 = new Date(2019, 7, 10, 1, 2, 3, 567);
+
+let dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined});
+assert.sameValue(dtf.format(d1), "02:03", "no fractionalSecondDigits");
+assert.sameValue(dtf.format(d2), "02:03", "no fractionalSecondDigits");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1});
+assert.sameValue(dtf.format(d1), "02:03.2", "1 fractionalSecondDigits round down");
+assert.sameValue(dtf.format(d2), "02:03.5", "1 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2});
+assert.sameValue(dtf.format(d1), "02:03.23", "2 fractionalSecondDigits round down");
+assert.sameValue(dtf.format(d2), "02:03.56", "2 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3});
+assert.sameValue(dtf.format(d1), "02:03.234", "3 fractionalSecondDigits round down");
+assert.sameValue(dtf.format(d2), "02:03.567", "3 fractionalSecondDigits round down");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js
new file mode 100644
index 0000000000..fe1ec0b080
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/length.js
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.format
+description: >
+ get Intl.DateTimeFormat.prototype.format.length is 0.
+info: |
+ get Intl.DateTimeFormat.prototype.format
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every built-in function object, including constructors, has a length
+ property whose value is an integer. Unless otherwise specified, this
+ value is equal to the largest number of named arguments shown in the
+ subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which
+ are shown using the form «...name») are not included in the default
+ argument count.
+ Unless otherwise specified, the length property of a built-in function
+ object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: true }.
+
+includes: [propertyHelper.js]
+---*/
+
+var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format");
+
+verifyProperty(desc.get, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js
new file mode 100644
index 0000000000..3f7419112f
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/name.js
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.format
+description: >
+ get Intl.DateTimeFormat.prototype.format.name is "get format".
+info: |
+ 12.4.3 get Intl.DateTimeFormat.prototype.format
+
+ 17 ECMAScript Standard Built-in Objects:
+ Every built-in Function object, including constructors, that is not
+ identified as an anonymous function has a name property whose value
+ is a String.
+
+ Unless otherwise specified, the name property of a built-in Function
+ object, if it exists, has the attributes { [[Writable]]: false,
+ [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+---*/
+
+var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format");
+
+verifyProperty(desc.get, "name", {
+ value: "get format",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js
new file mode 100644
index 0000000000..010d55def0
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/no-instanceof.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.format
+description: >
+ Tests that Intl.DateTimeFormat.prototype.format calls
+ OrdinaryHasInstance instead of the instanceof operator which includes a
+ Symbol.hasInstance lookup and call among other things.
+info: >
+ UnwrapDateTimeFormat ( dtf )
+ 2. If dtf does not have an [[InitializedDateTimeFormat]] internal slot and
+ ? OrdinaryHasInstance(%DateTimeFormat%, dtf) is true, then
+ a. Return ? Get(dtf, %Intl%.[[FallbackSymbol]]).
+---*/
+
+const dtf = Object.create(Intl.DateTimeFormat.prototype);
+
+Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
+ get() { throw new Test262Error(); }
+});
+
+assert.throws(TypeError, () => dtf.format);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js
new file mode 100644
index 0000000000..2f03dcae06
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/offset-timezone-gmt-same.js
@@ -0,0 +1,29 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that date and time formatting in an offset time zone
+ matches that in the equivalent Etc/GMT±n time zone.
+---*/
+let offsetTimeZones = {
+ '+0300': 'Etc/GMT-3',
+ '+1400': 'Etc/GMT-14',
+ '+02': 'Etc/GMT-2',
+ '+13:00': 'Etc/GMT-13',
+ '-07:00': 'Etc/GMT+7',
+ '-12': 'Etc/GMT+12',
+ '−0900': 'Etc/GMT+9',
+ '−10:00': 'Etc/GMT+10',
+ '−0500': 'Etc/GMT+5',
+};
+let date = new Date('1995-12-17T03:24:56Z');
+Object.entries(offsetTimeZones).forEach(([offsetZone, gmtZone]) => {
+ let offsetDf = new Intl.DateTimeFormat("en",
+ {timeZone: offsetZone, dateStyle: "short", timeStyle: "short"});
+ let gmtDf = new Intl.DateTimeFormat("en",
+ {timeZone: gmtZone, dateStyle: "short", timeStyle: "short"});
+ assert.sameValue(offsetDf.format(date), gmtDf.format(date), `${offsetZone} vs. ${gmtZone}:`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js
new file mode 100644
index 0000000000..c7f826ddfb
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/proleptic-gregorian-calendar.js
@@ -0,0 +1,33 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_FDT_7_a_iv
+description: >
+ Tests that format uses a proleptic Gregorian calendar with no year
+ 0.
+author: Norbert Lindenberg
+---*/
+
+var dates = [
+ 0, // January 1, 1970
+ -62151602400000, // in June 1 BC
+ -8640000000000000 // beginning of ECMAScript time
+];
+
+var format = new Intl.DateTimeFormat(["en-US"], {year: "numeric", era: "short", timeZone: "UTC"});
+
+// this test requires a Gregorian calendar, which we usually find in the US
+assert.sameValue(format.resolvedOptions().calendar, "gregory", "Internal error: Didn't find Gregorian calendar");
+
+dates.forEach(function (date) {
+ var year = new Date(date).getUTCFullYear();
+ var expectedYear = year <= 0 ? 1 - year : year;
+ var expectedYearString = expectedYear.toLocaleString(["en-US"], {useGrouping: false});
+ var expectedEra = year <= 0 ? /BC/ : /AD|(?:^|[^B])CE/;
+ var dateString = format.format(date);
+ assert.notSameValue(dateString.indexOf(expectedYearString), -1, "Formatted year doesn't contain expected year – expected " + expectedYearString + ", got " + dateString + ".");
+ assert(expectedEra.test(dateString), "Formatted year doesn't contain expected era – expected " + expectedEra + ", got " + dateString + ".");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js
new file mode 100644
index 0000000000..55970d90a1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/prop-desc.js
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.format
+description: >
+ "format" property of Intl.DateTimeFormat.prototype.
+info: |
+ get Intl.DateTimeFormat.prototype.format
+
+ 7 Requirements for Standard Built-in ECMAScript Objects
+
+ Unless specified otherwise in this document, the objects, functions, and constructors
+ described in this standard are subject to the generic requirements and restrictions
+ specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+ Specification, 9th edition, clause 17, or successor.
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every accessor property described in clauses 18 through 26 and in Annex B.2 has the
+ attributes { [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified.
+ If only a get accessor function is described, the set accessor function is the default
+ value, undefined. If only a set accessor is described the get accessor is the default
+ value, undefined.
+
+includes: [propertyHelper.js]
+---*/
+
+var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format");
+
+assert.sameValue(desc.set, undefined);
+assert.sameValue(typeof desc.get, "function");
+
+verifyProperty(Intl.DateTimeFormat.prototype, "format", {
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js
new file mode 100644
index 0000000000..46be36f3c1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/related-year-zh.js
@@ -0,0 +1,20 @@
+// Copyright 2019 Google Inc, Igalia S.L. All rights reserved.
+// Copyright 2020 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: >
+ Checks the output of 'relatedYear' and 'yearName' type, and
+ the choice of pattern based on calendar.
+locale: [zh-u-ca-chinese]
+features: [Array.prototype.includes]
+---*/
+
+const df = new Intl.DateTimeFormat("zh-u-ca-chinese", {year: "numeric"});
+const date = new Date(2019, 5, 1);
+const formatted = df.format(date);
+const expected = ["2019己亥年", "己亥年"];
+assert(expected.includes(formatted));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js
new file mode 100644
index 0000000000..985f46c993
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/shell.js
@@ -0,0 +1,55 @@
+// GENERATED, DO NOT EDIT
+// file: dateConstants.js
+// Copyright (C) 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ Collection of date-centric values
+defines:
+ - date_1899_end
+ - date_1900_start
+ - date_1969_end
+ - date_1970_start
+ - date_1999_end
+ - date_2000_start
+ - date_2099_end
+ - date_2100_start
+ - start_of_time
+ - end_of_time
+---*/
+
+var date_1899_end = -2208988800001;
+var date_1900_start = -2208988800000;
+var date_1969_end = -1;
+var date_1970_start = 0;
+var date_1999_end = 946684799999;
+var date_2000_start = 946684800000;
+var date_2099_end = 4102444799999;
+var date_2100_start = 4102444800000;
+
+var start_of_time = -8.64e15;
+var end_of_time = 8.64e15;
+
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js
new file mode 100644
index 0000000000..b4ca8b4b0d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/taint-Object-prototype.js
@@ -0,0 +1,18 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_TLT_2
+description: >
+ Tests that the behavior of a Record is not affected by
+ adversarial changes to Object.prototype.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "inDST"]);
+
+var format = new Intl.DateTimeFormat();
+var time = format.format();
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js
new file mode 100644
index 0000000000..e9af1ca9c8
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js
@@ -0,0 +1,52 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 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: A time zone in resolvedOptions with a large offset still produces the correct string
+locale: [en]
+features: [Temporal]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDayPeriodSpace =
+ new Intl.DateTimeFormat("en-US", { timeStyle: "short" })
+ .formatToParts(0)
+ .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || "";
+
+const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" });
+
+const date = new Temporal.PlainDate(2021, 8, 4);
+const dateResult = formatter.format(date);
+assert.sameValue(dateResult, "8/4/2021", "plain date");
+
+const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789);
+const datetimeResult1 = formatter.format(datetime1);
+assert.sameValue(
+ datetimeResult1,
+ `8/4/2021, 12:30:45${usDayPeriodSpace}AM`,
+ "plain datetime close to beginning of day"
+);
+const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789);
+const datetimeResult2 = formatter.format(datetime2);
+assert.sameValue(datetimeResult2, `8/4/2021, 11:30:45${usDayPeriodSpace}PM`, "plain datetime close to end of day");
+
+const monthDay = new Temporal.PlainMonthDay(8, 4, "gregory");
+const monthDayResult = formatter.format(monthDay);
+assert.sameValue(monthDayResult, "8/4", "plain month-day");
+
+const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789);
+const timeResult1 = formatter.format(time1);
+assert.sameValue(timeResult1, `12:30:45${usDayPeriodSpace}AM`, "plain time close to beginning of day");
+const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789);
+const timeResult2 = formatter.format(time2);
+assert.sameValue(timeResult2, `11:30:45${usDayPeriodSpace}PM`, "plain time close to end of day");
+
+const month = new Temporal.PlainYearMonth(2021, 8, "gregory");
+const monthResult = formatter.format(month);
+assert.sameValue(monthResult, "8/2021", "plain year-month");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js
new file mode 100644
index 0000000000..d36514f42b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/temporal-zoneddatetime-not-supported.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 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.ZonedDateTime is not supported directly in format()
+features: [Temporal]
+---*/
+
+const formatter = new Intl.DateTimeFormat();
+
+// Check that TypeError would not be thrown for a different reason
+const {timeZone, ...options} = formatter.resolvedOptions();
+const datetime = new Temporal.ZonedDateTime(0n, timeZone);
+assert.sameValue(typeof datetime.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds");
+
+assert.throws(TypeError, () => formatter.format(datetime), "format() does not support Temporal.ZonedDateTime");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js
new file mode 100644
index 0000000000..598b9ec88e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/throws-value-non-finite.js
@@ -0,0 +1,20 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3.2_FDT_1
+description: Tests that format handles non-finite values correctly.
+author: Norbert Lindenberg
+---*/
+
+var invalidValues = [NaN, Infinity, -Infinity];
+
+var format = new Intl.DateTimeFormat();
+
+invalidValues.forEach(function (value) {
+ assert.throws(RangeError, function() {
+ var result = format.format(value);
+ }, "Invalid value " + value + " was not rejected.");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js
new file mode 100644
index 0000000000..0c415ec7ea
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-near-time-boundaries.js
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ TimeClip is applied when calling Intl.DateTimeFormat.prototype.format.
+info: >
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. ...
+
+ 20.3.1.15 TimeClip ( time )
+ ...
+ 2. If abs(time) > 8.64 × 10^15, return NaN.
+ ...
+
+includes: [dateConstants.js]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+// Test values near the start of the ECMAScript time range.
+assert.throws(RangeError, function() {
+ dtf.format(start_of_time - 1);
+});
+assert.sameValue(typeof dtf.format(start_of_time), "string");
+assert.sameValue(typeof dtf.format(start_of_time + 1), "string");
+
+// Test values near the end of the ECMAScript time range.
+assert.sameValue(typeof dtf.format(end_of_time - 1), "string");
+assert.sameValue(typeof dtf.format(end_of_time), "string");
+assert.throws(RangeError, function() {
+ dtf.format(end_of_time + 1);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js
new file mode 100644
index 0000000000..d7fbe4db66
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/time-clip-to-integer.js
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ TimeClip applies ToInteger on its input value.
+info: >
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. ...
+
+ 20.3.1.15 TimeClip ( time )
+ ...
+ 3. Let clippedTime be ! ToInteger(time).
+ 4. If clippedTime is -0, set clippedTime to +0.
+ 5. Return clippedTime.
+---*/
+
+// Switch to a time format instead of using DateTimeFormat's default date-only format.
+var dtf = new Intl.DateTimeFormat(undefined, {
+ hour: "numeric", minute: "numeric", second: "numeric"
+});
+
+var expected = dtf.format(0);
+
+assert.sameValue(dtf.format(-0.9), expected, "format(-0.9)");
+assert.sameValue(dtf.format(-0.5), expected, "format(-0.5)");
+assert.sameValue(dtf.format(-0.1), expected, "format(-0.1)");
+assert.sameValue(dtf.format(-Number.MIN_VALUE), expected, "format(-Number.MIN_VALUE)");
+assert.sameValue(dtf.format(-0), expected, "format(-0)");
+assert.sameValue(dtf.format(+0), expected, "format(+0)");
+assert.sameValue(dtf.format(Number.MIN_VALUE), expected, "format(Number.MIN_VALUE)");
+assert.sameValue(dtf.format(0.1), expected, "format(0.1)");
+assert.sameValue(dtf.format(0.5), expected, "format(0.5)");
+assert.sameValue(dtf.format(0.9), expected, "format(0.9)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js
new file mode 100644
index 0000000000..36893b5f9a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js
@@ -0,0 +1,114 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-date-time-style-pattern
+description: Checks basic handling of timeStyle and dateStyle.
+features: [Intl.DateTimeFormat-datetimestyle, Array.prototype.includes]
+locale: [en-US]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDayPeriodSpace =
+ new Intl.DateTimeFormat("en-US", { timeStyle: "short" })
+ .formatToParts(0)
+ .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || "";
+
+const date = new Date("1886-05-01T14:12:47Z");
+const dateOptions = [
+ ["full", "Saturday, May 1, 1886"],
+ ["long", "May 1, 1886"],
+ ["medium", "May 1, 1886"],
+ ["short", "5/1/86"],
+];
+
+const timeOptions = [
+ ["full", `2:12:47${usDayPeriodSpace}PM Coordinated Universal Time`, "14:12:47 Coordinated Universal Time"],
+ ["long", `2:12:47${usDayPeriodSpace}PM UTC`, "14:12:47 UTC"],
+ ["medium", `2:12:47${usDayPeriodSpace}PM`, "14:12:47"],
+ ["short", `2:12${usDayPeriodSpace}PM`, "14:12"],
+];
+
+const options12 = [
+ { "hour12": true },
+ { "hourCycle": "h11" },
+ { "hourCycle": "h12" },
+ { "hourCycle": "h23", "hour12": true },
+ { "hourCycle": "h24", "hour12": true },
+];
+
+const options24 = [
+ { "hour12": false },
+ { "hourCycle": "h23" },
+ { "hourCycle": "h24" },
+ { "hourCycle": "h11", "hour12": false },
+ { "hourCycle": "h12", "hour12": false },
+];
+
+for (const [dateStyle, expected] of dateOptions) {
+ const dtf = new Intl.DateTimeFormat("en-US", {
+ dateStyle,
+ timeZone: "UTC",
+ });
+
+ const dateString = dtf.format(date);
+ assert.sameValue(dateString, expected, `Result for ${dateStyle}`);
+}
+
+for (const [timeStyle, expected12, expected24] of timeOptions) {
+ const check = (locale, options, expected) => {
+ const dtf = new Intl.DateTimeFormat(locale, {
+ timeStyle,
+ timeZone: "UTC",
+ ...options
+ });
+
+ const dateString = dtf.format(date);
+ assert.sameValue(dateString, expected, `Result for ${timeStyle} with ${JSON.stringify(options)}`);
+ };
+
+ check("en-US", {}, expected12);
+ check("en-US-u-hc-h11", {}, expected12);
+ check("en-US-u-hc-h12", {}, expected12);
+ check("en-US-u-hc-h23", {}, expected24);
+ check("en-US-u-hc-h24", {}, expected24);
+
+ for (const hourOptions of options12) {
+ check("en-US", hourOptions, expected12);
+ check("en-US-u-hc-h11", hourOptions, expected12);
+ check("en-US-u-hc-h12", hourOptions, expected12);
+ check("en-US-u-hc-h23", hourOptions, expected12);
+ check("en-US-u-hc-h24", hourOptions, expected12);
+ }
+
+ for (const hourOptions of options24) {
+ check("en-US", hourOptions, expected24);
+ check("en-US-u-hc-h11", hourOptions, expected24);
+ check("en-US-u-hc-h12", hourOptions, expected24);
+ check("en-US-u-hc-h23", hourOptions, expected24);
+ check("en-US-u-hc-h24", hourOptions, expected24);
+ }
+}
+
+for (const [dateStyle, expectedDate] of dateOptions) {
+ for (const [timeStyle, expectedTime] of timeOptions) {
+ const dtf = new Intl.DateTimeFormat("en-US", {
+ dateStyle,
+ timeStyle,
+ timeZone: "UTC",
+ });
+ const result1 = [expectedDate, ", ", expectedTime].join("");
+ const result2 = [expectedDate, " at ", expectedTime].join("");
+
+ const dateString = dtf.format(date);
+ assert.sameValue(
+ [result1, result2].includes(dateString),
+ true,
+ `Result for date=${dateStyle} and time=${timeStyle}`
+ );
+ }
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js
new file mode 100644
index 0000000000..ee452b5358
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-date-string.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ The Date constructor is not called to convert the input value.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const dtf = new Intl.DateTimeFormat();
+const dateTimeString = "2017-11-10T14:09:00.000Z";
+const date = new Date(dateTimeString);
+// |dateTimeString| is valid ISO-8601 style date/time string.
+assert.notSameValue(date, NaN);
+
+// ToNumber() will try to parse the string as an integer and yield NaN, rather
+// than attempting to parse it like the Date constructor would.
+assert.throws(RangeError, function() {
+ dtf.formatRange(dateTimeString, date);
+});
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, dateTimeString);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js
new file mode 100644
index 0000000000..c6efcad3bf
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-near-time-boundaries.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatRange.
+info: |
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+ TimeClip ( time )
+ ...
+ 2. If abs(time) > 8.64 × 10^15, return NaN.
+ ...
+
+includes: [dateConstants.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const dtf = new Intl.DateTimeFormat();
+const date = Date.now();
+
+// Test values near the start of the ECMAScript time range.
+assert.throws(RangeError, function() {
+ dtf.formatRange(start_of_time - 1, date);
+});
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, start_of_time - 1);
+});
+assert.sameValue(typeof dtf.formatRange(start_of_time, date), "string");
+assert.sameValue(typeof dtf.formatRange(start_of_time + 1, date), "string");
+
+// Test values near the end of the ECMAScript time range.
+assert.sameValue(typeof dtf.formatRange(date, end_of_time - 1), "string");
+assert.sameValue(typeof dtf.formatRange(date, end_of_time), "string");
+assert.throws(RangeError, function() {
+ dtf.formatRange(end_of_time + 1, date);
+});
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, end_of_time + 1);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js
new file mode 100644
index 0000000000..b698b4b9a9
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-to-integer.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ TimeClip applies ToInteger on its input value.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+
+ TimeClip ( time )
+ ...
+ 3. Let clippedTime be ! ToInteger(time).
+ 4. If clippedTime is -0, set clippedTime to +0.
+ 5. Return clippedTime.
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+// Switch to a time format instead of using DateTimeFormat's default date-only format.
+const dtf = new Intl.DateTimeFormat(undefined, {
+ hour: "numeric", minute: "numeric", second: "numeric"
+});
+const date = Date.now();
+const expected = dtf.formatRange(0, date);
+
+assert.sameValue(dtf.formatRange(-0.9, date), expected, "formatRange(-0.9)");
+assert.sameValue(dtf.formatRange(-0.5, date), expected, "formatRange(-0.5)");
+assert.sameValue(dtf.formatRange(-0.1, date), expected, "formatRange(-0.1)");
+assert.sameValue(dtf.formatRange(-Number.MIN_VALUE, date), expected, "formatRange(-Number.MIN_VALUE)");
+assert.sameValue(dtf.formatRange(-0, date), expected, "formatRange(-0)");
+assert.sameValue(dtf.formatRange(+0, date), expected, "formatRange(+0)");
+assert.sameValue(dtf.formatRange(Number.MIN_VALUE, date), expected, "formatRange(Number.MIN_VALUE)");
+assert.sameValue(dtf.formatRange(0.1, date), expected, "formatRange(0.1)");
+assert.sameValue(dtf.formatRange(0.5, date), expected, "formatRange(0.5)");
+assert.sameValue(dtf.formatRange(0.9, date), expected, "formatRange(0.9)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js
new file mode 100644
index 0000000000..ddbe0ed2fe
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/argument-tonumber-throws.js
@@ -0,0 +1,56 @@
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Return abrupt completions from ToNumber(date)
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+features: [Symbol,Intl.DateTimeFormat-formatRange]
+---*/
+
+const date = Date.now();
+
+const objectValueOf = {
+ valueOf: function() {
+ throw new Test262Error();
+ }
+};
+
+const objectToString = {
+ toString: function() {
+ throw new Test262Error();
+ }
+};
+
+const dtf = new Intl.DateTimeFormat(["pt-BR"]);
+
+assert.throws(Test262Error, function() {
+ dtf.formatRange(objectValueOf, date);
+}, "valueOf start");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRange(date, objectValueOf);
+}, "valueOf end");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRange(objectToString, date);
+}, "toString start");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRange(date, objectToString);
+}, "toString end");
+
+const s = Symbol('1');
+assert.throws(TypeError, function() {
+ dtf.formatRange(s, date);
+}, "symbol start");
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(date, s);
+}, "symbol end");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js
new file mode 100644
index 0000000000..d457d6a40b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/builtin.js
@@ -0,0 +1,32 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-ecmascript-standard-built-in-objects
+description: >
+ Tests that the Intl.DateTimeFormat.prototype.formatRange function meets the
+ requirements for built-in objects defined by the ECMAScript Language
+ Specification.
+includes: [isConstructor.js]
+features: [Reflect.construct,Intl.DateTimeFormat-formatRange]
+---*/
+
+const formatRange = Intl.DateTimeFormat.prototype.formatRange;
+
+assert.sameValue(Object.prototype.toString.call(formatRange), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(formatRange),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(formatRange), Function.prototype);
+
+assert.sameValue(formatRange.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(formatRange), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js
new file mode 100644
index 0000000000..d59691d42d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-infinity-throws.js
@@ -0,0 +1,72 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to an Infinity value
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a RangeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 7. If x is greater than y, throw a RangeError exception.
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+
+ FormatDateTimeRange ( dateTimeFormat, x, y )
+
+ 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+ TimeClip ( time )
+ 1. If time is not finite, return NaN.
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var date = new Date();
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(Infinity, date);
+}, "+Infinity/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(-Infinity, date);
+}, "-Infinity/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, Infinity);
+}, "date/+Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, -Infinity);
+}, "date/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(Infinity, Infinity);
+}, "+Infinity/+Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(-Infinity, -Infinity);
+}, "-Infinity/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(Infinity, -Infinity);
+}, "+Infinity/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(-Infinity, Infinity);
+}, "-Infinity/+Infinity");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js
new file mode 100644
index 0000000000..25d90bafd6
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-is-nan-throws.js
@@ -0,0 +1,49 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to NaN
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a RangeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 7. If x is greater than y, throw a RangeError exception.
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+
+ FormatDateTimeRange ( dateTimeFormat, x, y )
+
+ 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var date = new Date();
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(NaN, date);
+}, "NaN/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(date, NaN);
+}, "date/NaN");
+
+assert.throws(RangeError, function() {
+ dtf.formatRange(NaN, NaN);
+}, "NaN/NaN");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js
new file mode 100644
index 0000000000..e2dab6cbc1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-same-returns-single-date.js
@@ -0,0 +1,63 @@
+// Copyright 2021 Google Inc. All rights reserved.
+// Copyright 2021 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ When startDate is equal to endDate, the output should be a string equal
+ to the output of Intl.DateTimeFormat.prototype.format.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 4. Let x be ? ToNumber(startDate).
+ 5. Let y be ? ToNumber(endDate).
+ 6. Return ? FormatDateTimeRange(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 13. If dateFieldsPracticallyEqual is true, then
+ a. Let pattern be dateTimeFormat.[[Pattern]].
+ b. Let patternParts be PartitionPattern(pattern).
+ c. Let result be ? FormatDateTimePattern(dateTimeFormat, patternParts, tm1).
+ d. For each r in result do
+ i. Set r.[[Source]] to "shared".
+ e. Return result.
+
+features: [Intl.DateTimeFormat-formatRange]
+locale: [en-US]
+---*/
+
+{
+ const date = new Date(2019, 7, 10, 1, 2, 3, 234);
+
+ let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+ assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with date options");
+
+ dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+ assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with time options");
+
+ dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+ assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with date-time options");
+
+ dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+ assert.sameValue(dtf.formatRange(date, date), dtf.format(date), "same output with dateStyle/timeStyle");
+}
+{
+ const date1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+ const date2 = new Date(2019, 7, 10, 1, 2, 3, 235);
+
+ let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+ assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with date options");
+
+ dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+ assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with time options");
+
+ dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+ assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with date-time options");
+
+ dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+ assert.sameValue(dtf.formatRange(date1, date2), dtf.format(date1), "same output with dateStyle/timeStyle");
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js
new file mode 100644
index 0000000000..639d941101
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-undefined-throws.js
@@ -0,0 +1,44 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if startDate or endDate is undefined.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a TypeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(); // Not possible to poison this one
+}, "no args");
+
+var poison = { valueOf() { throw new Test262Error(); } };
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(undefined, poison);
+}, "date/undefined");
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(poison, undefined);
+}, "undefined/date");
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(poison);
+}, "only one arg");
+
+assert.throws(TypeError, function() {
+ dtf.formatRange(undefined, undefined);
+}, "undefined/undefined");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js
new file mode 100644
index 0000000000..1ddc9d49c7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/date-x-greater-than-y-not-throws.js
@@ -0,0 +1,35 @@
+// Copyright 2022 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Return a string if date x is greater than y.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 4. Let x be ? ToNumber(startDate).
+ 5. Let y be ? ToNumber(endDate).
+ 6. Return ? FormatDateTimeRange(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var x = new Date();
+var y = new Date();
+x.setDate(y.getDate() + 1);
+
+assert.sameValue("string", typeof dtf.formatRange(x, y));
+assert.sameValue("string", typeof dtf.formatRange(x, x));
+assert.sameValue("string", typeof dtf.formatRange(y, y));
+assert.sameValue("string", typeof dtf.formatRange(y, x));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js
new file mode 100644
index 0000000000..756b9f8f35
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/en-US.js
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 the V8 project authors, Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: Basic tests for the en-US output of formatRange()
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+locale: [en-US]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === "literal" && part.source === "shared").value;
+
+const date1 = new Date("2019-01-03T00:00:00");
+const date2 = new Date("2019-01-05T00:00:00");
+const date3 = new Date("2019-03-04T00:00:00");
+const date4 = new Date("2020-03-04T00:00:00");
+
+let dtf = new Intl.DateTimeFormat("en-US");
+assert.sameValue(dtf.formatRange(date1, date1), "1/3/2019");
+assert.sameValue(dtf.formatRange(date1, date2), `1/3/2019${usDateRangeSeparator}1/5/2019`);
+assert.sameValue(dtf.formatRange(date1, date3), `1/3/2019${usDateRangeSeparator}3/4/2019`);
+assert.sameValue(dtf.formatRange(date1, date4), `1/3/2019${usDateRangeSeparator}3/4/2020`);
+assert.sameValue(dtf.formatRange(date2, date3), `1/5/2019${usDateRangeSeparator}3/4/2019`);
+assert.sameValue(dtf.formatRange(date2, date4), `1/5/2019${usDateRangeSeparator}3/4/2020`);
+assert.sameValue(dtf.formatRange(date3, date4), `3/4/2019${usDateRangeSeparator}3/4/2020`);
+
+dtf = new Intl.DateTimeFormat("en-US", {year: "numeric", month: "short", day: "numeric"});
+assert.sameValue(dtf.formatRange(date1, date1), "Jan 3, 2019");
+assert.sameValue(dtf.formatRange(date1, date2), `Jan 3${usDateRangeSeparator}5, 2019`);
+assert.sameValue(dtf.formatRange(date1, date3), `Jan 3${usDateRangeSeparator}Mar 4, 2019`);
+assert.sameValue(dtf.formatRange(date1, date4), `Jan 3, 2019${usDateRangeSeparator}Mar 4, 2020`);
+assert.sameValue(dtf.formatRange(date2, date3), `Jan 5${usDateRangeSeparator}Mar 4, 2019`);
+assert.sameValue(dtf.formatRange(date2, date4), `Jan 5, 2019${usDateRangeSeparator}Mar 4, 2020`);
+assert.sameValue(dtf.formatRange(date3, date4), `Mar 4, 2019${usDateRangeSeparator}Mar 4, 2020`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js
new file mode 100644
index 0000000000..781ea43d26
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js
@@ -0,0 +1,42 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of fractionalSecondDigits.
+features: [Intl.DateTimeFormat-fractionalSecondDigits, Intl.DateTimeFormat-formatRange]
+locale: [en-US]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === "literal" && part.source === "shared").value;
+
+const d1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+const d2 = new Date(2019, 7, 10, 1, 2, 3, 567);
+const d3 = new Date(2019, 7, 10, 1, 2, 13, 987);
+
+let dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined});
+assert.sameValue(dtf.formatRange(d1, d2), "02:03", "no fractionalSecondDigits");
+assert.sameValue(dtf.formatRange(d1, d3), `02:03${usDateRangeSeparator}02:13`, "no fractionalSecondDigits");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1});
+assert.sameValue(dtf.formatRange(d1, d2), `02:03.2${usDateRangeSeparator}02:03.5`, "1 fractionalSecondDigits round down");
+assert.sameValue(dtf.formatRange(d1, d3), `02:03.2${usDateRangeSeparator}02:13.9`, "1 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2});
+assert.sameValue(dtf.formatRange(d1, d2), `02:03.23${usDateRangeSeparator}02:03.56`, "2 fractionalSecondDigits round down");
+assert.sameValue(dtf.formatRange(d1, d3), `02:03.23${usDateRangeSeparator}02:13.98`, "2 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3});
+assert.sameValue(dtf.formatRange(d1, d2), `02:03.234${usDateRangeSeparator}02:03.567`, "3 fractionalSecondDigits round down");
+assert.sameValue(dtf.formatRange(d1, d3), `02:03.234${usDateRangeSeparator}02:13.987`, "3 fractionalSecondDigits round down");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js
new file mode 100644
index 0000000000..bd1605e0ce
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/length.js
@@ -0,0 +1,16 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatRange.length.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatRange, 'length', {
+ value: 2,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js
new file mode 100644
index 0000000000..f3ded8535e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/name.js
@@ -0,0 +1,16 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatRange.name value and descriptor.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatRange, 'name', {
+ value: 'formatRange',
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js
new file mode 100644
index 0000000000..e022b19320
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/prop-desc.js
@@ -0,0 +1,23 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Property type and descriptor.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+assert.sameValue(
+ typeof Intl.DateTimeFormat.prototype.formatRange,
+ 'function',
+ '`typeof Intl.DateTimeFormat.prototype.formatRange` is `function`'
+);
+
+verifyProperty(Intl.DateTimeFormat.prototype, 'formatRange', {
+ enumerable: false,
+ writable: true,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js
new file mode 100644
index 0000000000..985f46c993
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/shell.js
@@ -0,0 +1,55 @@
+// GENERATED, DO NOT EDIT
+// file: dateConstants.js
+// Copyright (C) 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ Collection of date-centric values
+defines:
+ - date_1899_end
+ - date_1900_start
+ - date_1969_end
+ - date_1970_start
+ - date_1999_end
+ - date_2000_start
+ - date_2099_end
+ - date_2100_start
+ - start_of_time
+ - end_of_time
+---*/
+
+var date_1899_end = -2208988800001;
+var date_1900_start = -2208988800000;
+var date_1969_end = -1;
+var date_1970_start = 0;
+var date_1999_end = 946684799999;
+var date_2000_start = 946684800000;
+var date_2099_end = 4102444799999;
+var date_2100_start = 4102444800000;
+
+var start_of_time = -8.64e15;
+var end_of_time = 8.64e15;
+
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js
new file mode 100644
index 0000000000..a381435baa
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 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: A time zone in resolvedOptions with a large offset still produces the correct string
+locale: [en]
+features: [Temporal, Intl.DateTimeFormat-formatRange]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDayPeriodSpace =
+ new Intl.DateTimeFormat("en-US", { timeStyle: "short" })
+ .formatToParts(0)
+ .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || "";
+const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === "literal" && part.source === "shared").value;
+
+const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" });
+
+const date1 = new Temporal.PlainDate(2021, 8, 4);
+const date2 = new Temporal.PlainDate(2021, 8, 5);
+const dateResult = formatter.formatRange(date1, date2);
+assert.sameValue(dateResult, `8/4/2021${usDateRangeSeparator}8/5/2021`, "plain dates");
+
+const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789);
+const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789);
+const datetimeResult = formatter.formatRange(datetime1, datetime2);
+assert.sameValue(
+ datetimeResult,
+ `8/4/2021, 12:30:45${usDayPeriodSpace}AM${usDateRangeSeparator}11:30:45${usDayPeriodSpace}PM`,
+ "plain datetimes"
+);
+
+const monthDay1 = new Temporal.PlainMonthDay(8, 4, "gregory");
+const monthDay2 = new Temporal.PlainMonthDay(8, 5, "gregory");
+const monthDayResult = formatter.formatRange(monthDay1, monthDay2);
+assert.sameValue(monthDayResult, `8/4${usDateRangeSeparator}8/5`, "plain month-days");
+
+const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789);
+const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789);
+const timeResult = formatter.formatRange(time1, time2);
+assert.sameValue(
+ timeResult,
+ `12:30:45${usDayPeriodSpace}AM${usDateRangeSeparator}11:30:45${usDayPeriodSpace}PM`,
+ "plain times"
+);
+
+const month1 = new Temporal.PlainYearMonth(2021, 8, "gregory");
+const month2 = new Temporal.PlainYearMonth(2021, 9, "gregory");
+const monthResult = formatter.formatRange(month1, month2);
+assert.sameValue(monthResult, `8/2021${usDateRangeSeparator}9/2021`, "plain year-months");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js
new file mode 100644
index 0000000000..3eca117f82
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/temporal-zoneddatetime-not-supported.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.formatRangeToParts
+description: Temporal.ZonedDateTime is not supported directly in formatRangeToParts()
+features: [Temporal]
+---*/
+
+const formatter = new Intl.DateTimeFormat();
+
+// Check that TypeError would not be thrown for a different reason
+const {timeZone, ...options} = formatter.resolvedOptions();
+const datetime1 = new Temporal.ZonedDateTime(0n, timeZone);
+assert.sameValue(typeof datetime1.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds");
+
+const datetime2 = new Temporal.ZonedDateTime(1_000_000_000n, timeZone);
+assert.throws(TypeError, () => formatter.formatRangeToParts(datetime1, datetime2), "formatRangeToParts() does not support Temporal.ZonedDateTime");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js
new file mode 100644
index 0000000000..e669dc4421
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-bad-object.js
@@ -0,0 +1,28 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if this is not a DateTimeFormat object
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const formatRange = Intl.DateTimeFormat.prototype.formatRange;
+
+assert.throws(TypeError, function() {
+ formatRange.call({});
+}, "{}");
+
+assert.throws(TypeError, function() {
+ formatRange.call(new Date());
+}, "new Date()");
+
+assert.throws(TypeError, function() {
+ formatRange.call(Intl.DateTimeFormat);
+}, "Intl.DateTimeFormat");
+
+assert.throws(TypeError, function() {
+ formatRange.call(Intl.DateTimeFormat.prototype);
+}, "Intl.DateTimeFormat.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js
new file mode 100644
index 0000000000..970d3e3d33
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRange/this-is-not-object-throws.js
@@ -0,0 +1,49 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if this is not Object.
+info: |
+ Intl.DateTimeFormat.prototype.formatRange ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+
+features: [Intl.DateTimeFormat-formatRange, Symbol]
+---*/
+
+let formatRange = Intl.DateTimeFormat.prototype.formatRange;
+let d1 = new Date("1997-08-22T00:00");
+let d2 = new Date("1999-06-26T00:00");
+
+assert.throws(TypeError, function() {
+ formatRange.call(undefined, d1, d2);
+}, "undefined");
+
+assert.throws(TypeError, function() {
+ formatRange.call(null, d1, d2);
+}, "null");
+
+assert.throws(TypeError, function() {
+ formatRange.call(42, d1, d2);
+}, "number");
+
+assert.throws(TypeError, function() {
+ formatRange.call("foo", d1, d2);
+}, "string");
+
+assert.throws(TypeError, function() {
+ formatRange.call(false, d1, d2);
+}, "false");
+
+assert.throws(TypeError, function() {
+ formatRange.call(true, d1, d2);
+}, "true");
+
+var s = Symbol('3');
+assert.throws(TypeError, function() {
+ formatRange.call(s, d1, d2);
+}, "symbol");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js
new file mode 100644
index 0000000000..56c7156a63
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-date-string.js
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ The Date constructor is not called to convert the input value.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const dtf = new Intl.DateTimeFormat();
+const dateTimeString = "2017-11-10T14:09:00.000Z";
+const date = new Date(dateTimeString);
+// |dateTimeString| is valid ISO-8601 style date/time string.
+assert.notSameValue(date, NaN);
+
+// ToNumber() will try to parse the string as an integer and yield NaN, rather
+// than attempting to parse it like the Date constructor would.
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(dateTimeString, date);
+});
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, dateTimeString);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js
new file mode 100644
index 0000000000..ea87893bf1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-near-time-boundaries.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatRangeToParts.
+info: |
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+ TimeClip ( time )
+ ...
+ 2. If abs(time) > 8.64 × 10^15, return NaN.
+ ...
+
+includes: [dateConstants.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const dtf = new Intl.DateTimeFormat();
+const date = Date.now();
+
+// Test values near the start of the ECMAScript time range.
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(start_of_time - 1, date);
+});
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, start_of_time - 1);
+});
+assert.sameValue(typeof dtf.formatRangeToParts(start_of_time, date), "object");
+assert.sameValue(typeof dtf.formatRangeToParts(start_of_time + 1, date), "object");
+
+// Test values near the end of the ECMAScript time range.
+assert.sameValue(typeof dtf.formatRangeToParts(date, end_of_time - 1), "object");
+assert.sameValue(typeof dtf.formatRangeToParts(date, end_of_time), "object");
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(end_of_time + 1, date);
+});
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, end_of_time + 1);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js
new file mode 100644
index 0000000000..df97c735a1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-to-integer.js
@@ -0,0 +1,56 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// Copyright (C) 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ TimeClip applies ToInteger on its input value.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+
+ TimeClip ( time )
+ ...
+ 3. Let clippedTime be ! ToInteger(time).
+ 4. If clippedTime is -0, set clippedTime to +0.
+ 5. Return clippedTime.
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+function* zip(a, b) {
+ assert.sameValue(a.length, b.length);
+ for (let i = 0; i < a.length; ++i) {
+ yield [i, a[i], b[i]];
+ }
+}
+
+function compare(actual, expected, message) {
+ for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) {
+ assert.sameValue(actualEntry.type, expectedEntry.type, `${message}: type for entry ${i}`);
+ assert.sameValue(actualEntry.value, expectedEntry.value, `${message}: value for entry ${i}`);
+ assert.sameValue(actualEntry.source, expectedEntry.source, `${message}: source for entry ${i}`);
+ }
+}
+
+// Switch to a time format instead of using DateTimeFormat's default date-only format.
+const dtf = new Intl.DateTimeFormat(undefined, {
+ hour: "numeric", minute: "numeric", second: "numeric"
+});
+const date = Date.now();
+const expected = dtf.formatRangeToParts(0, date);
+
+compare(dtf.formatRangeToParts(-0.9, date), expected, "formatRangeToParts(-0.9)");
+compare(dtf.formatRangeToParts(-0.5, date), expected, "formatRangeToParts(-0.5)");
+compare(dtf.formatRangeToParts(-0.1, date), expected, "formatRangeToParts(-0.1)");
+compare(dtf.formatRangeToParts(-Number.MIN_VALUE, date), expected, "formatRangeToParts(-Number.MIN_VALUE)");
+compare(dtf.formatRangeToParts(-0, date), expected, "formatRangeToParts(-0)");
+compare(dtf.formatRangeToParts(+0, date), expected, "formatRangeToParts(+0)");
+compare(dtf.formatRangeToParts(Number.MIN_VALUE, date), expected, "formatRangeToParts(Number.MIN_VALUE)");
+compare(dtf.formatRangeToParts(0.1, date), expected, "formatRangeToParts(0.1)");
+compare(dtf.formatRangeToParts(0.5, date), expected, "formatRangeToParts(0.5)");
+compare(dtf.formatRangeToParts(0.9, date), expected, "formatRangeToParts(0.9)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js
new file mode 100644
index 0000000000..d38b20da1c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/argument-tonumber-throws.js
@@ -0,0 +1,56 @@
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Return abrupt completions from ToNumber(date)
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+features: [Symbol,Intl.DateTimeFormat-formatRange]
+---*/
+
+const date = Date.now();
+
+const objectValueOf = {
+ valueOf: function() {
+ throw new Test262Error();
+ }
+};
+
+const objectToString = {
+ toString: function() {
+ throw new Test262Error();
+ }
+};
+
+const dtf = new Intl.DateTimeFormat(["pt-BR"]);
+
+assert.throws(Test262Error, function() {
+ dtf.formatRangeToParts(objectValueOf, date);
+}, "valueOf start");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRangeToParts(date, objectValueOf);
+}, "valueOf end");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRangeToParts(objectToString, date);
+}, "toString start");
+
+assert.throws(Test262Error, function() {
+ dtf.formatRangeToParts(date, objectToString);
+}, "toString end");
+
+const s = Symbol('1');
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(s, date);
+}, "symbol start");
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(date, s);
+}, "symbol end");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js
new file mode 100644
index 0000000000..840c232f07
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/builtin.js
@@ -0,0 +1,32 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-ecmascript-standard-built-in-objects
+description: >
+ Tests that the Intl.DateTimeFormat.prototype.formatRangeToParts function meets the
+ requirements for built-in objects defined by the ECMAScript Language
+ Specification.
+includes: [isConstructor.js]
+features: [Reflect.construct,Intl.DateTimeFormat-formatRange]
+---*/
+
+const formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts;
+
+assert.sameValue(Object.prototype.toString.call(formatRangeToParts), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(formatRangeToParts),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(formatRangeToParts), Function.prototype);
+
+assert.sameValue(formatRangeToParts.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(formatRangeToParts), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js
new file mode 100644
index 0000000000..9074bc63f0
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-infinity-throws.js
@@ -0,0 +1,71 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to an Infinity value
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a RangeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 7. If x is greater than y, throw a RangeError exception.
+ 8. Return ? FormatDateTimeRangeToParts(dtf, x, y).
+
+ FormatDateTimeRangeToParts ( dateTimeFormat, x, y )
+
+ 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+ TimeClip ( time )
+ 1. If time is not finite, return NaN.
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var date = new Date();
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(Infinity, date);
+}, "+Infinity/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(-Infinity, date);
+}, "-Infinity/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, Infinity);
+}, "date/+Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, -Infinity);
+}, "date/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(Infinity, Infinity);
+}, "+Infinity/+Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(-Infinity, -Infinity);
+}, "-Infinity/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(Infinity, -Infinity);
+}, "+Infinity/-Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(-Infinity, Infinity);
+}, "-Infinity/+Infinity");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js
new file mode 100644
index 0000000000..a96a0f3d70
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-is-nan-throws.js
@@ -0,0 +1,49 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to Nan
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a RangeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+ 7. If x is greater than y, throw a RangeError exception.
+ 8. Return ? FormatDateTimeRangeToParts(dtf, x, y).
+
+ FormatDateTimeRangeToParts ( dateTimeFormat, x, y )
+
+ 1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var date = new Date();
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(NaN, date);
+}, "NaN/date");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(date, NaN);
+}, "date/NaN");
+
+assert.throws(RangeError, function() {
+ dtf.formatRangeToParts(NaN, NaN);
+}, "NaN/NaN");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js
new file mode 100644
index 0000000000..551a1fddcc
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-same-returns-single-date.js
@@ -0,0 +1,78 @@
+// Copyright 2021 Google Inc. All rights reserved.
+// Copyright 2021 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: >
+ When startDate is equal to endDate, the output should be an Array of objects with the
+ same value for the `type` and `value` fields as in the Array returned by
+ Intl.DateTimeFormat.prototype.formatToParts.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 4. Let x be ? ToNumber(startDate).
+ 5. Let y be ? ToNumber(endDate).
+ 6. Return ? FormatDateTimeRange(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+
+ 13. If dateFieldsPracticallyEqual is true, then
+ a. Let pattern be dateTimeFormat.[[Pattern]].
+ b. Let patternParts be PartitionPattern(pattern).
+ c. Let result be ? FormatDateTimePattern(dateTimeFormat, patternParts, tm1).
+ d. For each r in result do
+ i. Set r.[[Source]] to "shared".
+ e. Return result.
+
+features: [Intl.DateTimeFormat-formatRange]
+locale: [en-US]
+---*/
+
+function* zip(a, b) {
+ assert.sameValue(a.length, b.length);
+ for (let i = 0; i < a.length; ++i) {
+ yield [i, a[i], b[i]];
+ }
+}
+
+function compare(actual, expected) {
+ for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) {
+ assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`);
+ assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`);
+ }
+}
+
+{
+ const date = new Date(2019, 7, 10, 1, 2, 3, 234);
+
+ let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+ compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with date options");
+
+ dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+ compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with time options");
+
+ dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+ compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with date-time options");
+
+ dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+ compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date), "same output with dateStyle/timeStyle");
+}
+{
+ const date1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+ const date2 = new Date(2019, 7, 10, 1, 2, 3, 235);
+
+ let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+ compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with date options");
+
+ dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+ compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with time options");
+
+ dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+ compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with date-time options");
+
+ dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+ compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1), "same output with dateStyle/timeStyle");
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js
new file mode 100644
index 0000000000..5c3e06dd10
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-undefined-throws.js
@@ -0,0 +1,43 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if startDate or endDate are undefined.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+ 3. If dtf does not have an [[InitializedDateTimeFormat]] internal slot, throw a TypeError exception.
+ 4. If startDate is undefined or endDate is undefined, throw a TypeError exception.
+ 5. Let x be ? ToNumber(startDate).
+ 6. Let y be ? ToNumber(endDate).
+
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+var dtf = new Intl.DateTimeFormat();
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(); // Not possible to poison this one
+}, "no args");
+
+var poison = { valueOf() { throw new Test262Error(); } };
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(undefined, poison);
+}, "date/undefined");
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(poison, undefined);
+}, "undefined/date");
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(poison);
+}, "only one arg");
+
+assert.throws(TypeError, function() {
+ dtf.formatRangeToParts(undefined, undefined);
+}, "undefined/undefined");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js
new file mode 100644
index 0000000000..ae527481cd
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/date-x-greater-than-y-not-throws.js
@@ -0,0 +1,33 @@
+// Copyright 2022 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Return an object if date x is greater than y.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 4. Let x be ? ToNumber(startDate).
+ 5. Let y be ? ToNumber(endDate).
+ 6. Return ? FormatDateTimeRangeToParts(dtf, x, y).
+
+ PartitionDateTimeRangePattern ( dateTimeFormat, x, y )
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. Let y be TimeClip(y).
+ 4. If y is NaN, throw a RangeError exception.
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var x = new Date();
+var y = new Date();
+x.setDate(y.getDate() + 1);
+
+assert.sameValue("object", typeof dtf.formatRangeToParts(x, y));
+assert.sameValue("object", typeof dtf.formatRangeToParts(x, x));
+assert.sameValue("object", typeof dtf.formatRangeToParts(y, y));
+assert.sameValue("object", typeof dtf.formatRangeToParts(y, x));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js
new file mode 100644
index 0000000000..559d8eb2fd
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js
@@ -0,0 +1,208 @@
+// Copyright (C) 2019 the V8 project authors, Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimerangepattern
+description: Basic tests for the en-US output of formatRangeToParts()
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 8. Return ? FormatDateTimeRange(dtf, x, y).
+locale: [en-US]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === "literal" && part.source === "shared").value;
+
+function* zip(a, b) {
+ assert.sameValue(a.length, b.length);
+ for (let i = 0; i < a.length; ++i) {
+ yield [i, a[i], b[i]];
+ }
+}
+
+function compare(actual, expected) {
+ for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) {
+ assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`);
+ assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`);
+ assert.sameValue(actualEntry.source, expectedEntry.source, `source for entry ${i}`);
+ }
+}
+
+const date1 = new Date("2019-01-03T00:00:00");
+const date2 = new Date("2019-01-05T00:00:00");
+const date3 = new Date("2019-03-04T00:00:00");
+const date4 = new Date("2020-03-04T00:00:00");
+
+let dtf = new Intl.DateTimeFormat("en-US");
+compare(dtf.formatRangeToParts(date1, date1), [
+ { type: "month", value: "1", source: "shared" },
+ { type: "literal", value: "/", source: "shared" },
+ { type: "day", value: "3", source: "shared" },
+ { type: "literal", value: "/", source: "shared" },
+ { type: "year", value: "2019", source: "shared" },
+]);
+compare(dtf.formatRangeToParts(date1, date2), [
+ { type: "month", value: "1", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "1", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "5", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2019", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date1, date3), [
+ { type: "month", value: "1", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "3", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2019", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date1, date4), [
+ { type: "month", value: "1", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "3", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date2, date3), [
+ { type: "month", value: "1", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "5", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "3", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2019", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date2, date4), [
+ { type: "month", value: "1", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "5", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "3", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date3, date4), [
+ { type: "month", value: "3", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "4", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "3", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+
+dtf = new Intl.DateTimeFormat("en-US", {year: "numeric", month: "short", day: "numeric"});
+compare(dtf.formatRangeToParts(date1, date1), [
+ { type: "month", value: "Jan", source: "shared" },
+ { type: "literal", value: " ", source: "shared" },
+ { type: "day", value: "3", source: "shared" },
+ { type: "literal", value: ", ", source: "shared" },
+ { type: "year", value: "2019", source: "shared" },
+]);
+compare(dtf.formatRangeToParts(date1, date2), [
+ { type: "month", value: "Jan", source: "shared" },
+ { type: "literal", value: " ", source: "shared" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "day", value: "5", source: "endRange" },
+ { type: "literal", value: ", ", source: "shared" },
+ { type: "year", value: "2019", source: "shared" },
+]);
+compare(dtf.formatRangeToParts(date1, date3), [
+ { type: "month", value: "Jan", source: "startRange" },
+ { type: "literal", value: " ", source: "startRange" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "Mar", source: "endRange" },
+ { type: "literal", value: " ", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: ", ", source: "shared" },
+ { type: "year", value: "2019", source: "shared" },
+]);
+compare(dtf.formatRangeToParts(date1, date4), [
+ { type: "month", value: "Jan", source: "startRange" },
+ { type: "literal", value: " ", source: "startRange" },
+ { type: "day", value: "3", source: "startRange" },
+ { type: "literal", value: ", ", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "Mar", source: "endRange" },
+ { type: "literal", value: " ", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: ", ", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date2, date3), [
+ { type: "month", value: "Jan", source: "startRange" },
+ { type: "literal", value: " ", source: "startRange" },
+ { type: "day", value: "5", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "Mar", source: "endRange" },
+ { type: "literal", value: " ", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: ", ", source: "shared" },
+ { type: "year", value: "2019", source: "shared" },
+]);
+compare(dtf.formatRangeToParts(date2, date4), [
+ { type: "month", value: "Jan", source: "startRange" },
+ { type: "literal", value: " ", source: "startRange" },
+ { type: "day", value: "5", source: "startRange" },
+ { type: "literal", value: ", ", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "Mar", source: "endRange" },
+ { type: "literal", value: " ", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: ", ", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+compare(dtf.formatRangeToParts(date3, date4), [
+ { type: "month", value: "Mar", source: "startRange" },
+ { type: "literal", value: " ", source: "startRange" },
+ { type: "day", value: "4", source: "startRange" },
+ { type: "literal", value: ", ", source: "startRange" },
+ { type: "year", value: "2019", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "Mar", source: "endRange" },
+ { type: "literal", value: " ", source: "endRange" },
+ { type: "day", value: "4", source: "endRange" },
+ { type: "literal", value: ", ", source: "endRange" },
+ { type: "year", value: "2020", source: "endRange" },
+]);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js
new file mode 100644
index 0000000000..0840f80d25
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js
@@ -0,0 +1,160 @@
+// Copyright 2020 Google Inc, Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of fractionalSecondDigits.
+features: [Intl.DateTimeFormat-fractionalSecondDigits, Intl.DateTimeFormat-formatRange]
+locale: [en-US]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDateRangeSeparator = new Intl.DateTimeFormat("en-US", { dateStyle: "short" })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === "literal" && part.source === "shared").value;
+
+function* zip(a, b) {
+ assert.sameValue(a.length, b.length);
+ for (let i = 0; i < a.length; ++i) {
+ yield [i, a[i], b[i]];
+ }
+}
+
+function compare(actual, expected) {
+ for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) {
+ assert.sameValue(actualEntry.type, expectedEntry.type, `type for entry ${i}`);
+ assert.sameValue(actualEntry.value, expectedEntry.value, `value for entry ${i}`);
+ assert.sameValue(actualEntry.source, expectedEntry.source, `source for entry ${i}`);
+ }
+}
+
+const d1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+const d2 = new Date(2019, 7, 10, 1, 2, 3, 567);
+const d3 = new Date(2019, 7, 10, 1, 2, 13, 987);
+
+assert.throws(RangeError, () => {
+ new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 0});
+ }, "fractionalSecondDigits 0 should throw RangeError for out of range");
+
+assert.throws(RangeError, () => {
+ new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 4});
+ }, "fractionalSecondDigits 4 should throw RangeError for out of range");
+
+let dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined});
+
+compare(dtf.formatRangeToParts(d1, d2), [
+ { type: "minute", value: "02", source: "shared" },
+ { type: "literal", value: ":", source: "shared" },
+ { type: "second", value: "03", source: "shared" }
+]);
+
+compare(dtf.formatRangeToParts(d1, d3), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "13", source: "endRange" }
+]);
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1});
+
+compare(dtf.formatRangeToParts(d1, d2), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "2", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "03", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "5", source: "endRange" }
+]);
+
+compare(dtf.formatRangeToParts(d1, d3), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "2", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "13", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "9", source: "endRange" }
+]);
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2});
+
+compare(dtf.formatRangeToParts(d1, d2), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "23", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "03", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "56", source: "endRange" }
+]);
+
+compare(dtf.formatRangeToParts(d1, d3), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "23", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "13", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "98", source: "endRange" }
+]);
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3});
+
+compare(dtf.formatRangeToParts(d1, d2), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "234", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "03", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "567", source: "endRange" }
+]);
+
+compare(dtf.formatRangeToParts(d1, d3), [
+ { type: "minute", value: "02", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "03", source: "startRange" },
+ { type: "literal", value: ".", source: "startRange" },
+ { type: "fractionalSecond", value: "234", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "minute", value: "02", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "13", source: "endRange" },
+ { type: "literal", value: ".", source: "endRange" },
+ { type: "fractionalSecond", value: "987", source: "endRange" }
+]);
+
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js
new file mode 100644
index 0000000000..0a41d864dc
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/length.js
@@ -0,0 +1,16 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatRangeToParts.length.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatRangeToParts, 'length', {
+ value: 2,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js
new file mode 100644
index 0000000000..0d857a6e83
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/name.js
@@ -0,0 +1,16 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatRangeToParts.name value and descriptor.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatRangeToParts, 'name', {
+ value: 'formatRangeToParts',
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js
new file mode 100644
index 0000000000..f36730d122
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/pattern-on-calendar.js
@@ -0,0 +1,40 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks the DateTimeFormat choose different patterns based
+ on calendar.
+includes: [testIntl.js]
+features: [Intl.DateTimeFormat-formatRange]
+locale: [en]
+---*/
+
+let calendars = allCalendars();
+let date1 = new Date(2017, 3, 12);
+let date2 = new Date();
+
+// serialize parts to a string by considering only the type and literal.
+function serializeTypesAndLiteral(parts) {
+ let types = parts.map(part => {
+ if (part.type == "literal") {
+ return `${part.type}(${part.value})`;
+ }
+ return part.type;
+ });
+ return types.join(":");
+}
+
+let df = new Intl.DateTimeFormat("en");
+let base = serializeTypesAndLiteral(df.formatRangeToParts(date1, date2));
+
+const foundDifferentPattern = calendars.some(function(calendar) {
+ let cdf = new Intl.DateTimeFormat("en-u-ca-" + calendar);
+ return base != serializeTypesAndLiteral(cdf.formatRangeToParts(date1, date2));
+});
+
+// Expect at least some calendar use different pattern.
+assert.sameValue(foundDifferentPattern, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js
new file mode 100644
index 0000000000..edd871b1ad
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/prop-desc.js
@@ -0,0 +1,23 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// Copyright 2019 Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Property type and descriptor.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+assert.sameValue(
+ typeof Intl.DateTimeFormat.prototype.formatRangeToParts,
+ 'function',
+ '`typeof Intl.DateTimeFormat.prototype.formatRangeToParts` is `function`'
+);
+
+verifyProperty(Intl.DateTimeFormat.prototype, 'formatRangeToParts', {
+ enumerable: false,
+ writable: true,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js
new file mode 100644
index 0000000000..99241dca55
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/shell.js
@@ -0,0 +1,384 @@
+// GENERATED, DO NOT EDIT
+// file: dateConstants.js
+// Copyright (C) 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ Collection of date-centric values
+defines:
+ - date_1899_end
+ - date_1900_start
+ - date_1969_end
+ - date_1970_start
+ - date_1999_end
+ - date_2000_start
+ - date_2099_end
+ - date_2100_start
+ - start_of_time
+ - end_of_time
+---*/
+
+var date_1899_end = -2208988800001;
+var date_1900_start = -2208988800000;
+var date_1969_end = -1;
+var date_1970_start = 0;
+var date_1999_end = 946684799999;
+var date_2000_start = 946684800000;
+var date_2099_end = 4102444799999;
+var date_2100_start = 4102444800000;
+
+var start_of_time = -8.64e15;
+var end_of_time = 8.64e15;
+
+// file: deepEqual.js
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: >
+ Compare two values structurally
+defines: [assert.deepEqual]
+---*/
+
+assert.deepEqual = function(actual, expected, message) {
+ var format = assert.deepEqual.format;
+ assert(
+ assert.deepEqual._compare(actual, expected),
+ `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}`
+ );
+};
+
+assert.deepEqual.format = function(value, seen) {
+ switch (typeof value) {
+ case 'string':
+ return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`;
+ case 'number':
+ case 'boolean':
+ case 'symbol':
+ case 'bigint':
+ return value.toString();
+ case 'undefined':
+ return 'undefined';
+ case 'function':
+ return `[Function${value.name ? `: ${value.name}` : ''}]`;
+ case 'object':
+ if (value === null) return 'null';
+ if (value instanceof Date) return `Date "${value.toISOString()}"`;
+ if (value instanceof RegExp) return value.toString();
+ if (!seen) {
+ seen = {
+ counter: 0,
+ map: new Map()
+ };
+ }
+
+ let usage = seen.map.get(value);
+ if (usage) {
+ usage.used = true;
+ return `[Ref: #${usage.id}]`;
+ }
+
+ usage = { id: ++seen.counter, used: false };
+ seen.map.set(value, usage);
+
+ if (typeof Set !== "undefined" && value instanceof Set) {
+ return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (typeof Map !== "undefined" && value instanceof Map) {
+ return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (Array.isArray ? Array.isArray(value) : value instanceof Array) {
+ return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object';
+ if (tag === 'Object' && Object.getPrototypeOf(value) === null) {
+ tag = '[Object: null prototype]';
+ }
+ return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`;
+ default:
+ return typeof value;
+ }
+};
+
+assert.deepEqual._compare = (function () {
+ var EQUAL = 1;
+ var NOT_EQUAL = -1;
+ var UNKNOWN = 0;
+
+ function deepEqual(a, b) {
+ return compareEquality(a, b) === EQUAL;
+ }
+
+ function compareEquality(a, b, cache) {
+ return compareIf(a, b, isOptional, compareOptionality)
+ || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality)
+ || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache)
+ || NOT_EQUAL;
+ }
+
+ function compareIf(a, b, test, compare, cache) {
+ return !test(a)
+ ? !test(b) ? UNKNOWN : NOT_EQUAL
+ : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache);
+ }
+
+ function tryCompareStrictEquality(a, b) {
+ return a === b ? EQUAL : UNKNOWN;
+ }
+
+ function tryCompareTypeOfEquality(a, b) {
+ return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function tryCompareToStringTagEquality(a, b) {
+ var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
+ var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined;
+ return aTag !== bTag ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function isOptional(value) {
+ return value === undefined
+ || value === null;
+ }
+
+ function compareOptionality(a, b) {
+ return tryCompareStrictEquality(a, b)
+ || NOT_EQUAL;
+ }
+
+ function isPrimitiveEquatable(value) {
+ switch (typeof value) {
+ case 'string':
+ case 'number':
+ case 'bigint':
+ case 'boolean':
+ case 'symbol':
+ return true;
+ default:
+ return isBoxed(value);
+ }
+ }
+
+ function comparePrimitiveEquality(a, b) {
+ if (isBoxed(a)) a = a.valueOf();
+ if (isBoxed(b)) b = b.valueOf();
+ return tryCompareStrictEquality(a, b)
+ || tryCompareTypeOfEquality(a, b)
+ || compareIf(a, b, isNaNEquatable, compareNaNEquality)
+ || NOT_EQUAL;
+ }
+
+ function isNaNEquatable(value) {
+ return typeof value === 'number';
+ }
+
+ function compareNaNEquality(a, b) {
+ return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL;
+ }
+
+ function isObjectEquatable(value) {
+ return typeof value === 'object';
+ }
+
+ function compareObjectEquality(a, b, cache) {
+ if (!cache) cache = new Map();
+ return getCache(cache, a, b)
+ || setCache(cache, a, b, EQUAL) // consider equal for now
+ || cacheComparison(a, b, tryCompareStrictEquality, cache)
+ || cacheComparison(a, b, tryCompareToStringTagEquality, cache)
+ || compareIf(a, b, isValueOfEquatable, compareValueOfEquality)
+ || compareIf(a, b, isToStringEquatable, compareToStringEquality)
+ || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
+ || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache)
+ || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || cacheComparison(a, b, fail, cache);
+ }
+
+ function isBoxed(value) {
+ return value instanceof String
+ || value instanceof Number
+ || value instanceof Boolean
+ || typeof Symbol === 'function' && value instanceof Symbol
+ || typeof BigInt === 'function' && value instanceof BigInt;
+ }
+
+ function isValueOfEquatable(value) {
+ return value instanceof Date;
+ }
+
+ function compareValueOfEquality(a, b) {
+ return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isToStringEquatable(value) {
+ return value instanceof RegExp;
+ }
+
+ function compareToStringEquality(a, b) {
+ return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isArrayLikeEquatable(value) {
+ return (Array.isArray ? Array.isArray(value) : value instanceof Array)
+ || (typeof Uint8Array === 'function' && value instanceof Uint8Array)
+ || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
+ || (typeof Uint16Array === 'function' && value instanceof Uint16Array)
+ || (typeof Uint32Array === 'function' && value instanceof Uint32Array)
+ || (typeof Int8Array === 'function' && value instanceof Int8Array)
+ || (typeof Int16Array === 'function' && value instanceof Int16Array)
+ || (typeof Int32Array === 'function' && value instanceof Int32Array)
+ || (typeof Float32Array === 'function' && value instanceof Float32Array)
+ || (typeof Float64Array === 'function' && value instanceof Float64Array)
+ || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array)
+ || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array);
+ }
+
+ function compareArrayLikeEquality(a, b, cache) {
+ if (a.length !== b.length) return NOT_EQUAL;
+ for (var i = 0; i < a.length; i++) {
+ if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+ return EQUAL;
+ }
+
+ function isStructurallyEquatable(value) {
+ return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference
+ || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference
+ || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
+ || typeof Map === 'function' && value instanceof Map // comparable via @@iterator
+ || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator
+ }
+
+ function compareStructuralEquality(a, b, cache) {
+ var aKeys = [];
+ for (var key in a) aKeys.push(key);
+
+ var bKeys = [];
+ for (var key in b) bKeys.push(key);
+
+ if (aKeys.length !== bKeys.length) {
+ return NOT_EQUAL;
+ }
+
+ aKeys.sort();
+ bKeys.sort();
+
+ for (var i = 0; i < aKeys.length; i++) {
+ var aKey = aKeys[i];
+ var bKey = bKeys[i];
+ if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+
+ return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || EQUAL;
+ }
+
+ function isIterableEquatable(value) {
+ return typeof Symbol === 'function'
+ && typeof value[Symbol.iterator] === 'function';
+ }
+
+ function compareIteratorEquality(a, b, cache) {
+ if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
+ typeof Set === 'function' && a instanceof Set && b instanceof Set) {
+ if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
+ }
+
+ var ar, br;
+ while (true) {
+ ar = a.next();
+ br = b.next();
+ if (ar.done) {
+ if (br.done) return EQUAL;
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ if (br.done) {
+ if (a.return) a.return();
+ return NOT_EQUAL;
+ }
+ if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
+ if (a.return) a.return();
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ }
+ }
+
+ function compareIterableEquality(a, b, cache) {
+ return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
+ }
+
+ function cacheComparison(a, b, compare, cache) {
+ var result = compare(a, b, cache);
+ if (cache && (result === EQUAL || result === NOT_EQUAL)) {
+ setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
+ }
+ return result;
+ }
+
+ function fail() {
+ return NOT_EQUAL;
+ }
+
+ function setCache(cache, left, right, result) {
+ var otherCache;
+
+ otherCache = cache.get(left);
+ if (!otherCache) cache.set(left, otherCache = new Map());
+ otherCache.set(right, result);
+
+ otherCache = cache.get(right);
+ if (!otherCache) cache.set(right, otherCache = new Map());
+ otherCache.set(left, result);
+ }
+
+ function getCache(cache, left, right) {
+ var otherCache;
+ var result;
+
+ otherCache = cache.get(left);
+ result = otherCache && otherCache.get(right);
+ if (result) return result;
+
+ otherCache = cache.get(right);
+ result = otherCache && otherCache.get(left);
+ if (result) return result;
+
+ return UNKNOWN;
+ }
+
+ return deepEqual;
+})();
+
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js
new file mode 100644
index 0000000000..ec34d8e9a9
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js
@@ -0,0 +1,117 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 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: A time zone in resolvedOptions with a large offset still produces the correct string
+locale: [en]
+includes: [deepEqual.js]
+features: [Temporal, Intl.DateTimeFormat-formatRange]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDayPeriodSpace =
+ new Intl.DateTimeFormat('en-US', { timeStyle: 'short' })
+ .formatToParts(0)
+ .find((part, i, parts) => part.type === 'literal' && parts[i + 1].type === 'dayPeriod')?.value || '';
+const usDateRangeSeparator = new Intl.DateTimeFormat('en-US', { dateStyle: 'short' })
+ .formatRangeToParts(1 * 86400 * 1000, 366 * 86400 * 1000)
+ .find((part) => part.type === 'literal' && part.source === 'shared').value;
+
+const formatter = new Intl.DateTimeFormat('en-US', { timeZone: 'Pacific/Apia' });
+
+const date1 = new Temporal.PlainDate(2021, 8, 4);
+const date2 = new Temporal.PlainDate(2021, 8, 5);
+const dateResult = formatter.formatRangeToParts(date1, date2);
+assert.deepEqual(dateResult, [
+ { type: "month", value: "8", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "4", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2021", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "8", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "5", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2021", source: "endRange" },
+], "plain dates");
+
+const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789);
+const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789);
+const datetimeResult = formatter.formatRangeToParts(datetime1, datetime2);
+assert.deepEqual(datetimeResult, [
+ { type: "month", value: "8", source: "shared" },
+ { type: "literal", value: "/", source: "shared" },
+ { type: "day", value: "4", source: "shared" },
+ { type: "literal", value: "/", source: "shared" },
+ { type: "year", value: "2021", source: "shared" },
+ { type: "literal", value: ", ", source: "shared" },
+ { type: "hour", value: "12", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "minute", value: "30", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "45", source: "startRange" },
+ { type: "literal", value: usDayPeriodSpace, source: "startRange" },
+ { type: "dayPeriod", value: "AM", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "hour", value: "11", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "minute", value: "30", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "45", source: "endRange" },
+ { type: "literal", value: usDayPeriodSpace, source: "endRange" },
+ { type: "dayPeriod", value: "PM", source: "endRange" },
+], "plain datetimes");
+
+const monthDay1 = new Temporal.PlainMonthDay(8, 4, "gregory");
+const monthDay2 = new Temporal.PlainMonthDay(8, 5, "gregory");
+const monthDayResult = formatter.formatRangeToParts(monthDay1, monthDay2);
+assert.deepEqual(monthDayResult, [
+ { type: "month", value: "8", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "day", value: "4", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "8", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "day", value: "5", source: "endRange" },
+], "plain month-days");
+
+const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789);
+const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789);
+const timeResult = formatter.formatRangeToParts(time1, time2);
+assert.deepEqual(timeResult, [
+ { type: "hour", value: "12", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "minute", value: "30", source: "startRange" },
+ { type: "literal", value: ":", source: "startRange" },
+ { type: "second", value: "45", source: "startRange" },
+ { type: "literal", value: usDayPeriodSpace, source: "startRange" },
+ { type: "dayPeriod", value: "AM", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "hour", value: "11", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "minute", value: "30", source: "endRange" },
+ { type: "literal", value: ":", source: "endRange" },
+ { type: "second", value: "45", source: "endRange" },
+ { type: "literal", value: usDayPeriodSpace, source: "endRange" },
+ { type: "dayPeriod", value: "PM", source: "endRange" },
+], "plain times");
+
+const month1 = new Temporal.PlainYearMonth(2021, 8, "gregory");
+const month2 = new Temporal.PlainYearMonth(2021, 9, "gregory");
+const monthResult = formatter.formatRangeToParts(month1, month2);
+assert.deepEqual(monthResult, [
+ { type: "month", value: "8", source: "startRange" },
+ { type: "literal", value: "/", source: "startRange" },
+ { type: "year", value: "2021", source: "startRange" },
+ { type: "literal", value: usDateRangeSeparator, source: "shared" },
+ { type: "month", value: "9", source: "endRange" },
+ { type: "literal", value: "/", source: "endRange" },
+ { type: "year", value: "2021", source: "endRange" },
+], "plain year-months");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js
new file mode 100644
index 0000000000..edc0263d10
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-zoneddatetime-not-supported.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.formatRange
+description: Temporal.ZonedDateTime is not supported directly in formatRange()
+features: [Temporal]
+---*/
+
+const formatter = new Intl.DateTimeFormat();
+
+// Check that TypeError would not be thrown for a different reason
+const {timeZone, ...options} = formatter.resolvedOptions();
+const datetime1 = new Temporal.ZonedDateTime(0n, timeZone);
+assert.sameValue(typeof datetime1.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds");
+
+const datetime2 = new Temporal.ZonedDateTime(1_000_000_000n, timeZone);
+assert.throws(TypeError, () => formatter.formatRange(datetime1, datetime2), "formatRange() does not support Temporal.ZonedDateTime");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js
new file mode 100644
index 0000000000..21f29b4541
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-bad-object.js
@@ -0,0 +1,28 @@
+// Copyright 2019 Igalia, S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if this is not a DateTimeFormat object
+features: [Intl.DateTimeFormat-formatRange]
+---*/
+
+const formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts;
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call({});
+}, "{}");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(new Date());
+}, "new Date()");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(Intl.DateTimeFormat);
+}, "Intl.DateTimeFormat");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(Intl.DateTimeFormat.prototype);
+}, "Intl.DateTimeFormat.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js
new file mode 100644
index 0000000000..7fe4599531
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatRangeToParts/this-is-not-object-throws.js
@@ -0,0 +1,49 @@
+// Copyright 2019 Google, Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if this is not Object.
+info: |
+ Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate , endDate )
+
+ 1. Let dtf be this value.
+ 2. If Type(dtf) is not Object, throw a TypeError exception.
+
+features: [Intl.DateTimeFormat-formatRange, Symbol]
+---*/
+
+let formatRangeToParts = Intl.DateTimeFormat.prototype.formatRangeToParts;
+let d1 = new Date("1997-08-22T00:00");
+let d2 = new Date("1999-06-26T00:00");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(undefined, d1, d2);
+}, "undefined");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(null, d1, d2);
+}, "null");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(42, d1, d2);
+}, "number");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call("foo", d1, d2);
+}, "string");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(false, d1, d2);
+}, "false");
+
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(true, d1, d2);
+}, "true");
+
+var s = Symbol('3');
+assert.throws(TypeError, function() {
+ formatRangeToParts.call(s, d1, d2);
+}, "symbol");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js
new file mode 100644
index 0000000000..9c63ee3e52
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ The Date constructor is not called to convert the input value.
+info: >
+ 12.4.4 Intl.DateTimeFormat.prototype.formatToParts ( date )
+
+ ...
+ 4. If date is undefined, then
+ ...
+ 5. Else,
+ a. Let x be ? ToNumber(date).
+ 5. Return ? FormatDateTimeToParts(dtf, x).
+
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. ...
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+var dateTimeString = "2017-11-10T14:09:00.000Z";
+
+// |dateTimeString| is valid ISO-8601 style date/time string.
+assert.notSameValue(new Date(dateTimeString), NaN);
+
+// Ensure string input values are not converted to time values by calling the
+// Date constructor.
+assert.throws(RangeError, function() {
+ dtf.formatToParts(dateTimeString);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js
new file mode 100644
index 0000000000..071c07ed45
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-infinity-throws.js
@@ -0,0 +1,35 @@
+// Copyright 2016 Leonardo Balter. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to an Infinity value
+info: |
+ Intl.DateTimeFormat.prototype.formatToParts ([ date ])
+
+ 4. If _date_ is not provided or is *undefined*, then
+ a. Let _x_ be *%Date_now%*().
+ 5. Else,
+ a. Let _x_ be ? ToNumber(_date_).
+ 6. Return ? FormatDateTimeToParts(_dtf_, _x_).
+
+ FormatDateTimeToParts(dateTimeFormat, x)
+
+ 1. Let _parts_ be ? PartitionDateTimePattern(_dateTimeFormat_, _x_).
+
+ PartitionDateTimePattern (dateTimeFormat, x)
+
+ 1. If _x_ is not a finite Number, throw a *RangeError* exception.
+---*/
+
+var dtf = new Intl.DateTimeFormat(["pt-BR"]);
+
+assert.throws(RangeError, function() {
+ dtf.formatToParts(Infinity);
+}, "+Infinity");
+
+assert.throws(RangeError, function() {
+ dtf.formatToParts(-Infinity);
+}, "-Infinity");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js
new file mode 100644
index 0000000000..ab062734e0
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/date-is-nan-throws.js
@@ -0,0 +1,35 @@
+// Copyright 2016 Leonardo Balter. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a RangeError if date arg is cast to NaN
+info: |
+ Intl.DateTimeFormat.prototype.formatToParts ([ date ])
+
+ 4. If _date_ is not provided or is *undefined*, then
+ a. Let _x_ be *%Date_now%*().
+ 5. Else,
+ a. Let _x_ be ? ToNumber(_date_).
+ 6. Return ? FormatDateTimeToParts(_dtf_, _x_).
+
+ FormatDateTimeToParts(dateTimeFormat, x)
+
+ 1. Let _parts_ be ? PartitionDateTimePattern(_dateTimeFormat_, _x_).
+
+ PartitionDateTimePattern (dateTimeFormat, x)
+
+ 1. If _x_ is not a finite Number, throw a *RangeError* exception.
+---*/
+
+var dtf = new Intl.DateTimeFormat(["pt-BR"]);
+
+assert.throws(RangeError, function() {
+ dtf.formatToParts(NaN);
+});
+
+assert.throws(RangeError, function() {
+ dtf.formatToParts("lol");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js
new file mode 100644
index 0000000000..ef2e24f43d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js
@@ -0,0 +1,108 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of dayPeriod, long format.
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const long = new Intl.DateTimeFormat('en', { dayPeriod: 'long' });
+
+function assertParts(parts, expected, message) {
+ assert.sameValue(parts.length, 1, `length should be 1, ${message}`);
+ assert.sameValue(parts[0].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`);
+}
+
+assertParts(long.formatToParts(d0000), 'at night', '00:00, long format');
+assertParts(long.formatToParts(d0100), 'at night', '01:00, long format');
+assertParts(long.formatToParts(d0200), 'at night', '02:00, long format');
+assertParts(long.formatToParts(d0300), 'at night', '03:00, long format');
+assertParts(long.formatToParts(d0400), 'at night', '04:00, long format');
+assertParts(long.formatToParts(d0500), 'at night', '05:00, long format');
+assertParts(long.formatToParts(d0600), 'in the morning', '06:00, long format');
+assertParts(long.formatToParts(d0700), 'in the morning', '07:00, long format');
+assertParts(long.formatToParts(d0800), 'in the morning', '08:00, long format');
+assertParts(long.formatToParts(d0900), 'in the morning', '09:00, long format');
+assertParts(long.formatToParts(d1000), 'in the morning', '10:00, long format');
+assertParts(long.formatToParts(d1100), 'in the morning', '11:00, long format');
+assertParts(long.formatToParts(d1200), 'noon', '12:00, long format');
+assertParts(long.formatToParts(d1300), 'in the afternoon', '13:00, long format');
+assertParts(long.formatToParts(d1400), 'in the afternoon', '14:00, long format');
+assertParts(long.formatToParts(d1500), 'in the afternoon', '15:00, long format');
+assertParts(long.formatToParts(d1600), 'in the afternoon', '16:00, long format');
+assertParts(long.formatToParts(d1700), 'in the afternoon', '17:00, long format');
+assertParts(long.formatToParts(d1800), 'in the evening', '18:00, long format');
+assertParts(long.formatToParts(d1900), 'in the evening', '19:00, long format');
+assertParts(long.formatToParts(d2000), 'in the evening', '20:00, long format');
+assertParts(long.formatToParts(d2100), 'at night', '21:00, long format');
+assertParts(long.formatToParts(d2200), 'at night', '22:00, long format');
+assertParts(long.formatToParts(d2300), 'at night', '23:00, long format');
+
+const longNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'long',
+ hour: 'numeric'
+});
+
+function assertPartsNumeric(parts, hour, expected, message) {
+ assert.sameValue(parts.length, 3, `length should be 3, ${message}`);
+ assert.sameValue(parts[0].value, hour, `hour part value. ${message}`);
+ assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`);
+ assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`);
+ assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`);
+ assert.sameValue(parts[2].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`);
+}
+
+assertPartsNumeric(longNumeric.formatToParts(d0000), '12', 'at night', '00:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0100), '1', 'at night', '01:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0200), '2', 'at night', '02:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0300), '3', 'at night', '03:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0400), '4', 'at night', '04:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0500), '5', 'at night', '05:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1200), '12', 'noon', '12:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d2100), '9', 'at night', '21:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d2200), '10', 'at night', '22:00, long-numeric');
+assertPartsNumeric(longNumeric.formatToParts(d2300), '11', 'at night', '23:00, long-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js
new file mode 100644
index 0000000000..7bcebc2537
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js
@@ -0,0 +1,108 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of dayPeriod, narrow format.
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const narrow = new Intl.DateTimeFormat('en', { dayPeriod: 'narrow' });
+
+function assertParts(parts, expected, message) {
+ assert.sameValue(parts.length, 1, `length should be 1, ${message}`);
+ assert.sameValue(parts[0].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`);
+}
+
+assertParts(narrow.formatToParts(d0000), 'at night', '00:00, narrow format');
+assertParts(narrow.formatToParts(d0100), 'at night', '01:00, narrow format');
+assertParts(narrow.formatToParts(d0200), 'at night', '02:00, narrow format');
+assertParts(narrow.formatToParts(d0300), 'at night', '03:00, narrow format');
+assertParts(narrow.formatToParts(d0400), 'at night', '04:00, narrow format');
+assertParts(narrow.formatToParts(d0500), 'at night', '05:00, narrow format');
+assertParts(narrow.formatToParts(d0600), 'in the morning', '06:00, narrow format');
+assertParts(narrow.formatToParts(d0700), 'in the morning', '07:00, narrow format');
+assertParts(narrow.formatToParts(d0800), 'in the morning', '08:00, narrow format');
+assertParts(narrow.formatToParts(d0900), 'in the morning', '09:00, narrow format');
+assertParts(narrow.formatToParts(d1000), 'in the morning', '10:00, narrow format');
+assertParts(narrow.formatToParts(d1100), 'in the morning', '11:00, narrow format');
+assertParts(narrow.formatToParts(d1200), 'n', '12:00, narrow format');
+assertParts(narrow.formatToParts(d1300), 'in the afternoon', '13:00, narrow format');
+assertParts(narrow.formatToParts(d1400), 'in the afternoon', '14:00, narrow format');
+assertParts(narrow.formatToParts(d1500), 'in the afternoon', '15:00, narrow format');
+assertParts(narrow.formatToParts(d1600), 'in the afternoon', '16:00, narrow format');
+assertParts(narrow.formatToParts(d1700), 'in the afternoon', '17:00, narrow format');
+assertParts(narrow.formatToParts(d1800), 'in the evening', '18:00, narrow format');
+assertParts(narrow.formatToParts(d1900), 'in the evening', '19:00, narrow format');
+assertParts(narrow.formatToParts(d2000), 'in the evening', '20:00, narrow format');
+assertParts(narrow.formatToParts(d2100), 'at night', '21:00, narrow format');
+assertParts(narrow.formatToParts(d2200), 'at night', '22:00, narrow format');
+assertParts(narrow.formatToParts(d2300), 'at night', '23:00, narrow format');
+
+const narrowNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'narrow',
+ hour: 'numeric'
+});
+
+function assertPartsNumeric(parts, hour, expected, message) {
+ assert.sameValue(parts.length, 3, `length should be 3, ${message}`);
+ assert.sameValue(parts[0].value, hour, `hour part value. ${message}`);
+ assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`);
+ assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`);
+ assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`);
+ assert.sameValue(parts[2].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`);
+}
+
+assertPartsNumeric(narrowNumeric.formatToParts(d0000), '12', 'at night', '00:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0100), '1', 'at night', '01:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0200), '2', 'at night', '02:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0300), '3', 'at night', '03:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0400), '4', 'at night', '04:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0500), '5', 'at night', '05:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1200), '12', 'n', '12:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d2100), '9', 'at night', '21:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d2200), '10', 'at night', '22:00, narrow-numeric');
+assertPartsNumeric(narrowNumeric.formatToParts(d2300), '11', 'at night', '23:00, narrow-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js
new file mode 100644
index 0000000000..66ec863b3d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js
@@ -0,0 +1,108 @@
+// Copyright 2019 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of dayPeriod, short format.
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const d0000 = new Date(2017, 11, 12, 0, 0, 0, 0);
+const d0100 = new Date(2017, 11, 12, 1, 0, 0, 0);
+const d0200 = new Date(2017, 11, 12, 2, 0, 0, 0);
+const d0300 = new Date(2017, 11, 12, 3, 0, 0, 0);
+const d0400 = new Date(2017, 11, 12, 4, 0, 0, 0);
+const d0500 = new Date(2017, 11, 12, 5, 0, 0, 0);
+const d0600 = new Date(2017, 11, 12, 6, 0, 0, 0);
+const d0700 = new Date(2017, 11, 12, 7, 0, 0, 0);
+const d0800 = new Date(2017, 11, 12, 8, 0, 0, 0);
+const d0900 = new Date(2017, 11, 12, 9, 0, 0, 0);
+const d1000 = new Date(2017, 11, 12, 10, 0, 0, 0);
+const d1100 = new Date(2017, 11, 12, 11, 0, 0, 0);
+const d1200 = new Date(2017, 11, 12, 12, 0, 0, 0);
+const d1300 = new Date(2017, 11, 12, 13, 0, 0, 0);
+const d1400 = new Date(2017, 11, 12, 14, 0, 0, 0);
+const d1500 = new Date(2017, 11, 12, 15, 0, 0, 0);
+const d1600 = new Date(2017, 11, 12, 16, 0, 0, 0);
+const d1700 = new Date(2017, 11, 12, 17, 0, 0, 0);
+const d1800 = new Date(2017, 11, 12, 18, 0, 0, 0);
+const d1900 = new Date(2017, 11, 12, 19, 0, 0, 0);
+const d2000 = new Date(2017, 11, 12, 20, 0, 0, 0);
+const d2100 = new Date(2017, 11, 12, 21, 0, 0, 0);
+const d2200 = new Date(2017, 11, 12, 22, 0, 0, 0);
+const d2300 = new Date(2017, 11, 12, 23, 0, 0, 0);
+
+const short = new Intl.DateTimeFormat('en', { dayPeriod: 'short' });
+
+function assertParts(parts, expected, message) {
+ assert.sameValue(parts.length, 1, `length should be 1, ${message}`);
+ assert.sameValue(parts[0].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[0].type, 'dayPeriod', `part type is dayPeriod. ${message}`);
+}
+
+assertParts(short.formatToParts(d0000), 'at night', '00:00, short format');
+assertParts(short.formatToParts(d0100), 'at night', '01:00, short format');
+assertParts(short.formatToParts(d0200), 'at night', '02:00, short format');
+assertParts(short.formatToParts(d0300), 'at night', '03:00, short format');
+assertParts(short.formatToParts(d0400), 'at night', '04:00, short format');
+assertParts(short.formatToParts(d0500), 'at night', '05:00, short format');
+assertParts(short.formatToParts(d0600), 'in the morning', '06:00, short format');
+assertParts(short.formatToParts(d0700), 'in the morning', '07:00, short format');
+assertParts(short.formatToParts(d0800), 'in the morning', '08:00, short format');
+assertParts(short.formatToParts(d0900), 'in the morning', '09:00, short format');
+assertParts(short.formatToParts(d1000), 'in the morning', '10:00, short format');
+assertParts(short.formatToParts(d1100), 'in the morning', '11:00, short format');
+assertParts(short.formatToParts(d1200), 'noon', '12:00, short format');
+assertParts(short.formatToParts(d1300), 'in the afternoon', '13:00, short format');
+assertParts(short.formatToParts(d1400), 'in the afternoon', '14:00, short format');
+assertParts(short.formatToParts(d1500), 'in the afternoon', '15:00, short format');
+assertParts(short.formatToParts(d1600), 'in the afternoon', '16:00, short format');
+assertParts(short.formatToParts(d1700), 'in the afternoon', '17:00, short format');
+assertParts(short.formatToParts(d1800), 'in the evening', '18:00, short format');
+assertParts(short.formatToParts(d1900), 'in the evening', '19:00, short format');
+assertParts(short.formatToParts(d2000), 'in the evening', '20:00, short format');
+assertParts(short.formatToParts(d2100), 'at night', '21:00, short format');
+assertParts(short.formatToParts(d2200), 'at night', '22:00, short format');
+assertParts(short.formatToParts(d2300), 'at night', '23:00, short format');
+
+const shortNumeric = new Intl.DateTimeFormat('en', {
+ dayPeriod: 'short',
+ hour: 'numeric'
+});
+
+function assertPartsNumeric(parts, hour, expected, message) {
+ assert.sameValue(parts.length, 3, `length should be 3, ${message}`);
+ assert.sameValue(parts[0].value, hour, `hour part value. ${message}`);
+ assert.sameValue(parts[0].type, 'hour', `hour part type. ${message}`);
+ assert.sameValue(parts[1].value, ' ', `literal part value. ${message}`);
+ assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`);
+ assert.sameValue(parts[2].value, expected, `expected part value. ${message}`);
+ assert.sameValue(parts[2].type, 'dayPeriod', `expected part type. ${message}`);
+}
+
+assertPartsNumeric(shortNumeric.formatToParts(d0000), '12', 'at night', '00:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0100), '1', 'at night', '01:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0200), '2', 'at night', '02:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0300), '3', 'at night', '03:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0400), '4', 'at night', '04:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0500), '5', 'at night', '05:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0600), '6', 'in the morning', '06:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0700), '7', 'in the morning', '07:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0800), '8', 'in the morning', '08:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d0900), '9', 'in the morning', '09:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1000), '10', 'in the morning', '10:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1100), '11', 'in the morning', '11:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1200), '12', 'noon', '12:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1300), '1', 'in the afternoon', '13:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1400), '2', 'in the afternoon', '14:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1500), '3', 'in the afternoon', '15:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1600), '4', 'in the afternoon', '16:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1700), '5', 'in the afternoon', '17:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1800), '6', 'in the evening', '18:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d1900), '7', 'in the evening', '19:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d2000), '8', 'in the evening', '20:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d2100), '9', 'at night', '21:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d2200), '10', 'at night', '22:00, short-numeric');
+assertPartsNumeric(shortNumeric.formatToParts(d2300), '11', 'at night', '23:00, short-numeric');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js
new file mode 100644
index 0000000000..a0045ba71c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/formatToParts.js
@@ -0,0 +1,21 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Property type and descriptor.
+includes: [propertyHelper.js]
+---*/
+
+assert.sameValue(
+ typeof Intl.DateTimeFormat.prototype.formatToParts,
+ 'function',
+ '`typeof Intl.DateTimeFormat.prototype.formatToParts` is `function`'
+);
+
+verifyProperty(Intl.DateTimeFormat.prototype, "formatToParts", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js
new file mode 100644
index 0000000000..543dfb2274
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js
@@ -0,0 +1,69 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: Checks basic handling of fractionalSecondDigits.
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+locale: [en-US]
+---*/
+
+const d1 = new Date(2019, 7, 10, 1, 2, 3, 234);
+const d2 = new Date(2019, 7, 10, 1, 2, 3, 567);
+
+function assertParts(parts, minute, second, fractionalSecond, message) {
+ if (fractionalSecond === null) {
+ assert.sameValue(parts.length, 3, `length should be 3, ${message}`);
+ } else {
+ assert.sameValue(parts.length, 5, `length should be 5, ${message}`);
+ }
+ assert.sameValue(parts[0].value, minute, `minute part value. ${message}`);
+ assert.sameValue(parts[0].type, 'minute', `minute part type. ${message}`);
+ assert.sameValue(parts[1].value, ':', `literal part value. ${message}`);
+ assert.sameValue(parts[1].type, 'literal', `literal part type. ${message}`);
+ assert.sameValue(parts[2].value, second, `second part value. ${message}`);
+ assert.sameValue(parts[2].type, 'second', `second part type. ${message}`);
+ if (fractionalSecond !== null) {
+ assert.sameValue(parts[3].value, '.', `literal part value. ${message}`);
+ assert.sameValue(parts[3].type, 'literal', `literal part type. ${message}`);
+ assert.sameValue(parts[4].value, fractionalSecond, `fractionalSecond part value. ${message}`);
+ assert.sameValue(parts[4].type, 'fractionalSecond', `fractionalSecond part type. ${message}`);
+ }
+}
+
+assert.throws(RangeError, () => {
+ new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 0});
+}, "fractionalSecondDigits 0 should throw RangeError for out of range");
+
+assert.throws(RangeError, () => {
+ new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 4});
+}, "fractionalSecondDigits 4 should throw RangeError for out of range");
+
+let dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric"});
+assertParts(dtf.formatToParts(d1), "02", "03", null, "no fractionalSecondDigits round down");
+assertParts(dtf.formatToParts(d2), "02", "03", null, "no fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: undefined});
+assertParts(dtf.formatToParts(d1), "02", "03", null, "no fractionalSecondDigits round down");
+assertParts(dtf.formatToParts(d2), "02", "03", null, "no fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 1});
+assertParts(dtf.formatToParts(d1), "02", "03", "2", "1 fractionalSecondDigits round down");
+assertParts(dtf.formatToParts(d2), "02", "03", "5", "1 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 2});
+assertParts(dtf.formatToParts(d1), "02", "03", "23", "2 fractionalSecondDigits round down");
+assertParts(dtf.formatToParts(d2), "02", "03", "56", "2 fractionalSecondDigits round down");
+
+dtf = new Intl.DateTimeFormat(
+ 'en', { minute: "numeric", second: "numeric", fractionalSecondDigits: 3});
+assertParts(dtf.formatToParts(d1), "02", "03", "234", "3 fractionalSecondDigits round down");
+assertParts(dtf.formatToParts(d2), "02", "03", "567", "3 fractionalSecondDigits round down");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js
new file mode 100644
index 0000000000..cc596ada97
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/length.js
@@ -0,0 +1,15 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatToParts.length.
+includes: [propertyHelper.js]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatToParts, 'length', {
+ value: 1,
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js
new file mode 100644
index 0000000000..b42b917232
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/main.js
@@ -0,0 +1,76 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Tests for existance and behavior of Intl.DateTimeFormat.prototype.formatToParts
+features: [Array.prototype.includes]
+---*/
+
+function reduce(parts) {
+ return parts.map(part => part.value).join('');
+}
+
+function compareFTPtoFormat(locales, options, value) {
+ const dtf = new Intl.DateTimeFormat(locales, options);
+ assert.sameValue(
+ dtf.format(value),
+ reduce(dtf.formatToParts(value)),
+ `Expected the same value for value ${value},
+ locales: ${locales} and options: ${options}`
+ );
+}
+
+compareFTPtoFormat();
+compareFTPtoFormat('pl');
+compareFTPtoFormat(['pl']);
+compareFTPtoFormat([]);
+compareFTPtoFormat(['de'], undefined, 0);
+compareFTPtoFormat(['de'], undefined, -10);
+compareFTPtoFormat(['de'], undefined, 25324234235);
+compareFTPtoFormat(['de'], {
+ day: '2-digit'
+}, Date.now());
+compareFTPtoFormat(['de'], {
+ day: 'numeric',
+ year: '2-digit'
+}, Date.now());
+compareFTPtoFormat(['ar'], {
+ month: 'numeric',
+ day: 'numeric',
+ year: '2-digit'
+}, Date.now());
+
+const actualPartTypes = new Intl.DateTimeFormat('en-us', {
+ weekday: 'long',
+ era: 'long',
+ year: 'numeric',
+ month: 'numeric',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ hour12: true,
+ timeZone: 'UTC',
+ timeZoneName: 'long'
+}).formatToParts(Date.UTC(2012, 11, 17, 3, 0, 42))
+ .map(part => part.type);
+
+const legalPartTypes = [
+ 'weekday',
+ 'era',
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ 'literal',
+ 'dayPeriod',
+ 'timeZoneName',
+];
+
+actualPartTypes.forEach(function(type) {
+ assert(legalPartTypes.includes(type), `${type} is not a legal type`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js
new file mode 100644
index 0000000000..92b4805ee9
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/name.js
@@ -0,0 +1,15 @@
+// Copyright 2016 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Intl.DateTimeFormat.prototype.formatToParts.name value and descriptor.
+includes: [propertyHelper.js]
+---*/
+verifyProperty(Intl.DateTimeFormat.prototype.formatToParts, 'name', {
+ value: 'formatToParts',
+ enumerable: false,
+ writable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js
new file mode 100644
index 0000000000..1ebffa9a77
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js
@@ -0,0 +1,30 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that formatted hour and minute are correct for offset time zones.
+---*/
+let date = new Date('1995-12-17T03:24:56Z');
+let tests = {
+ '+0301': {hour: "6", minute: "25"},
+ '+1412': {hour: "5", minute: "36"},
+ '+02': {hour: "5", minute: "24"},
+ '+13:49': {hour: "5", minute: "13"},
+ '-07:56': {hour: "7", minute: "28"},
+ '-12': {hour: "3", minute: "24"},
+ '−0914': {hour: "6", minute: "10"},
+ '−10:03': {hour: "5", minute: "21"},
+ '−0509': {hour: "10", minute: "15"},
+};
+Object.entries(tests).forEach(([timeZone, expected]) => {
+ let df = new Intl.DateTimeFormat("en",
+ {timeZone, timeStyle: "short"});
+ let res = df.formatToParts(date);
+ let hour = res.filter((t) => t.type === "hour")[0].value
+ let minute = res.filter((t) => t.type === "minute")[0].value
+ assert.sameValue(hour, expected.hour, `hour in ${timeZone} time zone:`);
+ assert.sameValue(minute, expected.minute, `minute in ${timeZone} time zone:`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js
new file mode 100644
index 0000000000..7a9a753983
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/pattern-on-calendar.js
@@ -0,0 +1,38 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Checks the DateTimeFormat choose different patterns based
+ on calendar.
+includes: [testIntl.js]
+locale: [en]
+---*/
+
+let calendars = allCalendars();
+let date = new Date();
+
+// serialize parts to a string by considering only the type and literal.
+function serializeTypesAndLiteral(parts) {
+ let types = parts.map(part => {
+ if (part.type == "literal") {
+ return `${part.type}(${part.value})`;
+ }
+ return part.type;
+ });
+ return types.join(":");
+}
+
+let df = new Intl.DateTimeFormat("en");
+let base = serializeTypesAndLiteral(df.formatToParts(date));
+
+const foundDifferentPattern = calendars.some(function(calendar) {
+ let cdf = new Intl.DateTimeFormat("en-u-ca-" + calendar);
+ return base != serializeTypesAndLiteral(cdf.formatToParts(date));
+});
+
+// Expect at least some calendar use different pattern.
+assert.sameValue(foundDifferentPattern, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js
new file mode 100644
index 0000000000..1033404e00
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js
@@ -0,0 +1,35 @@
+// Copyright 2019 Google Inc, Igalia S.L. All rights reserved.
+// Copyright 2020 Apple Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: >
+ Checks the output of 'relatedYear' and 'yearName' type, and
+ the choice of pattern based on calendar.
+locale: [zh-u-ca-chinese]
+---*/
+
+const df = new Intl.DateTimeFormat("zh-u-ca-chinese", {year: "numeric"});
+const date = new Date(2019, 5, 1);
+const actual = df.formatToParts(date);
+
+const expected = [
+ {type: "relatedYear", value: "2019"},
+ {type: "yearName", value: "己亥"},
+ {type: "literal", value: "年"},
+];
+
+assert.sameValue(Array.isArray(actual), true, 'actual is Array');
+
+if (actual.length <= 2) {
+ expected.shift(); // removes the relatedYear
+}
+
+actual.forEach(({ type, value }, i) => {
+ const { type: eType, value: eValue } = expected[i];
+ assert.sameValue(type, eType, `actual[${i}].type should be ${eType}`);
+ assert.sameValue(value, eValue, `actual[${i}].value should be ${eValue}`);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js
new file mode 100644
index 0000000000..92aae9e730
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/related-year.js
@@ -0,0 +1,23 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: >
+ Checks the output of 'relatedYear' and 'yearName' type, and
+ the choose of pattern base on calendar.
+locale: [en-u-ca-chinese]
+---*/
+
+let df = new Intl.DateTimeFormat("en-u-ca-chinese", {year: "numeric"});
+let parts = df.formatToParts(new Date());
+var relatedYearCount = 0;
+var yearNameCount = 0;
+parts.forEach(function(part) {
+ relatedYearCount += (part.type == "relatedYear") ? 1 : 0;
+ yearNameCount += (part.type == "yearName") ? 1 : 0;
+});
+assert.sameValue(relatedYearCount > 0, true);
+assert.sameValue(yearNameCount > 0, true);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js
new file mode 100644
index 0000000000..b8141a3776
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/return-abrupt-tonumber-date.js
@@ -0,0 +1,44 @@
+// Copyright 2016 Leonardo Balter. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Return abrupt completions from ToNumber(date)
+info: |
+ Intl.DateTimeFormat.prototype.formatToParts ([ date ])
+
+ 4. If _date_ is not provided or is *undefined*, then
+ a. Let _x_ be *%Date_now%*().
+ 5. Else,
+ a. Let _x_ be ? ToNumber(_date_).
+features: [Symbol]
+---*/
+
+var obj1 = {
+ valueOf: function() {
+ throw new Test262Error();
+ }
+};
+
+var obj2 = {
+ toString: function() {
+ throw new Test262Error();
+ }
+};
+
+var dtf = new Intl.DateTimeFormat(["pt-BR"]);
+
+assert.throws(Test262Error, function() {
+ dtf.formatToParts(obj1);
+}, "valueOf");
+
+assert.throws(Test262Error, function() {
+ dtf.formatToParts(obj2);
+}, "toString");
+
+var s = Symbol('1');
+assert.throws(TypeError, function() {
+ dtf.formatToParts(s);
+}, "symbol");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js
new file mode 100644
index 0000000000..cce6b3c2a3
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/shell.js
@@ -0,0 +1,360 @@
+// GENERATED, DO NOT EDIT
+// file: dateConstants.js
+// Copyright (C) 2009 the Sputnik authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ Collection of date-centric values
+defines:
+ - date_1899_end
+ - date_1900_start
+ - date_1969_end
+ - date_1970_start
+ - date_1999_end
+ - date_2000_start
+ - date_2099_end
+ - date_2100_start
+ - start_of_time
+ - end_of_time
+---*/
+
+var date_1899_end = -2208988800001;
+var date_1900_start = -2208988800000;
+var date_1969_end = -1;
+var date_1970_start = 0;
+var date_1999_end = 946684799999;
+var date_2000_start = 946684800000;
+var date_2099_end = 4102444799999;
+var date_2100_start = 4102444800000;
+
+var start_of_time = -8.64e15;
+var end_of_time = 8.64e15;
+
+// file: deepEqual.js
+// Copyright 2019 Ron Buckton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: >
+ Compare two values structurally
+defines: [assert.deepEqual]
+---*/
+
+assert.deepEqual = function(actual, expected, message) {
+ var format = assert.deepEqual.format;
+ assert(
+ assert.deepEqual._compare(actual, expected),
+ `Expected ${format(actual)} to be structurally equal to ${format(expected)}. ${(message || '')}`
+ );
+};
+
+assert.deepEqual.format = function(value, seen) {
+ switch (typeof value) {
+ case 'string':
+ return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`;
+ case 'number':
+ case 'boolean':
+ case 'symbol':
+ case 'bigint':
+ return value.toString();
+ case 'undefined':
+ return 'undefined';
+ case 'function':
+ return `[Function${value.name ? `: ${value.name}` : ''}]`;
+ case 'object':
+ if (value === null) return 'null';
+ if (value instanceof Date) return `Date "${value.toISOString()}"`;
+ if (value instanceof RegExp) return value.toString();
+ if (!seen) {
+ seen = {
+ counter: 0,
+ map: new Map()
+ };
+ }
+
+ let usage = seen.map.get(value);
+ if (usage) {
+ usage.used = true;
+ return `[Ref: #${usage.id}]`;
+ }
+
+ usage = { id: ++seen.counter, used: false };
+ seen.map.set(value, usage);
+
+ if (typeof Set !== "undefined" && value instanceof Set) {
+ return `Set {${Array.from(value).map(value => assert.deepEqual.format(value, seen)).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (typeof Map !== "undefined" && value instanceof Map) {
+ return `Map {${Array.from(value).map(pair => `${assert.deepEqual.format(pair[0], seen)} => ${assert.deepEqual.format(pair[1], seen)}}`).join(', ')}}${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ if (Array.isArray ? Array.isArray(value) : value instanceof Array) {
+ return `[${value.map(value => assert.deepEqual.format(value, seen)).join(', ')}]${usage.used ? ` as #${usage.id}` : ''}`;
+ }
+ let tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object';
+ if (tag === 'Object' && Object.getPrototypeOf(value) === null) {
+ tag = '[Object: null prototype]';
+ }
+ return `${tag ? `${tag} ` : ''}{ ${Object.keys(value).map(key => `${key.toString()}: ${assert.deepEqual.format(value[key], seen)}`).join(', ')} }${usage.used ? ` as #${usage.id}` : ''}`;
+ default:
+ return typeof value;
+ }
+};
+
+assert.deepEqual._compare = (function () {
+ var EQUAL = 1;
+ var NOT_EQUAL = -1;
+ var UNKNOWN = 0;
+
+ function deepEqual(a, b) {
+ return compareEquality(a, b) === EQUAL;
+ }
+
+ function compareEquality(a, b, cache) {
+ return compareIf(a, b, isOptional, compareOptionality)
+ || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality)
+ || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache)
+ || NOT_EQUAL;
+ }
+
+ function compareIf(a, b, test, compare, cache) {
+ return !test(a)
+ ? !test(b) ? UNKNOWN : NOT_EQUAL
+ : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache);
+ }
+
+ function tryCompareStrictEquality(a, b) {
+ return a === b ? EQUAL : UNKNOWN;
+ }
+
+ function tryCompareTypeOfEquality(a, b) {
+ return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function tryCompareToStringTagEquality(a, b) {
+ var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined;
+ var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined;
+ return aTag !== bTag ? NOT_EQUAL : UNKNOWN;
+ }
+
+ function isOptional(value) {
+ return value === undefined
+ || value === null;
+ }
+
+ function compareOptionality(a, b) {
+ return tryCompareStrictEquality(a, b)
+ || NOT_EQUAL;
+ }
+
+ function isPrimitiveEquatable(value) {
+ switch (typeof value) {
+ case 'string':
+ case 'number':
+ case 'bigint':
+ case 'boolean':
+ case 'symbol':
+ return true;
+ default:
+ return isBoxed(value);
+ }
+ }
+
+ function comparePrimitiveEquality(a, b) {
+ if (isBoxed(a)) a = a.valueOf();
+ if (isBoxed(b)) b = b.valueOf();
+ return tryCompareStrictEquality(a, b)
+ || tryCompareTypeOfEquality(a, b)
+ || compareIf(a, b, isNaNEquatable, compareNaNEquality)
+ || NOT_EQUAL;
+ }
+
+ function isNaNEquatable(value) {
+ return typeof value === 'number';
+ }
+
+ function compareNaNEquality(a, b) {
+ return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL;
+ }
+
+ function isObjectEquatable(value) {
+ return typeof value === 'object';
+ }
+
+ function compareObjectEquality(a, b, cache) {
+ if (!cache) cache = new Map();
+ return getCache(cache, a, b)
+ || setCache(cache, a, b, EQUAL) // consider equal for now
+ || cacheComparison(a, b, tryCompareStrictEquality, cache)
+ || cacheComparison(a, b, tryCompareToStringTagEquality, cache)
+ || compareIf(a, b, isValueOfEquatable, compareValueOfEquality)
+ || compareIf(a, b, isToStringEquatable, compareToStringEquality)
+ || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache)
+ || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache)
+ || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || cacheComparison(a, b, fail, cache);
+ }
+
+ function isBoxed(value) {
+ return value instanceof String
+ || value instanceof Number
+ || value instanceof Boolean
+ || typeof Symbol === 'function' && value instanceof Symbol
+ || typeof BigInt === 'function' && value instanceof BigInt;
+ }
+
+ function isValueOfEquatable(value) {
+ return value instanceof Date;
+ }
+
+ function compareValueOfEquality(a, b) {
+ return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isToStringEquatable(value) {
+ return value instanceof RegExp;
+ }
+
+ function compareToStringEquality(a, b) {
+ return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality)
+ || NOT_EQUAL;
+ }
+
+ function isArrayLikeEquatable(value) {
+ return (Array.isArray ? Array.isArray(value) : value instanceof Array)
+ || (typeof Uint8Array === 'function' && value instanceof Uint8Array)
+ || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray)
+ || (typeof Uint16Array === 'function' && value instanceof Uint16Array)
+ || (typeof Uint32Array === 'function' && value instanceof Uint32Array)
+ || (typeof Int8Array === 'function' && value instanceof Int8Array)
+ || (typeof Int16Array === 'function' && value instanceof Int16Array)
+ || (typeof Int32Array === 'function' && value instanceof Int32Array)
+ || (typeof Float32Array === 'function' && value instanceof Float32Array)
+ || (typeof Float64Array === 'function' && value instanceof Float64Array)
+ || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array)
+ || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array);
+ }
+
+ function compareArrayLikeEquality(a, b, cache) {
+ if (a.length !== b.length) return NOT_EQUAL;
+ for (var i = 0; i < a.length; i++) {
+ if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+ return EQUAL;
+ }
+
+ function isStructurallyEquatable(value) {
+ return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference
+ || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference
+ || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference
+ || typeof Map === 'function' && value instanceof Map // comparable via @@iterator
+ || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator
+ }
+
+ function compareStructuralEquality(a, b, cache) {
+ var aKeys = [];
+ for (var key in a) aKeys.push(key);
+
+ var bKeys = [];
+ for (var key in b) bKeys.push(key);
+
+ if (aKeys.length !== bKeys.length) {
+ return NOT_EQUAL;
+ }
+
+ aKeys.sort();
+ bKeys.sort();
+
+ for (var i = 0; i < aKeys.length; i++) {
+ var aKey = aKeys[i];
+ var bKey = bKeys[i];
+ if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) {
+ return NOT_EQUAL;
+ }
+ }
+
+ return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache)
+ || EQUAL;
+ }
+
+ function isIterableEquatable(value) {
+ return typeof Symbol === 'function'
+ && typeof value[Symbol.iterator] === 'function';
+ }
+
+ function compareIteratorEquality(a, b, cache) {
+ if (typeof Map === 'function' && a instanceof Map && b instanceof Map ||
+ typeof Set === 'function' && a instanceof Set && b instanceof Set) {
+ if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size
+ }
+
+ var ar, br;
+ while (true) {
+ ar = a.next();
+ br = b.next();
+ if (ar.done) {
+ if (br.done) return EQUAL;
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ if (br.done) {
+ if (a.return) a.return();
+ return NOT_EQUAL;
+ }
+ if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) {
+ if (a.return) a.return();
+ if (b.return) b.return();
+ return NOT_EQUAL;
+ }
+ }
+ }
+
+ function compareIterableEquality(a, b, cache) {
+ return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache);
+ }
+
+ function cacheComparison(a, b, compare, cache) {
+ var result = compare(a, b, cache);
+ if (cache && (result === EQUAL || result === NOT_EQUAL)) {
+ setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result));
+ }
+ return result;
+ }
+
+ function fail() {
+ return NOT_EQUAL;
+ }
+
+ function setCache(cache, left, right, result) {
+ var otherCache;
+
+ otherCache = cache.get(left);
+ if (!otherCache) cache.set(left, otherCache = new Map());
+ otherCache.set(right, result);
+
+ otherCache = cache.get(right);
+ if (!otherCache) cache.set(right, otherCache = new Map());
+ otherCache.set(left, result);
+ }
+
+ function getCache(cache, left, right) {
+ var otherCache;
+ var result;
+
+ otherCache = cache.get(left);
+ result = otherCache && otherCache.get(right);
+ if (result) return result;
+
+ otherCache = cache.get(right);
+ result = otherCache && otherCache.get(left);
+ if (result) return result;
+
+ return UNKNOWN;
+ }
+
+ return deepEqual;
+})();
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js
new file mode 100644
index 0000000000..f764995862
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js
@@ -0,0 +1,107 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.formatToParts
+description: A time zone in resolvedOptions with a large offset still produces the correct string
+locale: [en]
+includes: [deepEqual.js]
+features: [Temporal]
+---*/
+
+// Tolerate implementation variance by expecting consistency without being prescriptive.
+// TODO: can we change tests to be less reliant on CLDR formats while still testing that
+// Temporal and Intl are behaving as expected?
+const usDayPeriodSpace =
+ new Intl.DateTimeFormat("en-US", { timeStyle: "short" })
+ .formatToParts(0)
+ .find((part, i, parts) => part.type === "literal" && parts[i + 1].type === "dayPeriod")?.value || "";
+
+const formatter = new Intl.DateTimeFormat("en-US", { timeZone: "Pacific/Apia" });
+
+const date = new Temporal.PlainDate(2021, 8, 4);
+const dateResult = formatter.formatToParts(date);
+assert.deepEqual(dateResult, [
+ { type: "month", value: "8" },
+ { type: "literal", value: "/" },
+ { type: "day", value: "4" },
+ { type: "literal", value: "/" },
+ { type: "year", value: "2021" },
+], "plain date");
+
+const datetime1 = new Temporal.PlainDateTime(2021, 8, 4, 0, 30, 45, 123, 456, 789);
+const datetimeResult1 = formatter.formatToParts(datetime1);
+assert.deepEqual(datetimeResult1, [
+ { type: "month", value: "8" },
+ { type: "literal", value: "/" },
+ { type: "day", value: "4" },
+ { type: "literal", value: "/" },
+ { type: "year", value: "2021" },
+ { type: "literal", value: ", " },
+ { type: "hour", value: "12" },
+ { type: "literal", value: ":" },
+ { type: "minute", value: "30" },
+ { type: "literal", value: ":" },
+ { type: "second", value: "45" },
+ { type: "literal", value: usDayPeriodSpace },
+ { type: "dayPeriod", value: "AM" },
+], "plain datetime close to beginning of day");
+const datetime2 = new Temporal.PlainDateTime(2021, 8, 4, 23, 30, 45, 123, 456, 789);
+const datetimeResult2 = formatter.formatToParts(datetime2);
+assert.deepEqual(datetimeResult2, [
+ { type: "month", value: "8" },
+ { type: "literal", value: "/" },
+ { type: "day", value: "4" },
+ { type: "literal", value: "/" },
+ { type: "year", value: "2021" },
+ { type: "literal", value: ", " },
+ { type: "hour", value: "11" },
+ { type: "literal", value: ":" },
+ { type: "minute", value: "30" },
+ { type: "literal", value: ":" },
+ { type: "second", value: "45" },
+ { type: "literal", value: usDayPeriodSpace },
+ { type: "dayPeriod", value: "PM" },
+], "plain datetime close to end of day");
+
+const monthDay = new Temporal.PlainMonthDay(8, 4, "gregory");
+const monthDayResult = formatter.formatToParts(monthDay);
+assert.deepEqual(monthDayResult, [
+ { type: "month", value: "8" },
+ { type: "literal", value: "/" },
+ { type: "day", value: "4" },
+], "plain month-day");
+
+const time1 = new Temporal.PlainTime(0, 30, 45, 123, 456, 789);
+const timeResult1 = formatter.formatToParts(time1);
+assert.deepEqual(timeResult1, [
+ { type: "hour", value: "12" },
+ { type: "literal", value: ":" },
+ { type: "minute", value: "30" },
+ { type: "literal", value: ":" },
+ { type: "second", value: "45" },
+ { type: "literal", value: usDayPeriodSpace },
+ { type: "dayPeriod", value: "AM" },
+], "plain time close to beginning of day");
+const time2 = new Temporal.PlainTime(23, 30, 45, 123, 456, 789);
+const timeResult2 = formatter.formatToParts(time2);
+assert.deepEqual(timeResult2, [
+ { type: "hour", value: "11" },
+ { type: "literal", value: ":" },
+ { type: "minute", value: "30" },
+ { type: "literal", value: ":" },
+ { type: "second", value: "45" },
+ { type: "literal", value: usDayPeriodSpace },
+ { type: "dayPeriod", value: "PM" },
+], "plain time close to end of day");
+
+const month = new Temporal.PlainYearMonth(2021, 8, "gregory");
+const monthResult = formatter.formatToParts(month);
+assert.deepEqual(monthResult, [
+ { type: "month", value: "8" },
+ { type: "literal", value: "/" },
+ { type: "year", value: "2021" },
+], "plain year-month");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js
new file mode 100644
index 0000000000..ec7438195b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/temporal-zoneddatetime-not-supported.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.formatToParts
+description: Temporal.ZonedDateTime is not supported directly in formatToParts()
+features: [Temporal]
+---*/
+
+const formatter = new Intl.DateTimeFormat();
+
+// Check that TypeError would not be thrown for a different reason
+const {timeZone, ...options} = formatter.resolvedOptions();
+const datetime = new Temporal.ZonedDateTime(0n, timeZone);
+assert.sameValue(typeof datetime.toLocaleString(undefined, options), "string", "toLocaleString() with same options succeeds");
+
+assert.throws(TypeError, () => formatter.formatToParts(datetime), "formatToParts() does not support Temporal.ZonedDateTime");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js
new file mode 100644
index 0000000000..18dae83a16
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-has-not-internal-throws.js
@@ -0,0 +1,19 @@
+// Copyright 2016 Leonardo Balter. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: >
+ Throws a TypeError if this is not a DateTimeFormat object
+---*/
+
+var formatToParts = Intl.DateTimeFormat.prototype.formatToParts;
+
+assert.throws(TypeError, function() {
+ formatToParts.call({});
+}, "{}");
+
+assert.throws(TypeError, function() {
+ formatToParts.call(new Date());
+}, "new Date()");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js
new file mode 100644
index 0000000000..0837bfb1ca
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/this-is-not-object-throws.js
@@ -0,0 +1,40 @@
+// Copyright 2016 Leonardo Balter. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+description: Throws a TypeError if this is not Object
+features: [Symbol]
+---*/
+
+var formatToParts = Intl.DateTimeFormat.prototype.formatToParts;
+
+assert.throws(TypeError, function() {
+ formatToParts.call(undefined);
+}, "undefined");
+
+assert.throws(TypeError, function() {
+ formatToParts.call(null);
+}, "null");
+
+assert.throws(TypeError, function() {
+ formatToParts.call(42);
+}, "number");
+
+assert.throws(TypeError, function() {
+ formatToParts.call("foo");
+}, "string");
+
+assert.throws(TypeError, function() {
+ formatToParts.call(false);
+}, "false");
+
+assert.throws(TypeError, function() {
+ formatToParts.call(true);
+}, "true");
+
+var s = Symbol('1');
+assert.throws(TypeError, function() {
+ formatToParts.call(s);
+}, "symbol");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js
new file mode 100644
index 0000000000..61599ebbc1
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-near-time-boundaries.js
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ TimeClip is applied when calling Intl.DateTimeFormat.prototype.formatToParts.
+info: >
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. If x is NaN, throw a RangeError exception.
+ 3. ...
+
+ 20.3.1.15 TimeClip ( time )
+ ...
+ 2. If abs(time) > 8.64 × 10^15, return NaN.
+ ...
+
+includes: [dateConstants.js]
+---*/
+
+var dtf = new Intl.DateTimeFormat();
+
+// Test values near the start of the ECMAScript time range.
+assert.throws(RangeError, function() {
+ dtf.formatToParts(start_of_time - 1);
+});
+assert.sameValue(typeof dtf.formatToParts(start_of_time), "object");
+assert.sameValue(typeof dtf.formatToParts(start_of_time + 1), "object");
+
+// Test values near the end of the ECMAScript time range.
+assert.sameValue(typeof dtf.formatToParts(end_of_time - 1), "object");
+assert.sameValue(typeof dtf.formatToParts(end_of_time), "object");
+assert.throws(RangeError, function() {
+ dtf.formatToParts(end_of_time + 1);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js
new file mode 100644
index 0000000000..576b08ca92
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/formatToParts/time-clip-to-integer.js
@@ -0,0 +1,43 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-partitiondatetimepattern
+description: |
+ TimeClip applies ToInteger on its input value.
+info: >
+ 12.1.6 PartitionDateTimePattern ( dateTimeFormat, x )
+
+ 1. Let x be TimeClip(x).
+ 2. ...
+
+ 20.3.1.15 TimeClip ( time )
+ ...
+ 3. Let clippedTime be ! ToInteger(time).
+ 4. If clippedTime is -0, set clippedTime to +0.
+ 5. Return clippedTime.
+---*/
+
+// Switch to a time format instead of using DateTimeFormat's default date-only format.
+var dtf = new Intl.DateTimeFormat(undefined, {
+ hour: "numeric", minute: "numeric", second: "numeric"
+});
+
+function formatAsString(dtf, time) {
+ return dtf.formatToParts(time).map(part => part.value).join("");
+}
+
+var expected = formatAsString(dtf, 0);
+
+assert.sameValue(formatAsString(dtf, -0.9), expected, "formatToParts(-0.9)");
+assert.sameValue(formatAsString(dtf, -0.5), expected, "formatToParts(-0.5)");
+assert.sameValue(formatAsString(dtf, -0.1), expected, "formatToParts(-0.1)");
+assert.sameValue(formatAsString(dtf, -Number.MIN_VALUE), expected, "formatToParts(-Number.MIN_VALUE)");
+assert.sameValue(formatAsString(dtf, -0), expected, "formatToParts(-0)");
+assert.sameValue(formatAsString(dtf, +0), expected, "formatToParts(+0)");
+assert.sameValue(formatAsString(dtf, Number.MIN_VALUE), expected, "formatToParts(Number.MIN_VALUE)");
+assert.sameValue(formatAsString(dtf, 0.1), expected, "formatToParts(0.1)");
+assert.sameValue(formatAsString(dtf, 0.5), expected, "formatToParts(0.5)");
+assert.sameValue(formatAsString(dtf, 0.9), expected, "formatToParts(0.9)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js
new file mode 100644
index 0000000000..711e47059a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/prop-desc.js
@@ -0,0 +1,19 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.2.1
+description: >
+ Tests that Intl.DateTimeFormat.prototype has the required
+ attributes.
+author: Norbert Lindenberg
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat, "prototype", {
+ writable: false,
+ enumerable: false,
+ configurable: false,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js
new file mode 100644
index 0000000000..4ca918bb63
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/basic.js
@@ -0,0 +1,53 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.3.3
+description: >
+ Tests that the object returned by
+ Intl.DateTimeFormat.prototype.resolvedOptions has the right
+ properties.
+author: Norbert Lindenberg
+includes: [testIntl.js, propertyHelper.js]
+---*/
+
+var actual = new Intl.DateTimeFormat().resolvedOptions();
+
+var actual2 = new Intl.DateTimeFormat().resolvedOptions();
+assert.notSameValue(actual2, actual, "resolvedOptions returned the same object twice.");
+
+var calendars = allCalendars();
+
+// this assumes the default values where the specification provides them
+assert(isCanonicalizedStructurallyValidLanguageTag(actual.locale),
+ "Invalid locale: " + actual.locale);
+assert.notSameValue(calendars.indexOf(actual.calendar), -1,
+ "Invalid calendar: " + actual.calendar);
+assert(isValidNumberingSystem(actual.numberingSystem),
+ "Invalid numbering system: " + actual.numberingSystem);
+assert(isCanonicalizedStructurallyValidTimeZoneName(actual.timeZone),
+ "Invalid time zone: " + actual.timeZone);
+assert.notSameValue(["2-digit", "numeric"].indexOf(actual.year), -1,
+ "Invalid year: " + actual.year);
+assert.notSameValue(["2-digit", "numeric", "narrow", "short", "long"].indexOf(actual.month), -1,
+ "Invalid month: " + actual.month);
+assert.notSameValue(["2-digit", "numeric"].indexOf(actual.day), -1,
+ "Invalid day: " + actual.day);
+
+var dataPropertyDesc = { writable: true, enumerable: true, configurable: true };
+verifyProperty(actual, "locale", dataPropertyDesc);
+verifyProperty(actual, "calendar", dataPropertyDesc);
+verifyProperty(actual, "numberingSystem", dataPropertyDesc);
+verifyProperty(actual, "timeZone", dataPropertyDesc);
+verifyProperty(actual, "weekday", undefined);
+verifyProperty(actual, "era", undefined);
+verifyProperty(actual, "year", dataPropertyDesc);
+verifyProperty(actual, "month", dataPropertyDesc);
+verifyProperty(actual, "day", dataPropertyDesc);
+verifyProperty(actual, "hour", undefined);
+verifyProperty(actual, "minute", undefined);
+verifyProperty(actual, "second", undefined);
+verifyProperty(actual, "timeZoneName", undefined);
+verifyProperty(actual, "hour12", undefined);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js
new file mode 100644
index 0000000000..643376e7e2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/builtin.js
@@ -0,0 +1,30 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.3.3_L15
+description: >
+ Tests that Intl.DateTimeFormat.prototype.resolvedOptions meets
+ the requirements for built-in objects defined by the introduction
+ of chapter 17 of the ECMAScript Language Specification.
+author: Norbert Lindenberg
+includes: [isConstructor.js]
+features: [Reflect.construct]
+---*/
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype.resolvedOptions), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(Intl.DateTimeFormat.prototype.resolvedOptions),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.prototype.resolvedOptions), Function.prototype);
+
+assert.sameValue(Intl.DateTimeFormat.prototype.resolvedOptions.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(Intl.DateTimeFormat.prototype.resolvedOptions), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js
new file mode 100644
index 0000000000..ebab7d4ad9
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js
@@ -0,0 +1,93 @@
+// Copyright 2019 Mozilla Corporation, Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions properly
+ reflect hourCycle settings when using dateStyle.
+ Note: "properly reflect hourCycle settings when using dateStyle", in this context, means "if dateStyle but not timeStyle is set, both hourCycle and hour12 will be *undefined*". This is because the CreateDateTimeFormat AO resets [[HourCycle]] to *undefined* if [[Hour]] is *undefined*, and if dateStyle but not timeStyle is set, [[HourCycle]] is set to *undefined*.
+info: |
+ 11.3.7 Intl.DateTimeFormat.prototype.resolvedOptions()
+ ...
+ 5. For each row of Table 6, except the header row, in table order, do
+ a. Let p be the Property value of the current row.
+ b. If p is "hour12", then
+ i. Let hc be dtf.[[HourCycle]].
+ ii. If hc is "h11" or "h12", let v be true.
+ iii. Else if, hc is "h23" or "h24", let v be false.
+ iv. Else, let v be undefined.
+ c. Else,
+ i. Let v be the value of dtf's internal slot whose name is the Internal Slot value of the current row.
+ d. If the Internal Slot value of the current row is an Internal Slot value in Table 7, then
+ i. If dtf.[[DateStyle]] is not undefined or dtf.[[TimeStyle]] is not undefined, then
+ 1. Let v be undefined.
+ e. If v is not undefined, then
+ i. Perform ! CreateDataPropertyOrThrow(options, p, v).
+
+ 11.1.2 CreateDateTimeFormat( newTarget, locales, options, required, defaults)
+ ...
+ 45. If dateTimeFormat.[[Hour]] is undefined, then
+
+ a. Set dateTimeFormat.[[HourCycle]] to undefined.
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+const hcValues = ["h11", "h12", "h23", "h24"];
+const hour12Values = ["h11", "h12"];
+
+for (const dateStyle of ["full", "long", "medium", "short"]) {
+ assert.sameValue(new Intl.DateTimeFormat([], { dateStyle }).resolvedOptions().dateStyle,
+ dateStyle,
+ `Should support dateStyle=${dateStyle}`);
+
+ /* Values passed via unicode extension key set to *undefined* */
+
+ for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, {
+ dateStyle,
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, undefined);
+ assert.sameValue(resolvedOptions.hour12, undefined);
+ }
+
+ /* Values passed via options set to *undefined**/
+
+ for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat("en-US", {
+ dateStyle,
+ hourCycle: hcValue
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, undefined);
+ assert.sameValue(resolvedOptions.hour12, undefined);
+ }
+
+ let resolvedOptions = new Intl.DateTimeFormat("en-US-u-hc-h12", {
+ dateStyle,
+ hourCycle: "h23"
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, undefined);
+ assert.sameValue(resolvedOptions.hour12, undefined);
+
+ resolvedOptions = new Intl.DateTimeFormat("fr", {
+ dateStyle,
+ hour12: true,
+ hourCycle: "h23"
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, undefined);
+ assert.sameValue(resolvedOptions.hour12, undefined);
+
+ resolvedOptions = new Intl.DateTimeFormat("fr-u-hc-h24", {
+ dateStyle,
+ hour12: true,
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, undefined);
+ assert.sameValue(resolvedOptions.hour12, undefined);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js
new file mode 100644
index 0000000000..9063e045a6
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js
@@ -0,0 +1,47 @@
+// Copyright 2019 Google Inc., 2023 Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions properly
+ reflect hourCycle settings.
+info: |
+ 11.3.7 Intl.DateTimeFormat.prototype.resolvedOptions()
+
+ 11.1.2 CreateDateTimeFormat ( dateTimeFormat, locales, options, required, defaults )
+ 23. Let dataLocaleData be localeData.[[<dataLocale>]].
+ 24. If hour12 is true, then
+ a. Let hc be dataLocaleData.[[hourCycle12]].
+ 25. Else if hour12 is false, then
+ a. Let hc be dataLocaleData.[[hourCycle24]].
+ 26. Else,
+ a. Assert: hour12 is undefined.
+ b. Let hc be r.[[hc]].
+ c. If hc is null, set hc to dataLocaleData.[[hourCycle]].
+ 27. Set dateTimeFormat.[[HourCycle]] to hc.
+
+locale: [en, fr, it, ja, zh, ko, ar, hi, en-u-hc-h24]
+---*/
+
+let locales = ["en", "fr", "it", "ja", "ja-u-hc-h11", "zh", "ko", "ar", "hi", "en-u-hc-h24"];
+
+locales.forEach(function(locale) {
+ let hcDefault = new Intl.DateTimeFormat(locale, { hour: "numeric" }).resolvedOptions().hourCycle;
+ if (hcDefault === "h11" || hcDefault === "h12") {
+ assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: true }).resolvedOptions().hourCycle, hcDefault);
+
+ // no locale has "h24" as a default. see https://github.com/tc39/ecma402/pull/758#issue-1622377292
+ assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: false }).resolvedOptions().hourCycle, "h23");
+ }
+
+ // however, "h24" can be set via locale extension.
+ if (hcDefault === "h23" || hcDefault === "h24") {
+ assert.sameValue(new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: false }).resolvedOptions().hourCycle, hcDefault);
+ }
+
+ let hcHour12 = new Intl.DateTimeFormat(locale, { hour: "numeric", hour12: true }).resolvedOptions().hourCycle;
+ assert(hcHour12 === "h11" || hcHour12 === "h12", "Expected `hourCycle`: " + hcHour12 + " to be in [\"h11\", \"h12\"]");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js
new file mode 100644
index 0000000000..e471fbdc60
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-timeStyle.js
@@ -0,0 +1,89 @@
+// Copyright 2019 Mozilla Corporation, Igalia S.L. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions properly
+ reflect hourCycle settings when using timeStyle.
+includes: [propertyHelper.js]
+features: [Intl.DateTimeFormat-datetimestyle, Array.prototype.includes]
+---*/
+
+const hcValues = ["h11", "h12", "h23", "h24"];
+const hour12Values = ["h11", "h12"];
+const dataPropertyDesc = { writable: true, enumerable: true, configurable: true };
+
+for (const timeStyle of ["full", "long", "medium", "short"]) {
+ assert.sameValue(new Intl.DateTimeFormat([], { timeStyle }).resolvedOptions().timeStyle,
+ timeStyle,
+ `Should support timeStyle=${timeStyle}`);
+
+ /* Values passed via unicode extension key work */
+
+ for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, {
+ timeStyle,
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, hcValue);
+ assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue));
+ }
+
+ /* Values passed via options work */
+
+ for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat("en-US", {
+ timeStyle,
+ hourCycle: hcValue
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, hcValue);
+ assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue));
+
+ verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc);
+ verifyProperty(resolvedOptions, "hour12", dataPropertyDesc);
+ }
+
+ /* When both extension key and option is passed, option takes precedence */
+
+ let resolvedOptions = new Intl.DateTimeFormat("en-US-u-hc-h12", {
+ timeStyle,
+ hourCycle: "h23"
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, "h23");
+ assert.sameValue(resolvedOptions.hour12, false);
+
+ verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc);
+ verifyProperty(resolvedOptions, "hour12", dataPropertyDesc);
+
+ /* When hour12 and hourCycle are set, hour12 takes precedence */
+
+ resolvedOptions = new Intl.DateTimeFormat("fr", {
+ timeStyle,
+ hour12: true,
+ hourCycle: "h23"
+ }).resolvedOptions();
+
+ assert(hour12Values.includes(resolvedOptions.hourCycle));
+ assert.sameValue(resolvedOptions.hour12, true);
+
+ verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc);
+ verifyProperty(resolvedOptions, "hour12", dataPropertyDesc);
+
+ /* When hour12 and extension key are set, hour12 takes precedence */
+
+ resolvedOptions = new Intl.DateTimeFormat("fr-u-hc-h24", {
+ timeStyle,
+ hour12: true,
+ }).resolvedOptions();
+
+ assert(hour12Values.includes(resolvedOptions.hourCycle));
+ assert.sameValue(resolvedOptions.hour12, true);
+
+ verifyProperty(resolvedOptions, "hourCycle", dataPropertyDesc);
+ verifyProperty(resolvedOptions, "hour12", dataPropertyDesc);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js
new file mode 100644
index 0000000000..c92578e3af
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js
@@ -0,0 +1,102 @@
+// Copyright 2017 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions properly
+ reflect hourCycle settings.
+info: |
+ 12.4.5 Intl.DateTimeFormat.prototype.resolvedOptions()
+
+includes: [propertyHelper.js]
+features: [Array.prototype.includes]
+---*/
+
+/* Values passed via unicode extension key work */
+
+const hcValues = ['h11', 'h12', 'h23', 'h24'];
+const hour12Values = ['h11', 'h12'];
+
+const dataPropertyDesc = { writable: true, enumerable: true, configurable: true };
+
+for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat(`de-u-hc-${hcValue}`, {
+ hour: 'numeric'
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, hcValue);
+ assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue));
+
+ verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc);
+ verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc);
+}
+
+/* Values passed via options work */
+
+for (const hcValue of hcValues) {
+ const resolvedOptions = new Intl.DateTimeFormat(`en-US`, {
+ hour: 'numeric',
+ hourCycle: hcValue
+ }).resolvedOptions();
+
+ assert.sameValue(resolvedOptions.hourCycle, hcValue);
+ assert.sameValue(resolvedOptions.hour12, hour12Values.includes(hcValue));
+
+ verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc);
+ verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc);
+}
+
+/* When both extension key and option is passed, option takes precedence */
+
+let resolvedOptions = new Intl.DateTimeFormat(`en-US-u-hc-h12`, {
+ hour: 'numeric',
+ hourCycle: 'h23'
+}).resolvedOptions();
+
+assert.sameValue(resolvedOptions.hourCycle, 'h23');
+assert.sameValue(resolvedOptions.hour12, false);
+
+verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc);
+verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc);
+
+/* When hour12 and hourCycle are set, hour12 takes precedence */
+
+resolvedOptions = new Intl.DateTimeFormat(`fr`, {
+ hour: 'numeric',
+ hour12: true,
+ hourCycle: 'h23'
+}).resolvedOptions();
+
+assert(hour12Values.includes(resolvedOptions.hourCycle));
+assert.sameValue(resolvedOptions.hour12, true);
+
+verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc);
+verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc);
+
+/* When hour12 and extension key are set, hour12 takes precedence */
+
+resolvedOptions = new Intl.DateTimeFormat(`fr-u-hc-h24`, {
+ hour: 'numeric',
+ hour12: true,
+}).resolvedOptions();
+
+assert(hour12Values.includes(resolvedOptions.hourCycle));
+assert.sameValue(resolvedOptions.hour12, true);
+
+verifyProperty(resolvedOptions, 'hourCycle', dataPropertyDesc);
+verifyProperty(resolvedOptions, 'hour12', dataPropertyDesc);
+
+/* When the hour is not in the pattern, hourCycle and hour12 are not defined. */
+
+resolvedOptions = new Intl.DateTimeFormat("fr", {
+ hourCycle: "h12",
+ hour12: false,
+}).resolvedOptions();
+
+assert.sameValue(resolvedOptions.hour, undefined,
+ "Precondition: hour should not be included by default");
+assert.sameValue(resolvedOptions.hourCycle, undefined);
+assert.sameValue(resolvedOptions.hour12, undefined);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js
new file mode 100644
index 0000000000..7f0bf43eb6
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/length.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions.length is 0.
+info: |
+ Intl.DateTimeFormat.prototype.resolvedOptions ()
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every built-in function object, including constructors, has a length
+ property whose value is an integer. Unless otherwise specified, this
+ value is equal to the largest number of named arguments shown in the
+ subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which
+ are shown using the form «...name») are not included in the default
+ argument count.
+ Unless otherwise specified, the length property of a built-in function
+ object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: true }.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.prototype.resolvedOptions, "length", {
+ value: 0,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js
new file mode 100644
index 0000000000..33915a9338
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/name.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ Intl.DateTimeFormat.prototype.resolvedOptions.name is "resolvedOptions".
+info: |
+ 12.4.4 Intl.DateTimeFormat.prototype.resolvedOptions ()
+
+ 17 ECMAScript Standard Built-in Objects:
+ Every built-in Function object, including constructors, that is not
+ identified as an anonymous function has a name property whose value
+ is a String.
+
+ Unless otherwise specified, the name property of a built-in Function
+ object, if it exists, has the attributes { [[Writable]]: false,
+ [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.prototype.resolvedOptions, "name", {
+ value: "resolvedOptions",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js
new file mode 100644
index 0000000000..0e81ebb1be
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/no-instanceof.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: >
+ Tests that Intl.DateTimeFormat.prototype.resolvedOptions calls
+ OrdinaryHasInstance instead of the instanceof operator which includes a
+ Symbol.hasInstance lookup and call among other things.
+info: >
+ UnwrapDateTimeFormat ( dtf )
+ 2. If dtf does not have an [[InitializedDateTimeFormat]] internal slot and
+ ? OrdinaryHasInstance(%DateTimeFormat%, dtf) is true, then
+ a. Return ? Get(dtf, %Intl%.[[FallbackSymbol]]).
+---*/
+
+const dtf = Object.create(Intl.DateTimeFormat.prototype);
+
+Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
+ get() { throw new Test262Error(); }
+});
+
+assert.throws(TypeError, () => dtf.resolvedOptions());
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js
new file mode 100644
index 0000000000..9f89b6106c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-basic.js
@@ -0,0 +1,30 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: Tests that offset time zones are correctly normalized in resolvedOptions() output.
+---*/
+let validOffsetTimeZones = [
+ '+03',
+ '+13',
+ '+23',
+ '-07',
+ '-14',
+ '-21',
+ '+01:03',
+ '+15:59',
+ '+22:27',
+ '-02:32',
+ '-17:01',
+ '-22:23',
+];
+validOffsetTimeZones.forEach((timeZone) => {
+ let df = new Intl.DateTimeFormat(undefined, {timeZone});
+ let expected = timeZone;
+ if (expected.length == 3) {
+ expected += ":00";
+ }
+ assert.sameValue(df.resolvedOptions().timeZone, expected, timeZone);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js
new file mode 100644
index 0000000000..714286e287
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/offset-timezone-change.js
@@ -0,0 +1,35 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-createdatetimeformat
+description: Tests that offset time zones are correctly normalized in resolvedOptions() output.
+---*/
+let validOffsetTimeZones = {
+ '-00': '+00:00',
+ '-00:00': '+00:00',
+ '−00:00': '+00:00',
+ '+00': '+00:00',
+ '+0000': '+00:00',
+ '+0300': '+03:00',
+ '+03:00': '+03:00',
+ '+13:00': '+13:00',
+ '+2300': '+23:00',
+ '-07:00': '-07:00',
+ '-14': '-14:00',
+ '-2100': '-21:00',
+ '−2200': '-22:00',
+ '+0103': '+01:03',
+ '+15:59': '+15:59',
+ '+2227': '+22:27',
+ '-02:32': '-02:32',
+ '-1701': '-17:01',
+ '-22:23': '-22:23',
+ '−22:53': '-22:53',
+};
+Object.keys(validOffsetTimeZones).forEach((timeZone) => {
+ let df = new Intl.DateTimeFormat(undefined, {timeZone});
+ let expected = validOffsetTimeZones[timeZone];
+ assert.sameValue(df.resolvedOptions().timeZone, expected, timeZone);
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js
new file mode 100644
index 0000000000..971ba2ac42
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-dayPeriod.js
@@ -0,0 +1,38 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+const options = new Intl.DateTimeFormat([], {
+ "dayPeriod": "short",
+ "hour": "numeric",
+ "minute": "numeric",
+}).resolvedOptions();
+
+const expected = [
+ "locale",
+ "calendar",
+ "numberingSystem",
+ "timeZone",
+ "hourCycle",
+ "hour12",
+ "dayPeriod",
+ "hour",
+ "minute",
+];
+
+let actual = Object.getOwnPropertyNames(options);
+
+// Ensure all expected items are in actual and also allow other properties
+// implemented in new proposals.
+assert(actual.indexOf("locale") > -1, "\"locale\" is present");
+for (var i = 1; i < expected.length; i++) {
+ // Ensure the order as expected but allow additional new property in between
+ assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js
new file mode 100644
index 0000000000..2fc022b0da
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-fractionalSecondDigits.js
@@ -0,0 +1,36 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+const options = new Intl.DateTimeFormat([], {
+ "fractionalSecondDigits": 3,
+ "minute": "numeric",
+ "second": "numeric",
+}).resolvedOptions();
+
+const expected = [
+ "locale",
+ "calendar",
+ "numberingSystem",
+ "timeZone",
+ "minute",
+ "second",
+ "fractionalSecondDigits",
+];
+
+let actual = Object.getOwnPropertyNames(options);
+
+// Ensure all expected items are in actual and also allow other properties
+// implemented in new proposals.
+assert(actual.indexOf("locale") > -1, "\"locale\" is present");
+for (var i = 1; i < expected.length; i++) {
+ // Ensure the order as expected but allow additional new property in between
+ assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js
new file mode 100644
index 0000000000..2546b1b746
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order-style.js
@@ -0,0 +1,42 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+features: [Intl.DateTimeFormat-datetimestyle]
+---*/
+
+const options = new Intl.DateTimeFormat([], {
+ "hourCycle": "h24",
+ "weekday": "short",
+ "era": "short",
+ "year": "numeric",
+ "month": "numeric",
+ "day": "numeric",
+ "hour": "numeric",
+ "minute": "numeric",
+ "second": "numeric",
+ "timeZoneName": "short",
+}).resolvedOptions();
+
+const expected = [
+ "locale",
+ "calendar",
+ "numberingSystem",
+ "timeZone",
+ "hourCycle",
+ "hour12",
+];
+
+let actual = Object.getOwnPropertyNames(options);
+
+// Ensure all expected items are in actual and also allow other properties
+// implemented in new proposals.
+assert(actual.indexOf("locale") > -1, "\"locale\" is present");
+for (var i = 1; i < expected.length; i++) {
+ // Ensure the order as expected but allow additional new property in between
+ assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
new file mode 100644
index 0000000000..13b318c5e4
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
@@ -0,0 +1,50 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+---*/
+
+const options = new Intl.DateTimeFormat([], {
+ "hourCycle": "h24",
+ "weekday": "short",
+ "era": "short",
+ "year": "numeric",
+ "month": "numeric",
+ "day": "numeric",
+ "hour": "numeric",
+ "minute": "numeric",
+ "second": "numeric",
+ "timeZoneName": "short",
+}).resolvedOptions();
+
+const expected = [
+ "locale",
+ "calendar",
+ "numberingSystem",
+ "timeZone",
+ "hourCycle",
+ "hour12",
+ "weekday",
+ "era",
+ "year",
+ "month",
+ "day",
+ "hour",
+ "minute",
+ "second",
+ "timeZoneName",
+];
+
+let actual = Object.getOwnPropertyNames(options);
+
+// Ensure all expected items are in actual and also allow other properties
+// implemented in new proposals.
+assert(actual.indexOf("locale") > -1, "\"locale\" is present");
+for (var i = 1; i < expected.length; i++) {
+ // Ensure the order as expected but allow additional new property in between
+ assert(actual.indexOf(expected[i-1]) < actual.indexOf(expected[i]), `"${expected[i-1]}" precedes "${expected[i]}"`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js
new file mode 100644
index 0000000000..b5918cfa1e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/prop-desc.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: >
+ "resolvedOptions" property of Intl.DateTimeFormat.prototype.
+info: |
+ Intl.DateTimeFormat.prototype.resolvedOptions ()
+
+ 7 Requirements for Standard Built-in ECMAScript Objects
+
+ Unless specified otherwise in this document, the objects, functions, and constructors
+ described in this standard are subject to the generic requirements and restrictions
+ specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+ Specification, 9th edition, clause 17, or successor.
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every other data property described in clauses 18 through 26 and in Annex B.2 has the
+ attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+ unless otherwise specified.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.prototype, "resolvedOptions", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js
new file mode 100644
index 0000000000..95d5f4c666
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js
@@ -0,0 +1,88 @@
+// Copyright 2018 André Bargull. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.prototype.resolvedOptions
+description: >
+ The resolved locale doesn't include a hc Unicode extension value if the
+ hour12 or hourCycle option is also present.
+info: |
+ 11.1.2 CreateDateTimeFormat( dateTimeFormat, locales, options, required, defaults )
+ ...
+ 13. Let hour12 be ? GetOption(options, "hour12", boolean, empty, undefined).
+ 14. Let hourCycle be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined).
+ 15. If hour12 is not undefined, then
+ a. Set hourCycle to null.
+ ...
+
+ 9.2.6 ResolveLocale(availableLocales, requestedLocales, options, relevantExtensionKeys, localeData)
+ ...
+ 8. For each element key of relevantExtensionKeys in List order, do
+ ...
+ i. If options has a field [[<key>]], then
+ i. Let optionsValue be options.[[<key>]].
+ ii. Assert: Type(optionsValue) is either String, Undefined, or Null.
+ iii. If keyLocaleData contains optionsValue, then
+ 1. If SameValue(optionsValue, value) is false, then
+ a. Let value be optionsValue.
+ b. Let supportedExtensionAddition be "".
+ ...
+---*/
+
+var defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale;
+var defaultLocaleWithHourCycle = defaultLocale + "-u-hc-h11";
+
+function assertLocale(locale, expectedLocale, options, message) {
+ var resolved = new Intl.DateTimeFormat(locale, {
+ hour: "2-digit",
+ hour12: options.hour12,
+ hourCycle: options.hourCycle,
+ }).resolvedOptions();
+ assert.sameValue(resolved.locale, expectedLocale, message + " (With hour option.)");
+
+ // Also test the case when no hour option is present at all.
+ // The resolved options don't include hour12 and hourCycle if the date-time
+ // formatter doesn't include an hour option. This restriction doesn't apply
+ // to the hc Unicode extension value.
+ resolved = new Intl.DateTimeFormat(locale, {
+ hour12: options.hour12,
+ hourCycle: options.hourCycle,
+ }).resolvedOptions();
+ assert.sameValue(resolved.locale, expectedLocale, message + " (Without hour option.)");
+}
+
+assertLocale(defaultLocaleWithHourCycle, defaultLocale, {
+ hour12: false,
+ hourCycle: "h23",
+}, "hour12 and hourCycle options and hc Unicode extension value are present.");
+
+assertLocale(defaultLocaleWithHourCycle, defaultLocale, {
+ hour12: false,
+}, "hour12 option and hc Unicode extension value are present.");
+
+assertLocale(defaultLocaleWithHourCycle, defaultLocale, {
+ hourCycle: "h23",
+}, "hourCycle option and hc Unicode extension value are present.");
+
+assertLocale(defaultLocaleWithHourCycle, defaultLocaleWithHourCycle, {
+}, "Only hc Unicode extension value is present.");
+
+// And make sure the hc Unicode extension doesn't get added if it's not present
+// in the requested locale.
+assertLocale(defaultLocale, defaultLocale, {
+ hour12: false,
+ hourCycle: "h23",
+}, "hour12 and hourCycle options are present, but no hc Unicode extension value.");
+
+assertLocale(defaultLocale, defaultLocale, {
+ hour12: false,
+}, "hourCycle option is present, but no hc Unicode extension value.");
+
+assertLocale(defaultLocale, defaultLocale, {
+ hourCycle: "h23",
+}, "hourCycle option is present, but no hc Unicode extension value.");
+
+assertLocale(defaultLocale, defaultLocale, {
+}, "No options are present and no hc Unicode extension value.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/shell.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js
new file mode 100644
index 0000000000..34db44141b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-datetimeformat-prototype.js
@@ -0,0 +1,17 @@
+// Copyright 2012 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-properties-of-intl-datetimeformat-prototype-object
+description: >
+ Tests that Intl.DateTimeFormat.prototype is not an object that has
+ been initialized as an Intl.DateTimeFormat.
+author: Roozbeh Pournader
+---*/
+
+// test by calling a function that should fail as "this" is not an object
+// initialized as an Intl.DateTimeFormat
+assert.throws(TypeError, () => Intl.DateTimeFormat.prototype.format(0),
+ "Intl.DateTimeFormat's prototype is not an object that has been initialized as an Intl.DateTimeFormat");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js
new file mode 100644
index 0000000000..4805ca2f69
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/this-value-not-datetimeformat.js
@@ -0,0 +1,28 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.3_b
+description: >
+ Tests that Intl.DateTimeFormat.prototype functions throw a
+ TypeError if called on a non-object value or an object that hasn't
+ been initialized as a DateTimeFormat.
+author: Norbert Lindenberg
+---*/
+
+var functions = {
+ "format getter": Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get,
+ resolvedOptions: Intl.DateTimeFormat.prototype.resolvedOptions
+};
+var invalidTargets = [undefined, null, true, 0, "DateTimeFormat", [], {}];
+
+Object.getOwnPropertyNames(functions).forEach(function (functionName) {
+ var f = functions[functionName];
+ invalidTargets.forEach(function (target) {
+ assert.throws(TypeError, function() {
+ f.call(target);
+ }, "Calling " + functionName + " on " + target + " was not rejected.");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/shell.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js
new file mode 100644
index 0000000000..69b853ad0a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-changed-tag.js
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype-@@tostringtag
+description: >
+ Object.prototype.toString utilizes Intl.DateTimeFormat.prototype[@@toStringTag].
+info: |
+ Object.prototype.toString ( )
+
+ [...]
+ 14. Else, let builtinTag be "Object".
+ 15. Let tag be ? Get(O, @@toStringTag).
+ 16. If Type(tag) is not String, set tag to builtinTag.
+ 17. Return the string-concatenation of "[object ", tag, and "]".
+
+ Intl.DateTimeFormat.prototype [ @@toStringTag ]
+
+ This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+features: [Symbol.toStringTag]
+---*/
+
+Object.defineProperty(Intl.DateTimeFormat.prototype, Symbol.toStringTag, {
+ value: "test262",
+});
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object test262]");
+assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object test262]");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js
new file mode 100644
index 0000000000..170562a720
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString-removed-tag.js
@@ -0,0 +1,24 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype-@@tostringtag
+description: >
+ Object.prototype.toString doesn't special-case neither Intl.DateTimeFormat instances nor its prototype.
+info: |
+ Object.prototype.toString ( )
+
+ [...]
+ 14. Else, let builtinTag be "Object".
+ 15. Let tag be ? Get(O, @@toStringTag).
+ 16. If Type(tag) is not String, set tag to builtinTag.
+ 17. Return the string-concatenation of "[object ", tag, and "]".
+features: [Symbol.toStringTag]
+---*/
+
+delete Intl.DateTimeFormat.prototype[Symbol.toStringTag];
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object Object]");
+assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object Object]");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js
new file mode 100644
index 0000000000..f8e5d3db50
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toString.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype-@@tostringtag
+description: >
+ Object.prototype.toString utilizes Intl.DateTimeFormat.prototype[@@toStringTag].
+info: |
+ Object.prototype.toString ( )
+
+ [...]
+ 14. Else, let builtinTag be "Object".
+ 15. Let tag be ? Get(O, @@toStringTag).
+ 16. If Type(tag) is not String, set tag to builtinTag.
+ 17. Return the string-concatenation of "[object ", tag, and "]".
+
+ Intl.DateTimeFormat.prototype [ @@toStringTag ]
+
+ The initial value of the @@toStringTag property is the String value "Intl.DateTimeFormat".
+features: [Symbol.toStringTag]
+---*/
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.prototype), "[object Intl.DateTimeFormat]");
+assert.sameValue(Object.prototype.toString.call(new Intl.DateTimeFormat()), "[object Intl.DateTimeFormat]");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js
new file mode 100644
index 0000000000..b118adeac8
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/toStringTag/toStringTag.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype-@@tostringtag
+description: >
+ Property descriptor of Intl.DateTimeFormat.prototype[@@toStringTag].
+info: |
+ Intl.DateTimeFormat.prototype [ @@toStringTag ]
+
+ The initial value of the @@toStringTag property is the String value "Intl.DateTimeFormat".
+
+ This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+features: [Symbol.toStringTag]
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.prototype, Symbol.toStringTag, {
+ value: "Intl.DateTimeFormat",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js b/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js
new file mode 100644
index 0000000000..6a17fc5edb
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/required-date-time-formats.js
@@ -0,0 +1,48 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.2.3_c
+description: >
+ Tests that Intl.DateTimeFormat provides the required date-time
+ format component subsets.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+var locales = ["de-DE", "en-US", "hi-IN", "id-ID", "ja-JP", "th-TH", "zh-Hans-CN", "zh-Hant-TW", "zxx"];
+var subsets = [
+ {weekday: "long", year: "numeric", month: "numeric", day: "numeric",
+ hour: "numeric", minute: "numeric", second: "numeric"},
+ {weekday: "long", year: "numeric", month: "numeric", day: "numeric"},
+ {year: "numeric", month: "numeric", day: "numeric"},
+ {year: "numeric", month: "numeric"},
+ {month: "numeric", day: "numeric"},
+ {hour: "numeric", minute: "numeric", second: "numeric"},
+ {hour: "numeric", minute: "numeric"}
+];
+
+locales.forEach(function (locale) {
+ subsets.forEach(function (subset) {
+ var format = new Intl.DateTimeFormat([locale], subset);
+ var actual = format.resolvedOptions();
+ getDateTimeComponents().forEach(function (component) {
+ if (actual.hasOwnProperty(component)) {
+ assert(subset.hasOwnProperty(component),
+ "Unrequested component " + component +
+ " added to requested subset " + JSON.stringify(subset) +
+ "; locale " + locale + ".");
+ assert.notSameValue(getDateTimeComponentValues(component).indexOf(actual[component]), -1,
+ "Invalid value " + actual[component] + " for date-time component " + component + "." +
+ " (Testing locale " + locale + "; subset " + JSON.stringify(subset) + ")");
+ } else {
+ assert.sameValue(subset.hasOwnProperty(component), false,
+ "Missing component " + component +
+ " from requested subset " + JSON.stringify(subset) +
+ "; locale " + locale + ".");
+ }
+ });
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/shell.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js b/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js
new file mode 100644
index 0000000000..c7167676b8
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/subclassing.js
@@ -0,0 +1,30 @@
+// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.2
+description: Tests that Intl.DateTimeFormat can be subclassed.
+author: Norbert Lindenberg
+includes: [compareArray.js]
+---*/
+
+// get a date-time format and have it format an array of dates for comparison with the subclass
+var locales = ["tlh", "id", "en"];
+var a = [new Date(0), Date.now(), new Date(Date.parse("1989-11-09T17:57:00Z"))];
+var referenceDateTimeFormat = new Intl.DateTimeFormat(locales);
+var referenceFormatted = a.map(referenceDateTimeFormat.format);
+
+class MyDateTimeFormat extends Intl.DateTimeFormat {
+ constructor(locales, options) {
+ super(locales, options);
+ // could initialize MyDateTimeFormat properties
+ }
+ // could add methods to MyDateTimeFormat.prototype
+}
+
+var format = new MyDateTimeFormat(locales);
+var actual = a.map(format.format);
+assert.compareArray(actual, referenceFormatted);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js
new file mode 100644
index 0000000000..8b4e2884e7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/basic.js
@@ -0,0 +1,25 @@
+// Copyright 2012 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.2.2_a
+description: >
+ Tests that Intl.DateTimeFormat has a supportedLocalesOf property,
+ and it works as planned.
+author: Roozbeh Pournader
+---*/
+
+var defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale;
+var notSupported = 'zxx'; // "no linguistic content"
+var requestedLocales = [defaultLocale, notSupported];
+
+var supportedLocales;
+
+assert(Intl.DateTimeFormat.hasOwnProperty('supportedLocalesOf'), "Intl.DateTimeFormat doesn't have a supportedLocalesOf property.");
+
+supportedLocales = Intl.DateTimeFormat.supportedLocalesOf(requestedLocales);
+assert.sameValue(supportedLocales.length, 1, 'The length of supported locales list is not 1.');
+
+assert.sameValue(supportedLocales[0], defaultLocale, 'The default locale is not returned in the supported list.');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/browser.js
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js
new file mode 100644
index 0000000000..5af3ea6504
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/builtin.js
@@ -0,0 +1,30 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.2.2_L15
+description: >
+ Tests that Intl.DateTimeFormat.supportedLocalesOf meets the
+ requirements for built-in objects defined by the introduction of
+ chapter 17 of the ECMAScript Language Specification.
+author: Norbert Lindenberg
+includes: [isConstructor.js]
+features: [Reflect.construct]
+---*/
+
+assert.sameValue(Object.prototype.toString.call(Intl.DateTimeFormat.supportedLocalesOf), "[object Function]",
+ "The [[Class]] internal property of a built-in function must be " +
+ "\"Function\".");
+
+assert(Object.isExtensible(Intl.DateTimeFormat.supportedLocalesOf),
+ "Built-in objects must be extensible.");
+
+assert.sameValue(Object.getPrototypeOf(Intl.DateTimeFormat.supportedLocalesOf), Function.prototype);
+
+assert.sameValue(Intl.DateTimeFormat.supportedLocalesOf.hasOwnProperty("prototype"), false,
+ "Built-in functions that aren't constructors must not have a prototype property.");
+
+assert.sameValue(isConstructor(Intl.DateTimeFormat.supportedLocalesOf), false,
+ "Built-in functions don't implement [[Construct]] unless explicitly specified.");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js
new file mode 100644
index 0000000000..cf5e2db00b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/length.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.supportedlocalesof
+description: >
+ Intl.DateTimeFormat.supportedLocalesOf.length is 1.
+info: |
+ Intl.DateTimeFormat.supportedLocalesOf ( locales [ , options ] )
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every built-in function object, including constructors, has a length
+ property whose value is an integer. Unless otherwise specified, this
+ value is equal to the largest number of named arguments shown in the
+ subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which
+ are shown using the form «...name») are not included in the default
+ argument count.
+ Unless otherwise specified, the length property of a built-in function
+ object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
+ [[Configurable]]: true }.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.supportedLocalesOf, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js
new file mode 100644
index 0000000000..ca0654027b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/name.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.DateTimeFormat.supportedLocalesOf
+description: >
+ Intl.DateTimeFormat.supportedLocalesOf.name is "supportedLocalesOf".
+info: |
+ 12.3.2 Intl.DateTimeFormat.supportedLocalesOf (locales [ , options ])
+
+ 17 ECMAScript Standard Built-in Objects:
+ Every built-in Function object, including constructors, that is not
+ identified as an anonymous function has a name property whose value
+ is a String.
+
+ Unless otherwise specified, the name property of a built-in Function
+ object, if it exists, has the attributes { [[Writable]]: false,
+ [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat.supportedLocalesOf, "name", {
+ value: "supportedLocalesOf",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js
new file mode 100644
index 0000000000..d5e93a5be4
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/prop-desc.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.supportedlocalesof
+description: >
+ "supportedLocalesOf" property of Intl.DateTimeFormat.
+info: |
+ Intl.DateTimeFormat.supportedLocalesOf ( locales [ , options ] )
+
+ 7 Requirements for Standard Built-in ECMAScript Objects
+
+ Unless specified otherwise in this document, the objects, functions, and constructors
+ described in this standard are subject to the generic requirements and restrictions
+ specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+ Specification, 9th edition, clause 17, or successor.
+
+ 17 ECMAScript Standard Built-in Objects:
+
+ Every other data property described in clauses 18 through 26 and in Annex B.2 has the
+ attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+ unless otherwise specified.
+
+includes: [propertyHelper.js]
+---*/
+
+verifyProperty(Intl.DateTimeFormat, "supportedLocalesOf", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js
new file mode 100644
index 0000000000..47ed85a18c
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/supportedLocalesOf/taint-Object-prototype.js
@@ -0,0 +1,16 @@
+// Copyright 2013 Mozilla Corporation. All rights reserved.
+// This code is governed by the license found in the LICENSE file.
+
+/*---
+es5id: 12.2.2_b
+description: >
+ Tests that Intl.DateTimeFormat.supportedLocalesOf doesn't access
+ arguments that it's not given.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+taintDataProperty(Object.prototype, "1");
+new Intl.DateTimeFormat("und");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js
new file mode 100644
index 0000000000..a05e77b80e
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-date-time-components.js
@@ -0,0 +1,18 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_22
+description: >
+ Tests that the behavior of a Record is not affected by
+ adversarial changes to Object.prototype.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZone"]);
+
+var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
+assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + ".");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js
new file mode 100644
index 0000000000..6b51db065d
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-dayPeriod.js
@@ -0,0 +1,18 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that the behavior of a Record is not affected by
+ adversarial changes to Object.prototype.
+includes: [testIntl.js]
+features: [Intl.DateTimeFormat-dayPeriod]
+---*/
+
+taintProperties(["dayPeriod"]);
+
+var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
+assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + ".");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js
new file mode 100644
index 0000000000..8792628e97
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype-fractionalSecondDigits.js
@@ -0,0 +1,18 @@
+// Copyright 2019 Google Inc. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-createdatetimeformat
+description: >
+ Tests that the behavior of a Record is not affected by
+ adversarial changes to Object.prototype.
+includes: [testIntl.js]
+features: [Intl.DateTimeFormat-fractionalSecondDigits]
+---*/
+
+taintProperties(["fractionalSecondDigits"]);
+
+var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
+assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + ".");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js
new file mode 100644
index 0000000000..5dd7b61535
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/taint-Object-prototype.js
@@ -0,0 +1,18 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_5
+description: >
+ Tests that the behavior of a Record is not affected by
+ adversarial changes to Object.prototype.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+taintProperties(["localeMatcher"]);
+
+var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale;
+assert(isCanonicalizedStructurallyValidLanguageTag(locale), "DateTimeFormat returns invalid locale " + locale + ".");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js
new file mode 100644
index 0000000000..a0e0a16dc7
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-date-time-components.js
@@ -0,0 +1,17 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_23
+description: >
+ Tests that the options for the date and time components are
+ processed correctly.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+getDateTimeComponents().forEach(function (component) {
+ testOption(Intl.DateTimeFormat, component, "string", getDateTimeComponentValues(component), undefined, {isILD: true});
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js
new file mode 100644
index 0000000000..41c25d6e99
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-formatMatcher.js
@@ -0,0 +1,13 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_25
+description: Tests that the option formatMatcher is processed correctly.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+testOption(Intl.DateTimeFormat, "formatMatcher", "string", ["basic", "best fit"], "best fit", {noReturn: true});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js
new file mode 100644
index 0000000000..c6a4124bf9
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-hour12.js
@@ -0,0 +1,16 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_18
+description: Tests that the option hour12 is processed correctly.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined,
+ {extra: {any: {hour: "numeric", minute: "numeric"}}});
+testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined,
+ {noReturn: true});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js b/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js
new file mode 100644
index 0000000000..6adf184682
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/test-option-localeMatcher.js
@@ -0,0 +1,13 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 12.1.1_6
+description: Tests that the option localeMatcher is processed correctly.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+testOption(Intl.DateTimeFormat, "localeMatcher", "string", ["lookup", "best fit"], "best fit", {noReturn: true});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js b/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js
new file mode 100644
index 0000000000..e96110d1ca
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/this-value-ignored.js
@@ -0,0 +1,37 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl-datetimeformat-constructor
+description: >
+ Tests that the this-value is ignored in DateTimeFormat, if the this-value
+ isn't a DateTimeFormat instance.
+author: Norbert Lindenberg
+includes: [testIntl.js]
+---*/
+
+testWithIntlConstructors(function (Constructor) {
+ if (Constructor === Intl.DateTimeFormat)
+ return;
+
+ var obj, newObj;
+
+ // variant 1: use constructor in a "new" expression
+ obj = new Constructor();
+ newObj = Intl.DateTimeFormat.call(obj);
+ assert.notSameValue(obj, newObj, "DateTimeFormat object created with \"new\" was not ignored as this-value.");
+
+ // variant 2: use constructor as a function
+ if (Constructor !== Intl.Collator &&
+ Constructor !== Intl.NumberFormat &&
+ Constructor !== Intl.DateTimeFormat)
+ {
+ // Newer Intl constructors are not callable as a function.
+ return;
+ }
+ obj = Constructor();
+ newObj = Intl.DateTimeFormat.call(obj);
+ assert.notSameValue(obj, newObj, "DateTimeFormat object created with constructor as function was not ignored as this-value.");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js
new file mode 100644
index 0000000000..f52468843a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-case-insensitive.js
@@ -0,0 +1,638 @@
+// Copyright (C) 2023 Justin Grant. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializedatetimeformat
+description: Time zone identifiers are case-normalized
+---*/
+
+const timeZoneIdentifiers = [
+ // IANA TZDB Zone names
+ "Africa/Abidjan",
+ "Africa/Algiers",
+ "Africa/Bissau",
+ "Africa/Cairo",
+ "Africa/Casablanca",
+ "Africa/Ceuta",
+ "Africa/El_Aaiun",
+ "Africa/Johannesburg",
+ "Africa/Juba",
+ "Africa/Khartoum",
+ "Africa/Lagos",
+ "Africa/Maputo",
+ "Africa/Monrovia",
+ "Africa/Nairobi",
+ "Africa/Ndjamena",
+ "Africa/Sao_Tome",
+ "Africa/Tripoli",
+ "Africa/Tunis",
+ "Africa/Windhoek",
+ "America/Adak",
+ "America/Anchorage",
+ "America/Araguaina",
+ "America/Argentina/Buenos_Aires",
+ "America/Argentina/Catamarca",
+ "America/Argentina/Cordoba",
+ "America/Argentina/Jujuy",
+ "America/Argentina/La_Rioja",
+ "America/Argentina/Mendoza",
+ "America/Argentina/Rio_Gallegos",
+ "America/Argentina/Salta",
+ "America/Argentina/San_Juan",
+ "America/Argentina/San_Luis",
+ "America/Argentina/Tucuman",
+ "America/Argentina/Ushuaia",
+ "America/Asuncion",
+ "America/Bahia",
+ "America/Bahia_Banderas",
+ "America/Barbados",
+ "America/Belem",
+ "America/Belize",
+ "America/Boa_Vista",
+ "America/Bogota",
+ "America/Boise",
+ "America/Cambridge_Bay",
+ "America/Campo_Grande",
+ "America/Cancun",
+ "America/Caracas",
+ "America/Cayenne",
+ "America/Chicago",
+ "America/Chihuahua",
+ // 'America/Ciudad_Juarez' // uncomment after Node supports this ID added in TZDB 2022g
+ "America/Costa_Rica",
+ "America/Cuiaba",
+ "America/Danmarkshavn",
+ "America/Dawson",
+ "America/Dawson_Creek",
+ "America/Denver",
+ "America/Detroit",
+ "America/Edmonton",
+ "America/Eirunepe",
+ "America/El_Salvador",
+ "America/Fort_Nelson",
+ "America/Fortaleza",
+ "America/Glace_Bay",
+ "America/Goose_Bay",
+ "America/Grand_Turk",
+ "America/Guatemala",
+ "America/Guayaquil",
+ "America/Guyana",
+ "America/Halifax",
+ "America/Havana",
+ "America/Hermosillo",
+ "America/Indiana/Indianapolis",
+ "America/Indiana/Knox",
+ "America/Indiana/Marengo",
+ "America/Indiana/Petersburg",
+ "America/Indiana/Tell_City",
+ "America/Indiana/Vevay",
+ "America/Indiana/Vincennes",
+ "America/Indiana/Winamac",
+ "America/Inuvik",
+ "America/Iqaluit",
+ "America/Jamaica",
+ "America/Juneau",
+ "America/Kentucky/Louisville",
+ "America/Kentucky/Monticello",
+ "America/La_Paz",
+ "America/Lima",
+ "America/Los_Angeles",
+ "America/Maceio",
+ "America/Managua",
+ "America/Manaus",
+ "America/Martinique",
+ "America/Matamoros",
+ "America/Mazatlan",
+ "America/Menominee",
+ "America/Merida",
+ "America/Metlakatla",
+ "America/Mexico_City",
+ "America/Miquelon",
+ "America/Moncton",
+ "America/Monterrey",
+ "America/Montevideo",
+ "America/New_York",
+ "America/Nome",
+ "America/Noronha",
+ "America/North_Dakota/Beulah",
+ "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem",
+ "America/Nuuk",
+ "America/Ojinaga",
+ "America/Panama",
+ "America/Paramaribo",
+ "America/Phoenix",
+ "America/Port-au-Prince",
+ "America/Porto_Velho",
+ "America/Puerto_Rico",
+ "America/Punta_Arenas",
+ "America/Rankin_Inlet",
+ "America/Recife",
+ "America/Regina",
+ "America/Resolute",
+ "America/Rio_Branco",
+ "America/Santarem",
+ "America/Santiago",
+ "America/Santo_Domingo",
+ "America/Sao_Paulo",
+ "America/Scoresbysund",
+ "America/Sitka",
+ "America/St_Johns",
+ "America/Swift_Current",
+ "America/Tegucigalpa",
+ "America/Thule",
+ "America/Tijuana",
+ "America/Toronto",
+ "America/Vancouver",
+ "America/Whitehorse",
+ "America/Winnipeg",
+ "America/Yakutat",
+ "America/Yellowknife",
+ "Antarctica/Casey",
+ "Antarctica/Davis",
+ "Antarctica/Macquarie",
+ "Antarctica/Mawson",
+ "Antarctica/Palmer",
+ "Antarctica/Rothera",
+ "Antarctica/Troll",
+ "Asia/Almaty",
+ "Asia/Amman",
+ "Asia/Anadyr",
+ "Asia/Aqtau",
+ "Asia/Aqtobe",
+ "Asia/Ashgabat",
+ "Asia/Atyrau",
+ "Asia/Baghdad",
+ "Asia/Baku",
+ "Asia/Bangkok",
+ "Asia/Barnaul",
+ "Asia/Beirut",
+ "Asia/Bishkek",
+ "Asia/Chita",
+ "Asia/Choibalsan",
+ "Asia/Colombo",
+ "Asia/Damascus",
+ "Asia/Dhaka",
+ "Asia/Dili",
+ "Asia/Dubai",
+ "Asia/Dushanbe",
+ "Asia/Famagusta",
+ "Asia/Gaza",
+ "Asia/Hebron",
+ "Asia/Ho_Chi_Minh",
+ "Asia/Hong_Kong",
+ "Asia/Hovd",
+ "Asia/Irkutsk",
+ "Asia/Jakarta",
+ "Asia/Jayapura",
+ "Asia/Jerusalem",
+ "Asia/Kabul",
+ "Asia/Kamchatka",
+ "Asia/Karachi",
+ "Asia/Kathmandu",
+ "Asia/Khandyga",
+ "Asia/Kolkata",
+ "Asia/Krasnoyarsk",
+ "Asia/Kuching",
+ "Asia/Macau",
+ "Asia/Magadan",
+ "Asia/Makassar",
+ "Asia/Manila",
+ "Asia/Nicosia",
+ "Asia/Novokuznetsk",
+ "Asia/Novosibirsk",
+ "Asia/Omsk",
+ "Asia/Oral",
+ "Asia/Pontianak",
+ "Asia/Pyongyang",
+ "Asia/Qatar",
+ "Asia/Qostanay",
+ "Asia/Qyzylorda",
+ "Asia/Riyadh",
+ "Asia/Sakhalin",
+ "Asia/Samarkand",
+ "Asia/Seoul",
+ "Asia/Shanghai",
+ "Asia/Singapore",
+ "Asia/Srednekolymsk",
+ "Asia/Taipei",
+ "Asia/Tashkent",
+ "Asia/Tbilisi",
+ "Asia/Tehran",
+ "Asia/Thimphu",
+ "Asia/Tokyo",
+ "Asia/Tomsk",
+ "Asia/Ulaanbaatar",
+ "Asia/Urumqi",
+ "Asia/Ust-Nera",
+ "Asia/Vladivostok",
+ "Asia/Yakutsk",
+ "Asia/Yangon",
+ "Asia/Yekaterinburg",
+ "Asia/Yerevan",
+ "Atlantic/Azores",
+ "Atlantic/Bermuda",
+ "Atlantic/Canary",
+ "Atlantic/Cape_Verde",
+ "Atlantic/Faroe",
+ "Atlantic/Madeira",
+ "Atlantic/South_Georgia",
+ "Atlantic/Stanley",
+ "Australia/Adelaide",
+ "Australia/Brisbane",
+ "Australia/Broken_Hill",
+ "Australia/Darwin",
+ "Australia/Eucla",
+ "Australia/Hobart",
+ "Australia/Lindeman",
+ "Australia/Lord_Howe",
+ "Australia/Melbourne",
+ "Australia/Perth",
+ "Australia/Sydney",
+ "CET",
+ "CST6CDT",
+ "EET",
+ "EST",
+ "EST5EDT",
+ "Etc/GMT",
+ "Etc/GMT+1",
+ "Etc/GMT+10",
+ "Etc/GMT+11",
+ "Etc/GMT+12",
+ "Etc/GMT+2",
+ "Etc/GMT+3",
+ "Etc/GMT+4",
+ "Etc/GMT+5",
+ "Etc/GMT+6",
+ "Etc/GMT+7",
+ "Etc/GMT+8",
+ "Etc/GMT+9",
+ "Etc/GMT-1",
+ "Etc/GMT-10",
+ "Etc/GMT-11",
+ "Etc/GMT-12",
+ "Etc/GMT-13",
+ "Etc/GMT-14",
+ "Etc/GMT-2",
+ "Etc/GMT-3",
+ "Etc/GMT-4",
+ "Etc/GMT-5",
+ "Etc/GMT-6",
+ "Etc/GMT-7",
+ "Etc/GMT-8",
+ "Etc/GMT-9",
+ "Etc/UTC",
+ "Europe/Andorra",
+ "Europe/Astrakhan",
+ "Europe/Athens",
+ "Europe/Belgrade",
+ "Europe/Berlin",
+ "Europe/Brussels",
+ "Europe/Bucharest",
+ "Europe/Budapest",
+ "Europe/Chisinau",
+ "Europe/Dublin",
+ "Europe/Gibraltar",
+ "Europe/Helsinki",
+ "Europe/Istanbul",
+ "Europe/Kaliningrad",
+ "Europe/Kirov",
+ "Europe/Kyiv",
+ "Europe/Lisbon",
+ "Europe/London",
+ "Europe/Madrid",
+ "Europe/Malta",
+ "Europe/Minsk",
+ "Europe/Moscow",
+ "Europe/Paris",
+ "Europe/Prague",
+ "Europe/Riga",
+ "Europe/Rome",
+ "Europe/Samara",
+ "Europe/Saratov",
+ "Europe/Simferopol",
+ "Europe/Sofia",
+ "Europe/Tallinn",
+ "Europe/Tirane",
+ "Europe/Ulyanovsk",
+ "Europe/Vienna",
+ "Europe/Vilnius",
+ "Europe/Volgograd",
+ "Europe/Warsaw",
+ "Europe/Zurich",
+ "HST",
+ "Indian/Chagos",
+ "Indian/Maldives",
+ "Indian/Mauritius",
+ "MET",
+ "MST",
+ "MST7MDT",
+ "PST8PDT",
+ "Pacific/Apia",
+ "Pacific/Auckland",
+ "Pacific/Bougainville",
+ "Pacific/Chatham",
+ "Pacific/Easter",
+ "Pacific/Efate",
+ "Pacific/Fakaofo",
+ "Pacific/Fiji",
+ "Pacific/Galapagos",
+ "Pacific/Gambier",
+ "Pacific/Guadalcanal",
+ "Pacific/Guam",
+ "Pacific/Honolulu",
+ "Pacific/Kanton",
+ "Pacific/Kiritimati",
+ "Pacific/Kosrae",
+ "Pacific/Kwajalein",
+ "Pacific/Marquesas",
+ "Pacific/Nauru",
+ "Pacific/Niue",
+ "Pacific/Norfolk",
+ "Pacific/Noumea",
+ "Pacific/Pago_Pago",
+ "Pacific/Palau",
+ "Pacific/Pitcairn",
+ "Pacific/Port_Moresby",
+ "Pacific/Rarotonga",
+ "Pacific/Tahiti",
+ "Pacific/Tarawa",
+ "Pacific/Tongatapu",
+
+ // IANA TZDB Link names
+ "WET",
+ "Africa/Accra",
+ "Africa/Addis_Ababa",
+ "Africa/Asmara",
+ "Africa/Asmera",
+ "Africa/Bamako",
+ "Africa/Bangui",
+ "Africa/Banjul",
+ "Africa/Blantyre",
+ "Africa/Brazzaville",
+ "Africa/Bujumbura",
+ "Africa/Conakry",
+ "Africa/Dakar",
+ "Africa/Dar_es_Salaam",
+ "Africa/Djibouti",
+ "Africa/Douala",
+ "Africa/Freetown",
+ "Africa/Gaborone",
+ "Africa/Harare",
+ "Africa/Kampala",
+ "Africa/Kigali",
+ "Africa/Kinshasa",
+ "Africa/Libreville",
+ "Africa/Lome",
+ "Africa/Luanda",
+ "Africa/Lubumbashi",
+ "Africa/Lusaka",
+ "Africa/Malabo",
+ "Africa/Maseru",
+ "Africa/Mbabane",
+ "Africa/Mogadishu",
+ "Africa/Niamey",
+ "Africa/Nouakchott",
+ "Africa/Ouagadougou",
+ "Africa/Porto-Novo",
+ "Africa/Timbuktu",
+ "America/Anguilla",
+ "America/Antigua",
+ "America/Argentina/ComodRivadavia",
+ "America/Aruba",
+ "America/Atikokan",
+ "America/Atka",
+ "America/Blanc-Sablon",
+ "America/Buenos_Aires",
+ "America/Catamarca",
+ "America/Cayman",
+ "America/Coral_Harbour",
+ "America/Cordoba",
+ "America/Creston",
+ "America/Curacao",
+ "America/Dominica",
+ "America/Ensenada",
+ "America/Fort_Wayne",
+ "America/Godthab",
+ "America/Grenada",
+ "America/Guadeloupe",
+ "America/Indianapolis",
+ "America/Jujuy",
+ "America/Knox_IN",
+ "America/Kralendijk",
+ "America/Louisville",
+ "America/Lower_Princes",
+ "America/Marigot",
+ "America/Mendoza",
+ "America/Montreal",
+ "America/Montserrat",
+ "America/Nassau",
+ "America/Nipigon",
+ "America/Pangnirtung",
+ "America/Port_of_Spain",
+ "America/Porto_Acre",
+ "America/Rainy_River",
+ "America/Rosario",
+ "America/Santa_Isabel",
+ "America/Shiprock",
+ "America/St_Barthelemy",
+ "America/St_Kitts",
+ "America/St_Lucia",
+ "America/St_Thomas",
+ "America/St_Vincent",
+ "America/Thunder_Bay",
+ "America/Tortola",
+ "America/Virgin",
+ "Antarctica/DumontDUrville",
+ "Antarctica/McMurdo",
+ "Antarctica/South_Pole",
+ "Antarctica/Syowa",
+ "Antarctica/Vostok",
+ "Arctic/Longyearbyen",
+ "Asia/Aden",
+ "Asia/Ashkhabad",
+ "Asia/Bahrain",
+ "Asia/Brunei",
+ "Asia/Calcutta",
+ "Asia/Chongqing",
+ "Asia/Chungking",
+ "Asia/Dacca",
+ "Asia/Harbin",
+ "Asia/Istanbul",
+ "Asia/Kashgar",
+ "Asia/Katmandu",
+ "Asia/Kuala_Lumpur",
+ "Asia/Kuwait",
+ "Asia/Macao",
+ "Asia/Muscat",
+ "Asia/Phnom_Penh",
+ "Asia/Rangoon",
+ "Asia/Saigon",
+ "Asia/Tel_Aviv",
+ "Asia/Thimbu",
+ "Asia/Ujung_Pandang",
+ "Asia/Ulan_Bator",
+ "Asia/Vientiane",
+ "Atlantic/Faeroe",
+ "Atlantic/Jan_Mayen",
+ "Atlantic/Reykjavik",
+ "Atlantic/St_Helena",
+ "Australia/ACT",
+ "Australia/Canberra",
+ "Australia/Currie",
+ "Australia/LHI",
+ "Australia/NSW",
+ "Australia/North",
+ "Australia/Queensland",
+ "Australia/South",
+ "Australia/Tasmania",
+ "Australia/Victoria",
+ "Australia/West",
+ "Australia/Yancowinna",
+ "Brazil/Acre",
+ "Brazil/DeNoronha",
+ "Brazil/East",
+ "Brazil/West",
+ "Canada/Atlantic",
+ "Canada/Central",
+ "Canada/Eastern",
+ "Canada/Mountain",
+ "Canada/Newfoundland",
+ "Canada/Pacific",
+ "Canada/Saskatchewan",
+ "Canada/Yukon",
+ "Chile/Continental",
+ "Chile/EasterIsland",
+ "Cuba",
+ "Egypt",
+ "Eire",
+ "Etc/GMT+0",
+ "Etc/GMT-0",
+ "Etc/GMT0",
+ "Etc/Greenwich",
+ "Etc/UCT",
+ "Etc/Universal",
+ "Etc/Zulu",
+ "Europe/Amsterdam",
+ "Europe/Belfast",
+ "Europe/Bratislava",
+ "Europe/Busingen",
+ "Europe/Copenhagen",
+ "Europe/Guernsey",
+ "Europe/Isle_of_Man",
+ "Europe/Jersey",
+ "Europe/Kiev",
+ "Europe/Ljubljana",
+ "Europe/Luxembourg",
+ "Europe/Mariehamn",
+ "Europe/Monaco",
+ "Europe/Nicosia",
+ "Europe/Oslo",
+ "Europe/Podgorica",
+ "Europe/San_Marino",
+ "Europe/Sarajevo",
+ "Europe/Skopje",
+ "Europe/Stockholm",
+ "Europe/Tiraspol",
+ "Europe/Uzhgorod",
+ "Europe/Vaduz",
+ "Europe/Vatican",
+ "Europe/Zagreb",
+ "Europe/Zaporozhye",
+ "GB",
+ "GB-Eire",
+ "GMT",
+ "GMT+0",
+ "GMT-0",
+ "GMT0",
+ "Greenwich",
+ "Hongkong",
+ "Iceland",
+ "Indian/Antananarivo",
+ "Indian/Christmas",
+ "Indian/Cocos",
+ "Indian/Comoro",
+ "Indian/Kerguelen",
+ "Indian/Mahe",
+ "Indian/Mayotte",
+ "Indian/Reunion",
+ "Iran",
+ "Israel",
+ "Jamaica",
+ "Japan",
+ "Kwajalein",
+ "Libya",
+ "Mexico/BajaNorte",
+ "Mexico/BajaSur",
+ "Mexico/General",
+ "NZ",
+ "NZ-CHAT",
+ "Navajo",
+ "PRC",
+ "Pacific/Chuuk",
+ "Pacific/Enderbury",
+ "Pacific/Funafuti",
+ "Pacific/Johnston",
+ "Pacific/Majuro",
+ "Pacific/Midway",
+ "Pacific/Pohnpei",
+ "Pacific/Ponape",
+ "Pacific/Saipan",
+ "Pacific/Samoa",
+ "Pacific/Truk",
+ "Pacific/Wake",
+ "Pacific/Wallis",
+ "Pacific/Yap",
+ "Poland",
+ "Portugal",
+ "ROC",
+ "ROK",
+ "Singapore",
+ "Turkey",
+ "UCT",
+ "US/Alaska",
+ "US/Aleutian",
+ "US/Arizona",
+ "US/Central",
+ "US/East-Indiana",
+ "US/Eastern",
+ "US/Hawaii",
+ "US/Indiana-Starke",
+ "US/Michigan",
+ "US/Mountain",
+ "US/Pacific",
+ "US/Pacific-New",
+ "US/Samoa",
+ "UTC",
+ "Universal",
+ "W-SU",
+ "Zulu"
+];
+
+// We want to test all available named time zone identifiers (both primary and non-primary),
+// but no ECMAScript built-in API exposes that list. So we use a union of two sources:
+// 1. A hard-coded list of Zone and Link identifiers from the 2022g version of IANA TZDB.
+// 2. Canonical IDs exposed by Intl.supportedValuesOf('timeZone'), which ensures that IDs
+// added to TZDB later than 2022g will be tested. (New IDs are almost always added as primary.)
+const ids = [...new Set([...timeZoneIdentifiers, ...Intl.supportedValuesOf("timeZone")])];
+for (const id of ids) {
+ const lower = id.toLowerCase();
+ const upper = id.toUpperCase();
+ assert.sameValue(
+ new Intl.DateTimeFormat("en", { timeZone: id }).resolvedOptions().timeZone,
+ id,
+ `Time zone created from string "${id}"`
+ );
+ assert.sameValue(
+ new Intl.DateTimeFormat("en", { timeZone: upper }).resolvedOptions().timeZone,
+ id,
+ `Time zone created from string "${upper}"`
+ );
+ assert.sameValue(
+ new Intl.DateTimeFormat("en", { timeZone: lower }).resolvedOptions().timeZone,
+ id,
+ `Time zone created from string "${lower}"`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js
new file mode 100644
index 0000000000..f42ffd0201
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-invalid.js
@@ -0,0 +1,28 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 6.4_b
+description: Tests that invalid time zone names are not accepted.
+author: Norbert Lindenberg
+---*/
+
+var invalidTimeZoneNames = [
+ "",
+ "MEZ", // localized abbreviation
+ "Pacific Time", // localized long form
+ "cnsha", // BCP 47 time zone code
+ "invalid", // as the name says
+ "Europe/İstanbul", // non-ASCII letter
+ "asıa/baku", // non-ASCII letter
+ "europe/brußels" // non-ASCII letter
+];
+
+invalidTimeZoneNames.forEach(function (name) {
+ // this must throw an exception for an invalid time zone name
+ assert.throws(RangeError, function() {
+ var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name});
+ }, "Invalid time zone name " + name + " was not rejected.");
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js
new file mode 100644
index 0000000000..7218ad448b
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-not-canonicalized.js
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 Justin Grant. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializedatetimeformat
+description: Time zone identifiers are not canonicalized before storing in internal slots
+---*/
+
+const baseOptions = {
+ timeZoneName: "long",
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ hour: "numeric",
+ minute: "numeric"
+};
+const dtf1 = new Intl.DateTimeFormat("en", { ...baseOptions, timeZone: "Asia/Calcutta" });
+const dtf2 = new Intl.DateTimeFormat("en", { ...baseOptions, timeZone: "Asia/Kolkata" });
+
+const resolvedId1 = dtf1.resolvedOptions().timeZone;
+const resolvedId2 = dtf2.resolvedOptions().timeZone;
+
+const output1 = dtf1.format(0);
+const output2 = dtf2.format(0);
+
+assert.sameValue(output1, output2);
+assert.sameValue(resolvedId1, "Asia/Calcutta");
+assert.sameValue(resolvedId2, "Asia/Kolkata");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js b/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js
new file mode 100644
index 0000000000..f27d109b1a
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/timezone-utc.js
@@ -0,0 +1,21 @@
+// Copyright 2012 Mozilla Corporation. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es5id: 6.4_a
+description: Tests that valid time zone names are accepted.
+author: Norbert Lindenberg
+---*/
+
+var validTimeZoneNames = [
+ "UTC",
+ "utc" // time zone names are case-insensitive
+];
+
+validTimeZoneNames.forEach(function (name) {
+ // this must not throw an exception for a valid time zone name
+ var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name});
+ assert.sameValue(format.resolvedOptions().timeZone, name.toUpperCase(), "Time zone name " + name + " was not correctly accepted.");
+});
+
+reportCompare(0, 0);