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 1090907f792..455368a69bd 100644 --- a/core/engine/src/builtins/intl/date_time_format/mod.rs +++ b/core/engine/src/builtins/intl/date_time_format/mod.rs @@ -177,6 +177,11 @@ impl BuiltInConstructor for DateTimeFormat { let options = args.get_or_undefined(1); // 2. Let dateTimeFormat be ? CreateDateTimeFormat(newTarget, locales, options, any, date). + let prototype = get_prototype_from_constructor( + new_target_inner, + StandardConstructors::date_time_format, + context, + )?; let dtf = create_date_time_format( locales, options, @@ -184,11 +189,6 @@ impl BuiltInConstructor for DateTimeFormat { FormatDefaults::Date, context, )?; - let prototype = get_prototype_from_constructor( - new_target_inner, - StandardConstructors::date_time_format, - context, - )?; let date_time_format = JsObject::from_proto_and_data(prototype, dtf); // 3. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then @@ -534,6 +534,11 @@ pub(crate) fn create_date_time_format( defaults: FormatDefaults, 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 + // (e.g. toLocaleString methods of Date and Temporal objects) + // 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]]. @@ -1025,24 +1030,6 @@ pub(crate) fn format_date_time_locale( context: &mut Context, ) -> JsResult { let options = coerce_options_to_object(options, context)?; - if format_type != FormatType::Time - && get_option::(&options, js_string!("dateStyle"), context)?.is_none() - { - options.create_data_property_or_throw( - js_string!("dateStyle"), - JsValue::from(js_string!("long")), - context, - )?; - } - if format_type != FormatType::Date - && get_option::(&options, js_string!("timeStyle"), context)?.is_none() - { - options.create_data_property_or_throw( - js_string!("timeStyle"), - JsValue::from(js_string!("long")), - context, - )?; - } let options_value = options.into(); let dtf = create_date_time_format(locales, &options_value, format_type, defaults, context)?; // FormatDateTime steps 1–2: TimeClip and NaN check (format_timestamp_with_dtf does ToLocalTime + format only). diff --git a/core/engine/src/builtins/intl/date_time_format/tests.rs b/core/engine/src/builtins/intl/date_time_format/tests.rs index 66d97ccfd99..2d0e83a41e4 100644 --- a/core/engine/src/builtins/intl/date_time_format/tests.rs +++ b/core/engine/src/builtins/intl/date_time_format/tests.rs @@ -65,3 +65,54 @@ fn dtf_basic() { TestAction::assert_eq("result === 'Sunday, 20 December 2020 at 14:23:16'", true), ]); } + +#[cfg(feature = "intl_bundled")] +#[test] +fn date_to_locale_string() { + run_test_actions([ + TestAction::run(indoc! {" + // Setup date + const date = new Date(Date.UTC(2021, 3, 12, 6, 7)); + + let result = date.toLocaleString('en-US', { dateStyle: 'short' }); + "}), + TestAction::assert_eq("result === '4/12/21'", true), + ]); + run_test_actions([ + TestAction::run(indoc! {" + // Setup date + const date = new Date(Date.UTC(2021, 3, 12, 6, 7)); + + let result = date.toLocaleString('en-US', { timeStyle: 'short' }); + "}), + TestAction::assert_eq("result === '6:07\u{202f}AM'", true), + ]); +} + +#[cfg(feature = "intl_bundled")] +#[test] +fn dtf_ctor_observable_behavior() { + run_test_actions([ + TestAction::run(indoc! {" + const expected = []; + + const proxyConstructor = new Proxy(Intl.DateTimeFormat, { + get(target, prop) { + if (prop === 'prototype') { + expected.push('prototype-access'); + } + return target[prop]; + } + }); + + try { + new proxyConstructor('en', { timeZone: 'Invalid/Zone' }); + } catch (e) { + expected.push('error-thrown'); + } + "}), + TestAction::assert_eq("expected.length === 2", true), + TestAction::assert_eq("expected[0] === 'prototype-access'", true), + TestAction::assert_eq("expected[1] === 'error-thrown'", true), + ]); +}