|
Lines 329-346
void IntlDateTimeFormat::setFormatsFromPattern(const StringView& pattern)
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec1
|
| 329 |
++i; |
329 |
++i; |
| 330 |
} |
330 |
} |
| 331 |
|
331 |
|
| 332 |
// If hourCycle was null, this sets it to the locale default. |
|
|
| 333 |
if (m_hourCycle.isNull()) { |
| 334 |
if (currentCharacter == 'h') |
| 335 |
m_hourCycle = "h12"_s; |
| 336 |
else if (currentCharacter == 'H') |
| 337 |
m_hourCycle = "h23"_s; |
| 338 |
else if (currentCharacter == 'k') |
| 339 |
m_hourCycle = "h24"_s; |
| 340 |
else if (currentCharacter == 'K') |
| 341 |
m_hourCycle = "h11"_s; |
| 342 |
} |
| 343 |
|
| 344 |
switch (currentCharacter) { |
332 |
switch (currentCharacter) { |
| 345 |
case 'G': |
333 |
case 'G': |
| 346 |
if (count <= 3) |
334 |
if (count <= 3) |
|
Lines 398-409
void IntlDateTimeFormat::setFormatsFromPattern(const StringView& pattern)
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec2
|
| 398 |
case 'h': |
386 |
case 'h': |
| 399 |
case 'H': |
387 |
case 'H': |
| 400 |
case 'k': |
388 |
case 'k': |
| 401 |
case 'K': |
389 |
case 'K': { |
|
|
390 |
// Populate hourCycle from actually generated patterns. It is possible that locale or option is specifying hourCycle explicitly, |
| 391 |
// but the generated pattern does not include related part since the pattern does not include hours. |
| 392 |
// This is tested in test262/test/intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-dateStyle.js and our stress tests. |
| 393 |
// Example: |
| 394 |
// new Intl.DateTimeFormat(`de-u-hc-h11`, { |
| 395 |
// dateStyle: "full" |
| 396 |
// }).resolvedOptions().hourCycle === undefined |
| 397 |
switch (currentCharacter) { |
| 398 |
case 'h': |
| 399 |
m_hourCycle = HourCycle::H12; |
| 400 |
break; |
| 401 |
case 'H': |
| 402 |
m_hourCycle = HourCycle::H23; |
| 403 |
break; |
| 404 |
case 'k': |
| 405 |
m_hourCycle = HourCycle::H24; |
| 406 |
break; |
| 407 |
case 'K': |
| 408 |
m_hourCycle = HourCycle::H11; |
| 409 |
break; |
| 410 |
} |
| 402 |
if (count == 1) |
411 |
if (count == 1) |
| 403 |
m_hour = Hour::Numeric; |
412 |
m_hour = Hour::Numeric; |
| 404 |
else if (count == 2) |
413 |
else if (count == 2) |
| 405 |
m_hour = Hour::TwoDigit; |
414 |
m_hour = Hour::TwoDigit; |
| 406 |
break; |
415 |
break; |
|
|
416 |
} |
| 407 |
case 'm': |
417 |
case 'm': |
| 408 |
if (count == 1) |
418 |
if (count == 1) |
| 409 |
m_minute = Minute::Numeric; |
419 |
m_minute = Minute::Numeric; |
|
Lines 431-436
void IntlDateTimeFormat::setFormatsFromPattern(const StringView& pattern)
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec3
|
| 431 |
} |
441 |
} |
| 432 |
} |
442 |
} |
| 433 |
|
443 |
|
|
|
444 |
IntlDateTimeFormat::HourCycle IntlDateTimeFormat::parseHourCycle(const String& hourCycle) |
| 445 |
{ |
| 446 |
if (hourCycle == "h11"_s) |
| 447 |
return HourCycle::H11; |
| 448 |
if (hourCycle == "h12"_s) |
| 449 |
return HourCycle::H12; |
| 450 |
if (hourCycle == "h23"_s) |
| 451 |
return HourCycle::H23; |
| 452 |
if (hourCycle == "h24"_s) |
| 453 |
return HourCycle::H24; |
| 454 |
return HourCycle::None; |
| 455 |
} |
| 456 |
|
| 457 |
IntlDateTimeFormat::HourCycle IntlDateTimeFormat::hourCycleFromPattern(const Vector<UChar, 32>& pattern) |
| 458 |
{ |
| 459 |
for (auto character : pattern) { |
| 460 |
switch (character) { |
| 461 |
case 'K': |
| 462 |
return HourCycle::H11; |
| 463 |
case 'h': |
| 464 |
return HourCycle::H12; |
| 465 |
case 'H': |
| 466 |
return HourCycle::H23; |
| 467 |
case 'k': |
| 468 |
return HourCycle::H24; |
| 469 |
} |
| 470 |
} |
| 471 |
return HourCycle::None; |
| 472 |
} |
| 473 |
|
| 474 |
void IntlDateTimeFormat::replaceHourCycleInSkeleton(Vector<UChar, 32>& skeleton, bool isHour12) |
| 475 |
{ |
| 476 |
UChar skeletonCharacter = 'H'; |
| 477 |
if (isHour12) |
| 478 |
skeletonCharacter = 'h'; |
| 479 |
for (auto& character : skeleton) { |
| 480 |
switch (character) { |
| 481 |
case 'h': |
| 482 |
case 'H': |
| 483 |
case 'j': |
| 484 |
character = skeletonCharacter; |
| 485 |
break; |
| 486 |
} |
| 487 |
} |
| 488 |
} |
| 489 |
|
| 490 |
void IntlDateTimeFormat::replaceHourCycleInPattern(Vector<UChar, 32>& pattern, HourCycle hourCycle) |
| 491 |
{ |
| 492 |
UChar hourFromHourCycle = 'H'; |
| 493 |
switch (hourCycle) { |
| 494 |
case HourCycle::H11: |
| 495 |
hourFromHourCycle = 'K'; |
| 496 |
break; |
| 497 |
case HourCycle::H12: |
| 498 |
hourFromHourCycle = 'h'; |
| 499 |
break; |
| 500 |
case HourCycle::H23: |
| 501 |
hourFromHourCycle = 'H'; |
| 502 |
break; |
| 503 |
case HourCycle::H24: |
| 504 |
hourFromHourCycle = 'k'; |
| 505 |
break; |
| 506 |
case HourCycle::None: |
| 507 |
return; |
| 508 |
} |
| 509 |
|
| 510 |
for (auto& character : pattern) { |
| 511 |
switch (character) { |
| 512 |
case 'K': |
| 513 |
case 'h': |
| 514 |
case 'H': |
| 515 |
case 'k': |
| 516 |
character = hourFromHourCycle; |
| 517 |
break; |
| 518 |
} |
| 519 |
} |
| 520 |
} |
| 521 |
|
| 434 |
// https://tc39.github.io/ecma402/#sec-initializedatetimeformat |
522 |
// https://tc39.github.io/ecma402/#sec-initializedatetimeformat |
| 435 |
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject, JSValue locales, JSValue originalOptions) |
523 |
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject, JSValue locales, JSValue originalOptions) |
| 436 |
{ |
524 |
{ |
|
Lines 470-486
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec4
|
| 470 |
|
558 |
|
| 471 |
TriState hour12 = intlBooleanOption(globalObject, options, vm.propertyNames->hour12); |
559 |
TriState hour12 = intlBooleanOption(globalObject, options, vm.propertyNames->hour12); |
| 472 |
RETURN_IF_EXCEPTION(scope, void()); |
560 |
RETURN_IF_EXCEPTION(scope, void()); |
| 473 |
bool isHour12Undefined = (hour12 == TriState::Indeterminate); |
|
|
| 474 |
|
561 |
|
| 475 |
String hourCycle = intlStringOption(globalObject, options, vm.propertyNames->hourCycle, { "h11", "h12", "h23", "h24" }, "hourCycle must be \"h11\", \"h12\", \"h23\", or \"h24\"", nullptr); |
562 |
HourCycle hourCycle = intlOption<HourCycle>(globalObject, options, vm.propertyNames->hourCycle, { { "h11"_s, HourCycle::H11 }, { "h12"_s, HourCycle::H12 }, { "h23"_s, HourCycle::H23 }, { "h24"_s, HourCycle::H24 } }, "hourCycle must be \"h11\", \"h12\", \"h23\", or \"h24\""_s, HourCycle::None); |
| 476 |
RETURN_IF_EXCEPTION(scope, void()); |
563 |
RETURN_IF_EXCEPTION(scope, void()); |
| 477 |
if (isHour12Undefined) { |
564 |
if (hour12 == TriState::Indeterminate) { |
| 478 |
// Set hour12 here to simplify hour logic later. |
565 |
if (hourCycle != HourCycle::None) |
| 479 |
hour12 = triState(hourCycle == "h11" || hourCycle == "h12"); |
566 |
localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = String(hourCycleString(hourCycle)); |
| 480 |
if (!hourCycle.isNull()) |
567 |
} else { |
| 481 |
localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = hourCycle; |
568 |
// If there is hour12, hourCycle is ignored. |
| 482 |
} else |
|
|
| 483 |
localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = String(); |
569 |
localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = String(); |
|
|
570 |
} |
| 484 |
|
571 |
|
| 485 |
const HashSet<String>& availableLocales = intlDateTimeFormatAvailableLocales(); |
572 |
const HashSet<String>& availableLocales = intlDateTimeFormatAvailableLocales(); |
| 486 |
auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Ca, RelevantExtensionKey::Hc, RelevantExtensionKey::Nu }, localeData); |
573 |
auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Ca, RelevantExtensionKey::Hc, RelevantExtensionKey::Nu }, localeData); |
|
Lines 499-505
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec5
|
| 499 |
else if (m_calendar == "ethioaa") |
586 |
else if (m_calendar == "ethioaa") |
| 500 |
m_calendar = "ethiopic-amete-alem"_s; |
587 |
m_calendar = "ethiopic-amete-alem"_s; |
| 501 |
|
588 |
|
| 502 |
m_hourCycle = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Hc)]; |
589 |
hourCycle = parseHourCycle(resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Hc)]); |
| 503 |
m_numberingSystem = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Nu)]; |
590 |
m_numberingSystem = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Nu)]; |
| 504 |
m_dataLocale = resolved.dataLocale; |
591 |
m_dataLocale = resolved.dataLocale; |
| 505 |
CString dataLocaleWithExtensions = makeString(m_dataLocale, "-u-ca-", m_calendar, "-nu-", m_numberingSystem).utf8(); |
592 |
CString dataLocaleWithExtensions = makeString(m_dataLocale, "-u-ca-", m_calendar, "-nu-", m_numberingSystem).utf8(); |
|
Lines 609-633
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec6
|
| 609 |
|
696 |
|
| 610 |
Hour hour = intlOption<Hour>(globalObject, options, vm.propertyNames->hour, { { "2-digit"_s, Hour::TwoDigit }, { "numeric"_s, Hour::Numeric } }, "hour must be \"2-digit\" or \"numeric\""_s, Hour::None); |
697 |
Hour hour = intlOption<Hour>(globalObject, options, vm.propertyNames->hour, { { "2-digit"_s, Hour::TwoDigit }, { "numeric"_s, Hour::Numeric } }, "hour must be \"2-digit\" or \"numeric\""_s, Hour::None); |
| 611 |
RETURN_IF_EXCEPTION(scope, void()); |
698 |
RETURN_IF_EXCEPTION(scope, void()); |
| 612 |
switch (hour) { |
699 |
{ |
| 613 |
case Hour::TwoDigit: |
700 |
// In skeleton construction, there is no way to specify h11 v.s. h12, h23 v.s. h24. They are enforced after generating pattern. |
| 614 |
if (isHour12Undefined && m_hourCycle.isNull()) |
701 |
UChar skeletonCharacter = 'j'; |
| 615 |
skeletonBuilder.appendLiteral("jj"); |
702 |
if (hour12 == TriState::Indeterminate) { |
| 616 |
else if (hour12 == TriState::True) |
703 |
switch (hourCycle) { |
| 617 |
skeletonBuilder.appendLiteral("hh"); |
704 |
case HourCycle::None: |
| 618 |
else |
705 |
skeletonCharacter = 'j'; |
| 619 |
skeletonBuilder.appendLiteral("HH"); |
706 |
break; |
| 620 |
break; |
707 |
case HourCycle::H11: |
| 621 |
case Hour::Numeric: |
708 |
case HourCycle::H12: |
| 622 |
if (isHour12Undefined && m_hourCycle.isNull()) |
709 |
skeletonCharacter = 'h'; |
| 623 |
skeletonBuilder.append('j'); |
710 |
break; |
| 624 |
else if (hour12 == TriState::True) |
711 |
case HourCycle::H23: |
| 625 |
skeletonBuilder.append('h'); |
712 |
case HourCycle::H24: |
| 626 |
else |
713 |
skeletonCharacter = 'H'; |
| 627 |
skeletonBuilder.append('H'); |
714 |
break; |
| 628 |
break; |
715 |
} |
| 629 |
case Hour::None: |
716 |
} else { |
| 630 |
break; |
717 |
// We prefer hour12 over hourCycle. If hour12 is specified, we ignore hourCycle. |
|
|
718 |
if (hour12 == TriState::True) |
| 719 |
skeletonCharacter = 'h'; |
| 720 |
else |
| 721 |
skeletonCharacter = 'H'; |
| 722 |
} |
| 723 |
|
| 724 |
switch (hour) { |
| 725 |
case Hour::TwoDigit: |
| 726 |
skeletonBuilder.append(skeletonCharacter); |
| 727 |
skeletonBuilder.append(skeletonCharacter); |
| 728 |
break; |
| 729 |
case Hour::Numeric: |
| 730 |
skeletonBuilder.append(skeletonCharacter); |
| 731 |
break; |
| 732 |
case Hour::None: |
| 733 |
break; |
| 734 |
} |
| 631 |
} |
735 |
} |
| 632 |
|
736 |
|
| 633 |
if (Options::useIntlDateTimeFormatDayPeriod()) { |
737 |
if (Options::useIntlDateTimeFormatDayPeriod()) { |
|
Lines 701-707
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec7
|
| 701 |
m_timeStyle = intlOption<DateTimeStyle>(globalObject, options, vm.propertyNames->timeStyle, { { "full"_s, DateTimeStyle::Full }, { "long"_s, DateTimeStyle::Long }, { "medium"_s, DateTimeStyle::Medium }, { "short"_s, DateTimeStyle::Short } }, "timeStyle must be \"full\", \"long\", \"medium\", or \"short\""_s, DateTimeStyle::None); |
805 |
m_timeStyle = intlOption<DateTimeStyle>(globalObject, options, vm.propertyNames->timeStyle, { { "full"_s, DateTimeStyle::Full }, { "long"_s, DateTimeStyle::Long }, { "medium"_s, DateTimeStyle::Medium }, { "short"_s, DateTimeStyle::Short } }, "timeStyle must be \"full\", \"long\", \"medium\", or \"short\""_s, DateTimeStyle::None); |
| 702 |
RETURN_IF_EXCEPTION(scope, void()); |
806 |
RETURN_IF_EXCEPTION(scope, void()); |
| 703 |
|
807 |
|
| 704 |
bool canIncludeHour = true; |
808 |
|
|
|
809 |
auto patternFromSkeleton = [&](const UChar* skeleton, unsigned skeletonSize, Vector<UChar, 32>& patternBuffer, UErrorCode& status) { |
| 810 |
// Always use ICU date format generator, rather than our own pattern list and matcher. |
| 811 |
auto generator = std::unique_ptr<UDateTimePatternGenerator, ICUDeleter<udatpg_close>>(udatpg_open(dataLocaleWithExtensions.data(), &status)); |
| 812 |
if (U_FAILURE(status)) |
| 813 |
return; |
| 814 |
|
| 815 |
status = callBufferProducingFunction(udatpg_getBestPatternWithOptions, generator.get(), skeleton, skeletonSize, UDATPG_MATCH_HOUR_FIELD_LENGTH, patternBuffer); |
| 816 |
if (U_FAILURE(status)) |
| 817 |
return; |
| 818 |
}; |
| 819 |
|
| 705 |
Vector<UChar, 32> patternBuffer; |
820 |
Vector<UChar, 32> patternBuffer; |
| 706 |
if (m_dateStyle != DateTimeStyle::None || m_timeStyle != DateTimeStyle::None) { |
821 |
if (m_dateStyle != DateTimeStyle::None || m_timeStyle != DateTimeStyle::None) { |
| 707 |
// 30. For each row in Table 1, except the header row, do |
822 |
// 30. For each row in Table 1, except the header row, do |
|
Lines 714-725
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec8
|
| 714 |
return; |
829 |
return; |
| 715 |
} |
830 |
} |
| 716 |
|
831 |
|
| 717 |
// If timeStyle is not specified, m_hourCycle does not matter. Let's skip enforcing step. |
|
|
| 718 |
if (m_timeStyle == DateTimeStyle::None) { |
| 719 |
canIncludeHour = false; |
| 720 |
m_hourCycle = String(); |
| 721 |
} |
| 722 |
|
| 723 |
auto parseUDateFormatStyle = [](DateTimeStyle style) { |
832 |
auto parseUDateFormatStyle = [](DateTimeStyle style) { |
| 724 |
switch (style) { |
833 |
switch (style) { |
| 725 |
case DateTimeStyle::Full: |
834 |
case DateTimeStyle::Full: |
|
Lines 738-744
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec9
|
| 738 |
|
847 |
|
| 739 |
// We cannot use this UDateFormat directly yet because we need to enforce specified hourCycle. |
848 |
// We cannot use this UDateFormat directly yet because we need to enforce specified hourCycle. |
| 740 |
// First, we create UDateFormat via dateStyle and timeStyle. And then convert it to pattern string. |
849 |
// First, we create UDateFormat via dateStyle and timeStyle. And then convert it to pattern string. |
| 741 |
// After updating this pattern string with m_hourCycle, we create a final UDateFormat with the updated pattern string. |
850 |
// After updating this pattern string with hourCycle, we create a final UDateFormat with the updated pattern string. |
| 742 |
UErrorCode status = U_ZERO_ERROR; |
851 |
UErrorCode status = U_ZERO_ERROR; |
| 743 |
StringView timeZoneView(m_timeZone); |
852 |
StringView timeZoneView(m_timeZone); |
| 744 |
auto dateFormatFromStyle = std::unique_ptr<UDateFormat, UDateFormatDeleter>(udat_open(parseUDateFormatStyle(m_timeStyle), parseUDateFormatStyle(m_dateStyle), dataLocaleWithExtensions.data(), timeZoneView.upconvertedCharacters(), timeZoneView.length(), nullptr, -1, &status)); |
853 |
auto dateFormatFromStyle = std::unique_ptr<UDateFormat, UDateFormatDeleter>(udat_open(parseUDateFormatStyle(m_timeStyle), parseUDateFormatStyle(m_dateStyle), dataLocaleWithExtensions.data(), timeZoneView.upconvertedCharacters(), timeZoneView.length(), nullptr, -1, &status)); |
|
Lines 752-833
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec10
|
| 752 |
throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); |
861 |
throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); |
| 753 |
return; |
862 |
return; |
| 754 |
} |
863 |
} |
| 755 |
} else { |
|
|
| 756 |
// If hour is not specified, m_hourCycle does not matter. Let's skip enforcing step. |
| 757 |
if (hour == Hour::None) { |
| 758 |
canIncludeHour = false; |
| 759 |
m_hourCycle = String(); |
| 760 |
} |
| 761 |
|
864 |
|
| 762 |
// Always use ICU date format generator, rather than our own pattern list and matcher. |
865 |
// It is possible that timeStyle includes dayPeriod, which is sensitive to hour-cycle. |
| 763 |
UErrorCode status = U_ZERO_ERROR; |
866 |
// If dayPeriod is included, just replacing hour based on hourCycle / hour12 produces strange results. |
| 764 |
auto* generator = udatpg_open(dataLocaleWithExtensions.data(), &status); |
867 |
// Let's consider about the example. The formatted result looks like "02:12:47 PM Coordinated Universal Time" |
| 765 |
if (U_FAILURE(status)) { |
868 |
// If we simply replace 02 to 14, this becomes "14:12:47 PM Coordinated Universal Time", this looks strange. |
| 766 |
throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); |
869 |
// We should retrieve skeleton from the pattern, enforcing hour-cycle, and re-generating the best pattern from the modified skeleton to get non-strange result. |
| 767 |
return; |
870 |
if (m_timeStyle != DateTimeStyle::None) { |
|
|
871 |
if (hourCycle != HourCycle::None || hour12 != TriState::Indeterminate) { |
| 872 |
auto isHour12 = [](HourCycle hourCycle) { |
| 873 |
return hourCycle == HourCycle::H11 || hourCycle == HourCycle::H12; |
| 874 |
}; |
| 875 |
bool specifiedHour12 = false; |
| 876 |
// If hour12 is specified, we prefer it and dignore hourCycle. |
| 877 |
if (hour12 != TriState::Indeterminate) |
| 878 |
specifiedHour12 = hour12 == TriState::True; |
| 879 |
else |
| 880 |
specifiedHour12 = isHour12(hourCycle); |
| 881 |
if (isHour12(hourCycleFromPattern(patternBuffer)) != specifiedHour12) { |
| 882 |
Vector<UChar, 32> skeleton; |
| 883 |
auto status = callBufferProducingFunction(udatpg_getSkeleton, nullptr, patternBuffer.data(), patternBuffer.size(), skeleton); |
| 884 |
if (U_FAILURE(status)) { |
| 885 |
throwTypeError(globalObject, scope, "failed to initialize DateIntervalFormat"_s); |
| 886 |
return; |
| 887 |
} |
| 888 |
replaceHourCycleInSkeleton(skeleton, specifiedHour12); |
| 889 |
dataLogLnIf(IntlDateTimeFormatInternal::verbose, "replaced:(", StringView(skeleton.data(), skeleton.size()), ")"); |
| 890 |
patternBuffer.clear(); |
| 891 |
patternFromSkeleton(skeleton.data(), skeleton.size(), patternBuffer, status); |
| 892 |
if (U_FAILURE(status)) { |
| 893 |
throwTypeError(globalObject, scope, "failed to initialize DateIntervalFormat"_s); |
| 894 |
return; |
| 895 |
} |
| 896 |
} |
| 897 |
} |
| 768 |
} |
898 |
} |
| 769 |
|
899 |
} else { |
|
|
900 |
UErrorCode status = U_ZERO_ERROR; |
| 770 |
String skeleton = skeletonBuilder.toString(); |
901 |
String skeleton = skeletonBuilder.toString(); |
| 771 |
StringView skeletonView(skeleton); |
902 |
patternFromSkeleton(StringView(skeleton).upconvertedCharacters().get(), skeleton.length(), patternBuffer, status); |
| 772 |
status = callBufferProducingFunction(udatpg_getBestPatternWithOptions, generator, skeletonView.upconvertedCharacters().get(), skeletonView.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, patternBuffer); |
|
|
| 773 |
udatpg_close(generator); |
| 774 |
if (U_FAILURE(status)) { |
903 |
if (U_FAILURE(status)) { |
| 775 |
throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); |
904 |
throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat"_s); |
| 776 |
return; |
905 |
return; |
| 777 |
} |
906 |
} |
| 778 |
} |
907 |
} |
| 779 |
|
908 |
|
| 780 |
// Enforce our hourCycle, replacing hour characters in pattern. ICU can pick format which does not agree with specified hourCycle. |
909 |
// In skeleton construction, there is no way to specify h11 v.s. h12, or h23 v.s. h24. |
| 781 |
// This step modifies generated pattern to use specified hourCycle, and it is specified in 1.1.1 InitializeDateTimeFormat step 33. |
910 |
// After generating pattern from skeleton, we need to change h11 and h12 / h23 and h24 if hourCycle is specified. |
| 782 |
// FIXME: We should cache `hourCycleDefault` value obtained by generating "jjmm" pattern from UDateTimePatternGenerator. |
911 |
if (hourCycle != HourCycle::None) |
| 783 |
// https://bugs.webkit.org/show_bug.cgi?id=213459 |
912 |
replaceHourCycleInPattern(patternBuffer, hourCycle); |
| 784 |
if (canIncludeHour) { |
|
|
| 785 |
bool hasHour = false; |
| 786 |
if (!m_hourCycle.isNull() || !isHour12Undefined) { |
| 787 |
UChar hourFromHourCycle = 'H'; // H23 |
| 788 |
if (m_hourCycle == "h11") |
| 789 |
hourFromHourCycle = 'K'; |
| 790 |
else if (m_hourCycle == "h12") |
| 791 |
hourFromHourCycle = 'h'; |
| 792 |
else if (m_hourCycle == "h24") |
| 793 |
hourFromHourCycle = 'k'; |
| 794 |
|
| 795 |
bool isEscaped = false; |
| 796 |
for (auto& c : patternBuffer) { |
| 797 |
if (c == '\'') |
| 798 |
isEscaped = !isEscaped; |
| 799 |
else if (!isEscaped && (c == 'h' || c == 'H' || c == 'k' || c == 'K')) { |
| 800 |
switch (c) { |
| 801 |
case 'K': |
| 802 |
case 'H': { |
| 803 |
if (isHour12Undefined) |
| 804 |
c = hourFromHourCycle; |
| 805 |
else if (hour12 == TriState::True) |
| 806 |
c = 'K'; |
| 807 |
else |
| 808 |
c = 'H'; |
| 809 |
break; |
| 810 |
} |
| 811 |
case 'h': |
| 812 |
case 'k': { |
| 813 |
if (isHour12Undefined) |
| 814 |
c = hourFromHourCycle; |
| 815 |
else if (hour12 == TriState::True) |
| 816 |
c = 'h'; |
| 817 |
else |
| 818 |
c = 'k'; |
| 819 |
break; |
| 820 |
} |
| 821 |
default: |
| 822 |
ASSERT_NOT_REACHED(); |
| 823 |
} |
| 824 |
hasHour = true; |
| 825 |
} |
| 826 |
} |
| 827 |
} |
| 828 |
if (!hasHour) |
| 829 |
m_hourCycle = String(); |
| 830 |
} |
| 831 |
|
913 |
|
| 832 |
StringView pattern(patternBuffer.data(), patternBuffer.size()); |
914 |
StringView pattern(patternBuffer.data(), patternBuffer.size()); |
| 833 |
setFormatsFromPattern(pattern); |
915 |
setFormatsFromPattern(pattern); |
|
Lines 848-853
void IntlDateTimeFormat::initializeDateTimeFormat(JSGlobalObject* globalObject,
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec11
|
| 848 |
ucal_setGregorianChange(cal, minECMAScriptTime, &status); |
930 |
ucal_setGregorianChange(cal, minECMAScriptTime, &status); |
| 849 |
} |
931 |
} |
| 850 |
|
932 |
|
|
|
933 |
ASCIILiteral IntlDateTimeFormat::hourCycleString(HourCycle hourCycle) |
| 934 |
{ |
| 935 |
switch (hourCycle) { |
| 936 |
case HourCycle::H11: |
| 937 |
return "h11"_s; |
| 938 |
case HourCycle::H12: |
| 939 |
return "h12"_s; |
| 940 |
case HourCycle::H23: |
| 941 |
return "h23"_s; |
| 942 |
case HourCycle::H24: |
| 943 |
return "h24"_s; |
| 944 |
case HourCycle::None: |
| 945 |
ASSERT_NOT_REACHED(); |
| 946 |
return ASCIILiteral::null(); |
| 947 |
} |
| 948 |
ASSERT_NOT_REACHED(); |
| 949 |
return ASCIILiteral::null(); |
| 950 |
} |
| 951 |
|
| 851 |
ASCIILiteral IntlDateTimeFormat::weekdayString(Weekday weekday) |
952 |
ASCIILiteral IntlDateTimeFormat::weekdayString(Weekday weekday) |
| 852 |
{ |
953 |
{ |
| 853 |
switch (weekday) { |
954 |
switch (weekday) { |
|
Lines 1040-1048
JSObject* IntlDateTimeFormat::resolvedOptions(JSGlobalObject* globalObject) cons
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec12
|
| 1040 |
options->putDirect(vm, vm.propertyNames->numberingSystem, jsNontrivialString(vm, m_numberingSystem)); |
1141 |
options->putDirect(vm, vm.propertyNames->numberingSystem, jsNontrivialString(vm, m_numberingSystem)); |
| 1041 |
options->putDirect(vm, vm.propertyNames->timeZone, jsNontrivialString(vm, m_timeZone)); |
1142 |
options->putDirect(vm, vm.propertyNames->timeZone, jsNontrivialString(vm, m_timeZone)); |
| 1042 |
|
1143 |
|
| 1043 |
if (!m_hourCycle.isNull()) { |
1144 |
if (m_hourCycle != HourCycle::None) { |
| 1044 |
options->putDirect(vm, vm.propertyNames->hourCycle, jsNontrivialString(vm, m_hourCycle)); |
1145 |
options->putDirect(vm, vm.propertyNames->hourCycle, jsNontrivialString(vm, hourCycleString(m_hourCycle))); |
| 1045 |
options->putDirect(vm, vm.propertyNames->hour12, jsBoolean(m_hourCycle == "h11" || m_hourCycle == "h12")); |
1146 |
options->putDirect(vm, vm.propertyNames->hour12, jsBoolean(m_hourCycle == HourCycle::H11 || m_hourCycle == HourCycle::H12)); |
| 1046 |
} |
1147 |
} |
| 1047 |
|
1148 |
|
| 1048 |
if (m_weekday != Weekday::None) |
1149 |
if (m_weekday != Weekday::None) |
|
Lines 1267-1274
UDateIntervalFormat* IntlDateTimeFormat::createDateIntervalFormatIfNecessary(JSG
a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp_sec13
|
| 1267 |
// We need to enforce HourCycle by setting "hc" extension if it is specified. |
1368 |
// We need to enforce HourCycle by setting "hc" extension if it is specified. |
| 1268 |
StringBuilder localeBuilder; |
1369 |
StringBuilder localeBuilder; |
| 1269 |
localeBuilder.append(m_dataLocale, "-u-ca-", m_calendar, "-nu-", m_numberingSystem); |
1370 |
localeBuilder.append(m_dataLocale, "-u-ca-", m_calendar, "-nu-", m_numberingSystem); |
| 1270 |
if (!m_hourCycle.isNull()) |
1371 |
if (m_hourCycle != HourCycle::None) |
| 1271 |
localeBuilder.append("-hc-", m_hourCycle); |
1372 |
localeBuilder.append("-hc-", hourCycleString(m_hourCycle)); |
| 1272 |
CString dataLocaleWithExtensions = localeBuilder.toString().utf8(); |
1373 |
CString dataLocaleWithExtensions = localeBuilder.toString().utf8(); |
| 1273 |
|
1374 |
|
| 1274 |
UErrorCode status = U_ZERO_ERROR; |
1375 |
UErrorCode status = U_ZERO_ERROR; |