WebKit Bugzilla
Attachment 345763 Details for
Bug 188006
: [INTL] Implement hourCycle in DateTimeFormat
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188006-20180725102925.patch (text/plain), 30.06 KB, created by
Andy VanWagoner
on 2018-07-25 09:29:26 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Andy VanWagoner
Created:
2018-07-25 09:29:26 PDT
Size:
30.06 KB
patch
obsolete
>Subversion Revision: 234130 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 22a1d91db810f8f6c0a054cfba29491a113b073b..16b0ed9a3a36fbd3d99c59bcdc2a5fe9ffa5e4a6 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,26 @@ >+2018-07-25 Andy VanWagoner <andy@vanwagoner.family> >+ >+ [INTL] Implement hourCycle in DateTimeFormat >+ https://bugs.webkit.org/show_bug.cgi?id=188006 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Implemented hourCycle, updating both the skeleton and the final pattern. >+ Changed resolveLocale to assume undefined options are not given and null >+ strings actually mean null, which removes the tag extension. >+ >+ * runtime/CommonIdentifiers.h: >+ * runtime/IntlCollator.cpp: >+ (JSC::IntlCollator::initializeCollator): >+ * runtime/IntlDateTimeFormat.cpp: >+ (JSC::IntlDTFInternal::localeData): >+ (JSC::IntlDateTimeFormat::setFormatsFromPattern): >+ (JSC::IntlDateTimeFormat::initializeDateTimeFormat): >+ (JSC::IntlDateTimeFormat::resolvedOptions): >+ * runtime/IntlDateTimeFormat.h: >+ * runtime/IntlObject.cpp: >+ (JSC::resolveLocale): >+ > 2018-07-23 Saam Barati <sbarati@apple.com> > > need to didFoldClobberWorld when we constant fold GetByVal >diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h >index 0d27c4e3ae4558a56ab2ea3bc6b4e42724afa0c5..80227f77a827d72c4f04d22de9a2225c3f95e389 100644 >--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h >+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h >@@ -138,6 +138,7 @@ > macro(hash) \ > macro(header) \ > macro(hour) \ >+ macro(hourCycle) \ > macro(hour12) \ > macro(href) \ > macro(id) \ >diff --git a/Source/JavaScriptCore/runtime/IntlCollator.cpp b/Source/JavaScriptCore/runtime/IntlCollator.cpp >index 144f76183f2e347645d2528fcadc299709043a80..eeba37f3dd8c2f7389a229adf835872e123b2de0 100644 >--- a/Source/JavaScriptCore/runtime/IntlCollator.cpp >+++ b/Source/JavaScriptCore/runtime/IntlCollator.cpp >@@ -216,12 +216,14 @@ void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue > RETURN_IF_EXCEPTION(scope, void()); > if (!usesFallback) > numericString = numeric ? "true"_s : "false"_s; >- opt.add("kn"_s, numericString); >+ if (!numericString.isNull()) >+ opt.add("kn"_s, numericString); > } > { > String caseFirst = intlStringOption(state, options, vm.propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr); > RETURN_IF_EXCEPTION(scope, void()); >- opt.add("kf"_s, caseFirst); >+ if (!caseFirst.isNull()) >+ opt.add("kf"_s, caseFirst); > } > > auto& availableLocales = state.jsCallee()->globalObject(vm)->intlCollatorAvailableLocales(); >diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp >index f340301a9d273ac902aabbb2d6ad14ca96718e5f..ff5044405832f2cad874c03c76d74710a9cf2407 100644 >--- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp >+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp >@@ -52,11 +52,12 @@ static const double minECMAScriptTime = -8.64E15; > const ClassInfo IntlDateTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlDateTimeFormat) }; > > namespace IntlDTFInternal { >-static const char* const relevantExtensionKeys[2] = { "ca", "nu" }; >+static const char* const relevantExtensionKeys[3] = { "ca", "nu", "hc" }; > } > > static const size_t indexOfExtensionKeyCa = 0; > static const size_t indexOfExtensionKeyNu = 1; >+static const size_t indexOfExtensionKeyHc = 2; > > void IntlDateTimeFormat::UDateFormatDeleter::operator()(UDateFormat* dateFormat) const > { >@@ -223,6 +224,14 @@ static Vector<String> localeData(const String& locale, size_t keyIndex) > case indexOfExtensionKeyNu: > keyLocaleData = numberingSystemsForLocale(locale); > break; >+ case indexOfExtensionKeyHc: >+ // Null default so we know to use 'j' in pattern. >+ keyLocaleData.append(String()); >+ keyLocaleData.append("h11"_s); >+ keyLocaleData.append("h12"_s); >+ keyLocaleData.append("h23"_s); >+ keyLocaleData.append("h24"_s); >+ break; > default: > ASSERT_NOT_REACHED(); > } >@@ -343,10 +352,17 @@ void IntlDateTimeFormat::setFormatsFromPattern(const StringView& pattern) > ++i; > } > >- if (currentCharacter == 'h' || currentCharacter == 'K') >- m_hour12 = true; >- else if (currentCharacter == 'H' || currentCharacter == 'k') >- m_hour12 = false; >+ // If hourCycle was null, this sets it to the locale default. >+ if (m_hourCycle.isNull()) { >+ if (currentCharacter == 'h') >+ m_hourCycle = "h12"_s; >+ else if (currentCharacter == 'H') >+ m_hourCycle = "h23"_s; >+ else if (currentCharacter == 'k') >+ m_hourCycle = "h24"_s; >+ else if (currentCharacter == 'K') >+ m_hourCycle = "h11"_s; >+ } > > switch (currentCharacter) { > case 'G': >@@ -430,92 +446,72 @@ void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue local > VM& vm = exec.vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >- // 12.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) (ECMA-402 2.0) >- // 1. If dateTimeFormat.[[initializedIntlObject]] is true, throw a TypeError exception. >- // 2. Set dateTimeFormat.[[initializedIntlObject]] to true. >+ // 12.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) (ECMA-402) >+ // https://tc39.github.io/ecma402/#sec-initializedatetimeformat > >- // 3. Let requestedLocales be CanonicalizeLocaleList(locales). > Vector<String> requestedLocales = canonicalizeLocaleList(exec, locales); >- // 4. ReturnIfAbrupt(requestedLocales), > RETURN_IF_EXCEPTION(scope, void()); > >- // 5. Let options be ToDateTimeOptions(options, "any", "date"). > JSObject* options = IntlDTFInternal::toDateTimeOptionsAnyDate(exec, originalOptions); >- // 6. ReturnIfAbrupt(options). > RETURN_IF_EXCEPTION(scope, void()); > >- // 7. Let opt be a new Record. >- HashMap<String, String> localeOpt; >+ HashMap<String, String> opt; > >- // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). > String localeMatcher = intlStringOption(exec, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); >- // 9. ReturnIfAbrupt(matcher). > RETURN_IF_EXCEPTION(scope, void()); >- // 10. Set opt.[[localeMatcher]] to matcher. >- localeOpt.add(vm.propertyNames->localeMatcher.string(), localeMatcher); >+ opt.add(vm.propertyNames->localeMatcher.string(), localeMatcher); >+ >+ bool isHour12Undefined; >+ bool hour12 = intlBooleanOption(exec, options, vm.propertyNames->hour12, isHour12Undefined); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ String hourCycle = intlStringOption(exec, options, vm.propertyNames->hourCycle, { "h11", "h12", "h23", "h24" }, "hourCycle must be \"h11\", \"h12\", \"h23\", or \"h24\"", nullptr); >+ RETURN_IF_EXCEPTION(scope, void()); >+ if (isHour12Undefined) { >+ // Set hour12 here to simplify hour logic later. >+ hour12 = (hourCycle == "h11" || hourCycle == "h12"); >+ if (!hourCycle.isNull()) >+ opt.add("hc"_s, hourCycle); >+ } else >+ opt.add("hc"_s, String()); > >- // 11. Let localeData be the value of %DateTimeFormat%.[[localeData]]. >- // 12. Let r be ResolveLocale( %DateTimeFormat%.[[availableLocales]], requestedLocales, opt, %DateTimeFormat%.[[relevantExtensionKeys]], localeData). > const HashSet<String> availableLocales = exec.jsCallee()->globalObject(vm)->intlDateTimeFormatAvailableLocales(); >- HashMap<String, String> resolved = resolveLocale(exec, availableLocales, requestedLocales, localeOpt, IntlDTFInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlDTFInternal::relevantExtensionKeys), IntlDTFInternal::localeData); >+ HashMap<String, String> resolved = resolveLocale(exec, availableLocales, requestedLocales, opt, IntlDTFInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlDTFInternal::relevantExtensionKeys), IntlDTFInternal::localeData); > >- // 13. Set dateTimeFormat.[[locale]] to the value of r.[[locale]]. > m_locale = resolved.get(vm.propertyNames->locale.string()); > if (m_locale.isEmpty()) { > throwTypeError(&exec, scope, "failed to initialize DateTimeFormat due to invalid locale"_s); > return; > } >- // 14. Set dateTimeFormat.[[calendar]] to the value of r.[[ca]]. >+ > m_calendar = resolved.get("ca"_s); >- // Switch to preferred aliases. > if (m_calendar == "gregorian") > m_calendar = "gregory"_s; > else if (m_calendar == "islamicc") > m_calendar = "islamic-civil"_s; > else if (m_calendar == "ethioaa") > m_calendar = "ethiopic-amete-alem"_s; >- // 15. Set dateTimeFormat.[[numberingSystem]] to the value of r.[[nu]]. >+ >+ m_hourCycle = resolved.get("hc"_s); > m_numberingSystem = resolved.get("nu"_s); >- // 16. Let dataLocale be the value of r.[[dataLocale]]. > String dataLocale = resolved.get("dataLocale"_s); > >- // 17. Let tz be Get(options, "timeZone"). > JSValue tzValue = options->get(&exec, vm.propertyNames->timeZone); >- // 18. ReturnIfAbrupt(tz). > RETURN_IF_EXCEPTION(scope, void()); >- >- // 19. If tz is not undefined, then > String tz; > if (!tzValue.isUndefined()) { >- // a. Let tz be ToString(tz). > String originalTz = tzValue.toWTFString(&exec); >- // b. ReturnIfAbrupt(tz). > RETURN_IF_EXCEPTION(scope, void()); >- // c. If the result of IsValidTimeZoneName(tz) is false, then i. Throw a RangeError exception. >- // d. Let tz be CanonicalizeTimeZoneName(tz). > tz = canonicalizeTimeZoneName(originalTz); > if (tz.isNull()) { > throwRangeError(&exec, scope, String::format("invalid time zone: %s", originalTz.utf8().data())); > return; > } >- } else { >- // 20. Else, >- // a. Let tz be DefaultTimeZone(). >+ } else > tz = defaultTimeZone(); >- } >- >- // 21. Set dateTimeFormat.[[timeZone]] to tz. > m_timeZone = tz; > >- // 22. Let opt be a new Record. >- // Rather than building a record, build the skeleton pattern. > StringBuilder skeletonBuilder; >- >- // 23. For each row of Table 3, except the header row, do: >- // a. Let prop be the name given in the Property column of the row. >- // b. Let value be GetOption(options, prop, "string", «the strings given in the Values column of the row», undefined). >- // c. ReturnIfAbrupt(value). >- // d. Set opt.[[<prop>]] to value. > auto narrowShortLong = { "narrow", "short", "long" }; > auto twoDigitNumeric = { "2-digit", "numeric" }; > auto twoDigitNumericNarrowShortLong = { "2-digit", "numeric", "narrow", "short", "long" }; >@@ -578,32 +574,22 @@ void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue local > > String hour = intlStringOption(exec, options, vm.propertyNames->hour, twoDigitNumeric, "hour must be \"2-digit\" or \"numeric\"", nullptr); > RETURN_IF_EXCEPTION(scope, void()); >- >- // We need hour12 to make the hour skeleton pattern decision, so do this early. >- // 32. Let hr12 be GetOption(options, "hour12", "boolean", undefined, undefined). >- bool isHour12Undefined; >- bool hr12 = intlBooleanOption(exec, options, vm.propertyNames->hour12, isHour12Undefined); >- // 33. ReturnIfAbrupt(hr12). >- RETURN_IF_EXCEPTION(scope, void()); >- >- if (!hour.isNull()) { >- if (isHour12Undefined) { >- if (hour == "2-digit") >- skeletonBuilder.appendLiteral("jj"); >- else if (hour == "numeric") >- skeletonBuilder.append('j'); >- } else if (hr12) { >- if (hour == "2-digit") >- skeletonBuilder.appendLiteral("hh"); >- else if (hour == "numeric") >- skeletonBuilder.append('h'); >- } else { >- if (hour == "2-digit") >- skeletonBuilder.appendLiteral("HH"); >- else if (hour == "numeric") >- skeletonBuilder.append('H'); >- } >- } >+ if (hour == "2-digit") { >+ if (isHour12Undefined && m_hourCycle.isNull()) >+ skeletonBuilder.appendLiteral("jj"); >+ else if (hour12) >+ skeletonBuilder.appendLiteral("hh"); >+ else >+ skeletonBuilder.appendLiteral("HH"); >+ } else if (hour == "numeric") { >+ if (isHour12Undefined && m_hourCycle.isNull()) >+ skeletonBuilder.append('j'); >+ else if (hour12) >+ skeletonBuilder.append('h'); >+ else >+ skeletonBuilder.append('H'); >+ } else >+ m_hourCycle = String(); > > String minute = intlStringOption(exec, options, vm.propertyNames->minute, twoDigitNumeric, "minute must be \"2-digit\" or \"numeric\"", nullptr); > RETURN_IF_EXCEPTION(scope, void()); >@@ -632,15 +618,10 @@ void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue local > skeletonBuilder.appendLiteral("zzzz"); > } > >- // 24. Let dataLocaleData be Get(localeData, dataLocale). >- // 25. Let formats be Get(dataLocaleData, "formats"). >- // 26. Let matcher be GetOption(options, "formatMatcher", "string", «"basic", "best fit"», "best fit"). > intlStringOption(exec, options, vm.propertyNames->formatMatcher, { "basic", "best fit" }, "formatMatcher must be either \"basic\" or \"best fit\"", "best fit"); >- // 27. ReturnIfAbrupt(matcher). > RETURN_IF_EXCEPTION(scope, void()); > > // Always use ICU date format generator, rather than our own pattern list and matcher. >- // Covers steps 28-36. > UErrorCode status = U_ZERO_ERROR; > UDateTimePatternGenerator* generator = udatpg_open(dataLocale.utf8().data(), &status); > if (U_FAILURE(status)) { >@@ -664,6 +645,31 @@ void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue local > return; > } > >+ // Enforce our hourCycle, replacing hour characters in pattern. >+ if (!m_hourCycle.isNull()) { >+ UChar hour = 'H'; >+ if (m_hourCycle == "h11") >+ hour = 'K'; >+ else if (m_hourCycle == "h12") >+ hour = 'h'; >+ else if (m_hourCycle == "h24") >+ hour = 'k'; >+ >+ bool isEscaped = false; >+ bool hasHour = false; >+ for (auto i = 0; i < patternLength; ++i) { >+ UChar c = patternBuffer[i]; >+ if (c == '\'') >+ isEscaped = !isEscaped; >+ else if (!isEscaped && (c == 'h' || c == 'H' || c == 'k' || c == 'K')) { >+ patternBuffer[i] = hour; >+ hasHour = true; >+ } >+ } >+ if (!hasHour) >+ m_hourCycle = String(); >+ } >+ > StringView pattern(patternBuffer.data(), patternLength); > setFormatsFromPattern(pattern); > >@@ -680,13 +686,7 @@ void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue local > UCalendar* cal = const_cast<UCalendar*>(udat_getCalendar(m_dateFormat.get())); > ucal_setGregorianChange(cal, minECMAScriptTime, &status); > >- // 37. Set dateTimeFormat.[[boundFormat]] to undefined. >- // Already undefined. >- >- // 38. Set dateTimeFormat.[[initializedDateTimeFormat]] to true. > m_initializedDateTimeFormat = true; >- >- // 39. Return dateTimeFormat. > } > > ASCIILiteral IntlDateTimeFormat::weekdayString(Weekday weekday) >@@ -868,9 +868,12 @@ JSObject* IntlDateTimeFormat::resolvedOptions(ExecState& exec) > if (m_day != Day::None) > options->putDirect(vm, vm.propertyNames->day, jsNontrivialString(&exec, dayString(m_day))); > >- if (m_hour != Hour::None) { >+ if (m_hour != Hour::None) > options->putDirect(vm, vm.propertyNames->hour, jsNontrivialString(&exec, hourString(m_hour))); >- options->putDirect(vm, vm.propertyNames->hour12, jsBoolean(m_hour12)); >+ >+ if (!m_hourCycle.isNull()) { >+ options->putDirect(vm, vm.propertyNames->hourCycle, jsNontrivialString(&exec, m_hourCycle)); >+ options->putDirect(vm, vm.propertyNames->hour12, jsBoolean(m_hourCycle == "h11" || m_hourCycle == "h12")); > } > > if (m_minute != Minute::None) >diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h >index e2dcd0f6df7472d69b1dbc729035f29e8cbdf500..0762639bd570d38c46aea8322863fc65da8d3117 100644 >--- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h >+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h >@@ -97,7 +97,7 @@ private: > String m_calendar; > String m_numberingSystem; > String m_timeZone; >- bool m_hour12 { true }; >+ String m_hourCycle; > Weekday m_weekday { Weekday::None }; > Era m_era { Era::None }; > Year m_year { Year::None }; >diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp >index a1eae22b69b87f8756b17aebe442490ccb0ba93c..c61dc7098a9e00b56bd666907d30a831bb8c75f4 100644 >--- a/Source/JavaScriptCore/runtime/IntlObject.cpp >+++ b/Source/JavaScriptCore/runtime/IntlObject.cpp >@@ -765,11 +765,11 @@ HashMap<String, String> resolveLocale(ExecState& state, const HashSet<String>& a > HashMap<String, String>::const_iterator iterator = options.find(key); > if (iterator != options.end()) { > const String& optionsValue = iterator->value; >- if (!optionsValue.isNull() && keyLocaleData.contains(optionsValue)) { >- if (optionsValue != value) { >- value = optionsValue; >- supportedExtensionAddition = String(); >- } >+ // Undefined should not get added to the options, it won't displace the extension. >+ // Null will remove the extension. >+ if ((optionsValue.isNull() || keyLocaleData.contains(optionsValue)) && optionsValue != value) { >+ value = optionsValue; >+ supportedExtensionAddition = String(); > } > } > result.add(key, value); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 222997712eb5f6bc15f9dfc1dd5c2f5cdff28200..0a43d9d84f8e80c8b341d62636bf8e1fdae019f9 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,15 @@ >+2018-07-25 Andy VanWagoner <andy@vanwagoner.family> >+ >+ [INTL] Implement hourCycle in DateTimeFormat >+ https://bugs.webkit.org/show_bug.cgi?id=188006 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Added tests for hourCycle. >+ >+ * js/intl-datetimeformat-expected.txt: >+ * js/script-tests/intl-datetimeformat.js: >+ > 2018-07-23 Andy VanWagoner <andy@vanwagoner.family> > > [INTL] Language tags are not canonicalized >diff --git a/LayoutTests/js/intl-datetimeformat-expected.txt b/LayoutTests/js/intl-datetimeformat-expected.txt >index 0c426b9ec7f68e314f330c5aa69a4aa1bb7e3a21..404587a3208be26957e7ee7df0068af5525277be 100644 >--- a/LayoutTests/js/intl-datetimeformat-expected.txt >+++ b/LayoutTests/js/intl-datetimeformat-expected.txt >@@ -99,6 +99,7 @@ PASS Intl.DateTimeFormat('en').resolvedOptions().month is 'numeric' > PASS Intl.DateTimeFormat('en').resolvedOptions().day is 'numeric' > PASS Intl.DateTimeFormat('en').resolvedOptions().year is 'numeric' > PASS Intl.DateTimeFormat('en').resolvedOptions().hour is undefined >+PASS Intl.DateTimeFormat('en').resolvedOptions().hourCycle is undefined > PASS Intl.DateTimeFormat('en').resolvedOptions().hour12 is undefined > PASS Intl.DateTimeFormat('en').resolvedOptions().minute is undefined > PASS Intl.DateTimeFormat('en').resolvedOptions().second is undefined >@@ -243,6 +244,24 @@ PASS Intl.DateTimeFormat('en-u-nu-tamldec', { timeZone: 'America/Los_Angeles' }) > PASS Intl.DateTimeFormat('en-u-nu-telu', { timeZone: 'America/Los_Angeles' }).format(1451099872641) is '౧౨/౨౫/౨౦౧౫' > PASS Intl.DateTimeFormat('en-u-nu-thai', { timeZone: 'America/Los_Angeles' }).format(1451099872641) is 'à¹à¹/à¹à¹/à¹à¹à¹à¹' > PASS Intl.DateTimeFormat('en-u-nu-tibt', { timeZone: 'America/Los_Angeles' }).format(1451099872641) is '༡༢/༢༥/༢༠༡༥' >+PASS Intl.DateTimeFormat('en-u-hc-h11').resolvedOptions().locale is 'en-u-hc-h11' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h12' }).resolvedOptions().locale is 'en' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h12' }).resolvedOptions().hourCycle is 'h12' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: true }).resolvedOptions().locale is 'en' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: true }).resolvedOptions().hourCycle is 'h12' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: false }).resolvedOptions().hourCycle is 'h23' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric' }).resolvedOptions().hourCycle is 'h11' >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric' }).resolvedOptions().hour12 is true >+PASS Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', timeZone: 'UTC' }).format(12 * 60 * 60 * 1000).slice(0, 1) is '0' >+PASS Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric' }).resolvedOptions().hourCycle is 'h12' >+PASS Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric' }).resolvedOptions().hour12 is true >+PASS Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric', timeZone: 'UTC' }).format(12 * 60 * 60 * 1000).slice(0, 2) is '12' >+PASS Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric' }).resolvedOptions().hourCycle is 'h23' >+PASS Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric' }).resolvedOptions().hour12 is false >+PASS Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric', timeZone: 'UTC' }).format(0) is '00' >+PASS Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric' }).resolvedOptions().hourCycle is 'h24' >+PASS Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric' }).resolvedOptions().hour12 is false >+PASS Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric', timeZone: 'UTC' }).format(0) is '24' > PASS Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-arab', { timeZone: 'America/Los_Angeles' }).format(1451099872641) is 'Ù£/١٤/١٤٣٧' > PASS Intl.DateTimeFormat('en', { weekday: { toString() { throw 'weekday' } } }) threw exception weekday. > PASS Intl.DateTimeFormat('en', { weekday:'invalid' }) threw exception RangeError: weekday must be "narrow", "short", or "long". >@@ -297,8 +316,10 @@ PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'2-digit', timeZone: 'UT > PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hour is 'numeric' > PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0) is '12:00 AM' > PASS Intl.DateTimeFormat('en').resolvedOptions().hour12 is undefined >+PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hourCycle is 'h12' > PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hour12 is true > PASS Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0) is '12:00 AM' >+PASS Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hourCycle is 'h23' > PASS Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hour12 is false > PASS Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0) is '00:00' > PASS Intl.DateTimeFormat('en', { minute: { toString() { throw 'minute' } } }) threw exception minute. >diff --git a/LayoutTests/js/script-tests/intl-datetimeformat.js b/LayoutTests/js/script-tests/intl-datetimeformat.js >index ffda67df2fda576c07690df1eaa3b5d5796e1a80..28aed4d3b12e03efba897df6c9820af2ea5b2451 100644 >--- a/LayoutTests/js/script-tests/intl-datetimeformat.js >+++ b/LayoutTests/js/script-tests/intl-datetimeformat.js >@@ -196,6 +196,7 @@ shouldBe("Intl.DateTimeFormat('en').resolvedOptions().month", "'numeric'"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().day", "'numeric'"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().year", "'numeric'"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().hour", "undefined"); >+shouldBe("Intl.DateTimeFormat('en').resolvedOptions().hourCycle", "undefined"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().hour12", "undefined"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().minute", "undefined"); > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().second", "undefined"); >@@ -349,6 +350,26 @@ shouldBe("Intl.DateTimeFormat('en-u-nu-telu', { timeZone: 'America/Los_Angeles' > shouldBe("Intl.DateTimeFormat('en-u-nu-thai', { timeZone: 'America/Los_Angeles' }).format(1451099872641)", "'à¹à¹/à¹à¹/à¹à¹à¹à¹'"); > shouldBe("Intl.DateTimeFormat('en-u-nu-tibt', { timeZone: 'America/Los_Angeles' }).format(1451099872641)", "'༡༢/༢༥/༢༠༡༥'"); > >+// Hour cycle sensitive format(). >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11').resolvedOptions().locale", "'en-u-hc-h11'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h12' }).resolvedOptions().locale", "'en'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h12' }).resolvedOptions().hourCycle", "'h12'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: true }).resolvedOptions().locale", "'en'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: true }).resolvedOptions().hourCycle", "'h12'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', hourCycle: 'h11', hour12: false }).resolvedOptions().hourCycle", "'h23'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric' }).resolvedOptions().hourCycle", "'h11'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric' }).resolvedOptions().hour12", "true") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h11', { hour: 'numeric', timeZone: 'UTC' }).format(12 * 60 * 60 * 1000).slice(0, 1)", "'0'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric' }).resolvedOptions().hourCycle", "'h12'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric' }).resolvedOptions().hour12", "true") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h12', { hour: 'numeric', timeZone: 'UTC' }).format(12 * 60 * 60 * 1000).slice(0, 2)", "'12'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric' }).resolvedOptions().hourCycle", "'h23'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric' }).resolvedOptions().hour12", "false") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h23', { hour: 'numeric', timeZone: 'UTC' }).format(0)", "'00'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric' }).resolvedOptions().hourCycle", "'h24'") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric' }).resolvedOptions().hour12", "false") >+shouldBe("Intl.DateTimeFormat('en-u-hc-h24', { hour: 'numeric', timeZone: 'UTC' }).format(0)", "'24'") >+ > // Tests multiple keys in extension. > shouldBe("Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-arab', { timeZone: 'America/Los_Angeles' }).format(1451099872641)", "'Ù£/١٤/١٤٣٧'"); > >@@ -411,8 +432,10 @@ shouldBe("Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolv > shouldBe("Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0)", "'12:00 AM'"); > > shouldBe("Intl.DateTimeFormat('en').resolvedOptions().hour12", "undefined"); >+shouldBe("Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hourCycle", "'h12'"); > shouldBe("Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hour12", "true"); > shouldBe("Intl.DateTimeFormat('en', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0)", "'12:00 AM'"); >+shouldBe("Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hourCycle", "'h23'"); > shouldBe("Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric' }).resolvedOptions().hour12", "false"); > shouldBe("Intl.DateTimeFormat('pt-BR', { minute:'2-digit', hour:'numeric', timeZone: 'UTC' }).format(0)", "'00:00'"); > >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index e40deacf43a18c306645ec3b4d3b0a007fadd0c3..d1f415e616491c09e6f304185699731cd091c7b5 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,14 @@ >+2018-07-25 Andy VanWagoner <andy@vanwagoner.family> >+ >+ [INTL] Implement hourCycle in DateTimeFormat >+ https://bugs.webkit.org/show_bug.cgi?id=188006 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Removed fixed hourCycle expectations. >+ >+ * test262/expectations.yaml: >+ > 2018-07-23 Saam Barati <sbarati@apple.com> > > need to didFoldClobberWorld when we constant fold GetByVal >diff --git a/JSTests/test262/expectations.yaml b/JSTests/test262/expectations.yaml >index b462a2b342776fefb5a7b548db739034e7df416c..9dc133da1bfa0747bf349bab540b1e413049f3ad 100644 >--- a/JSTests/test262/expectations.yaml >+++ b/JSTests/test262/expectations.yaml >@@ -1480,12 +1480,6 @@ test/intl402/DateTimeFormat/prototype/format/format-function-name.js: > test/intl402/DateTimeFormat/prototype/formatToParts/length.js: > default: 'Test262Error: Expected SameValue(ë0û, ë1û) to be true' > strict mode: 'Test262Error: Expected SameValue(ë0û, ë1û) to be true' >-test/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle.js: >- default: 'Test262Error: Expected SameValue(ëundefinedû, ëh11û) to be true' >- strict mode: 'Test262Error: Expected SameValue(ëundefinedû, ëh11û) to be true' >-test/intl402/DateTimeFormat/prototype/resolvedOptions/resolved-locale-with-hc-unicode.js: >- default: 'Test262Error: Only hc Unicode extension value is present. (With hour option.) Expected SameValue(ëen-USû, ëen-US-u-hc-h11û) to be true' >- strict mode: 'Test262Error: Only hc Unicode extension value is present. (With hour option.) Expected SameValue(ëen-USû, ëen-US-u-hc-h11û) to be true' > test/intl402/Intl/getCanonicalLocales/Locale-object.js: > default: "TypeError: undefined is not a constructor (evaluating 'new Intl.Locale(\"en-gb-oed\")')" > strict mode: "TypeError: undefined is not a constructor (evaluating 'new Intl.Locale(\"en-gb-oed\")')"
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188006
:
345763
|
345789
|
345912
|
345914
|
346002