import from UXP: Issue #2046 - Implement Intl.DateTimeFormat's date-/timeStyle and hourCycle options (4400677a)

This commit is contained in:
2023-07-07 15:23:39 +08:00
parent b404378802
commit df34fda785
5 changed files with 470 additions and 153 deletions
+304 -31
View File
@@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Range.h"
#include "mozilla/Span.h"
#include "jscntxt.h"
#include "jsfriendapi.h"
@@ -447,13 +448,139 @@ js::intl_defaultTimeZoneOffset(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
enum class HourCycle {
// 12 hour cycle, from 0 to 11.
H11,
// 12 hour cycle, from 1 to 12.
H12,
// 24 hour cycle, from 0 to 23.
H23,
// 24 hour cycle, from 1 to 24.
H24
};
static bool
IsHour12(HourCycle hc)
{
return hc == HourCycle::H11 || hc == HourCycle::H12;
}
static char16_t
HourSymbol(HourCycle hc)
{
switch (hc) {
case HourCycle::H11:
return 'K';
case HourCycle::H12:
return 'h';
case HourCycle::H23:
return 'H';
case HourCycle::H24:
return 'k';
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected hour cycle");
}
/**
* Parse a pattern according to the format specified in
* <https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns>.
*/
template <typename CharT>
class PatternIterator {
CharT* iter_;
const CharT* const end_;
public:
explicit PatternIterator(mozilla::Span<CharT> pattern)
: iter_(pattern.data()), end_(pattern.data() + pattern.size()) {}
CharT* next() {
MOZ_ASSERT(iter_ != nullptr);
bool inQuote = false;
while (iter_ < end_) {
CharT* cur = iter_++;
if (*cur == '\'') {
inQuote = !inQuote;
} else if (!inQuote) {
return cur;
}
}
iter_ = nullptr;
return nullptr;
}
};
/**
* Return the hour cycle for the given option string.
*/
static HourCycle
HourCycleFromOption(JSLinearString* str)
{
if (StringEqualsAscii(str, "h11")) {
return HourCycle::H11;
}
if (StringEqualsAscii(str, "h12")) {
return HourCycle::H12;
}
if (StringEqualsAscii(str, "h23")) {
return HourCycle::H23;
}
MOZ_ASSERT(StringEqualsAscii(str, "h24"));
return HourCycle::H24;
}
/**
* Return the hour cycle used in the input pattern or Nothing if none was found.
*/
static mozilla::Maybe<HourCycle>
HourCycleFromPattern(mozilla::Span<const char16_t> pattern)
{
PatternIterator<const char16_t> iter(pattern);
while (const auto* ptr = iter.next()) {
switch (*ptr) {
case 'K':
return mozilla::Some(HourCycle::H11);
case 'h':
return mozilla::Some(HourCycle::H12);
case 'H':
return mozilla::Some(HourCycle::H23);
case 'k':
return mozilla::Some(HourCycle::H24);
}
}
return mozilla::Nothing();
}
/**
* Replaces all hour pattern characters in |pattern| to use the matching hour
* representation for |hourCycle|.
*/
static void
ReplaceHourSymbol(mozilla::Span<char16_t> pattern, HourCycle hc)
{
char16_t replacement = HourSymbol(hc);
PatternIterator<char16_t> iter(pattern);
while (auto* ptr = iter.next()) {
char16_t ch = *ptr;
if (ch == 'K' || ch == 'h' || ch == 'H' || ch == 'k') {
*ptr = replacement;
}
}
}
bool
js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_ASSERT(args.length() == 3);
MOZ_ASSERT(args[0].isString());
MOZ_ASSERT(args[1].isString());
MOZ_ASSERT(args[2].isString() || args[2].isUndefined());
JSAutoByteString locale(cx, args[0].toString());
if (!locale)
@@ -467,6 +594,16 @@ js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp)
if (!stableChars.initTwoByte(cx, skeletonFlat))
return false;
mozilla::Maybe<HourCycle> hourCycle;
if (args[2].isString()) {
JSLinearString* hourCycleStr = args[2].toString()->ensureLinear(cx);
if (!hourCycleStr) {
return false;
}
hourCycle.emplace(HourCycleFromOption(hourCycleStr));
}
mozilla::Range<const char16_t> skeletonChars = stableChars.twoByteRange();
uint32_t skeletonLen = u_strlen(Char16ToUChar(skeletonChars.begin().get()));
@@ -478,69 +615,175 @@ js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp)
}
ScopedICUObject<UDateTimePatternGenerator, udatpg_close> toClose(gen);
JSString* str =
CallICU(cx, [gen, &skeletonChars, skeletonLen](UChar* chars, uint32_t size, UErrorCode* status) {
return udatpg_getBestPattern(gen, skeletonChars.begin().get(), skeletonLen,
chars, size, status);
Vector<char16_t, intl::INITIAL_CHAR_BUFFER_SIZE> pattern(cx);
int32_t patternSize = CallICU(
cx,
pattern,
[gen, &skeletonChars](UChar* chars, uint32_t size, UErrorCode* status) {
return udatpg_getBestPattern(gen, skeletonChars.begin().get(),
skeletonChars.length(), chars, size, status);
});
if (!str)
if (patternSize < 0) {
return false;
}
// If the hourCycle option was set, adjust the resolved pattern to use the
// requested hour cycle representation.
if (hourCycle) {
ReplaceHourSymbol(pattern, hourCycle.value());
}
JSString* str = NewStringCopyN<CanGC>(cx, pattern.begin(), pattern.length());
if (!str) {
return false;
}
args.rval().setString(str);
return true;
}
/**
* Find a matching pattern using the requested hour-12 options.
*
* This function is needed to work around the following two issues.
* - https://unicode-org.atlassian.net/browse/ICU-21023
* - https://unicode-org.atlassian.net/browse/CLDR-13425
*
* We're currently using a relatively simple workaround, which doesn't give the
* most accurate results. For example:
*
* ```
* var dtf = new Intl.DateTimeFormat("en", {
* timeZone: "UTC",
* dateStyle: "long",
* timeStyle: "long",
* hourCycle: "h12",
* });
* print(dtf.format(new Date("2020-01-01T00:00Z")));
* ```
*
* Returns the pattern "MMMM d, y 'at' h:mm:ss a z", but when going through
* |udatpg_getSkeleton| and then |udatpg_getBestPattern| to find an equivalent
* pattern for "h23", we'll end up with the pattern "MMMM d, y, HH:mm:ss z", so
* the combinator element " 'at' " was lost in the process.
*/
template <size_t N>
static bool
FindPatternWithHourCycle(JSContext* cx, const char* locale,
Vector<char16_t, N>& pattern, bool hour12)
{
UErrorCode status = U_ZERO_ERROR;
UDateTimePatternGenerator* gen = udatpg_open(IcuLocale(locale), &status);
if (U_FAILURE(status)) {
intl::ReportInternalError(cx);
return false;
}
ScopedICUObject<UDateTimePatternGenerator, udatpg_close> toClose(gen);
if (!gen) {
return false;
}
Vector<char16_t, intl::INITIAL_CHAR_BUFFER_SIZE> skeleton(cx);
int32_t skeletonSize = CallICU(
cx,
skeleton,
[&pattern](UChar* chars, uint32_t size, UErrorCode* status) {
return udatpg_getSkeleton(nullptr, pattern.begin(), pattern.length(),
chars, size, status);
});
if (skeletonSize < 0) {
return false;
}
// Input skeletons don't differentiate between "K" and "h" resp. "k" and "H".
ReplaceHourSymbol(skeleton, hour12 ? HourCycle::H12 : HourCycle::H23);
MOZ_ALWAYS_TRUE(pattern.resize(0));
int32_t patternSize = CallICU(
cx,
pattern,
[gen, &skeleton](UChar* chars, uint32_t size, UErrorCode* status) {
return udatpg_getBestPattern(gen, skeleton.begin(), skeleton.length(),
chars, size, status);
});
if (patternSize < 0) {
return false;
}
return true;
}
bool
js::intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 4);
MOZ_ASSERT(args.length() == 6);
MOZ_ASSERT(args[0].isString());
MOZ_ASSERT(args[1].isString() || args[1].isUndefined());
MOZ_ASSERT(args[2].isString() || args[2].isUndefined());
MOZ_ASSERT(args[3].isString());
MOZ_ASSERT(args[4].isBoolean() || args[4].isUndefined());
MOZ_ASSERT(args[5].isString() || args[5].isUndefined());
JSAutoByteString locale(cx, args[0].toString());
if (!locale)
return false;
auto toDateFormatStyle = [](JSLinearString* str) {
if (StringEqualsAscii(str, "full")) {
return UDAT_FULL;
}
if (StringEqualsAscii(str, "long")) {
return UDAT_LONG;
}
if (StringEqualsAscii(str, "medium")) {
return UDAT_MEDIUM;
}
MOZ_ASSERT(StringEqualsAscii(str, "short"));
return UDAT_SHORT;
};
UDateFormatStyle dateStyle = UDAT_NONE;
UDateFormatStyle timeStyle = UDAT_NONE;
if (args[1].isString()) {
JSLinearString* dateStyleStr = args[1].toString()->ensureLinear(cx);
if (!dateStyleStr)
return false;
if (StringEqualsAscii(dateStyleStr, "full"))
dateStyle = UDAT_FULL;
else if (StringEqualsAscii(dateStyleStr, "long"))
dateStyle = UDAT_LONG;
else if (StringEqualsAscii(dateStyleStr, "medium"))
dateStyle = UDAT_MEDIUM;
else if (StringEqualsAscii(dateStyleStr, "short"))
dateStyle = UDAT_SHORT;
else
MOZ_ASSERT_UNREACHABLE("unexpected dateStyle");
dateStyle = toDateFormatStyle(dateStyleStr);
}
UDateFormatStyle timeStyle = UDAT_NONE;
if (args[2].isString()) {
JSLinearString* timeStyleStr = args[2].toString()->ensureLinear(cx);
if (!timeStyleStr)
return false;
if (StringEqualsAscii(timeStyleStr, "full"))
timeStyle = UDAT_FULL;
else if (StringEqualsAscii(timeStyleStr, "long"))
timeStyle = UDAT_LONG;
else if (StringEqualsAscii(timeStyleStr, "medium"))
timeStyle = UDAT_MEDIUM;
else if (StringEqualsAscii(timeStyleStr, "short"))
timeStyle = UDAT_SHORT;
else
MOZ_ASSERT_UNREACHABLE("unexpected timeStyle");
timeStyle = toDateFormatStyle(timeStyleStr);
}
AutoStableStringChars timeZone(cx);
if (!timeZone.initTwoByte(cx, args[3].toString()))
return false;
mozilla::Maybe<bool> hour12;
if (args[4].isBoolean()) {
hour12.emplace(args[4].toBoolean());
}
mozilla::Maybe<HourCycle> hourCycle;
if (args[5].isString()) {
JSLinearString* hourCycleStr = args[5].toString()->ensureLinear(cx);
if (!hourCycleStr) {
return false;
}
hourCycle.emplace(HourCycleFromOption(hourCycleStr));
}
mozilla::Range<const char16_t> timeZoneChars = timeZone.twoByteRange();
UErrorCode status = U_ZERO_ERROR;
@@ -553,9 +796,39 @@ js::intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp)
}
ScopedICUObject<UDateFormat, udat_close> toClose(df);
JSString* str = CallICU(cx, [df](UChar* chars, uint32_t size, UErrorCode* status) {
return udat_toPattern(df, false, chars, size, status);
});
Vector<char16_t, intl::INITIAL_CHAR_BUFFER_SIZE> pattern(cx);
int32_t patternSize = CallICU(
cx,
pattern,
[df](UChar* chars, uint32_t size, UErrorCode* status) {
return udat_toPattern(df, false, chars, size, status);
});
if (patternSize < 0) {
return false;
}
// If a specific hour cycle was requested and this hour cycle doesn't match
// the hour cycle used in the resolved pattern, find an equivalent pattern
// with the correct hour cycle.
if (timeStyle != UDAT_NONE && (hour12 || hourCycle)) {
if (auto hcPattern = HourCycleFromPattern(pattern)) {
bool wantHour12 = hour12 ? hour12.value() : IsHour12(hourCycle.value());
if (wantHour12 != IsHour12(hcPattern.value())) {
if (!FindPatternWithHourCycle(cx, locale.ptr(), pattern, wantHour12)) {
return false;
}
}
}
}
// If the hourCycle option was set, adjust the resolved pattern to use the
// requested hour cycle representation.
if (hourCycle) {
ReplaceHourSymbol(pattern, hourCycle.value());
}
JSString* str = NewStringCopyN<CanGC>(cx, pattern.begin(), pattern.length());
if (!str)
return false;
args.rval().setString(str);
+8 -3
View File
@@ -119,7 +119,7 @@ intl_defaultTimeZoneOffset(JSContext* cx, unsigned argc, Value* vp);
* best-fit date-time format pattern corresponding to skeleton for the
* given locale.
*
* Usage: pattern = intl_patternForSkeleton(locale, skeleton)
* Usage: pattern = intl_patternForSkeleton(locale, skeleton, hourCycle)
*/
extern MOZ_MUST_USE bool
intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
@@ -128,7 +128,7 @@ intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
* Return a pattern in the date-time format pattern language of Unicode
* Technical Standard 35, Unicode Locale Data Markup Language, for the
* best-fit date-time style for the given locale.
* The function takes four arguments:
* The function takes six arguments:
*
* locale
* BCP47 compliant locale string
@@ -138,6 +138,10 @@ intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
* A string with values: full or long or medium or short, or `undefined`
* timeZone
* IANA time zone name
* hour12
* A boolean to request hour12 representation, or `undefined`
* hourCycle
* A string with values: h11, h12, h23, or h24, or `undefined`
*
* Date and time style categories map to CLDR time/date standard
* format patterns.
@@ -148,7 +152,8 @@ intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
* If `undefined` is passed to `dateStyle` or `timeStyle`, the respective
* portions of the pattern will not be included in the result.
*
* Usage: pattern = intl_patternForStyle(locale, dateStyle, timeStyle, timeZone)
* Usage: pattern = intl_patternForStyle(locale, dateStyle, timeStyle, timeZone,
* hour12, hourCycle)
*/
extern MOZ_MUST_USE bool
intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp);
+154 -117
View File
@@ -39,11 +39,6 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
//
// formatMatcher: "basic" / "best fit",
//
// mozExtensions: true / false,
//
//
// // If mozExtensions is true:
//
// dateStyle: "full" / "long" / "medium" / "short" / undefined,
//
// timeStyle: "full" / "long" / "medium" / "short" / undefined,
@@ -96,31 +91,25 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
// Steps 26-30, more or less - see comment after this function.
var pattern;
if (lazyDateTimeFormatData.mozExtensions) {
if (lazyDateTimeFormatData.patternOption !== undefined) {
pattern = lazyDateTimeFormatData.patternOption;
if (lazyDateTimeFormatData.patternOption !== undefined) {
pattern = lazyDateTimeFormatData.patternOption;
internalProps.patternOption = lazyDateTimeFormatData.patternOption;
} else if (lazyDateTimeFormatData.dateStyle || lazyDateTimeFormatData.timeStyle) {
pattern = intl_patternForStyle(dataLocale,
lazyDateTimeFormatData.dateStyle, lazyDateTimeFormatData.timeStyle,
lazyDateTimeFormatData.timeZone);
internalProps.patternOption = lazyDateTimeFormatData.patternOption;
} else if (lazyDateTimeFormatData.dateStyle !== undefined ||
lazyDateTimeFormatData.timeStyle !== undefined) {
pattern = intl_patternForStyle(dataLocale,
lazyDateTimeFormatData.dateStyle,
lazyDateTimeFormatData.timeStyle,
lazyDateTimeFormatData.timeZone,
formatOpt.hour12,
formatOpt.hourCycle);
internalProps.dateStyle = lazyDateTimeFormatData.dateStyle;
internalProps.timeStyle = lazyDateTimeFormatData.timeStyle;
} else {
pattern = toBestICUPattern(dataLocale, formatOpt);
}
internalProps.mozExtensions = true;
internalProps.dateStyle = lazyDateTimeFormatData.dateStyle;
internalProps.timeStyle = lazyDateTimeFormatData.timeStyle;
} else {
pattern = toBestICUPattern(dataLocale, formatOpt);
pattern = toBestICUPattern(dataLocale, formatOpt);
}
// If the hourCycle option was set, adjust the resolved pattern to use the
// requested hour cycle representation.
if (formatOpt.hourCycle !== undefined)
pattern = replaceHourRepresentation(pattern, formatOpt.hourCycle);
// Step 31.
internalProps.pattern = pattern;
@@ -130,47 +119,6 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
}
/**
* Replaces all hour pattern characters in |pattern| to use the matching hour
* representation for |hourCycle|.
*/
function replaceHourRepresentation(pattern, hourCycle) {
var hour;
switch (hourCycle) {
case "h11":
hour = "K";
break;
case "h12":
hour = "h";
break;
case "h23":
hour = "H";
break;
case "h24":
hour = "k";
break;
}
assert(hour !== undefined, "Unexpected hourCycle requested: " + hourCycle);
// Parse the pattern according to the format specified in
// https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
// and replace all hour symbols with |hour|.
var resultPattern = "";
var inQuote = false;
for (var i = 0; i < pattern.length; i++) {
var ch = pattern[i];
if (ch === "'") {
inQuote = !inQuote;
} else if (!inQuote && (ch === "h" || ch === "H" || ch === "k" || ch === "K")) {
ch = hour;
}
resultPattern += ch;
}
return resultPattern;
}
/**
* Returns an object containing the DateTimeFormat internal properties of |obj|.
*/
@@ -449,16 +397,9 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
var formatOpt = new Record();
lazyDateTimeFormatData.formatOpt = formatOpt;
lazyDateTimeFormatData.mozExtensions = mozExtensions;
if (mozExtensions) {
let pattern = GetOption(options, "pattern", "string", undefined, undefined);
lazyDateTimeFormatData.patternOption = pattern;
let dateStyle = GetOption(options, "dateStyle", "string", ["full", "long", "medium", "short"], undefined);
lazyDateTimeFormatData.dateStyle = dateStyle;
let timeStyle = GetOption(options, "timeStyle", "string", ["full", "long", "medium", "short"], undefined);
lazyDateTimeFormatData.timeStyle = timeStyle;
}
// Step 22.
@@ -482,6 +423,30 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
GetOption(options, "formatMatcher", "string", ["basic", "best fit"],
"best fit");
// "DateTimeFormat dateStyle & timeStyle" propsal
// https://github.com/tc39/proposal-intl-datetime-style
var dateStyle = GetOption(options, "dateStyle", "string", ["full", "long", "medium", "short"],
undefined);
lazyDateTimeFormatData.dateStyle = dateStyle;
var timeStyle = GetOption(options, "timeStyle", "string", ["full", "long", "medium", "short"],
undefined);
lazyDateTimeFormatData.timeStyle = timeStyle;
if (dateStyle !== undefined || timeStyle !== undefined) {
var optionsList = [
"weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName",
];
for (var i = 0; i < optionsList.length; i++) {
var option = optionsList[i];
if (formatOpt[option] !== undefined) {
ThrowTypeError(JSMSG_INVALID_DATETIME_OPTION, option,
dateStyle !== undefined ? "dateStyle" : "timeStyle");
}
}
}
// Steps 26-28 provided by ICU, more or less - see comment after this function.
// Steps 29-30.
@@ -698,7 +663,7 @@ function toBestICUPattern(locale, options) {
}
// Let ICU convert the ICU skeleton to an ICU pattern for the given locale.
return intl_patternForSkeleton(locale, skeleton);
return intl_patternForSkeleton(locale, skeleton, options.hourCycle);
}
@@ -744,6 +709,20 @@ function ToDateTimeOptions(options, required, defaults) {
needDefaults = false;
}
// "DateTimeFormat dateStyle & timeStyle" propsal
// https://github.com/tc39/proposal-intl-datetime-style
var dateStyle = options.dateStyle;
var timeStyle = options.timeStyle;
if (dateStyle !== undefined || timeStyle !== undefined)
needDefaults = false;
if (required === "date" && timeStyle !== undefined)
ThrowTypeError(JSMSG_INVALID_DATETIME_STYLE, "timeStyle", "toLocaleDateString");
if (required === "time" && dateStyle !== undefined)
ThrowTypeError(JSMSG_INVALID_DATETIME_STYLE, "dateStyle", "toLocaleTimeString");
// Step 6.
if (needDefaults && (defaults === "date" || defaults === "all")) {
// The specification says to call [[DefineOwnProperty]] with false for
@@ -1000,44 +979,34 @@ function Intl_DateTimeFormat_resolvedOptions() {
timeZone: internals.timeZone,
};
if (internals.mozExtensions) {
if (internals.patternOption !== undefined) {
result.pattern = internals.pattern;
} else if (internals.dateStyle || internals.timeStyle) {
result.dateStyle = internals.dateStyle;
result.timeStyle = internals.timeStyle;
}
if (internals.patternOption !== undefined) {
_DefineDataProperty(result, "pattern", internals.pattern);
}
resolveICUPattern(internals.pattern, result);
var hasDateStyle = internals.dateStyle !== undefined;
var hasTimeStyle = internals.timeStyle !== undefined;
if (hasDateStyle || hasTimeStyle) {
if (hasTimeStyle) {
// timeStyle (unlike dateStyle) requires resolving the pattern to
// ensure "hourCycle" and "hour12" properties are added to |result|.
resolveICUPattern(internals.pattern, result, /* includeDateTimeFields = */ false);
}
if (hasDateStyle) {
_DefineDataProperty(result, "dateStyle", internals.dateStyle);
}
if (hasTimeStyle) {
_DefineDataProperty(result, "timeStyle", internals.timeStyle);
}
} else {
resolveICUPattern(internals.pattern, result, /* includeDateTimeFields = */ true);
}
// Step 6.
return result;
}
// Table mapping ICU pattern characters back to the corresponding date-time
// components of DateTimeFormat. See
// http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
var icuPatternCharToComponent = {
E: "weekday",
G: "era",
y: "year",
M: "month",
L: "month",
d: "day",
h: "hour",
H: "hour",
k: "hour",
K: "hour",
m: "minute",
s: "second",
z: "timeZoneName",
v: "timeZoneName",
V: "timeZoneName"
};
/**
* Maps an ICU pattern string to a corresponding set of date-time components
* and their values, and adds properties for these components to the result
@@ -1045,8 +1014,12 @@ var icuPatternCharToComponent = {
* interpretation of ICU pattern characters, see
* http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
*/
function resolveICUPattern(pattern, result) {
function resolveICUPattern(pattern, result, includeDateTimeFields) {
assert(IsObject(result), "resolveICUPattern");
var hourCycle, weekday, era, year, month, day, hour, minute, second,
timeZoneName;
var i = 0;
while (i < pattern.length) {
var c = pattern[i++];
@@ -1106,27 +1079,91 @@ function resolveICUPattern(pattern, result) {
default:
// skip other pattern characters and literal text
}
if (hasOwn(c, icuPatternCharToComponent))
_DefineDataProperty(result, icuPatternCharToComponent[c], value);
// Map ICU pattern characters back to the corresponding date-time
// components of DateTimeFormat. See
// http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
switch (c) {
case "h":
_DefineDataProperty(result, "hourCycle", "h12");
_DefineDataProperty(result, "hour12", true);
case "E":
case "c":
weekday = value;
break;
case "K":
_DefineDataProperty(result, "hourCycle", "h11");
_DefineDataProperty(result, "hour12", true);
case "G":
era = value;
break;
case "y":
year = value;
break;
case "M":
case "L":
month = value;
break;
case "d":
day = value;
break;
case "h":
hourCycle = "h12";
hour = value;
break;
case "H":
_DefineDataProperty(result, "hourCycle", "h23");
_DefineDataProperty(result, "hour12", false);
hourCycle = "h23";
hour = value;
break;
case "k":
_DefineDataProperty(result, "hourCycle", "h24");
_DefineDataProperty(result, "hour12", false);
hourCycle = "h24";
hour = value;
break;
case "K":
hourCycle = "h11";
hour = value;
break;
case "m":
minute = value;
break;
case "s":
second = value;
break;
case "z":
case "v":
case "V":
timeZoneName = value;
break;
}
}
}
if (hourCycle) {
_DefineDataProperty(result, "hourCycle", hourCycle);
_DefineDataProperty(result, "hour12", hourCycle === "h11" || hourCycle === "h12");
}
if (!includeDateTimeFields) {
return;
}
if (weekday) {
_DefineDataProperty(result, "weekday", weekday);
}
if (era) {
_DefineDataProperty(result, "era", era);
}
if (year) {
_DefineDataProperty(result, "year", year);
}
if (month) {
_DefineDataProperty(result, "month", month);
}
if (day) {
_DefineDataProperty(result, "day", day);
}
if (hour) {
_DefineDataProperty(result, "hour", hour);
}
if (minute) {
_DefineDataProperty(result, "minute", minute);
}
if (second) {
_DefineDataProperty(result, "second", second);
}
if (timeZoneName) {
_DefineDataProperty(result, "timeZoneName", timeZoneName);
}
}
+2
View File
@@ -500,6 +500,8 @@ MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in loc
MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
MSG_DEF(JSMSG_INVALID_OPTION_VALUE, 2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
MSG_DEF(JSMSG_INVALID_TIME_ZONE, 1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
MSG_DEF(JSMSG_INVALID_DATETIME_OPTION, 2, JSEXN_TYPEERR, "can't set option {0} when {1} is used")
MSG_DEF(JSMSG_INVALID_DATETIME_STYLE, 2, JSEXN_TYPEERR, "can't set option {0} in Date.{1}()")
MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
// RegExp
+2 -2
View File
@@ -2655,8 +2655,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
JS_FN("intl_patternForStyle", intl_patternForStyle, 3,0),
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 3, 0),
JS_FN("intl_patternForStyle", intl_patternForStyle, 6, 0),
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2,0),