Changeset 266170 in webkit


Ignore:
Timestamp:
Aug 26, 2020 9:48:33 AM (9 months ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Implement Intl.DateTimeFormat fractionalSecondDigits
https://bugs.webkit.org/show_bug.cgi?id=215840

Reviewed by Ross Kirsling.

JSTests:

Test262 is showing wrong ordering of option property accesses compared to the latest PR.
Later, we should update Test262.

  • stress/intl-datetimeformat.js:

(const.options.get second):
(const.options.get fractionalSecondDigits):
(const.options.get localeMatcher):
(const.options.get timeZoneName):
(const.options.get formatMatcher):

  • test262/config.yaml:
  • test262/expectations.yaml:

Source/JavaScriptCore:

This patch implements fractionalSecondDigits option for Intl.DateTimeFormat. If it is
specified, milliseconds in N digits are represented in the formatted output.
This extension is about to be merged into the spec[1]. SpiderMonkey and V8 support it,
and V8 shipped it without flags.

[1]: https://github.com/tc39/ecma402/pull/347

  • builtins/DatePrototype.js:

(toLocaleString.toDateTimeOptionsAnyAll):
(toLocaleString):
(toLocaleTimeString.toDateTimeOptionsTimeTime):
(toLocaleTimeString):

  • runtime/CommonIdentifiers.h:
  • runtime/IntlDateTimeFormat.cpp:

(JSC::toDateTimeOptionsAnyDate):
(JSC::IntlDateTimeFormat::setFormatsFromPattern):
(JSC::IntlDateTimeFormat::initializeDateTimeFormat):
(JSC::IntlDateTimeFormat::resolvedOptions const):
(JSC::partTypeString):

  • runtime/IntlDateTimeFormat.h:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r266164 r266170  
     12020-08-26  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Implement Intl.DateTimeFormat fractionalSecondDigits
     4        https://bugs.webkit.org/show_bug.cgi?id=215840
     5
     6        Reviewed by Ross Kirsling.
     7
     8        Test262 is showing wrong ordering of option property accesses compared to the latest PR.
     9        Later, we should update Test262.
     10
     11        * stress/intl-datetimeformat.js:
     12        (const.options.get second):
     13        (const.options.get fractionalSecondDigits):
     14        (const.options.get localeMatcher):
     15        (const.options.get timeZoneName):
     16        (const.options.get formatMatcher):
     17        * test262/config.yaml:
     18        * test262/expectations.yaml:
     19
    1202020-08-26  Paulo Matos  <pmatos@igalia.com>
    221
  • trunk/JSTests/stress/intl-datetimeformat.js

    r266039 r266170  
    661661shouldBe(JSON.stringify(Intl.DateTimeFormat('zh-u-ca-chinese', { era: 'short', year: 'numeric' }).formatToParts(0)), parts);
    662662shouldBe(JSON.stringify(Intl.DateTimeFormat('zh', { era: 'short', year: 'numeric', calendar: 'chinese' }).formatToParts(0)), parts);
     663
     664{
     665    let t = new Date("2019-05-20T07:00:23.123");
     666    {
     667        let dtf = new Intl.DateTimeFormat("en", {hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 3});
     668        shouldBe(dtf.format(t), `7:00:23.123 AM`);
     669        let expected = [
     670            {type: "hour", value: "7"},
     671            {type: "literal", value: ":"},
     672            {type: "minute", value: "00"},
     673            {type: "literal", value: ":"},
     674            {type: "second", value: "23"},
     675            {type: "literal", value: "."},
     676            {type: "fractionalSecond", value: "123"},
     677            {type: "literal", value: " "},
     678            {type: "dayPeriod", value: "AM"}
     679        ];
     680        let actual = dtf.formatToParts(t);
     681        shouldBe(actual.length, expected.length);
     682        for (let index = 0; index < expected.length; ++index) {
     683            shouldBe(actual[index].type, expected[index].type);
     684            shouldBe(actual[index].value, expected[index].value);
     685        }
     686    }
     687    {
     688        let dtf = new Intl.DateTimeFormat("en", {hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 2});
     689        shouldBe(dtf.format(t), `7:00:23.12 AM`);
     690    }
     691    {
     692        let dtf = new Intl.DateTimeFormat("en", {hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 1});
     693        shouldBe(dtf.format(t), `7:00:23.1 AM`);
     694        shouldBe(JSON.stringify(dtf.resolvedOptions()), `{"locale":"en","calendar":"gregory","numberingSystem":"latn","timeZone":"America/Los_Angeles","hourCycle":"h12","hour12":true,"hour":"numeric","minute":"2-digit","second":"2-digit","fractionalSecondDigits":1}`);
     695    }
     696    shouldThrow(() => {
     697        new Intl.DateTimeFormat("en", {hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 0});
     698    }, RangeError);
     699    shouldThrow(() => {
     700        new Intl.DateTimeFormat("en", {hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 4});
     701    }, RangeError);
     702}
     703{
     704    const expected = [
     705      "second",
     706      "fractionalSecondDigits",
     707      "localeMatcher",
     708      "second",
     709      "fractionalSecondDigits",
     710      "timeZoneName",
     711      "formatMatcher",
     712    ];
     713
     714    const actual = [];
     715
     716    const options = {
     717      get second() {
     718        actual.push("second");
     719        return "numeric";
     720      },
     721      get fractionalSecondDigits() {
     722        actual.push("fractionalSecondDigits");
     723        return undefined;
     724      },
     725      get localeMatcher() {
     726        actual.push("localeMatcher");
     727        return undefined;
     728      },
     729      get timeZoneName() {
     730        actual.push("timeZoneName");
     731        return undefined;
     732      },
     733      get formatMatcher() {
     734        actual.push("formatMatcher");
     735        return undefined;
     736      },
     737    };
     738
     739    new Intl.DateTimeFormat("en", options);
     740    shouldBe(JSON.stringify(actual), JSON.stringify(expected));
     741}
     742{
     743    shouldBe(new Date(0).toLocaleTimeString('zh-Hans-CN', { timeZone: 'UTC', numberingSystem: 'hanidec', hour: "numeric", minute: "numeric", second: "numeric", fractionalSecondDigits: 2 }), "上午一二:〇〇:〇〇.〇〇");
     744}
  • trunk/JSTests/test262/config.yaml

    r266035 r266170  
    2626    - top-level-await
    2727    - Intl.DateTimeFormat-dayPeriod
    28     - Intl.DateTimeFormat-fractionalSecondDigits
    2928    - Intl.ListFormat
    3029  paths:
  • trunk/JSTests/test262/expectations.yaml

    r266117 r266170  
    15521552  default: "Test262Error: \"kn-true\" is returned in locale, but shouldn't be. Expected SameValue(«7», «-1») to be true"
    15531553  strict mode: "Test262Error: \"kn-true\" is returned in locale, but shouldn't be. Expected SameValue(«7», «-1») to be true"
     1554test/intl402/DateTimeFormat/constructor-options-order-fractionalSecondDigits.js:
     1555  default: 'Test262Error: Expected [second, fractionalSecondDigits, localeMatcher, second, fractionalSecondDigits, timeZoneName, formatMatcher] and [second, fractionalSecondDigits, localeMatcher, second, timeZoneName, fractionalSecondDigits, formatMatcher] to have the same contents. '
     1556  strict mode: 'Test262Error: Expected [second, fractionalSecondDigits, localeMatcher, second, fractionalSecondDigits, timeZoneName, formatMatcher] and [second, fractionalSecondDigits, localeMatcher, second, timeZoneName, fractionalSecondDigits, formatMatcher] to have the same contents. '
    15541557test/intl402/DateTimeFormat/prototype/format/timedatestyle-en.js:
    15551558  default: 'Test262Error: Result for full with {} Expected SameValue(«14:12:47 PM Coordinated Universal Time», «14:12:47 Coordinated Universal Time») to be true'
     
    15581561  default: 'Test262Error: Expected SameValue(«1/3/2019 – 1/5/2019», «1/3/2019 – 1/5/2019») to be true'
    15591562  strict mode: 'Test262Error: Expected SameValue(«1/3/2019 – 1/5/2019», «1/3/2019 – 1/5/2019») to be true'
     1563test/intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits.js:
     1564  default: 'Test262Error: no fractionalSecondDigits Expected SameValue(«02:03 – 02:13», «02:03 – 02:13») to be true'
     1565  strict mode: 'Test262Error: no fractionalSecondDigits Expected SameValue(«02:03 – 02:13», «02:03 – 02:13») to be true'
    15601566test/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js:
    15611567  default: 'Test262Error: Expected SameValue(«h24», «h23») to be true'
  • trunk/Source/JavaScriptCore/ChangeLog

    r266159 r266170  
     12020-08-26  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Implement Intl.DateTimeFormat fractionalSecondDigits
     4        https://bugs.webkit.org/show_bug.cgi?id=215840
     5
     6        Reviewed by Ross Kirsling.
     7
     8        This patch implements fractionalSecondDigits option for Intl.DateTimeFormat. If it is
     9        specified, milliseconds in N digits are represented in the formatted output.
     10        This extension is about to be merged into the spec[1]. SpiderMonkey and V8 support it,
     11        and V8 shipped it without flags.
     12
     13        [1]: https://github.com/tc39/ecma402/pull/347
     14
     15        * builtins/DatePrototype.js:
     16        (toLocaleString.toDateTimeOptionsAnyAll):
     17        (toLocaleString):
     18        (toLocaleTimeString.toDateTimeOptionsTimeTime):
     19        (toLocaleTimeString):
     20        * runtime/CommonIdentifiers.h:
     21        * runtime/IntlDateTimeFormat.cpp:
     22        (JSC::toDateTimeOptionsAnyDate):
     23        (JSC::IntlDateTimeFormat::setFormatsFromPattern):
     24        (JSC::IntlDateTimeFormat::initializeDateTimeFormat):
     25        (JSC::IntlDateTimeFormat::resolvedOptions const):
     26        (JSC::partTypeString):
     27        * runtime/IntlDateTimeFormat.h:
     28
    1292020-08-25  Yusuke Suzuki  <ysuzuki@apple.com>
    230
  • trunk/Source/JavaScriptCore/builtins/DatePrototype.js

    r266035 r266170  
    4949            options.hour === @undefined &&
    5050            options.minute === @undefined &&
    51             options.second === @undefined
     51            options.second === @undefined &&
     52            options.fractionalSecondDigits === @undefined
    5253        );
    5354
     
    164165            options.hour === @undefined &&
    165166            options.minute === @undefined &&
    166             options.second === @undefined
     167            options.second === @undefined &&
     168            options.fractionalSecondDigits === @undefined
    167169        );
    168170
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r266035 r266170  
    117117    macro(formatToParts) \
    118118    macro(forward) \
     119    macro(fractionalSecondDigits) \
    119120    macro(from) \
    120121    macro(fromCharCode) \
  • trunk/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp

    r266035 r266170  
    249249    // Always "any".
    250250
    251     // a. For each of the property names "hour", "minute", "second":
     251    // a. For each of the property names "hour", "minute", "second", "fractionalSecondDigits":
    252252    // i. Let prop be the property name.
    253253    // ii. Let value be Get(options, prop).
     
    267267    RETURN_IF_EXCEPTION(scope, nullptr);
    268268    if (!second.isUndefined())
     269        needDefaults = false;
     270
     271    JSValue fractionalSecondDigits = options->get(globalObject, vm.propertyNames->fractionalSecondDigits);
     272    RETURN_IF_EXCEPTION(scope, nullptr);
     273    if (!fractionalSecondDigits.isUndefined())
    269274        needDefaults = false;
    270275
     
    403408                m_timeZoneName = TimeZoneName::Long;
    404409            break;
     410        case 'S':
     411            m_fractionalSecondDigits = count;
     412            break;
    405413        }
    406414    }
     
    626634    }
    627635
     636    unsigned fractionalSecondDigits = intlNumberOption(globalObject, options, vm.propertyNames->fractionalSecondDigits, 1, 3, 0);
     637    RETURN_IF_EXCEPTION(scope, void());
     638    for (unsigned i = 0; i < fractionalSecondDigits; ++i)
     639        skeletonBuilder.append('S');
     640
    628641    TimeZoneName timeZoneName = intlOption<TimeZoneName>(globalObject, options, vm.propertyNames->timeZoneName, { { "short"_s, TimeZoneName::Short }, { "long"_s, TimeZoneName::Long } }, "timeZoneName must be \"short\" or \"long\""_s, TimeZoneName::None);
    629642    RETURN_IF_EXCEPTION(scope, void());
     
    656669        //     iii. If p is not undefined, then
    657670        //         1. Throw a TypeError exception.
    658         if (weekday != Weekday::None || era != Era::None || year != Year::None || month != Month::None || day != Day::None || hour != Hour::None || minute != Minute::None || second != Second::None || timeZoneName != TimeZoneName::None) {
     671        if (weekday != Weekday::None || era != Era::None || year != Year::None || month != Month::None || day != Day::None || hour != Hour::None || minute != Minute::None || second != Second::None || fractionalSecondDigits != 0 || timeZoneName != TimeZoneName::None) {
    659672            throwTypeError(globalObject, scope, "dateStyle and timeStyle may not be used with other DateTimeFormat options"_s);
    660673            return;
     
    9991012        options->putDirect(vm, vm.propertyNames->second, jsNontrivialString(vm, secondString(m_second)));
    10001013
     1014    if (m_fractionalSecondDigits)
     1015        options->putDirect(vm, vm.propertyNames->fractionalSecondDigits, jsNumber(m_fractionalSecondDigits));
     1016
    10011017    if (m_timeZoneName != TimeZoneName::None)
    10021018        options->putDirect(vm, vm.propertyNames->timeZoneName, jsNontrivialString(vm, timeZoneNameString(m_timeZoneName)));
     
    10531069        return "minute"_s;
    10541070    case UDAT_SECOND_FIELD:
     1071        return "second"_s;
    10551072    case UDAT_FRACTIONAL_SECOND_FIELD:
    1056         return "second"_s;
     1073        return "fractionalSecond"_s;
    10571074    case UDAT_DAY_OF_WEEK_FIELD:
    10581075    case UDAT_DOW_LOCAL_FIELD:
  • trunk/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h

    r266035 r266170  
    121121    Minute m_minute { Minute::None };
    122122    Second m_second { Second::None };
     123    uint8_t m_fractionalSecondDigits { 0 };
    123124    TimeZoneName m_timeZoneName { TimeZoneName::None };
    124125    DateTimeStyle m_dateStyle { DateTimeStyle::None };
Note: See TracChangeset for help on using the changeset viewer.