mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 769871 - Reimplement Date.toLocaleString per ECMA-402. r=jwalden
--HG-- extra : rebase_source : 77b0023432502bc4e110143d06c10825fb020190
This commit is contained in:
parent
66f19f7626
commit
4c42f1c4ef
@ -961,6 +961,7 @@ selfhosting:: selfhosted.out.h
|
||||
selfhosting_srcs := \
|
||||
$(srcdir)/builtin/Utilities.js \
|
||||
$(srcdir)/builtin/Array.js \
|
||||
$(srcdir)/builtin/Date.js \
|
||||
$(srcdir)/builtin/Intl.js \
|
||||
$(srcdir)/builtin/IntlData.js \
|
||||
$(srcdir)/builtin/Number.js \
|
||||
|
122
js/src/builtin/Date.js
Normal file
122
js/src/builtin/Date.js
Normal file
@ -0,0 +1,122 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*global date_CheckThisDate: false, intl_DateTimeFormat: false, */
|
||||
|
||||
|
||||
var dateTimeFormatCache = new Record();
|
||||
|
||||
|
||||
/**
|
||||
* Format this Date object into a date and time string, using the locale and
|
||||
* formatting options provided.
|
||||
*
|
||||
* Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.5.
|
||||
* Spec: ECMAScript Internationalization API Specification, 13.3.1.
|
||||
*/
|
||||
function Date_toLocaleString() {
|
||||
// Steps 1-2.
|
||||
callFunction(date_CheckThisDate, this);
|
||||
var x = callFunction(std_Date_valueOf, this);
|
||||
if (std_isNaN(x))
|
||||
return "Invalid Date";
|
||||
|
||||
// Steps 3-4.
|
||||
var locales = arguments.length > 0 ? arguments[0] : undefined;
|
||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 5-6.
|
||||
var dateTimeFormat;
|
||||
if (locales === undefined && options === undefined) {
|
||||
// This cache only optimizes for the old ES5 toLocaleString without
|
||||
// locales and options.
|
||||
if (dateTimeFormatCache.dateTimeFormat === undefined) {
|
||||
options = ToDateTimeOptions(options, "any", "all");
|
||||
dateTimeFormatCache.dateTimeFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
dateTimeFormat = dateTimeFormatCache.dateTimeFormat;
|
||||
} else {
|
||||
options = ToDateTimeOptions(options, "any", "all");
|
||||
dateTimeFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
return intl_FormatDateTime(dateTimeFormat, x);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format this Date object into a date string, using the locale and formatting
|
||||
* options provided.
|
||||
*
|
||||
* Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.6.
|
||||
* Spec: ECMAScript Internationalization API Specification, 13.3.2.
|
||||
*/
|
||||
function Date_toLocaleDateString() {
|
||||
// Steps 1-2.
|
||||
callFunction(date_CheckThisDate, this);
|
||||
var x = callFunction(std_Date_valueOf, this);
|
||||
if (std_isNaN(x))
|
||||
return "Invalid Date";
|
||||
|
||||
// Steps 3-4.
|
||||
var locales = arguments.length > 0 ? arguments[0] : undefined;
|
||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 5-6.
|
||||
var dateTimeFormat;
|
||||
if (locales === undefined && options === undefined) {
|
||||
// This cache only optimizes for the old ES5 toLocaleDateString without
|
||||
// locales and options.
|
||||
if (dateTimeFormatCache.dateFormat === undefined) {
|
||||
options = ToDateTimeOptions(options, "date", "date");
|
||||
dateTimeFormatCache.dateFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
dateTimeFormat = dateTimeFormatCache.dateFormat;
|
||||
} else {
|
||||
options = ToDateTimeOptions(options, "date", "date");
|
||||
dateTimeFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
return intl_FormatDateTime(dateTimeFormat, x);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format this Date object into a time string, using the locale and formatting
|
||||
* options provided.
|
||||
*
|
||||
* Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.7.
|
||||
* Spec: ECMAScript Internationalization API Specification, 13.3.3.
|
||||
*/
|
||||
function Date_toLocaleTimeString() {
|
||||
// Steps 1-2.
|
||||
callFunction(date_CheckThisDate, this);
|
||||
var x = callFunction(std_Date_valueOf, this);
|
||||
if (std_isNaN(x))
|
||||
return "Invalid Date";
|
||||
|
||||
// Steps 3-4.
|
||||
var locales = arguments.length > 0 ? arguments[0] : undefined;
|
||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 5-6.
|
||||
var dateTimeFormat;
|
||||
if (locales === undefined && options === undefined) {
|
||||
// This cache only optimizes for the old ES5 toLocaleTimeString without
|
||||
// locales and options.
|
||||
if (dateTimeFormatCache.timeFormat === undefined) {
|
||||
options = ToDateTimeOptions(options, "time", "time");
|
||||
dateTimeFormatCache.timeFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
dateTimeFormat = dateTimeFormatCache.timeFormat;
|
||||
} else {
|
||||
options = ToDateTimeOptions(options, "time", "time");
|
||||
dateTimeFormat = intl_DateTimeFormat(locales, options);
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
return intl_FormatDateTime(dateTimeFormat, x);
|
||||
}
|
@ -1546,14 +1546,11 @@ static JSFunctionSpec dateTimeFormat_methods[] = {
|
||||
* DateTimeFormat constructor.
|
||||
* Spec: ECMAScript Internationalization API Specification, 12.1
|
||||
*/
|
||||
static JSBool
|
||||
DateTimeFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
static bool
|
||||
DateTimeFormat(JSContext *cx, CallArgs args, bool construct)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedObject obj(cx);
|
||||
|
||||
bool construct = IsConstructing(args);
|
||||
if (!construct) {
|
||||
// 12.1.2.1 step 3
|
||||
JSObject *intl = cx->global()->getOrCreateIntlObject(cx);
|
||||
@ -1599,6 +1596,21 @@ DateTimeFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DateTimeFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return DateTimeFormat(cx, args, IsConstructing(args));
|
||||
}
|
||||
|
||||
JSBool
|
||||
js::intl_DateTimeFormat(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
JS_ASSERT(args.length() == 2);
|
||||
return DateTimeFormat(cx, args, true);
|
||||
}
|
||||
|
||||
static void
|
||||
dateTimeFormat_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
|
@ -127,6 +127,16 @@ intl_FormatNumber(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
/******************** DateTimeFormat ********************/
|
||||
|
||||
/**
|
||||
* Returns a new instance of the standard built-in DateTimeFormat constructor.
|
||||
* Self-hosted code cannot cache this constructor (as it does for others in
|
||||
* Utilities.js) because it is initialized after self-hosted code is compiled.
|
||||
*
|
||||
* Usage: dateTimeFormat = intl_DateTimeFormat(locales, options)
|
||||
*/
|
||||
extern JSBool
|
||||
intl_DateTimeFormat(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
/**
|
||||
* Returns an object indicating the supported locales for date and time
|
||||
* formatting by having a true-valued property for each such locale with the
|
||||
|
@ -39,6 +39,7 @@ var std_Array_unshift = Array.prototype.unshift;
|
||||
var std_Boolean_toString = Boolean.prototype.toString;
|
||||
var Std_Date = Date;
|
||||
var std_Date_now = Date.now;
|
||||
var std_Date_valueOf = Date.prototype.valueOf;
|
||||
var std_Function_bind = Function.prototype.bind;
|
||||
var std_Function_apply = Function.prototype.apply;
|
||||
var std_Math_floor = Math.floor;
|
||||
|
@ -59,7 +59,7 @@ using mozilla::ArrayLength;
|
||||
|
||||
/*
|
||||
* The JS 'Date' object is patterned after the Java 'Date' object.
|
||||
* Here is an script:
|
||||
* Here is a script:
|
||||
*
|
||||
* today = new Date();
|
||||
*
|
||||
@ -1392,6 +1392,26 @@ IsDate(const Value &v)
|
||||
return v.isObject() && v.toObject().hasClass(&DateClass);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
date_nop(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsDate(args.thisv()));
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
date_CheckThisDate(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// CallNonGenericMethod will handle proxies correctly and throw exceptions
|
||||
// in the right circumstances, but will report date_CheckThisDate as the
|
||||
// function name in the message. We need a better solution:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=844677
|
||||
return CallNonGenericMethod<IsDate, date_nop>(cx, args);
|
||||
}
|
||||
|
||||
/*
|
||||
* See ECMA 15.9.5.4 thru 15.9.5.23
|
||||
*/
|
||||
@ -2584,7 +2604,7 @@ date_toJSON(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* for Date.toLocaleString; interface to PRMJTime date struct.
|
||||
/* for Date.toLocaleFormat; interface to PRMJTime date struct.
|
||||
*/
|
||||
static void
|
||||
new_explode(double timeval, PRMJTime *split, DateTimeInfo *dtInfo)
|
||||
@ -2726,7 +2746,7 @@ date_format(JSContext *cx, double date, formatspec format, MutableHandleValue rv
|
||||
}
|
||||
|
||||
static bool
|
||||
ToLocaleHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandleValue rval)
|
||||
ToLocaleFormatHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandleValue rval)
|
||||
{
|
||||
double utctime = obj->getDateUTCTime().toNumber();
|
||||
|
||||
@ -2771,6 +2791,7 @@ ToLocaleHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandl
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !ENABLE_INTL_API
|
||||
static bool
|
||||
ToLocaleStringHelper(JSContext *cx, HandleObject thisObj, MutableHandleValue rval)
|
||||
{
|
||||
@ -2778,7 +2799,7 @@ ToLocaleStringHelper(JSContext *cx, HandleObject thisObj, MutableHandleValue rva
|
||||
* Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
|
||||
* with msvc; '%#c' requests that a full year be used in the result string.
|
||||
*/
|
||||
return ToLocaleHelper(cx, thisObj,
|
||||
return ToLocaleFormatHelper(cx, thisObj,
|
||||
#if defined(_WIN32) && !defined(__MWERKS__)
|
||||
"%#c"
|
||||
#else
|
||||
@ -2823,7 +2844,7 @@ date_toLocaleDateString_impl(JSContext *cx, CallArgs args)
|
||||
;
|
||||
|
||||
RootedObject thisObj(cx, &args.thisv().toObject());
|
||||
return ToLocaleHelper(cx, thisObj, format, args.rval());
|
||||
return ToLocaleFormatHelper(cx, thisObj, format, args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2840,7 +2861,7 @@ date_toLocaleTimeString_impl(JSContext *cx, CallArgs args)
|
||||
JS_ASSERT(IsDate(args.thisv()));
|
||||
|
||||
RootedObject thisObj(cx, &args.thisv().toObject());
|
||||
return ToLocaleHelper(cx, thisObj, "%X", args.rval());
|
||||
return ToLocaleFormatHelper(cx, thisObj, "%X", args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2849,6 +2870,7 @@ date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp)
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
date_toLocaleFormat_impl(JSContext *cx, CallArgs args)
|
||||
@ -2857,8 +2879,19 @@ date_toLocaleFormat_impl(JSContext *cx, CallArgs args)
|
||||
|
||||
RootedObject thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
if (args.length() == 0)
|
||||
return ToLocaleStringHelper(cx, thisObj, args.rval());
|
||||
if (args.length() == 0) {
|
||||
/*
|
||||
* Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
|
||||
* with msvc; '%#c' requests that a full year be used in the result string.
|
||||
*/
|
||||
return ToLocaleFormatHelper(cx, thisObj,
|
||||
#if defined(_WIN32) && !defined(__MWERKS__)
|
||||
"%#c"
|
||||
#else
|
||||
"%c"
|
||||
#endif
|
||||
, args.rval());
|
||||
}
|
||||
|
||||
RootedString fmt(cx, ToString<CanGC>(cx, args[0]));
|
||||
if (!fmt)
|
||||
@ -2868,7 +2901,7 @@ date_toLocaleFormat_impl(JSContext *cx, CallArgs args)
|
||||
if (!fmtbytes)
|
||||
return false;
|
||||
|
||||
return ToLocaleHelper(cx, thisObj, fmtbytes.ptr(), args.rval());
|
||||
return ToLocaleFormatHelper(cx, thisObj, fmtbytes.ptr(), args.rval());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -3018,9 +3051,6 @@ static JSFunctionSpec date_methods[] = {
|
||||
JS_FN("setMilliseconds", date_setMilliseconds, 1,0),
|
||||
JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
|
||||
JS_FN("toUTCString", date_toGMTString, 0,0),
|
||||
JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
|
||||
JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
|
||||
JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
|
||||
JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
|
||||
JS_FN("toDateString", date_toDateString, 0,0),
|
||||
JS_FN("toTimeString", date_toTimeString, 0,0),
|
||||
@ -3031,6 +3061,19 @@ static JSFunctionSpec date_methods[] = {
|
||||
#endif
|
||||
JS_FN(js_toString_str, date_toString, 0,0),
|
||||
JS_FN(js_valueOf_str, date_valueOf, 0,0),
|
||||
|
||||
// This must be at the end because of bug 853075: functions listed after
|
||||
// self-hosted methods aren't available in self-hosted code.
|
||||
#if ENABLE_INTL_API
|
||||
{js_toLocaleString_str, {NULL, NULL}, 0,0, "Date_toLocaleString"},
|
||||
{"toLocaleDateString", {NULL, NULL}, 0,0, "Date_toLocaleDateString"},
|
||||
{"toLocaleTimeString", {NULL, NULL}, 0,0, "Date_toLocaleTimeString"},
|
||||
#else
|
||||
JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
|
||||
JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
|
||||
JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
|
||||
#endif
|
||||
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@ -3261,9 +3304,6 @@ static const NativeImpl sReadOnlyDateMethods[] = {
|
||||
date_getTimezoneOffset_impl,
|
||||
date_toGMTString_impl,
|
||||
date_toISOString_impl,
|
||||
date_toLocaleString_impl,
|
||||
date_toLocaleDateString_impl,
|
||||
date_toLocaleTimeString_impl,
|
||||
date_toLocaleFormat_impl,
|
||||
date_toTimeString_impl,
|
||||
date_toDateString_impl,
|
||||
|
@ -65,6 +65,15 @@ js_DateGetMinutes(JSContext *cx, JSRawObject obj);
|
||||
extern JS_FRIEND_API(int)
|
||||
js_DateGetSeconds(JSRawObject obj);
|
||||
|
||||
/**
|
||||
* Checks that the this value provided meets the requirements for "this Date
|
||||
* object" in ES5.1, 15.9.5, and throws a TypeError if not.
|
||||
*
|
||||
* Usage: callFunction(date_CheckThisDate, this)
|
||||
*/
|
||||
extern JSBool
|
||||
date_CheckThisDate(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
/* Date constructor native. Exposed only so the JIT can know its address. */
|
||||
JSBool
|
||||
js_Date(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
@ -27,15 +27,26 @@ function test()
|
||||
|
||||
d = new Date(-maxms );
|
||||
y = d.getFullYear();
|
||||
l = d.toLocaleString();
|
||||
print(l);
|
||||
|
||||
actual = y;
|
||||
expect = -271821;
|
||||
reportCompare(expect, actual, summary + ': check year');
|
||||
|
||||
actual = l.match(new RegExp(y)) + '';
|
||||
expect = y + '';
|
||||
l = d.toLocaleString();
|
||||
print(l);
|
||||
if (this.hasOwnProperty("Intl")) {
|
||||
// ECMA-402 specifies that toLocaleString uses a proleptic Gregorian
|
||||
// calender without year 0.
|
||||
// Also, localized strings usually use era indicators such as "BC"
|
||||
// instead of minus signs.
|
||||
expect = Math.abs(y - 1) + '';
|
||||
} else {
|
||||
// ECMA-262 up to edition 5.1 didn't specify toLocaleString;
|
||||
// the previous implementation assumed a calendar with year 0 and used
|
||||
// minus sign.
|
||||
expect = y + '';
|
||||
}
|
||||
actual = l.match(/-?[0-9]{3,}/) + '';
|
||||
reportCompare(expect, actual, summary + ': check toLocaleString');
|
||||
|
||||
d = new Date(maxms );
|
||||
|
@ -20,7 +20,7 @@ var temp;
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
|
||||
var date = new Date("06/05/2005 00:00:00 GMT-0000");
|
||||
|
||||
expect = date.getTimezoneOffset() > 0 ? 'Sat' : 'Sun';
|
||||
@ -86,11 +86,6 @@ expect = '22';
|
||||
actual = date.toLocaleFormat('%W');
|
||||
reportCompare(expect, actual, 'Date.toLocaleFormat("%W")');
|
||||
|
||||
expect = date.toLocaleTimeString();
|
||||
actual = date.toLocaleFormat('%X');
|
||||
reportCompare(expect, actual, 'Date.toLocaleTimeString() == ' +
|
||||
'Date.toLocaleFormat("%X")');
|
||||
|
||||
expect = '05';
|
||||
actual = date.toLocaleFormat('%y');
|
||||
reportCompare(expect, actual, 'Date.toLocaleFormat("%y")');
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jsdate.h"
|
||||
#include "jsinterp.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
@ -470,19 +471,23 @@ JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("ShouldForceSequential", intrinsic_ShouldForceSequential, 0,0),
|
||||
JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
|
||||
|
||||
// See jsdate.h for descriptions of the date_* functions.
|
||||
JS_FN("date_CheckThisDate", date_CheckThisDate, 2,0),
|
||||
|
||||
// See builtin/Intl.h for descriptions of the intl_* functions.
|
||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||
JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
|
||||
JS_FN("intl_Collator", intl_Collator, 2,0),
|
||||
JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
|
||||
JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
|
||||
JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
|
||||
JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
|
||||
JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
|
||||
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
|
||||
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
|
||||
JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
|
||||
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
|
||||
JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
|
||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
|
||||
JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
|
||||
|
||||
// See jsnum.h for descriptions of the num_* functions.
|
||||
JS_FN("num_CheckThisNumber", num_CheckThisNumber, 2,0),
|
||||
|
Loading…
Reference in New Issue
Block a user