From 7953588aa75a14b025de74947b58109f33c4439b Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:29:07 +0300 Subject: [PATCH 01/15] Update doc comment for `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index de90a7fb999..e34d3896b55 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -593,9 +593,18 @@ impl ToLocalTime { // ==== Abstract Operations ==== -/// Creates a [`DateTimeFormat`] struct (internal slots only). The constructor wraps this in a -/// `JsObject` with the correct prototype; Date.prototype.toLocaleString (and friends) use it -/// directly with [`format_date_time`] without allocating a JS object. +/// Abstract operation [`CreateDateTimeFormat ( newTarget, locales, options, required, defaults [ , toLocaleStringTimeZone ] )`][spec] +/// +/// The abstract operation `CreateDateTimeFormat` takes arguments newTarget (a constructor), locales (an +/// ECMAScript language value), options (an ECMAScript language value), required (date, time, or any), and defaults +/// (date, time, or all) and optional argument toLocaleStringTimeZone (a primary time zone identifier) and returns +/// either a normal completion containing a `DateTimeFormat` object or a throw completion. +/// +/// If the additional toLocaleStringTimeZone argument is provided, the time zone will be overridden and some +/// adjustments will be made to the defaults in order to implement the behaviour of +/// Temporal.ZonedDateTime.prototype.toLocaleString. +/// +/// [spec]: https://tc39.es/proposal-temporal/#sec-createdatetimeformat pub(crate) fn create_date_time_format( locales: &JsValue, options: &JsValue, @@ -1203,7 +1212,7 @@ pub(crate) enum FormatDefaults { All, } -/// Abstract operation [`UnwrapDateTimeFormat ( dtf )`][spec]. +/// Abstract operation [`UnwrapDateTimeFormat ( dtf )`][spec] /// /// This also checks that the returned object is a `DateTimeFormat`, which skips the /// call to `RequireInternalSlot`. From 4d7e7ff27616fc2dcd935909a141f04bd6e424ab Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:38:14 +0300 Subject: [PATCH 02/15] Update `create_date_time_format` signature --- core/engine/src/builtins/intl/date_time_format/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index e34d3896b55..2f4dd3d09be 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -197,6 +197,7 @@ impl BuiltInConstructor for DateTimeFormat { options, FormatType::Any, FormatDefaults::Date, + None, context, )?; let date_time_format = JsObject::from_proto_and_data(prototype, dtf); @@ -610,6 +611,7 @@ pub(crate) fn create_date_time_format( options: &JsValue, date_time_format_type: FormatType, defaults: FormatDefaults, + to_locale_string_timezone: Option, context: &mut Context, ) -> JsResult { // NOTE: The below step's code was moved out into constructor to prevent unnecessary JsObject allocation when we create dtf internally From 24cc47f235c398b165c382084ba790867078fc8c Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:36:45 +0300 Subject: [PATCH 03/15] Add steps 2-3 doc to `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 2f4dd3d09be..7267456ed3f 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -619,20 +619,10 @@ pub(crate) fn create_date_time_format( // 1. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.DateTimeFormat.prototype%", // « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], // [[HourCycle]], [[DateStyle]], [[TimeStyle]], [[DateTimeFormat]], [[BoundFormat]] »). - // 2. Let hour12 be undefined. <- TODO - // 3. Let modifyResolutionOptions be a new Abstract Closure with parameters (options) that captures hour12 and performs the following steps when called: - // a. Set hour12 to options.[[hour12]]. - // b. Remove field [[hour12]] from options. - // c. If hour12 is not undefined, set options.[[hc]] to null. - // 4. Let optionsResolution be ? ResolveOptions(%Intl.DateTimeFormat%, %Intl.DateTimeFormat%.[[LocaleData]], - // locales, options, « coerce-options », modifyResolutionOptions). - // - // NOTE: We inline ResolveOptions here. (Could be worked into an abstract operation util function) - // ResolveOptions 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). + + // 2. Let requestedLocales be ? CanonicalizeLocaleList(locales). let requested_locales = canonicalize_locale_list(locales, context)?; - // NOTE: skip ResolveOptions 2, which is based on `REQUIRE-OPTIONS` vs `COERCE-OPTIONS` - // ResolveOptions 3. If specialBehaviours is present and contains coerce-options, - // set options to ? CoerceOptionsToObject(options). Otherwise, set options to ? GetOptionsObject(options). + // 3. Set options to ? CoerceOptionsToObject(options). let options = coerce_options_to_object(options, context)?; // ResolveOptions 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); From 904917570e805a8bbea6c8b870bd55f5f52cc09e Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:43:22 +0300 Subject: [PATCH 04/15] Implement steps 4-6 in `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 61 +++++++------------ 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 7267456ed3f..1a5bec9c292 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -624,31 +624,21 @@ pub(crate) fn create_date_time_format( let requested_locales = canonicalize_locale_list(locales, context)?; // 3. Set options to ? CoerceOptionsToObject(options). let options = coerce_options_to_object(options, context)?; - // ResolveOptions 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); + // 4. Let opt be a new Record. + let mut opt = IntlOptions::::default(); - // NOTE: We unroll the below const loop in step 6 using the - // ResolutionOptionDescriptors from the internal slots - // https://tc39.es/ecma402/#sec-intl.datetimeformat-internal-slots - let mut preferences = DateTimeFormatterPreferences::default(); - - // 6. For each Resolution Option Descriptor desc of constructor.[[ResolutionOptionDescriptors]], do - // a. If desc has a [[Type]] field, let type be desc.[[Type]]. Otherwise, let type be string. - // b. If desc has a [[Values]] field, let values be desc.[[Values]]. Otherwise, let values be empty. - // c. Let value be ? GetOption(options, desc.[[Property]], type, values, undefined). - // d. If value is not undefined, then - // i. Set value to ! ToString(value). - // ii. If value cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. - // e. Let key be desc.[[Key]]. - // f. Set opt.[[]] to value. + // 5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). + let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); + // 6. Set opt.[[localeMatcher]] to matcher. + opt.matcher = matcher; // Handle { [[Key]]: "ca", [[Property]]: "calendar" } - preferences.calendar_algorithm = + opt.preferences.calendar_algorithm = get_option::(&options, js_string!("calendar"), context)? .and_then(|ca| CalendarAlgorithm::try_from(&ca).ok()); // { [[Key]]: "nu", [[Property]]: "numberingSystem" } - preferences.numbering_system = + opt.preferences.numbering_system = get_option::(&options, js_string!("numberingSystem"), context)? .map(NumberingSystem::try_from) .transpose() @@ -658,7 +648,7 @@ pub(crate) fn create_date_time_format( let hour_12 = get_option::(&options, js_string!("hour12"), context)?; // { [[Key]]: "hc", [[Property]]: "hourCycle", [[Values]]: « "h11", "h12", "h23", "h24" » } - preferences.hour_cycle = + opt.preferences.hour_cycle = match get_option::(&options, js_string!("hourCycle"), context)? { // Handle steps 3.a-c here // c. If hour12 is not undefined, set options.[[hc]] to null. @@ -667,18 +657,10 @@ pub(crate) fn create_date_time_format( _ => None, }; - let mut intl_options = IntlOptions { - matcher, - preferences, - }; - // ResolveOptions 8. Let resolution be ResolveLocale(constructor.[[AvailableLocales]], requestedLocales, // opt, constructor.[[RelevantExtensionKeys]], localeData). - let resolved_locale = resolve_locale::( - requested_locales, - &mut intl_options, - context.intl_provider(), - )?; + let resolved_locale = + resolve_locale::(requested_locales, &mut opt, context.intl_provider())?; // TODO: The resolved calendar, numbering system, and hour cycle should come from // the ICU4X locale resolution result, not hardcoded defaults. However, ICU4X does @@ -686,22 +668,22 @@ pub(crate) fn create_date_time_format( // This means e.g. `new Intl.DateTimeFormat("ar").resolvedOptions().numberingSystem` // incorrectly returns "latn" instead of "arab". // Tracked at: unicode-org/icu4x#5868 - if intl_options.preferences.calendar_algorithm.is_none() { - intl_options.preferences.calendar_algorithm = CalendarAlgorithm::try_from( + if opt.preferences.calendar_algorithm.is_none() { + opt.preferences.calendar_algorithm = CalendarAlgorithm::try_from( &Value::try_from_str("gregory").expect("'gregory' is a valid BCP 47 value"), ) .ok(); } - if intl_options.preferences.numbering_system.is_none() { - intl_options.preferences.numbering_system = NumberingSystem::try_from( + if opt.preferences.numbering_system.is_none() { + opt.preferences.numbering_system = NumberingSystem::try_from( Value::try_from_str("latn").expect("'latn' is a valid BCP 47 value"), ) .ok(); } - if intl_options.preferences.hour_cycle.is_none() { - intl_options.preferences.hour_cycle = IcuHourCycle::try_from( + if opt.preferences.hour_cycle.is_none() { + opt.preferences.hour_cycle = IcuHourCycle::try_from( &Value::try_from_str("h12").expect("'h12' is a valid BCP 47 value"), ) .ok(); @@ -786,7 +768,8 @@ pub(crate) fn create_date_time_format( // d. Set formatOptions.[[]] to value. // e. If value is not undefined, then // i. Set hasExplicitFormatComponents to true. - let mut format_options = FormatOptions::try_init(&options, preferences.hour_cycle, context)?; + let mut format_options = + FormatOptions::try_init(&options, opt.preferences.hour_cycle, context)?; // TODO: how should formatMatcher be used? // 25. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit"). @@ -905,9 +888,9 @@ pub(crate) fn create_date_time_format( Ok(DateTimeFormat { locale: resolved_locale, - calendar_algorithm: intl_options.preferences.calendar_algorithm, - numbering_system: intl_options.preferences.numbering_system, - hour_cycle: intl_options.preferences.hour_cycle, + calendar_algorithm: opt.preferences.calendar_algorithm, + numbering_system: opt.preferences.numbering_system, + hour_cycle: opt.preferences.hour_cycle, date_style, time_style, fractional_second_digits: format_options.fractional_second_digits(), From 7ea9bfc8d458a8813bde59e9df08ee90e29986a3 Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 00:37:21 +0300 Subject: [PATCH 05/15] Add steps 7-9 doc to `create_date_time_format` --- core/engine/src/builtins/intl/date_time_format/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 1a5bec9c292..ba8359e4cc8 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -632,7 +632,10 @@ pub(crate) fn create_date_time_format( // 6. Set opt.[[localeMatcher]] to matcher. opt.matcher = matcher; - // Handle { [[Key]]: "ca", [[Property]]: "calendar" } + // 7. Let calendar be ? GetOption(options, "calendar", string, empty, undefined). + // 8. If calendar is not undefined, then + // a. If calendar cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. + // 9. Set opt.[[ca]] to calendar. opt.preferences.calendar_algorithm = get_option::(&options, js_string!("calendar"), context)? .and_then(|ca| CalendarAlgorithm::try_from(&ca).ok()); From 940d538dfdcd75844118123e534b67628ec67a3f Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 00:44:00 +0300 Subject: [PATCH 06/15] Add steps 10-12 doc to `create_date_time_format` --- core/engine/src/builtins/intl/date_time_format/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index ba8359e4cc8..fd8bb766d44 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -640,7 +640,10 @@ pub(crate) fn create_date_time_format( get_option::(&options, js_string!("calendar"), context)? .and_then(|ca| CalendarAlgorithm::try_from(&ca).ok()); - // { [[Key]]: "nu", [[Property]]: "numberingSystem" } + // 10. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined). + // 11. If numberingSystem is not undefined, then + // a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. + // 12. Set opt.[[nu]] to numberingSystem. opt.preferences.numbering_system = get_option::(&options, js_string!("numberingSystem"), context)? .map(NumberingSystem::try_from) From 8e3daab08d3774a52cdeff64ccb49a88688ded39 Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:29:33 +0300 Subject: [PATCH 07/15] Add steps 13-16 doc to `create_date_time_format` --- core/engine/src/builtins/intl/date_time_format/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index fd8bb766d44..d58058f5bed 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -650,14 +650,15 @@ pub(crate) fn create_date_time_format( .transpose() .map_err(|_icu4x_error| js_error!(RangeError: "unknown numbering system"))?; - // { [[Key]]: "hour12", [[Property]]: "hour12", [[Type]]: boolean } + // 13. Let hour12 be ? GetOption(options, "hour12", boolean, empty, undefined). let hour_12 = get_option::(&options, js_string!("hour12"), context)?; - // { [[Key]]: "hc", [[Property]]: "hourCycle", [[Values]]: « "h11", "h12", "h23", "h24" » } + // 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. + // 16. Set opt.[[hc]] to hourCycle. opt.preferences.hour_cycle = match get_option::(&options, js_string!("hourCycle"), context)? { - // Handle steps 3.a-c here - // c. If hour12 is not undefined, set options.[[hc]] to null. _ if hour_12.is_some() => None, Some(hc) => Some(IcuHourCycle::try_from(hc)?), _ => None, From 83510ca37cc146c41f0e1760c7274526fa16b42e Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:54:57 +0300 Subject: [PATCH 08/15] Add steps 17-22 doc to `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index d58058f5bed..9f874c63de1 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -664,10 +664,9 @@ pub(crate) fn create_date_time_format( _ => None, }; - // ResolveOptions 8. Let resolution be ResolveLocale(constructor.[[AvailableLocales]], requestedLocales, - // opt, constructor.[[RelevantExtensionKeys]], localeData). - let resolved_locale = - resolve_locale::(requested_locales, &mut opt, context.intl_provider())?; + // 17. Let r be ResolveLocale(%Intl.DateTimeFormat%.[[AvailableLocales]], requestedLocales, + // opt, %Intl.DateTimeFormat%.[[RelevantExtensionKeys]], %Intl.DateTimeFormat%.[[LocaleData]]). + let r = resolve_locale::(requested_locales, &mut opt, context.intl_provider())?; // TODO: The resolved calendar, numbering system, and hour cycle should come from // the ICU4X locale resolution result, not hardcoded defaults. However, ICU4X does @@ -695,13 +694,12 @@ pub(crate) fn create_date_time_format( ) .ok(); } - // 5. Set options to optionsResolution.[[Options]]. - // 6. Let r be optionsResolution.[[ResolvedLocale]]. - // 7. Set (deferred) dateTimeFormat.[[Locale]] to r.[[Locale]]. - // 8. Let (deferred) resolvedCalendar be r.[[ca]]. - // 9. Set (deferred) dateTimeFormat.[[Calendar]] to resolvedCalendar. - // 10. Set (deferred) dateTimeFormat.[[NumberingSystem]] to r.[[nu]]. - // 11. Let (deferred) resolvedLocaleData be r.[[LocaleData]]. + + // 18. Set (deferred) dateTimeFormat.[[Locale]] to r.[[Locale]]. + // 19. Let (deferred) resolvedCalendar be r.[[ca]]. + // 20. Set (deferred) dateTimeFormat.[[Calendar]] to resolvedCalendar. + // 21. Set (deferred) dateTimeFormat.[[NumberingSystem]] to r.[[nu]]. + // 22. Let (deferred) resolvedLocaleData be r.[[LocaleData]]. // TODO: Handle hour12 and hc // 12. If hour12 is true, then @@ -881,20 +879,20 @@ pub(crate) fn create_date_time_format( // 34. Return dateTimeFormat. let formatter = DateTimeFormatter::try_new_with_buffer_provider( context.intl_provider().erased_provider(), - resolved_locale.clone().into(), + r.clone().into(), fieldset, ) .map_err(|e| js_error!(RangeError: "failed to load formatter: {}", e))?; let range_formatter = DateRangeFormatter::try_new_with_buffer_provider( context.intl_provider().erased_provider(), - resolved_locale.clone().into(), + r.clone().into(), fieldset, ) .map_err(|e| js_error!(RangeError: "failed to load formatter: {}", e))?; Ok(DateTimeFormat { - locale: resolved_locale, + locale: r, calendar_algorithm: opt.preferences.calendar_algorithm, numbering_system: opt.preferences.numbering_system, hour_cycle: opt.preferences.hour_cycle, From 66a85abe9176d7c9a637424b719b45521eaf5f1b Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 18:13:38 +0300 Subject: [PATCH 09/15] Add steps 23-26 doc to `create_date_time_format` --- core/engine/src/builtins/intl/date_time_format/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 9f874c63de1..f0a872b8144 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -702,14 +702,15 @@ pub(crate) fn create_date_time_format( // 22. Let (deferred) resolvedLocaleData be r.[[LocaleData]]. // TODO: Handle hour12 and hc - // 12. If hour12 is true, then + // 23. If hour12 is true, then // a. Let hc be resolvedLocaleData.[[hourCycle12]]. - // 13. Else if hour12 is false, then + // 24. Else if hour12 is false, then // a. Let hc be resolvedLocaleData.[[hourCycle24]]. - // 14. Else, + // 25. Else, // a. Assert: hour12 is undefined. // b. Let hc be r.[[hc]]. // c. If hc is null, set hc to resolvedLocaleData.[[hourCycle]]. + // 26. Set (deferred) dateTimeFormat.[[HourCycle]] to hc. // 15. Let timeZone be ? Get(options, "timeZone"). let time_zone = options.get(js_string!("timeZone"), context)?; From 06d414583578e476d29bc388b64cf9d4427e3414 Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:55:44 +0300 Subject: [PATCH 10/15] Implement steps 27-29 of `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index f0a872b8144..bd688c4ce7b 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -58,6 +58,7 @@ use icu_time::{ models::{AtTime, Base}, }, }; +use temporal_rs::host::HostHooks; use timezone_provider::provider::TimeZoneId; use writeable::{PartsWrite, Writeable, adapters::CoreWriteAsPartsWrite}; @@ -611,7 +612,7 @@ pub(crate) fn create_date_time_format( options: &JsValue, date_time_format_type: FormatType, defaults: FormatDefaults, - to_locale_string_timezone: Option, + to_locale_string_timezone: Option, context: &mut Context, ) -> JsResult { // NOTE: The below step's code was moved out into constructor to prevent unnecessary JsObject allocation when we create dtf internally @@ -712,17 +713,31 @@ pub(crate) fn create_date_time_format( // c. If hc is null, set hc to resolvedLocaleData.[[hourCycle]]. // 26. Set (deferred) dateTimeFormat.[[HourCycle]] to hc. - // 15. Let timeZone be ? Get(options, "timeZone"). + // 27. Let timeZone be ? Get(options, "timeZone"). let time_zone = options.get(js_string!("timeZone"), context)?; - // 16. If timeZone is undefined, then + // 28. If timeZone is undefined, then let time_zone = if time_zone.is_undefined() { - // TODO (nekevss): Resolve system time zone - // a. Set timeZone to SystemTimeZoneIdentifier(). - JsString::from("Etc/UTC") - // 17. Else, + // a. If toLocaleStringTimeZone is present, then + if let Some(tz) = to_locale_string_timezone { + // i. Set timeZone to toLocaleStringTimeZone. + tz + // b. Else, + } else { + // b. Set timeZone to SystemTimeZoneIdentifier(). + let context: &Context = context; + let time_zone = context.get_system_time_zone(context.timezone_provider())?; + JsString::from(time_zone.identifier_with_provider(context.timezone_provider())?) + } + // 29. Else, } else { - // a. Set timeZone to ? ToString(timeZone). + // a. If toLocaleStringTimeZone is present, throw a TypeError exception. + if to_locale_string_timezone.is_some() { + return Err( + js_error!(TypeError: "can't set option timeZone when Temporal.ZonedDateTime.toLocaleString is used"), + ); + } + // b. Set timeZone to ? ToString(timeZone). time_zone.to_string(context)? }; // 18. If IsTimeZoneOffsetString(timeZone) is true, then From c1d2c5292975b2d77f9ae4c9a6e16bd1ca0607c8 Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Thu, 25 Jun 2026 19:11:25 +0300 Subject: [PATCH 11/15] Add steps 30-32 doc to `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index bd688c4ce7b..ece0f1b1ff9 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -724,7 +724,7 @@ pub(crate) fn create_date_time_format( tz // b. Else, } else { - // b. Set timeZone to SystemTimeZoneIdentifier(). + // i. Set timeZone to SystemTimeZoneIdentifier(). let context: &Context = context; let time_zone = context.get_system_time_zone(context.timezone_provider())?; JsString::from(time_zone.identifier_with_provider(context.timezone_provider())?) @@ -740,39 +740,37 @@ pub(crate) fn create_date_time_format( // b. Set timeZone to ? ToString(timeZone). time_zone.to_string(context)? }; - // 18. If IsTimeZoneOffsetString(timeZone) is true, then + + // 30. If IsTimeZoneOffsetString(timeZone) is true, then let time_zone_string = time_zone.to_std_string_escaped(); // Note: Should a timezone enum be part of temporal_rs, icu_time, or an ECMA402 wrapper lib let time_zone = if let Ok(utc_offset) = UtcOffset::try_from_str(&time_zone_string) { - // a. Let parseResult be ParseText(StringToCodePoints(timeZone), UTCOffset). - // b. Assert: parseResult is a Parse Node. - // c. If parseResult contains more than one MinuteSecond Parse Node, throw a RangeError exception. - // d. Let offsetNanoseconds be ParseTimeZoneOffsetString(timeZone). - // e. Let offsetMinutes be offsetNanoseconds / (6 × 10**10). - // f. Assert: offsetMinutes is an integer. - // g. Set timeZone to FormatOffsetTimeZoneIdentifier(offsetMinutes). + // a. Let parseResult be ParseText(StringToCodePoints(timeZone), UTCOffset[~SubMinutePrecision]). + // b. Assert: parseResult is a Parse Node. + // c. Let offsetNanoseconds be ? ParseDateTimeUTCOffset(timeZone). + // d. Let offsetMinutes be offsetNanoseconds / (6 × 10**10). + // e. Assert: offsetMinutes is an integer. + // f. Set timeZone to FormatOffsetTimeZoneIdentifier(offsetMinutes). FormatTimeZone::UtcOffset(utc_offset) + // 31. Else, } else { - // 19. Else, - // a. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone). - // b. If timeZoneIdentifierRecord is empty, throw a RangeError exception. - // c. Set timeZone to timeZoneIdentifierRecord.[[PrimaryIdentifier]]. + // a. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone). + // b. If timeZoneIdentifierRecord is empty, then + // i. Throw a RangeError exception. + // c. Set timeZone to timeZoneIdentifierRecord.[[Identifier]]. let parser = IanaParser::try_new_with_buffer_provider(context.intl_provider().erased_provider()) - .map_err(|_| { - JsNativeError::error().with_message("Failed to init time zone data provider") - })?; + .map_err(|_| js_error!(Error: "failed to init time zone data provider"))?; let time_zone = parser.as_borrowed().parse(&time_zone_string); let time_zone_id = context .timezone_provider() .get(time_zone_string.as_bytes()) - .map_err(|_| { - JsNativeError::range() - .with_message(format!("{time_zone_string:#?} was not a valid time zone.")) - })?; + .map_err( + |_| js_error!(RangeError: "{time_zone_string:?} was not a valid time zone."), + )?; FormatTimeZone::Identifier((time_zone, time_zone_id)) }; - // 20. (deferred) Set dateTimeFormat.[[TimeZone]] to timeZone. + // 32. (deferred) Set dateTimeFormat.[[TimeZone]] to timeZone. // 21. Let formatOptions be a new Record. // 22. Set formatOptions.[[hourCycle]] to hc. From bfb7cb93fe6479620a64efb1e8dc17235b99465f Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Fri, 26 Jun 2026 03:35:42 +0300 Subject: [PATCH 12/15] Add steps 33-42 doc to `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index ece0f1b1ff9..c81307f8134 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -50,7 +50,10 @@ use icu_datetime::{ }; use icu_decimal::preferences::NumberingSystem; use icu_decimal::provider::DecimalSymbolsV1; -use icu_locale::{Locale, extensions::unicode::Value}; +use icu_locale::{ + Locale, + extensions::unicode::{Key, Value}, +}; use icu_time::{ TimeZoneInfo, ZonedDateTime, zone::{ @@ -772,12 +775,11 @@ pub(crate) fn create_date_time_format( }; // 32. (deferred) Set dateTimeFormat.[[TimeZone]] to timeZone. - // 21. Let formatOptions be a new Record. - // 22. Set formatOptions.[[hourCycle]] to hc. - // 23. Let hasExplicitFormatComponents be false. - - // NOTE (nekevss): Step 24 is adopted in the `FormatOptions` - // 24. For each row of Table 16, except the header row, in table order, do + // 33. Let formatOptions be a new Record. + // 34. Set formatOptions.[[hourCycle]] to hc. + // 35. Let hasExplicitFormatComponents be false. + // NOTE (nekevss): Step 36 is adopted in the `FormatOptions` + // 36. For each row of Table 16, except the header row, in table order, do // a. Let prop be the name given in the Property column of the current row. // b. If prop is "fractionalSecondDigits", then // i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined). @@ -791,15 +793,18 @@ pub(crate) fn create_date_time_format( FormatOptions::try_init(&options, opt.preferences.hour_cycle, context)?; // TODO: how should formatMatcher be used? - // 25. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit"). + // 37. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit"). let format_matcher = get_option::(&options, js_string!("formatMatcher"), context)? .unwrap_or(FormatMatcher::BestFit); - // 26. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined). + + // 38. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined). let date_style = get_option::(&options, js_string!("dateStyle"), context)?; - // 27. Set dateTimeFormat.[[DateStyle]] to dateStyle. - // 28. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). + // 39. Set (deferred) dateTimeFormat.[[DateStyle]] to dateStyle. + + // 40. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). let time_style = get_option::(&options, js_string!("timeStyle"), context)?; + // 41. Set (deferred) dateTimeFormat.[[TimeStyle]] to timeStyle. let format_style = match (date_style, time_style) { (None, None) => None, @@ -811,7 +816,8 @@ pub(crate) fn create_date_time_format( }), }; - // 29. (deferred) Set dateTimeFormat.[[TimeStyle]] to timeStyle. + // 42. Let formats be resolvedLocaleData.[[formats]].[[]]. + // 30. If dateStyle is not undefined or timeStyle is not undefined, then let fieldset = if let Some(format_style) = format_style { // a. If hasExplicitFormatComponents is true, then From f3a7fc3ab49bd0795368889b44621c43995b8947 Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Fri, 31 Jul 2026 20:52:04 +0300 Subject: [PATCH 13/15] Add steps 43-46 doc to `create_date_time_format` --- .../src/builtins/intl/date_time_format/mod.rs | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index c81307f8134..045289322b3 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -50,10 +50,7 @@ use icu_datetime::{ }; use icu_decimal::preferences::NumberingSystem; use icu_decimal::provider::DecimalSymbolsV1; -use icu_locale::{ - Locale, - extensions::unicode::{Key, Value}, -}; +use icu_locale::{Locale, extensions::unicode::Value}; use icu_time::{ TimeZoneInfo, ZonedDateTime, zone::{ @@ -737,7 +734,7 @@ pub(crate) fn create_date_time_format( // a. If toLocaleStringTimeZone is present, throw a TypeError exception. if to_locale_string_timezone.is_some() { return Err( - js_error!(TypeError: "can't set option timeZone when Temporal.ZonedDateTime.toLocaleString is used"), + js_error!(TypeError: "cannot set option timeZone when Temporal.ZonedDateTime.toLocaleString is used"), ); } // b. Set timeZone to ? ToString(timeZone). @@ -818,7 +815,7 @@ pub(crate) fn create_date_time_format( // 42. Let formats be resolvedLocaleData.[[formats]].[[]]. - // 30. If dateStyle is not undefined or timeStyle is not undefined, then + // 43. If dateStyle is not undefined or timeStyle is not undefined, then let fieldset = if let Some(format_style) = format_style { // a. If hasExplicitFormatComponents is true, then if format_options.has_explicit_format_components() { @@ -849,14 +846,39 @@ pub(crate) fn create_date_time_format( } _ => {} } - - // TODO (nekevss): implement d-e + // TODO: implement d-k // TODO (nekevss): Do we have access to the styles? // d. Let styles be resolvedLocaleData.[[styles]].[[]]. // e. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles). date_time_style_format(format_style)? - // 31. Else, + // f. If dateStyle is not undefined, then + // i. Set dateTimeFormat.[[TemporalPlainDateFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "weekday", "era", "year", "month", "day" »). + // ii. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "era", "year", "month" »). + // iii. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "month", "day" »). + // g. Else, + // i. Set dateTimeFormat.[[TemporalPlainDateFormat]] to null. + // ii. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to null. + // iii. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to null. + // h. If timeStyle is not undefined, then + // i. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" »). + // i. Else, + // i. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to null. + // j. Set dateTimeFormat.[[TemporalPlainDateTimeFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "weekday", "era", "year", "month", "day", "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" »). + // k. Set dateTimeFormat.[[TemporalInstantFormat]] to bestFormat. + // 44. Else, } else { + // a. Let bestFormat be GetDateTimeFormat(formats, formatMatcher, formatOptions, required, defaults, all). + // b. Set dateTimeFormat.[[TemporalPlainDateFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, date, date, relevant). + // c. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, year-month, year-month, relevant). + // d. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, month-day, month-day, relevant). + // e. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, time, time, relevant). + // f. Set dateTimeFormat.[[TemporalPlainDateTimeFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, all, relevant). + // g. If toLocaleStringTimeZone is present, then + // i. Set dateTimeFormat.[[TemporalInstantFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, zoned-date-time, all). + // h. Else, + // i. Set dateTimeFormat.[[TemporalInstantFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, all, all). + + // NOTE: The below is temporally preserved 'as-is' for proper work. This is about to be delete in the near future // a. Let needDefaults be true. // b. If required is date or any, then // i. For each property name prop of « "weekday", "year", "month", "day" », do @@ -893,10 +915,8 @@ pub(crate) fn create_date_time_format( } } }; - // 32. Set dateTimeFormat.[[DateTimeFormat]] to bestFormat. - // 33. If bestFormat has a field [[hour]], then - // a. Set dateTimeFormat.[[HourCycle]] to hc. - // 34. Return dateTimeFormat. + // 45. Set dateTimeFormat.[[DateTimeFormat]] to bestFormat. + // 46. Return dateTimeFormat. let formatter = DateTimeFormatter::try_new_with_buffer_provider( context.intl_provider().erased_provider(), r.clone().into(), From d2081a383f08b7a34326e93f2bcdc279b4ceb62f Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:46:50 +0300 Subject: [PATCH 14/15] Fix `Date::to_locale_string_with` --- core/engine/src/builtins/date/mod.rs | 2 +- .../src/builtins/intl/date_time_format/mod.rs | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/engine/src/builtins/date/mod.rs b/core/engine/src/builtins/date/mod.rs index 05e28775e1b..a526377b417 100644 --- a/core/engine/src/builtins/date/mod.rs +++ b/core/engine/src/builtins/date/mod.rs @@ -1555,7 +1555,7 @@ impl Date { // 6. Return ! FormatDateTime(dateFormat, x). let locales = args.get_or_undefined(0); let options = args.get_or_undefined(1); - let dtf = create_date_time_format(locales, options, required, defaults, context)?; + let dtf = create_date_time_format(locales, options, required, defaults, None, context)?; format_date_time(&dtf, x, context) } diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 045289322b3..301a19fda4a 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -629,9 +629,8 @@ pub(crate) fn create_date_time_format( let mut opt = IntlOptions::::default(); // 5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 6. Set opt.[[localeMatcher]] to matcher. - opt.matcher = matcher; + opt.matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 7. Let calendar be ? GetOption(options, "calendar", string, empty, undefined). // 8. If calendar is not undefined, then @@ -696,11 +695,11 @@ pub(crate) fn create_date_time_format( .ok(); } - // 18. Set (deferred) dateTimeFormat.[[Locale]] to r.[[Locale]]. - // 19. Let (deferred) resolvedCalendar be r.[[ca]]. - // 20. Set (deferred) dateTimeFormat.[[Calendar]] to resolvedCalendar. - // 21. Set (deferred) dateTimeFormat.[[NumberingSystem]] to r.[[nu]]. - // 22. Let (deferred) resolvedLocaleData be r.[[LocaleData]]. + // 18. (deferred) Set dateTimeFormat.[[Locale]] to r.[[Locale]]. + // 19. (deferred) Let resolvedCalendar be r.[[ca]]. + // 20. (deferred) Set dateTimeFormat.[[Calendar]] to resolvedCalendar. + // 21. (deferred) Set dateTimeFormat.[[NumberingSystem]] to r.[[nu]]. + // 22. (deferred) Let resolvedLocaleData be r.[[LocaleData]]. // TODO: Handle hour12 and hc // 23. If hour12 is true, then @@ -711,7 +710,7 @@ pub(crate) fn create_date_time_format( // a. Assert: hour12 is undefined. // b. Let hc be r.[[hc]]. // c. If hc is null, set hc to resolvedLocaleData.[[hourCycle]]. - // 26. Set (deferred) dateTimeFormat.[[HourCycle]] to hc. + // 26. (deferred) Set dateTimeFormat.[[HourCycle]] to hc. // 27. Let timeZone be ? Get(options, "timeZone"). let time_zone = options.get(js_string!("timeZone"), context)?; @@ -775,7 +774,7 @@ pub(crate) fn create_date_time_format( // 33. Let formatOptions be a new Record. // 34. Set formatOptions.[[hourCycle]] to hc. // 35. Let hasExplicitFormatComponents be false. - // NOTE (nekevss): Step 36 is adopted in the `FormatOptions` + // NOTE: Step 36 is adopted in the `FormatOptions` // 36. For each row of Table 16, except the header row, in table order, do // a. Let prop be the name given in the Property column of the current row. // b. If prop is "fractionalSecondDigits", then @@ -797,11 +796,11 @@ pub(crate) fn create_date_time_format( // 38. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined). let date_style = get_option::(&options, js_string!("dateStyle"), context)?; - // 39. Set (deferred) dateTimeFormat.[[DateStyle]] to dateStyle. + // 39. (deferred) Set dateTimeFormat.[[DateStyle]] to dateStyle. // 40. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined). let time_style = get_option::(&options, js_string!("timeStyle"), context)?; - // 41. Set (deferred) dateTimeFormat.[[TimeStyle]] to timeStyle. + // 41. (deferred) Set dateTimeFormat.[[TimeStyle]] to timeStyle. let format_style = match (date_style, time_style) { (None, None) => None, @@ -865,6 +864,7 @@ pub(crate) fn create_date_time_format( // i. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to null. // j. Set dateTimeFormat.[[TemporalPlainDateTimeFormat]] to AdjustDateTimeStyleFormat(formats, bestFormat, formatMatcher, « "weekday", "era", "year", "month", "day", "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" »). // k. Set dateTimeFormat.[[TemporalInstantFormat]] to bestFormat. + // 44. Else, } else { // a. Let bestFormat be GetDateTimeFormat(formats, formatMatcher, formatOptions, required, defaults, all). From 52ba3a4d0f7d6ea24c9b9032a8e8c252459e84ad Mon Sep 17 00:00:00 2001 From: Vellumic <161718748+Vellumic@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:18:30 +0300 Subject: [PATCH 15/15] Fix --- .../src/builtins/intl/date_time_format/mod.rs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/core/engine/src/builtins/intl/date_time_format/mod.rs b/core/engine/src/builtins/intl/date_time_format/mod.rs index 301a19fda4a..3206b54f127 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -625,12 +625,14 @@ pub(crate) fn create_date_time_format( let requested_locales = canonicalize_locale_list(locales, context)?; // 3. Set options to ? CoerceOptionsToObject(options). let options = coerce_options_to_object(options, context)?; - // 4. Let opt be a new Record. - let mut opt = IntlOptions::::default(); + // 4. Let opt be a new Record. // 5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 6. Set opt.[[localeMatcher]] to matcher. - opt.matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); + let mut opt = IntlOptions:: { + matcher: get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(), + ..Default::default() + }; // 7. Let calendar be ? GetOption(options, "calendar", string, empty, undefined). // 8. If calendar is not undefined, then @@ -646,9 +648,7 @@ pub(crate) fn create_date_time_format( // 12. Set opt.[[nu]] to numberingSystem. opt.preferences.numbering_system = get_option::(&options, js_string!("numberingSystem"), context)? - .map(NumberingSystem::try_from) - .transpose() - .map_err(|_icu4x_error| js_error!(RangeError: "unknown numbering system"))?; + .and_then(|nu| NumberingSystem::try_from(nu).ok()); // 13. Let hour12 be ? GetOption(options, "hour12", boolean, empty, undefined). let hour_12 = get_option::(&options, js_string!("hour12"), context)?; @@ -666,14 +666,15 @@ pub(crate) fn create_date_time_format( // 17. Let r be ResolveLocale(%Intl.DateTimeFormat%.[[AvailableLocales]], requestedLocales, // opt, %Intl.DateTimeFormat%.[[RelevantExtensionKeys]], %Intl.DateTimeFormat%.[[LocaleData]]). - let r = resolve_locale::(requested_locales, &mut opt, context.intl_provider())?; + let locale = + resolve_locale::(requested_locales, &mut opt, context.intl_provider())?; // TODO: The resolved calendar, numbering system, and hour cycle should come from // the ICU4X locale resolution result, not hardcoded defaults. However, ICU4X does // not yet expose getters for these computed values on DateTimeFormatter. // This means e.g. `new Intl.DateTimeFormat("ar").resolvedOptions().numberingSystem` // incorrectly returns "latn" instead of "arab". - // Tracked at: unicode-org/icu4x#5868 + // Tracked at: https://github.com/unicode-org/icu4x/issues/5868 if opt.preferences.calendar_algorithm.is_none() { opt.preferences.calendar_algorithm = CalendarAlgorithm::try_from( &Value::try_from_str("gregory").expect("'gregory' is a valid BCP 47 value"), @@ -919,20 +920,20 @@ pub(crate) fn create_date_time_format( // 46. Return dateTimeFormat. let formatter = DateTimeFormatter::try_new_with_buffer_provider( context.intl_provider().erased_provider(), - r.clone().into(), + locale.clone().into(), fieldset, ) .map_err(|e| js_error!(RangeError: "failed to load formatter: {}", e))?; let range_formatter = DateRangeFormatter::try_new_with_buffer_provider( context.intl_provider().erased_provider(), - r.clone().into(), + locale.clone().into(), fieldset, ) .map_err(|e| js_error!(RangeError: "failed to load formatter: {}", e))?; Ok(DateTimeFormat { - locale: r, + locale, calendar_algorithm: opt.preferences.calendar_algorithm, numbering_system: opt.preferences.numbering_system, hour_cycle: opt.preferences.hour_cycle,