Add support for DateTimeFormat.formatToParts
Spec discussion: https://github.com/tc39/ecma402/issues/30 It's in stage 4 and Firefox has already implemented it. For now, it's added to HARMONY_IN_PROGRESS bucket behind '--datetime-format-to-parts' flag. BUG=v8:5244 TEST=intl/date-format/date-format-to-parts.js TEST=test262/intl402/DateTimeFormat/prototype/formatToParts/* Review-Url: https://codereview.chromium.org/2273953003 Cr-Commit-Position: refs/heads/master@{#39225}
This commit is contained in:
parent
01cc19fa6f
commit
a3db819c9e
1
BUILD.gn
1
BUILD.gn
@ -439,6 +439,7 @@ action("js2c_experimental") {
|
|||||||
|
|
||||||
if (v8_enable_i18n_support) {
|
if (v8_enable_i18n_support) {
|
||||||
sources += [
|
sources += [
|
||||||
|
"src/js/datetime-format-to-parts.js",
|
||||||
"src/js/icu-case-mapping.js",
|
"src/js/icu-case-mapping.js",
|
||||||
"src/js/intl-extra.js",
|
"src/js/intl-extra.js",
|
||||||
]
|
]
|
||||||
|
@ -210,7 +210,9 @@ class Genesis BASE_EMBEDDED {
|
|||||||
HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION)
|
HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION)
|
||||||
HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION)
|
HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION)
|
||||||
HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
|
HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
DECLARE_FEATURE_INITIALIZATION(intl_extra, "")
|
DECLARE_FEATURE_INITIALIZATION(intl_extra, "")
|
||||||
|
#endif
|
||||||
#undef DECLARE_FEATURE_INITIALIZATION
|
#undef DECLARE_FEATURE_INITIALIZATION
|
||||||
|
|
||||||
Handle<JSFunction> InstallArrayBuffer(Handle<JSObject> target,
|
Handle<JSFunction> InstallArrayBuffer(Handle<JSObject> target,
|
||||||
@ -2209,7 +2211,9 @@ void Genesis::InitializeExperimentalGlobal() {
|
|||||||
HARMONY_INPROGRESS(FEATURE_INITIALIZE_GLOBAL)
|
HARMONY_INPROGRESS(FEATURE_INITIALIZE_GLOBAL)
|
||||||
HARMONY_STAGED(FEATURE_INITIALIZE_GLOBAL)
|
HARMONY_STAGED(FEATURE_INITIALIZE_GLOBAL)
|
||||||
HARMONY_SHIPPING(FEATURE_INITIALIZE_GLOBAL)
|
HARMONY_SHIPPING(FEATURE_INITIALIZE_GLOBAL)
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
FEATURE_INITIALIZE_GLOBAL(intl_extra, "")
|
FEATURE_INITIALIZE_GLOBAL(intl_extra, "")
|
||||||
|
#endif
|
||||||
#undef FEATURE_INITIALIZE_GLOBAL
|
#undef FEATURE_INITIALIZE_GLOBAL
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2771,6 +2775,7 @@ void Bootstrapper::ExportExperimentalFromRuntime(Isolate* isolate,
|
|||||||
Handle<JSObject> container) {
|
Handle<JSObject> container) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
#define INITIALIZE_FLAG(FLAG) \
|
#define INITIALIZE_FLAG(FLAG) \
|
||||||
{ \
|
{ \
|
||||||
Handle<String> name = \
|
Handle<String> name = \
|
||||||
@ -2782,6 +2787,7 @@ void Bootstrapper::ExportExperimentalFromRuntime(Isolate* isolate,
|
|||||||
INITIALIZE_FLAG(FLAG_intl_extra)
|
INITIALIZE_FLAG(FLAG_intl_extra)
|
||||||
|
|
||||||
#undef INITIALIZE_FLAG
|
#undef INITIALIZE_FLAG
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2794,13 +2800,14 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_lookbehind)
|
|||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_named_captures)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_named_captures)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(intl_extra)
|
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_explicit_tailcalls)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_explicit_tailcalls)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tailcalls)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tailcalls)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_declarations)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_declarations)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_string_padding)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_string_padding)
|
||||||
#ifdef V8_I18N_SUPPORT
|
#ifdef V8_I18N_SUPPORT
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(datetime_format_to_parts)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(intl_extra)
|
||||||
#endif
|
#endif
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
|
||||||
@ -3381,7 +3388,6 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
static const char* harmony_regexp_named_captures_natives[] = {nullptr};
|
static const char* harmony_regexp_named_captures_natives[] = {nullptr};
|
||||||
static const char* harmony_regexp_property_natives[] = {nullptr};
|
static const char* harmony_regexp_property_natives[] = {nullptr};
|
||||||
static const char* harmony_function_sent_natives[] = {nullptr};
|
static const char* harmony_function_sent_natives[] = {nullptr};
|
||||||
static const char* intl_extra_natives[] = {"native intl-extra.js", nullptr};
|
|
||||||
static const char* harmony_object_values_entries_natives[] = {nullptr};
|
static const char* harmony_object_values_entries_natives[] = {nullptr};
|
||||||
static const char* harmony_object_own_property_descriptors_natives[] = {
|
static const char* harmony_object_own_property_descriptors_natives[] = {
|
||||||
nullptr};
|
nullptr};
|
||||||
@ -3391,6 +3397,9 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
#ifdef V8_I18N_SUPPORT
|
#ifdef V8_I18N_SUPPORT
|
||||||
static const char* icu_case_mapping_natives[] = {"native icu-case-mapping.js",
|
static const char* icu_case_mapping_natives[] = {"native icu-case-mapping.js",
|
||||||
nullptr};
|
nullptr};
|
||||||
|
static const char* intl_extra_natives[] = {"native intl-extra.js", nullptr};
|
||||||
|
static const char* datetime_format_to_parts_natives[] = {
|
||||||
|
"native datetime-format-to-parts.js", nullptr};
|
||||||
#endif
|
#endif
|
||||||
static const char* harmony_async_await_natives[] = {
|
static const char* harmony_async_await_natives[] = {
|
||||||
"native harmony-async-await.js", nullptr};
|
"native harmony-async-await.js", nullptr};
|
||||||
@ -3414,7 +3423,9 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
HARMONY_INPROGRESS(INSTALL_EXPERIMENTAL_NATIVES);
|
HARMONY_INPROGRESS(INSTALL_EXPERIMENTAL_NATIVES);
|
||||||
HARMONY_STAGED(INSTALL_EXPERIMENTAL_NATIVES);
|
HARMONY_STAGED(INSTALL_EXPERIMENTAL_NATIVES);
|
||||||
HARMONY_SHIPPING(INSTALL_EXPERIMENTAL_NATIVES);
|
HARMONY_SHIPPING(INSTALL_EXPERIMENTAL_NATIVES);
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
INSTALL_EXPERIMENTAL_NATIVES(intl_extra, "");
|
INSTALL_EXPERIMENTAL_NATIVES(intl_extra, "");
|
||||||
|
#endif
|
||||||
#undef INSTALL_EXPERIMENTAL_NATIVES
|
#undef INSTALL_EXPERIMENTAL_NATIVES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,16 +180,18 @@ DEFINE_BOOL(harmony, false, "enable all completed harmony features")
|
|||||||
DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
||||||
DEFINE_IMPLICATION(es_staging, harmony)
|
DEFINE_IMPLICATION(es_staging, harmony)
|
||||||
|
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
DEFINE_BOOL(intl_extra, false, "additional V8 Intl functions")
|
DEFINE_BOOL(intl_extra, false, "additional V8 Intl functions")
|
||||||
// Removing extra Intl functions is shipped
|
// Removing extra Intl functions is shipped
|
||||||
DEFINE_NEG_VALUE_IMPLICATION(harmony_shipping, intl_extra, true)
|
DEFINE_NEG_VALUE_IMPLICATION(harmony_shipping, intl_extra, true)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Activate on ClusterFuzz.
|
// Activate on ClusterFuzz.
|
||||||
DEFINE_IMPLICATION(es_staging, harmony_regexp_lookbehind)
|
DEFINE_IMPLICATION(es_staging, harmony_regexp_lookbehind)
|
||||||
DEFINE_IMPLICATION(es_staging, move_object_start)
|
DEFINE_IMPLICATION(es_staging, move_object_start)
|
||||||
|
|
||||||
// Features that are still work in progress (behind individual flags).
|
// Features that are still work in progress (behind individual flags).
|
||||||
#define HARMONY_INPROGRESS(V) \
|
#define HARMONY_INPROGRESS_BASE(V) \
|
||||||
V(harmony_array_prototype_values, "harmony Array.prototype.values") \
|
V(harmony_array_prototype_values, "harmony Array.prototype.values") \
|
||||||
V(harmony_function_sent, "harmony function.sent") \
|
V(harmony_function_sent, "harmony function.sent") \
|
||||||
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
||||||
@ -204,6 +206,14 @@ DEFINE_IMPLICATION(es_staging, move_object_start)
|
|||||||
V(harmony_trailing_commas, \
|
V(harmony_trailing_commas, \
|
||||||
"harmony trailing commas in function parameter lists")
|
"harmony trailing commas in function parameter lists")
|
||||||
|
|
||||||
|
#ifdef V8_I18N_SUPPORT
|
||||||
|
#define HARMONY_INPROGRESS(V) \
|
||||||
|
HARMONY_INPROGRESS_BASE(V) \
|
||||||
|
V(datetime_format_to_parts, "Intl.DateTimeFormat.formatToParts")
|
||||||
|
#else
|
||||||
|
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||||
#define HARMONY_STAGED_BASE(V) \
|
#define HARMONY_STAGED_BASE(V) \
|
||||||
V(harmony_regexp_lookbehind, "harmony regexp lookbehind") \
|
V(harmony_regexp_lookbehind, "harmony regexp lookbehind") \
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
#define INTERNALIZED_STRING_LIST(V) \
|
#define INTERNALIZED_STRING_LIST(V) \
|
||||||
V(anonymous_string, "anonymous") \
|
V(anonymous_string, "anonymous") \
|
||||||
V(apply_string, "apply") \
|
V(apply_string, "apply") \
|
||||||
V(assign_string, "assign") \
|
|
||||||
V(arguments_string, "arguments") \
|
V(arguments_string, "arguments") \
|
||||||
V(Arguments_string, "Arguments") \
|
V(Arguments_string, "Arguments") \
|
||||||
V(Array_string, "Array") \
|
|
||||||
V(arguments_to_string, "[object Arguments]") \
|
V(arguments_to_string, "[object Arguments]") \
|
||||||
|
V(Array_string, "Array") \
|
||||||
|
V(assign_string, "assign") \
|
||||||
V(array_to_string, "[object Array]") \
|
V(array_to_string, "[object Array]") \
|
||||||
V(boolean_to_string, "[object Boolean]") \
|
V(boolean_to_string, "[object Boolean]") \
|
||||||
V(date_to_string, "[object Date]") \
|
V(date_to_string, "[object Date]") \
|
||||||
@ -48,6 +48,8 @@
|
|||||||
V(construct_string, "construct") \
|
V(construct_string, "construct") \
|
||||||
V(create_string, "create") \
|
V(create_string, "create") \
|
||||||
V(Date_string, "Date") \
|
V(Date_string, "Date") \
|
||||||
|
V(dayperiod_string, "dayperiod") \
|
||||||
|
V(day_string, "day") \
|
||||||
V(default_string, "default") \
|
V(default_string, "default") \
|
||||||
V(defineProperty_string, "defineProperty") \
|
V(defineProperty_string, "defineProperty") \
|
||||||
V(deleteProperty_string, "deleteProperty") \
|
V(deleteProperty_string, "deleteProperty") \
|
||||||
@ -57,6 +59,7 @@
|
|||||||
V(dot_string, ".") \
|
V(dot_string, ".") \
|
||||||
V(entries_string, "entries") \
|
V(entries_string, "entries") \
|
||||||
V(enumerable_string, "enumerable") \
|
V(enumerable_string, "enumerable") \
|
||||||
|
V(era_string, "era") \
|
||||||
V(Error_string, "Error") \
|
V(Error_string, "Error") \
|
||||||
V(eval_string, "eval") \
|
V(eval_string, "eval") \
|
||||||
V(EvalError_string, "EvalError") \
|
V(EvalError_string, "EvalError") \
|
||||||
@ -74,6 +77,8 @@
|
|||||||
V(get_string, "get") \
|
V(get_string, "get") \
|
||||||
V(global_string, "global") \
|
V(global_string, "global") \
|
||||||
V(has_string, "has") \
|
V(has_string, "has") \
|
||||||
|
V(hour_string, "hour") \
|
||||||
|
V(ignoreCase_string, "ignoreCase") \
|
||||||
V(illegal_access_string, "illegal access") \
|
V(illegal_access_string, "illegal access") \
|
||||||
V(illegal_argument_string, "illegal argument") \
|
V(illegal_argument_string, "illegal argument") \
|
||||||
V(index_string, "index") \
|
V(index_string, "index") \
|
||||||
@ -92,10 +97,14 @@
|
|||||||
V(last_index_string, "lastIndex") \
|
V(last_index_string, "lastIndex") \
|
||||||
V(length_string, "length") \
|
V(length_string, "length") \
|
||||||
V(line_string, "line") \
|
V(line_string, "line") \
|
||||||
|
V(literal_string, "literal") \
|
||||||
V(Map_string, "Map") \
|
V(Map_string, "Map") \
|
||||||
V(message_string, "message") \
|
V(message_string, "message") \
|
||||||
V(minus_infinity_string, "-Infinity") \
|
V(minus_infinity_string, "-Infinity") \
|
||||||
V(minus_zero_string, "-0") \
|
V(minus_zero_string, "-0") \
|
||||||
|
V(minute_string, "minute") \
|
||||||
|
V(month_string, "month") \
|
||||||
|
V(multiline_string, "multiline") \
|
||||||
V(name_string, "name") \
|
V(name_string, "name") \
|
||||||
V(nan_string, "NaN") \
|
V(nan_string, "NaN") \
|
||||||
V(next_string, "next") \
|
V(next_string, "next") \
|
||||||
@ -120,6 +129,7 @@
|
|||||||
V(ReferenceError_string, "ReferenceError") \
|
V(ReferenceError_string, "ReferenceError") \
|
||||||
V(RegExp_string, "RegExp") \
|
V(RegExp_string, "RegExp") \
|
||||||
V(script_string, "script") \
|
V(script_string, "script") \
|
||||||
|
V(second_string, "second") \
|
||||||
V(setPrototypeOf_string, "setPrototypeOf") \
|
V(setPrototypeOf_string, "setPrototypeOf") \
|
||||||
V(set_string, "set") \
|
V(set_string, "set") \
|
||||||
V(Set_string, "Set") \
|
V(Set_string, "Set") \
|
||||||
@ -138,10 +148,12 @@
|
|||||||
V(this_string, "this") \
|
V(this_string, "this") \
|
||||||
V(throw_string, "throw") \
|
V(throw_string, "throw") \
|
||||||
V(timed_out, "timed-out") \
|
V(timed_out, "timed-out") \
|
||||||
|
V(timeZoneName_string, "timeZoneName") \
|
||||||
V(toJSON_string, "toJSON") \
|
V(toJSON_string, "toJSON") \
|
||||||
V(toString_string, "toString") \
|
V(toString_string, "toString") \
|
||||||
V(true_string, "true") \
|
V(true_string, "true") \
|
||||||
V(TypeError_string, "TypeError") \
|
V(TypeError_string, "TypeError") \
|
||||||
|
V(type_string, "type") \
|
||||||
V(uint16x8_string, "uint16x8") \
|
V(uint16x8_string, "uint16x8") \
|
||||||
V(Uint16x8_string, "Uint16x8") \
|
V(Uint16x8_string, "Uint16x8") \
|
||||||
V(uint32x4_string, "uint32x4") \
|
V(uint32x4_string, "uint32x4") \
|
||||||
@ -156,7 +168,9 @@
|
|||||||
V(value_string, "value") \
|
V(value_string, "value") \
|
||||||
V(WeakMap_string, "WeakMap") \
|
V(WeakMap_string, "WeakMap") \
|
||||||
V(WeakSet_string, "WeakSet") \
|
V(WeakSet_string, "WeakSet") \
|
||||||
V(writable_string, "writable")
|
V(weekday_string, "weekday") \
|
||||||
|
V(writable_string, "writable") \
|
||||||
|
V(year_string, "year")
|
||||||
|
|
||||||
#define PRIVATE_SYMBOL_LIST(V) \
|
#define PRIVATE_SYMBOL_LIST(V) \
|
||||||
V(array_iteration_kind_symbol) \
|
V(array_iteration_kind_symbol) \
|
||||||
|
12
src/i18n.cc
12
src/i18n.cc
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "src/i18n.h"
|
#include "src/i18n.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "src/api.h"
|
#include "src/api.h"
|
||||||
#include "src/factory.h"
|
#include "src/factory.h"
|
||||||
#include "src/isolate.h"
|
#include "src/isolate.h"
|
||||||
@ -115,13 +117,11 @@ icu::SimpleDateFormat* CreateICUDateFormat(
|
|||||||
icu::SimpleDateFormat* date_format = NULL;
|
icu::SimpleDateFormat* date_format = NULL;
|
||||||
icu::UnicodeString skeleton;
|
icu::UnicodeString skeleton;
|
||||||
if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
|
if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
|
||||||
icu::DateTimePatternGenerator* generator =
|
std::unique_ptr<icu::DateTimePatternGenerator> generator(
|
||||||
icu::DateTimePatternGenerator::createInstance(icu_locale, status);
|
icu::DateTimePatternGenerator::createInstance(icu_locale, status));
|
||||||
icu::UnicodeString pattern;
|
icu::UnicodeString pattern;
|
||||||
if (U_SUCCESS(status)) {
|
if (U_SUCCESS(status))
|
||||||
pattern = generator->getBestPattern(skeleton, status);
|
pattern = generator->getBestPattern(skeleton, status);
|
||||||
delete generator;
|
|
||||||
}
|
|
||||||
|
|
||||||
date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
|
date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
|
||||||
if (U_SUCCESS(status)) {
|
if (U_SUCCESS(status)) {
|
||||||
@ -132,7 +132,7 @@ icu::SimpleDateFormat* CreateICUDateFormat(
|
|||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
delete calendar;
|
delete calendar;
|
||||||
delete date_format;
|
delete date_format;
|
||||||
date_format = NULL;
|
date_format = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return date_format;
|
return date_format;
|
||||||
|
16
src/js/datetime-format-to-parts.js
Normal file
16
src/js/datetime-format-to-parts.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
(function(global, utils) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
%CheckIsBootstrapping();
|
||||||
|
|
||||||
|
var GlobalIntl = global.Intl;
|
||||||
|
var FormatDateToParts = utils.ImportNow("FormatDateToParts");
|
||||||
|
|
||||||
|
utils.InstallFunctions(GlobalIntl.DateTimeFormat.prototype, DONT_ENUM, [
|
||||||
|
'formatToParts', FormatDateToParts
|
||||||
|
]);
|
||||||
|
})
|
@ -1797,6 +1797,29 @@ function formatDate(formatter, dateValue) {
|
|||||||
new GlobalDate(dateMs));
|
new GlobalDate(dateMs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FormatDateToParts(dateValue) {
|
||||||
|
if (!IS_UNDEFINED(new.target)) {
|
||||||
|
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
|
||||||
|
}
|
||||||
|
CHECK_OBJECT_COERCIBLE(this, "Intl.DateTimeFormat.prototype.formatToParts");
|
||||||
|
if (!IS_OBJECT(this)) {
|
||||||
|
throw %make_type_error(kCalledOnNonObject, this);
|
||||||
|
}
|
||||||
|
var dateMs;
|
||||||
|
if (IS_UNDEFINED(dateValue)) {
|
||||||
|
dateMs = %DateCurrentTime();
|
||||||
|
} else {
|
||||||
|
dateMs = TO_NUMBER(dateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NUMBER_IS_FINITE(dateMs)) throw %make_range_error(kDateRange);
|
||||||
|
|
||||||
|
return %InternalDateFormatToParts(
|
||||||
|
%GetImplFromInitializedIntlObject(this), new GlobalDate(dateMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
%FunctionSetLength(FormatDateToParts, 0);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Date object representing the result of calling ToString(value)
|
* Returns a Date object representing the result of calling ToString(value)
|
||||||
@ -2291,8 +2314,11 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
%FunctionRemovePrototype(FormatDateToParts);
|
||||||
|
|
||||||
utils.Export(function(to) {
|
utils.Export(function(to) {
|
||||||
to.AddBoundMethod = AddBoundMethod;
|
to.AddBoundMethod = AddBoundMethod;
|
||||||
|
to.FormatDateToParts = FormatDateToParts;
|
||||||
to.IntlParseDate = IntlParseDate;
|
to.IntlParseDate = IntlParseDate;
|
||||||
to.IntlParseNumber = IntlParseNumber;
|
to.IntlParseNumber = IntlParseNumber;
|
||||||
});
|
});
|
||||||
|
@ -185,6 +185,7 @@ function PostNatives(utils) {
|
|||||||
"ArrayToString",
|
"ArrayToString",
|
||||||
"AsyncFunctionNext",
|
"AsyncFunctionNext",
|
||||||
"AsyncFunctionThrow",
|
"AsyncFunctionThrow",
|
||||||
|
"FormatDateToParts",
|
||||||
"GetIterator",
|
"GetIterator",
|
||||||
"GetMethod",
|
"GetMethod",
|
||||||
"GlobalPromise",
|
"GlobalPromise",
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include "unicode/decimfmt.h"
|
#include "unicode/decimfmt.h"
|
||||||
#include "unicode/dtfmtsym.h"
|
#include "unicode/dtfmtsym.h"
|
||||||
#include "unicode/dtptngen.h"
|
#include "unicode/dtptngen.h"
|
||||||
|
#include "unicode/fieldpos.h"
|
||||||
|
#include "unicode/fpositer.h"
|
||||||
#include "unicode/locid.h"
|
#include "unicode/locid.h"
|
||||||
#include "unicode/normalizer2.h"
|
#include "unicode/normalizer2.h"
|
||||||
#include "unicode/numfmt.h"
|
#include "unicode/numfmt.h"
|
||||||
@ -322,7 +324,7 @@ RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) {
|
|||||||
Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol();
|
Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol();
|
||||||
|
|
||||||
Handle<Object> impl = JSReceiver::GetDataProperty(obj, marker);
|
Handle<Object> impl = JSReceiver::GetDataProperty(obj, marker);
|
||||||
if (impl->IsTheHole(isolate)) {
|
if (!impl->IsJSObject()) {
|
||||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
isolate, NewTypeError(MessageTemplate::kNotIntlObject, obj));
|
isolate, NewTypeError(MessageTemplate::kNotIntlObject, obj));
|
||||||
}
|
}
|
||||||
@ -393,6 +395,138 @@ RUNTIME_FUNCTION(Runtime_InternalDateFormat) {
|
|||||||
result.length())));
|
result.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// The list comes from third_party/icu/source/i18n/unicode/udat.h.
|
||||||
|
// They're mapped to DateTimeFormat components listed at
|
||||||
|
// https://tc39.github.io/ecma402/#sec-datetimeformat-abstracts .
|
||||||
|
|
||||||
|
Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) {
|
||||||
|
switch (field_id) {
|
||||||
|
case -1:
|
||||||
|
return isolate->factory()->literal_string();
|
||||||
|
case UDAT_YEAR_FIELD:
|
||||||
|
case UDAT_EXTENDED_YEAR_FIELD:
|
||||||
|
case UDAT_YEAR_NAME_FIELD:
|
||||||
|
return isolate->factory()->year_string();
|
||||||
|
case UDAT_MONTH_FIELD:
|
||||||
|
case UDAT_STANDALONE_MONTH_FIELD:
|
||||||
|
return isolate->factory()->month_string();
|
||||||
|
case UDAT_DATE_FIELD:
|
||||||
|
return isolate->factory()->day_string();
|
||||||
|
case UDAT_HOUR_OF_DAY1_FIELD:
|
||||||
|
case UDAT_HOUR_OF_DAY0_FIELD:
|
||||||
|
case UDAT_HOUR1_FIELD:
|
||||||
|
case UDAT_HOUR0_FIELD:
|
||||||
|
return isolate->factory()->hour_string();
|
||||||
|
case UDAT_MINUTE_FIELD:
|
||||||
|
return isolate->factory()->minute_string();
|
||||||
|
case UDAT_SECOND_FIELD:
|
||||||
|
return isolate->factory()->second_string();
|
||||||
|
case UDAT_DAY_OF_WEEK_FIELD:
|
||||||
|
case UDAT_DOW_LOCAL_FIELD:
|
||||||
|
case UDAT_STANDALONE_DAY_FIELD:
|
||||||
|
return isolate->factory()->weekday_string();
|
||||||
|
case UDAT_AM_PM_FIELD:
|
||||||
|
return isolate->factory()->dayperiod_string();
|
||||||
|
case UDAT_TIMEZONE_FIELD:
|
||||||
|
case UDAT_TIMEZONE_RFC_FIELD:
|
||||||
|
case UDAT_TIMEZONE_GENERIC_FIELD:
|
||||||
|
case UDAT_TIMEZONE_SPECIAL_FIELD:
|
||||||
|
case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
|
||||||
|
case UDAT_TIMEZONE_ISO_FIELD:
|
||||||
|
case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
|
||||||
|
return isolate->factory()->timeZoneName_string();
|
||||||
|
case UDAT_ERA_FIELD:
|
||||||
|
return isolate->factory()->era_string();
|
||||||
|
default:
|
||||||
|
// Other UDAT_*_FIELD's cannot show up because there is no way to specify
|
||||||
|
// them via options of Intl.DateTimeFormat.
|
||||||
|
UNREACHABLE();
|
||||||
|
// To prevent MSVC from issuing C4715 warning.
|
||||||
|
return Handle<String>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddElement(Handle<JSArray> array, int index, int32_t field_id,
|
||||||
|
const icu::UnicodeString& formatted, int32_t begin, int32_t end,
|
||||||
|
Isolate* isolate) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
Factory* factory = isolate->factory();
|
||||||
|
Handle<JSObject> element = factory->NewJSObject(isolate->object_function());
|
||||||
|
Handle<String> value = IcuDateFieldIdToDateType(field_id, isolate);
|
||||||
|
JSObject::AddProperty(element, factory->type_string(), value, NONE);
|
||||||
|
|
||||||
|
icu::UnicodeString field(formatted.tempSubStringBetween(begin, end));
|
||||||
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||||
|
isolate, value, factory->NewStringFromTwoByte(Vector<const uint16_t>(
|
||||||
|
reinterpret_cast<const uint16_t*>(field.getBuffer()),
|
||||||
|
field.length())),
|
||||||
|
false);
|
||||||
|
|
||||||
|
JSObject::AddProperty(element, factory->value_string(), value, NONE);
|
||||||
|
RETURN_ON_EXCEPTION_VALUE(
|
||||||
|
isolate, JSObject::AddDataElement(array, index, element, NONE), false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_InternalDateFormatToParts) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
Factory* factory = isolate->factory();
|
||||||
|
|
||||||
|
DCHECK(args.length() == 2);
|
||||||
|
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
|
||||||
|
|
||||||
|
Handle<Object> value;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(date));
|
||||||
|
|
||||||
|
icu::SimpleDateFormat* date_format =
|
||||||
|
DateFormat::UnpackDateFormat(isolate, date_format_holder);
|
||||||
|
if (!date_format) return isolate->ThrowIllegalOperation();
|
||||||
|
|
||||||
|
icu::UnicodeString formatted;
|
||||||
|
icu::FieldPositionIterator fp_iter;
|
||||||
|
icu::FieldPosition fp;
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
date_format->format(value->Number(), formatted, &fp_iter, status);
|
||||||
|
if (U_FAILURE(status)) return isolate->heap()->undefined_value();
|
||||||
|
|
||||||
|
Handle<JSArray> result = factory->NewJSArray(0);
|
||||||
|
int32_t length = formatted.length();
|
||||||
|
if (length == 0) return *result;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
int32_t previous_end_pos = 0;
|
||||||
|
while (fp_iter.next(fp)) {
|
||||||
|
int32_t begin_pos = fp.getBeginIndex();
|
||||||
|
int32_t end_pos = fp.getEndIndex();
|
||||||
|
|
||||||
|
if (previous_end_pos < begin_pos) {
|
||||||
|
if (!AddElement(result, index, -1, formatted, previous_end_pos, begin_pos,
|
||||||
|
isolate)) {
|
||||||
|
return isolate->heap()->undefined_value();
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (!AddElement(result, index, fp.getField(), formatted, begin_pos, end_pos,
|
||||||
|
isolate)) {
|
||||||
|
return isolate->heap()->undefined_value();
|
||||||
|
}
|
||||||
|
previous_end_pos = end_pos;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (previous_end_pos < length) {
|
||||||
|
if (!AddElement(result, index, -1, formatted, previous_end_pos, length,
|
||||||
|
isolate)) {
|
||||||
|
return isolate->heap()->undefined_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JSObject::ValidateElements(result);
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_InternalDateParse) {
|
RUNTIME_FUNCTION(Runtime_InternalDateParse) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
@ -260,6 +260,7 @@ namespace internal {
|
|||||||
F(GetImplFromInitializedIntlObject, 1, 1) \
|
F(GetImplFromInitializedIntlObject, 1, 1) \
|
||||||
F(CreateDateTimeFormat, 3, 1) \
|
F(CreateDateTimeFormat, 3, 1) \
|
||||||
F(InternalDateFormat, 2, 1) \
|
F(InternalDateFormat, 2, 1) \
|
||||||
|
F(InternalDateFormatToParts, 2, 1) \
|
||||||
F(InternalDateParse, 2, 1) \
|
F(InternalDateParse, 2, 1) \
|
||||||
F(CreateNumberFormat, 3, 1) \
|
F(CreateNumberFormat, 3, 1) \
|
||||||
F(InternalNumberFormat, 2, 1) \
|
F(InternalNumberFormat, 2, 1) \
|
||||||
|
@ -2213,6 +2213,7 @@
|
|||||||
['v8_enable_i18n_support==1', {
|
['v8_enable_i18n_support==1', {
|
||||||
'library_files': ['js/i18n.js'],
|
'library_files': ['js/i18n.js'],
|
||||||
'experimental_library_files': [
|
'experimental_library_files': [
|
||||||
|
'js/datetime-format-to-parts.js',
|
||||||
'js/icu-case-mapping.js',
|
'js/icu-case-mapping.js',
|
||||||
'js/intl-extra.js',
|
'js/intl-extra.js',
|
||||||
],
|
],
|
||||||
|
@ -27,6 +27,14 @@
|
|||||||
|
|
||||||
// Some methods are taken from v8/test/mjsunit/mjsunit.js
|
// Some methods are taken from v8/test/mjsunit/mjsunit.js
|
||||||
|
|
||||||
|
|
||||||
|
function classOf(object) {
|
||||||
|
// Argument must not be null or undefined.
|
||||||
|
var string = Object.prototype.toString.call(object);
|
||||||
|
// String has format [object <ClassName>].
|
||||||
|
return string.substring(8, string.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two objects for key/value equality.
|
* Compares two objects for key/value equality.
|
||||||
* Returns true if they are equal, false otherwise.
|
* Returns true if they are equal, false otherwise.
|
||||||
|
20
test/intl/date-format/date-format-to-parts.js
Normal file
20
test/intl/date-format/date-format-to-parts.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --datetime-format-to-parts
|
||||||
|
|
||||||
|
var d = new Date(2016, 11, 15, 14, 10, 34);
|
||||||
|
var df = Intl.DateTimeFormat("ja",
|
||||||
|
{hour: 'numeric', minute: 'numeric', second: 'numeric', year: 'numeric',
|
||||||
|
month: 'numeric', day: 'numeric', timeZoneName: 'short', era: 'short'});
|
||||||
|
|
||||||
|
var formattedParts = df.formatToParts(d);
|
||||||
|
|
||||||
|
var formattedReconstructedFromParts = formattedParts.map((part) => part.value)
|
||||||
|
.reduce((accumulated, part) => accumulated + part);
|
||||||
|
assertEquals(df.format(d), formattedReconstructedFromParts);
|
||||||
|
// 西暦2016年11月15日 14:10:34 GMT-7
|
||||||
|
assertEquals(["era", "year", "literal", "month", "literal", "day", "literal",
|
||||||
|
"hour", "literal", "minute", "literal", "second", "literal",
|
||||||
|
"timeZoneName"], formattedParts.map((part) => part.type));
|
Loading…
Reference in New Issue
Block a user