зеркало из https://github.com/mozilla/gecko-dev.git
Bug 830304 - Compute correct time zone offsets for Date methods. r=Waldo
--HG-- extra : rebase_source : 480e087c1e19771f18ccb7146b55f063f347b817
This commit is contained in:
Родитель
1bba75e15f
Коммит
f5c8496af4
|
@ -13,6 +13,8 @@
|
|||
#include "mozilla/Unused.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
|
@ -4737,6 +4739,118 @@ DisableForEach(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetTimeZone(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
|
||||
if (args.length() != 0) {
|
||||
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto getTimeZone = [](std::time_t* now) -> const char* {
|
||||
std::tm local{};
|
||||
#if defined(_WIN32)
|
||||
_tzset();
|
||||
if (localtime_s(&local, now) == 0)
|
||||
return _tzname[local.tm_isdst > 0];
|
||||
#else
|
||||
tzset();
|
||||
#if defined(HAVE_LOCALTIME_R)
|
||||
if (localtime_r(now, &local)) {
|
||||
#else
|
||||
std::tm* localtm = std::localtime(now);
|
||||
if (localtm) {
|
||||
*local = *localtm;
|
||||
#endif /* HAVE_LOCALTIME_R */
|
||||
|
||||
#if defined(HAVE_TM_ZONE_TM_GMTOFF)
|
||||
return local.tm_zone;
|
||||
#else
|
||||
return tzname[local.tm_isdst > 0];
|
||||
#endif /* HAVE_TM_ZONE_TM_GMTOFF */
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
std::time_t now = std::time(nullptr);
|
||||
if (now != static_cast<std::time_t>(-1)) {
|
||||
if (const char* tz = getTimeZone(&now)) {
|
||||
JSString* str = JS_NewStringCopyZ(cx, tz);
|
||||
if (!str)
|
||||
return false;
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
SetTimeZone(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
|
||||
if (args.length() != 1) {
|
||||
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isString() && !args[0].isUndefined()) {
|
||||
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto setTimeZone = [](const char* value) {
|
||||
#if defined(_WIN32)
|
||||
return _putenv_s("TZ", value) == 0;
|
||||
#else
|
||||
return setenv("TZ", value, true) == 0;
|
||||
#endif /* _WIN32 */
|
||||
};
|
||||
|
||||
auto unsetTimeZone = []() {
|
||||
#if defined(_WIN32)
|
||||
return _putenv_s("TZ", "") == 0;
|
||||
#else
|
||||
return unsetenv("TZ") == 0;
|
||||
#endif /* _WIN32 */
|
||||
};
|
||||
|
||||
if (args[0].isString() && !args[0].toString()->empty()) {
|
||||
JSAutoByteString timeZone;
|
||||
if (!timeZone.encodeLatin1(cx, args[0].toString()))
|
||||
return false;
|
||||
|
||||
if (!setTimeZone(timeZone.ptr())) {
|
||||
JS_ReportErrorASCII(cx, "Failed to set 'TZ' environment variable");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!unsetTimeZone()) {
|
||||
JS_ReportErrorASCII(cx, "Failed to unset 'TZ' environment variable");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
_tzset();
|
||||
#else
|
||||
tzset();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
JS::ResetTimeZone();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(FUZZING) && defined(__AFL_COMPILER)
|
||||
static bool
|
||||
AflLoop(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
@ -5414,6 +5528,10 @@ gc::ZealModeHelpText),
|
|||
"isLegacyIterator(value)",
|
||||
" Returns whether the value is considered is a legacy iterator.\n"),
|
||||
|
||||
JS_FN_HELP("getTimeZone", GetTimeZone, 0, 0,
|
||||
"getTimeZone()",
|
||||
" Get the current time zone.\n"),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
||||
|
@ -5432,6 +5550,12 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = {
|
|||
"getErrorNotes(error)",
|
||||
" Returns an array of error notes."),
|
||||
|
||||
JS_FN_HELP("setTimeZone", SetTimeZone, 1, 0,
|
||||
"setTimeZone(tzname)",
|
||||
" Set the 'TZ' environment variable to the given time zone and applies the new time zone.\n"
|
||||
" An empty string or undefined resets the time zone to its default value.\n"
|
||||
" NOTE: The input string is not validated and will be passed verbatim to setenv()."),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
||||
|
|
|
@ -483,7 +483,14 @@ LocalTime(double t)
|
|||
static double
|
||||
UTC(double t)
|
||||
{
|
||||
return t - AdjustTime(t - DateTimeInfo::localTZA());
|
||||
// Following the ES2017 specification creates undesirable results at DST
|
||||
// transitions. For example when transitioning from PST to PDT,
|
||||
// |new Date(2016,2,13,2,0,0).toTimeString()| returns the string value
|
||||
// "01:00:00 GMT-0800 (PST)" instead of "03:00:00 GMT-0700 (PDT)". Follow
|
||||
// V8 and subtract one hour before computing the offset.
|
||||
// Spec bug: https://bugs.ecmascript.org/show_bug.cgi?id=4007
|
||||
|
||||
return t - AdjustTime(t - DateTimeInfo::localTZA() - msPerHour);
|
||||
}
|
||||
|
||||
/* ES5 15.9.1.10. */
|
||||
|
@ -2584,7 +2591,7 @@ date_toJSON(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
/* Interface to PRMJTime date struct. */
|
||||
static PRMJTime
|
||||
ToPRMJTime(double localTime)
|
||||
ToPRMJTime(double localTime, double utcTime)
|
||||
{
|
||||
double year = YearFromTime(localTime);
|
||||
|
||||
|
@ -2598,9 +2605,7 @@ ToPRMJTime(double localTime)
|
|||
prtm.tm_wday = int8_t(WeekDay(localTime));
|
||||
prtm.tm_year = year;
|
||||
prtm.tm_yday = int16_t(DayWithinYear(localTime, year));
|
||||
|
||||
// XXX: DaylightSavingTA expects utc-time argument.
|
||||
prtm.tm_isdst = (DaylightSavingTA(localTime) != 0);
|
||||
prtm.tm_isdst = (DaylightSavingTA(utcTime) != 0);
|
||||
|
||||
return prtm;
|
||||
}
|
||||
|
@ -2647,7 +2652,7 @@ FormatDate(JSContext* cx, double utcTime, FormatSpec format, MutableHandleValue
|
|||
*/
|
||||
|
||||
/* get a time zone string from the OS to include as a comment. */
|
||||
PRMJTime prtm = ToPRMJTime(utcTime);
|
||||
PRMJTime prtm = ToPRMJTime(localTime, utcTime);
|
||||
size_t tzlen = PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &prtm);
|
||||
if (tzlen != 0) {
|
||||
/*
|
||||
|
@ -2727,7 +2732,7 @@ ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, Mutabl
|
|||
strcpy(buf, js_NaN_date_str);
|
||||
} else {
|
||||
double localTime = LocalTime(utcTime);
|
||||
PRMJTime prtm = ToPRMJTime(localTime);
|
||||
PRMJTime prtm = ToPRMJTime(localTime, utcTime);
|
||||
|
||||
/* Let PRMJTime format it. */
|
||||
size_t result_len = PRMJ_FormatTime(buf, sizeof buf, format, &prtm);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
if (typeof setTimeZone === "undefined") {
|
||||
var setTimeZone = SpecialPowers.Cu.getJSTestingFunctions().setTimeZone;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
// |reftest| skip-if(!xulRuntime.shell)
|
||||
|
||||
// Note: The default time zone is set to PST8PDT for all jstests (when run in the shell).
|
||||
|
||||
assertEq(/^(PST|PDT)$/.test(getTimeZone()), true);
|
||||
|
||||
const msPerMinute = 60 * 1000;
|
||||
const msPerHour = 60 * 60 * 1000;
|
||||
|
||||
const Month = {
|
||||
January: 0,
|
||||
February: 1,
|
||||
March: 2,
|
||||
April: 3,
|
||||
May: 4,
|
||||
June: 5,
|
||||
July: 6,
|
||||
August: 7,
|
||||
September: 8,
|
||||
October: 9,
|
||||
November: 10,
|
||||
December: 11,
|
||||
};
|
||||
|
||||
// PDT -> PST, using milliseconds from epoch.
|
||||
{
|
||||
let midnight = new Date(2016, Month.November, 6, 0, 0, 0, 0);
|
||||
let midnightUTC = Date.UTC(2016, Month.November, 6, 0, 0, 0, 0);
|
||||
|
||||
// Ensure midnight time is correct.
|
||||
assertEq(midnightUTC - midnight.getTime(), -7 * msPerHour);
|
||||
|
||||
let tests = [
|
||||
{ offset: 0 * 60, date: "Sun Nov 06 2016", time: "00:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 0 * 60 + 30, date: "Sun Nov 06 2016", time: "00:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 1 * 60, date: "Sun Nov 06 2016", time: "01:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 1 * 60 + 30, date: "Sun Nov 06 2016", time: "01:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 2 * 60, date: "Sun Nov 06 2016", time: "01:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 2 * 60 + 30, date: "Sun Nov 06 2016", time: "01:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 3 * 60, date: "Sun Nov 06 2016", time: "02:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 3 * 60 + 30, date: "Sun Nov 06 2016", time: "02:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 4 * 60, date: "Sun Nov 06 2016", time: "03:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 4 * 60 + 30, date: "Sun Nov 06 2016", time: "03:30:00 GMT-0800 (PST)" },
|
||||
];
|
||||
|
||||
for (let {offset, date, time} of tests) {
|
||||
let dt = new Date(midnight.getTime() + offset * msPerMinute);
|
||||
assertEq(dt.toString(), `${date} ${time}`);
|
||||
assertEq(dt.toDateString(), date);
|
||||
assertEq(dt.toTimeString(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PDT -> PST, using local date-time.
|
||||
{
|
||||
let tests = [
|
||||
{ offset: 0 * 60, date: "Sun Nov 06 2016", time: "00:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 0 * 60 + 30, date: "Sun Nov 06 2016", time: "00:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 1 * 60, date: "Sun Nov 06 2016", time: "01:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 1 * 60 + 30, date: "Sun Nov 06 2016", time: "01:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 2 * 60, date: "Sun Nov 06 2016", time: "02:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 2 * 60 + 30, date: "Sun Nov 06 2016", time: "02:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 3 * 60, date: "Sun Nov 06 2016", time: "03:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 3 * 60 + 30, date: "Sun Nov 06 2016", time: "03:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 4 * 60, date: "Sun Nov 06 2016", time: "04:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 4 * 60 + 30, date: "Sun Nov 06 2016", time: "04:30:00 GMT-0800 (PST)" },
|
||||
];
|
||||
|
||||
for (let {offset, date, time} of tests) {
|
||||
let dt = new Date(2016, Month.November, 6, (offset / 60)|0, (offset % 60), 0, 0);
|
||||
assertEq(dt.toString(), `${date} ${time}`);
|
||||
assertEq(dt.toDateString(), date);
|
||||
assertEq(dt.toTimeString(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PST -> PDT, using milliseconds from epoch.
|
||||
{
|
||||
let midnight = new Date(2016, Month.March, 13, 0, 0, 0, 0);
|
||||
let midnightUTC = Date.UTC(2016, Month.March, 13, 0, 0, 0, 0);
|
||||
|
||||
// Ensure midnight time is correct.
|
||||
assertEq(midnightUTC - midnight.getTime(), -8 * msPerHour);
|
||||
|
||||
let tests = [
|
||||
{ offset: 0 * 60, date: "Sun Mar 13 2016", time: "00:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 0 * 60 + 30, date: "Sun Mar 13 2016", time: "00:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 1 * 60, date: "Sun Mar 13 2016", time: "01:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 1 * 60 + 30, date: "Sun Mar 13 2016", time: "01:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 2 * 60, date: "Sun Mar 13 2016", time: "03:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 2 * 60 + 30, date: "Sun Mar 13 2016", time: "03:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 3 * 60, date: "Sun Mar 13 2016", time: "04:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 3 * 60 + 30, date: "Sun Mar 13 2016", time: "04:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 4 * 60, date: "Sun Mar 13 2016", time: "05:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 4 * 60 + 30, date: "Sun Mar 13 2016", time: "05:30:00 GMT-0700 (PDT)" },
|
||||
];
|
||||
|
||||
for (let {offset, date, time} of tests) {
|
||||
let dt = new Date(midnight.getTime() + offset * msPerMinute);
|
||||
assertEq(dt.toString(), `${date} ${time}`);
|
||||
assertEq(dt.toDateString(), date);
|
||||
assertEq(dt.toTimeString(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PST -> PDT, using local date-time.
|
||||
{
|
||||
let tests = [
|
||||
{ offset: 0 * 60, date: "Sun Mar 13 2016", time: "00:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 0 * 60 + 30, date: "Sun Mar 13 2016", time: "00:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 1 * 60, date: "Sun Mar 13 2016", time: "01:00:00 GMT-0800 (PST)" },
|
||||
{ offset: 1 * 60 + 30, date: "Sun Mar 13 2016", time: "01:30:00 GMT-0800 (PST)" },
|
||||
{ offset: 2 * 60, date: "Sun Mar 13 2016", time: "03:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 2 * 60 + 30, date: "Sun Mar 13 2016", time: "03:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 3 * 60, date: "Sun Mar 13 2016", time: "03:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 3 * 60 + 30, date: "Sun Mar 13 2016", time: "03:30:00 GMT-0700 (PDT)" },
|
||||
{ offset: 4 * 60, date: "Sun Mar 13 2016", time: "04:00:00 GMT-0700 (PDT)" },
|
||||
{ offset: 4 * 60 + 30, date: "Sun Mar 13 2016", time: "04:30:00 GMT-0700 (PDT)" },
|
||||
];
|
||||
|
||||
for (let {offset, date, time} of tests) {
|
||||
let dt = new Date(2016, Month.March, 13, (offset / 60)|0, (offset % 60), 0, 0);
|
||||
assertEq(dt.toString(), `${date} ${time}`);
|
||||
assertEq(dt.toDateString(), date);
|
||||
assertEq(dt.toTimeString(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,64 @@
|
|||
// |reftest| skip-if(xulRuntime.OS=="WINNT"||xulRuntime.OS=="Darwin") -- Skip on OS X in addition to Windows
|
||||
|
||||
// Contains the tests from "time-zones.js" which fail on OS X.
|
||||
|
||||
const msPerHour = 60 * 60 * 1000;
|
||||
|
||||
const Month = {
|
||||
January: 0,
|
||||
February: 1,
|
||||
March: 2,
|
||||
April: 3,
|
||||
May: 4,
|
||||
June: 5,
|
||||
July: 6,
|
||||
August: 7,
|
||||
September: 8,
|
||||
October: 9,
|
||||
November: 10,
|
||||
December: 11,
|
||||
};
|
||||
|
||||
function inTimeZone(tzname, fn) {
|
||||
setTimeZone(tzname);
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
setTimeZone(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].join("|");
|
||||
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].join("|");
|
||||
const datePart = String.raw `(?:${weekdays}) (?:${months}) \d{2}`;
|
||||
const timePart = String.raw `\d{4,6} \d{2}:\d{2}:\d{2} GMT[+-]\d{4}`;
|
||||
const dateTimeRE = new RegExp(String.raw `^(${datePart} ${timePart})(?: \((.+)\))?$`);
|
||||
|
||||
function assertDateTime(date, expected) {
|
||||
let actual = date.toString();
|
||||
assertEq(dateTimeRE.test(expected), true, `${expected}`);
|
||||
assertEq(dateTimeRE.test(actual), true, `${actual}`);
|
||||
|
||||
let [, expectedDateTime, expectedTimeZone] = dateTimeRE.exec(expected);
|
||||
let [, actualDateTime, actualTimeZone] = dateTimeRE.exec(actual);
|
||||
|
||||
assertEq(actualDateTime, expectedDateTime);
|
||||
|
||||
// The time zone identifier is optional, so only compare its value if it's
|
||||
// present in |actual| and |expected|.
|
||||
if (expectedTimeZone !== undefined && actualTimeZone !== undefined) {
|
||||
assertEq(actualTimeZone, expectedTimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
// bug 637244
|
||||
inTimeZone("Asia/Novosibirsk", () => {
|
||||
let dt1 = new Date(1984, Month.April, 1, -1);
|
||||
assertDateTime(dt1, "Sat Mar 31 1984 23:00:00 GMT+0700 (NOVT)");
|
||||
|
||||
let dt2 = new Date(1984, Month.April, 1);
|
||||
assertDateTime(dt2, "Sun Apr 01 1984 01:00:00 GMT+0800 (NOVST)");
|
||||
});
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,198 @@
|
|||
// |reftest| skip-if(xulRuntime.OS=="WINNT"&&!xulRuntime.shell) -- Windows browser in automation doesn't pick up new time zones correctly
|
||||
|
||||
// Repeats the test from "time-zones.js", but uses POSIX instead of IANA names
|
||||
// for the time zones. This allows to run these tests on Windows, too.
|
||||
|
||||
// From bug 1330149:
|
||||
//
|
||||
// Windows only supports a very limited set of IANA time zone names for the TZ
|
||||
// environment variable.
|
||||
//
|
||||
// TZ format supported by Windows: "TZ=tzn[+|-]hh[:mm[:ss]][dzn]".
|
||||
//
|
||||
// Complete list of all IANA time zone ids matching that format.
|
||||
//
|
||||
// From tzdata's "northamerica" file:
|
||||
// EST5EDT
|
||||
// CST6CDT
|
||||
// MST7MDT
|
||||
// PST8PDT
|
||||
//
|
||||
// From tzdata's "backward" file:
|
||||
// GMT+0
|
||||
// GMT-0
|
||||
// GMT0
|
||||
|
||||
// Perform the following replacements:
|
||||
// America/New_York -> EST5EDT
|
||||
// America/Chicago -> CST6CDT
|
||||
// America/Denver -> MST7MDT
|
||||
// America/Los_Angeles -> PST8PDT
|
||||
//
|
||||
// And remove any tests not matching one of the four time zones from above.
|
||||
|
||||
const msPerHour = 60 * 60 * 1000;
|
||||
|
||||
const Month = {
|
||||
January: 0,
|
||||
February: 1,
|
||||
March: 2,
|
||||
April: 3,
|
||||
May: 4,
|
||||
June: 5,
|
||||
July: 6,
|
||||
August: 7,
|
||||
September: 8,
|
||||
October: 9,
|
||||
November: 10,
|
||||
December: 11,
|
||||
};
|
||||
|
||||
function inTimeZone(tzname, fn) {
|
||||
setTimeZone(tzname);
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
setTimeZone("PST8PDT");
|
||||
}
|
||||
}
|
||||
|
||||
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].join("|");
|
||||
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].join("|");
|
||||
const datePart = String.raw `(?:${weekdays}) (?:${months}) \d{2}`;
|
||||
const timePart = String.raw `\d{4,6} \d{2}:\d{2}:\d{2} GMT[+-]\d{4}`;
|
||||
const dateTimeRE = new RegExp(String.raw `^(${datePart} ${timePart})(?: \((.+)\))?$`);
|
||||
|
||||
function assertDateTime(date, expected) {
|
||||
let actual = date.toString();
|
||||
assertEq(dateTimeRE.test(expected), true, `${expected}`);
|
||||
assertEq(dateTimeRE.test(actual), true, `${actual}`);
|
||||
|
||||
let [, expectedDateTime, expectedTimeZone] = dateTimeRE.exec(expected);
|
||||
let [, actualDateTime, actualTimeZone] = dateTimeRE.exec(actual);
|
||||
|
||||
assertEq(actualDateTime, expectedDateTime);
|
||||
|
||||
// The time zone identifier is optional, so only compare its value if it's
|
||||
// present in |actual| and |expected|.
|
||||
if (expectedTimeZone !== undefined && actualTimeZone !== undefined) {
|
||||
assertEq(actualTimeZone, expectedTimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
// bug 294908
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt = new Date(2003, Month.April, 6, 2, 30, 00);
|
||||
assertDateTime(dt, "Sun Apr 06 2003 03:30:00 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 610183
|
||||
inTimeZone("PST8PDT", () => {
|
||||
let dt = new Date(2014, Month.November, 2, 1, 47, 42);
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:47:42 GMT-0700 (PDT)");
|
||||
});
|
||||
|
||||
// bug 629465
|
||||
inTimeZone("MST7MDT", () => {
|
||||
let dt1 = new Date(Date.UTC(2015, Month.November, 1, 0, 0, 0) + 6 * msPerHour);
|
||||
assertDateTime(dt1, "Sun Nov 01 2015 00:00:00 GMT-0600 (MDT)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2015, Month.November, 1, 1, 0, 0) + 6 * msPerHour);
|
||||
assertDateTime(dt2, "Sun Nov 01 2015 01:00:00 GMT-0600 (MDT)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2015, Month.November, 1, 1, 0, 0) + 7 * msPerHour);
|
||||
assertDateTime(dt3, "Sun Nov 01 2015 01:00:00 GMT-0700 (MST)");
|
||||
});
|
||||
|
||||
// bug 742427
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt = new Date(2009, Month.March, 8, 1, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 01:00:00 GMT-0500 (EST)");
|
||||
dt.setHours(dt.getHours() + 1);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 03:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
inTimeZone("MST7MDT", () => {
|
||||
let dt = new Date(2009, Month.March, 8, 1, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 01:00:00 GMT-0700 (MST)");
|
||||
dt.setHours(dt.getHours() + 1);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 03:00:00 GMT-0600 (MDT)");
|
||||
});
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt1 = new Date(Date.UTC(2008, Month.March, 9, 0, 0, 0) + 5 * msPerHour);
|
||||
assertDateTime(dt1, "Sun Mar 09 2008 00:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2008, Month.March, 9, 1, 0, 0) + 5 * msPerHour);
|
||||
assertDateTime(dt2, "Sun Mar 09 2008 01:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2008, Month.March, 9, 4, 0, 0) + 4 * msPerHour);
|
||||
assertDateTime(dt3, "Sun Mar 09 2008 04:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 802627
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt = new Date(0);
|
||||
assertDateTime(dt, "Wed Dec 31 1969 19:00:00 GMT-0500 (EST)");
|
||||
});
|
||||
|
||||
// bug 879261
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt1 = new Date(1362891600000);
|
||||
assertDateTime(dt1, "Sun Mar 10 2013 00:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt2 = new Date(dt1.setHours(dt1.getHours() + 24));
|
||||
assertDateTime(dt2, "Mon Mar 11 2013 00:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
inTimeZone("PST8PDT", () => {
|
||||
let dt1 = new Date(2014, Month.January, 1);
|
||||
assertDateTime(dt1, "Wed Jan 01 2014 00:00:00 GMT-0800 (PST)");
|
||||
|
||||
let dt2 = new Date(2014, Month.August, 1);
|
||||
assertDateTime(dt2, "Fri Aug 01 2014 00:00:00 GMT-0700 (PDT)");
|
||||
});
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt1 = new Date(2016, Month.October, 14, 3, 5, 9);
|
||||
assertDateTime(dt1, "Fri Oct 14 2016 03:05:09 GMT-0400 (EDT)");
|
||||
|
||||
let dt2 = new Date(2016, Month.January, 9, 23, 26, 40);
|
||||
assertDateTime(dt2, "Sat Jan 09 2016 23:26:40 GMT-0500 (EST)");
|
||||
});
|
||||
|
||||
// bug 1084547
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt = new Date(Date.parse("2014-11-02T02:00:00-04:00"));
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:00:00 GMT-0500 (EST)");
|
||||
|
||||
dt.setMilliseconds(0);
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 1303306
|
||||
inTimeZone("EST5EDT", () => {
|
||||
let dt = new Date(2016, Month.September, 15, 16, 14, 48);
|
||||
assertDateTime(dt, "Thu Sep 15 2016 16:14:48 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 1317364
|
||||
inTimeZone("PST8PDT", () => {
|
||||
let dt = new Date(2016, Month.March, 13, 2, 30, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 13 2016 03:30:00 GMT-0700 (PDT)");
|
||||
|
||||
let dt2 = new Date(2016, Month.January, 5, 0, 30, 30, 500);
|
||||
assertDateTime(dt2, "Tue Jan 05 2016 00:30:30 GMT-0800 (PST)");
|
||||
|
||||
let dt3 = new Date(dt2.getTime());
|
||||
dt3.setMonth(dt2.getMonth() + 2);
|
||||
dt3.setDate(dt2.getDate() + 7 + 1);
|
||||
dt3.setHours(dt2.getHours() + 2);
|
||||
|
||||
assertEq(dt3.getHours(), 3);
|
||||
});
|
||||
|
||||
// bug 1355272
|
||||
inTimeZone("PST8PDT", () => {
|
||||
let dt = new Date(2017, Month.April, 10, 17, 25, 07);
|
||||
assertDateTime(dt, "Mon Apr 10 2017 17:25:07 GMT-0700 (PDT)");
|
||||
});
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,310 @@
|
|||
// |reftest| skip-if(xulRuntime.OS=="WINNT") -- Windows doesn't accept IANA names for the TZ env variable
|
||||
|
||||
const msPerHour = 60 * 60 * 1000;
|
||||
|
||||
const Month = {
|
||||
January: 0,
|
||||
February: 1,
|
||||
March: 2,
|
||||
April: 3,
|
||||
May: 4,
|
||||
June: 5,
|
||||
July: 6,
|
||||
August: 7,
|
||||
September: 8,
|
||||
October: 9,
|
||||
November: 10,
|
||||
December: 11,
|
||||
};
|
||||
|
||||
function inTimeZone(tzname, fn) {
|
||||
setTimeZone(tzname);
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
setTimeZone(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].join("|");
|
||||
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].join("|");
|
||||
const datePart = String.raw `(?:${weekdays}) (?:${months}) \d{2}`;
|
||||
const timePart = String.raw `\d{4,6} \d{2}:\d{2}:\d{2} GMT[+-]\d{4}`;
|
||||
const dateTimeRE = new RegExp(String.raw `^(${datePart} ${timePart})(?: \((.+)\))?$`);
|
||||
|
||||
function assertDateTime(date, expected) {
|
||||
let actual = date.toString();
|
||||
assertEq(dateTimeRE.test(expected), true, `${expected}`);
|
||||
assertEq(dateTimeRE.test(actual), true, `${actual}`);
|
||||
|
||||
let [, expectedDateTime, expectedTimeZone] = dateTimeRE.exec(expected);
|
||||
let [, actualDateTime, actualTimeZone] = dateTimeRE.exec(actual);
|
||||
|
||||
assertEq(actualDateTime, expectedDateTime);
|
||||
|
||||
// The time zone identifier is optional, so only compare its value if it's
|
||||
// present in |actual| and |expected|.
|
||||
if (expectedTimeZone !== undefined && actualTimeZone !== undefined) {
|
||||
assertEq(actualTimeZone, expectedTimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
// bug 158328
|
||||
inTimeZone("Europe/London", () => {
|
||||
let dt1 = new Date(2002, Month.July, 19, 16, 10, 55);
|
||||
assertDateTime(dt1, "Fri Jul 19 2002 16:10:55 GMT+0100 (BST)");
|
||||
|
||||
let dt2 = new Date(2009, Month.December, 24, 13, 44, 52);
|
||||
assertDateTime(dt2, "Thu Dec 24 2009 13:44:52 GMT+0000 (GMT)");
|
||||
});
|
||||
|
||||
// bug 294908
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt = new Date(2003, Month.April, 6, 2, 30, 00);
|
||||
assertDateTime(dt, "Sun Apr 06 2003 03:30:00 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 610183
|
||||
inTimeZone("America/Los_Angeles", () => {
|
||||
let dt = new Date(2014, Month.November, 2, 1, 47, 42);
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:47:42 GMT-0700 (PDT)");
|
||||
});
|
||||
|
||||
// bug 629465
|
||||
inTimeZone("America/Denver", () => {
|
||||
let dt1 = new Date(Date.UTC(2015, Month.November, 1, 0, 0, 0) + 6 * msPerHour);
|
||||
assertDateTime(dt1, "Sun Nov 01 2015 00:00:00 GMT-0600 (MDT)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2015, Month.November, 1, 1, 0, 0) + 6 * msPerHour);
|
||||
assertDateTime(dt2, "Sun Nov 01 2015 01:00:00 GMT-0600 (MDT)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2015, Month.November, 1, 1, 0, 0) + 7 * msPerHour);
|
||||
assertDateTime(dt3, "Sun Nov 01 2015 01:00:00 GMT-0700 (MST)");
|
||||
});
|
||||
|
||||
// bug 637244
|
||||
inTimeZone("Europe/Helsinki", () => {
|
||||
let dt1 = new Date(2016, Month.March, 27, 2, 59);
|
||||
assertDateTime(dt1, "Sun Mar 27 2016 02:59:00 GMT+0200 (EET)");
|
||||
|
||||
let dt2 = new Date(2016, Month.March, 27, 3, 0);
|
||||
assertDateTime(dt2, "Sun Mar 27 2016 04:00:00 GMT+0300 (EEST)");
|
||||
});
|
||||
|
||||
// bug 718175
|
||||
inTimeZone("Europe/London", () => {
|
||||
let dt = new Date(0);
|
||||
assertEq(dt.getHours(), 1);
|
||||
});
|
||||
|
||||
// bug 719274
|
||||
inTimeZone("Pacific/Auckland", () => {
|
||||
let dt = new Date(2012, Month.January, 19, 12, 54, 27);
|
||||
assertDateTime(dt, "Thu Jan 19 2012 12:54:27 GMT+1300 (NZDT)");
|
||||
});
|
||||
|
||||
// bug 742427
|
||||
inTimeZone("Europe/Paris", () => {
|
||||
let dt1 = new Date(2009, Month.March, 29, 1, 0, 0);
|
||||
assertDateTime(dt1, "Sun Mar 29 2009 01:00:00 GMT+0100 (CET)");
|
||||
dt1.setHours(dt1.getHours() + 1);
|
||||
assertDateTime(dt1, "Sun Mar 29 2009 03:00:00 GMT+0200 (CEST)");
|
||||
|
||||
let dt2 = new Date(2010, Month.March, 29, 1, 0, 0);
|
||||
assertDateTime(dt2, "Mon Mar 29 2010 01:00:00 GMT+0200 (CEST)");
|
||||
dt2.setHours(dt2.getHours() + 1);
|
||||
assertDateTime(dt2, "Mon Mar 29 2010 02:00:00 GMT+0200 (CEST)");
|
||||
});
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt = new Date(2009, Month.March, 8, 1, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 01:00:00 GMT-0500 (EST)");
|
||||
dt.setHours(dt.getHours() + 1);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 03:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
inTimeZone("America/Denver", () => {
|
||||
let dt = new Date(2009, Month.March, 8, 1, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 01:00:00 GMT-0700 (MST)");
|
||||
dt.setHours(dt.getHours() + 1);
|
||||
assertDateTime(dt, "Sun Mar 08 2009 03:00:00 GMT-0600 (MDT)");
|
||||
});
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt1 = new Date(Date.UTC(2008, Month.March, 9, 0, 0, 0) + 5 * msPerHour);
|
||||
assertDateTime(dt1, "Sun Mar 09 2008 00:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2008, Month.March, 9, 1, 0, 0) + 5 * msPerHour);
|
||||
assertDateTime(dt2, "Sun Mar 09 2008 01:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2008, Month.March, 9, 4, 0, 0) + 4 * msPerHour);
|
||||
assertDateTime(dt3, "Sun Mar 09 2008 04:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
inTimeZone("Europe/Paris", () => {
|
||||
let dt1 = new Date(Date.UTC(2008, Month.March, 30, 0, 0, 0) - 1 * msPerHour);
|
||||
assertDateTime(dt1, "Sun Mar 30 2008 00:00:00 GMT+0100 (CET)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2008, Month.March, 30, 1, 0, 0) - 1 * msPerHour);
|
||||
assertDateTime(dt2, "Sun Mar 30 2008 01:00:00 GMT+0100 (CET)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2008, Month.March, 30, 3, 0, 0) - 2 * msPerHour);
|
||||
assertDateTime(dt3, "Sun Mar 30 2008 03:00:00 GMT+0200 (CEST)");
|
||||
|
||||
let dt4 = new Date(Date.UTC(2008, Month.March, 30, 4, 0, 0) - 2 * msPerHour);
|
||||
assertDateTime(dt4, "Sun Mar 30 2008 04:00:00 GMT+0200 (CEST)");
|
||||
});
|
||||
|
||||
// bug 802627
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt = new Date(0);
|
||||
assertDateTime(dt, "Wed Dec 31 1969 19:00:00 GMT-0500 (EST)");
|
||||
});
|
||||
|
||||
// bug 819820
|
||||
inTimeZone("Europe/London", () => {
|
||||
let dt1 = new Date(Date.UTC(2012, Month.October, 28, 0, 59, 59));
|
||||
assertDateTime(dt1, "Sun Oct 28 2012 01:59:59 GMT+0100 (BST)");
|
||||
|
||||
let dt2 = new Date(Date.UTC(2012, Month.October, 28, 1, 0, 0));
|
||||
assertDateTime(dt2, "Sun Oct 28 2012 01:00:00 GMT+0000 (GMT)");
|
||||
|
||||
let dt3 = new Date(Date.UTC(2012, Month.October, 28, 1, 59, 59));
|
||||
assertDateTime(dt3, "Sun Oct 28 2012 01:59:59 GMT+0000 (GMT)");
|
||||
|
||||
let dt4 = new Date(Date.UTC(2012, Month.October, 28, 2, 0, 0));
|
||||
assertDateTime(dt4, "Sun Oct 28 2012 02:00:00 GMT+0000 (GMT)");
|
||||
});
|
||||
|
||||
// bug 879261
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt1 = new Date(1362891600000);
|
||||
assertDateTime(dt1, "Sun Mar 10 2013 00:00:00 GMT-0500 (EST)");
|
||||
|
||||
let dt2 = new Date(dt1.setHours(dt1.getHours() + 24));
|
||||
assertDateTime(dt2, "Mon Mar 11 2013 00:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
inTimeZone("America/Los_Angeles", () => {
|
||||
let dt1 = new Date(2014, Month.January, 1);
|
||||
assertDateTime(dt1, "Wed Jan 01 2014 00:00:00 GMT-0800 (PST)");
|
||||
|
||||
let dt2 = new Date(2014, Month.August, 1);
|
||||
assertDateTime(dt2, "Fri Aug 01 2014 00:00:00 GMT-0700 (PDT)");
|
||||
});
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt1 = new Date(2016, Month.October, 14, 3, 5, 9);
|
||||
assertDateTime(dt1, "Fri Oct 14 2016 03:05:09 GMT-0400 (EDT)");
|
||||
|
||||
let dt2 = new Date(2016, Month.January, 9, 23, 26, 40);
|
||||
assertDateTime(dt2, "Sat Jan 09 2016 23:26:40 GMT-0500 (EST)");
|
||||
});
|
||||
|
||||
// bug 994086
|
||||
inTimeZone("Europe/Vienna", () => {
|
||||
let dt1 = new Date(2014, Month.March, 30, 2, 0);
|
||||
assertDateTime(dt1, "Sun Mar 30 2014 03:00:00 GMT+0200 (CEST)");
|
||||
|
||||
let dt2 = new Date(2014, Month.March, 30, 3, 0);
|
||||
assertDateTime(dt2, "Sun Mar 30 2014 03:00:00 GMT+0200 (CEST)");
|
||||
|
||||
let dt3 = new Date(2014, Month.March, 30, 4, 0);
|
||||
assertDateTime(dt3, "Sun Mar 30 2014 04:00:00 GMT+0200 (CEST)");
|
||||
});
|
||||
|
||||
// bug 1084434
|
||||
inTimeZone("America/Sao_Paulo", () => {
|
||||
let dt = new Date(2014, Month.October, 19);
|
||||
assertEq(dt.getDate(), 19);
|
||||
assertEq(dt.getHours(), 1);
|
||||
assertDateTime(dt, "Sun Oct 19 2014 01:00:00 GMT-0200 (BRST)");
|
||||
});
|
||||
|
||||
// bug 1084547
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt = new Date(Date.parse("2014-11-02T02:00:00-04:00"));
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:00:00 GMT-0500 (EST)");
|
||||
|
||||
dt.setMilliseconds(0);
|
||||
assertDateTime(dt, "Sun Nov 02 2014 01:00:00 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 1118690
|
||||
inTimeZone("Europe/London", () => {
|
||||
let dt = new Date(1965, Month.January, 1);
|
||||
assertEq(dt.getFullYear(), 1965);
|
||||
});
|
||||
|
||||
// bug 1155096
|
||||
inTimeZone("Europe/Moscow", () => {
|
||||
let dt1 = new Date(1981, Month.March, 32);
|
||||
assertEq(dt1.getDate(), 1);
|
||||
|
||||
let dt2 = new Date(1982, Month.March, 32);
|
||||
assertEq(dt2.getDate(), 1);
|
||||
|
||||
let dt3 = new Date(1983, Month.March, 32);
|
||||
assertEq(dt3.getDate(), 1);
|
||||
|
||||
let dt4 = new Date(1984, Month.March, 32);
|
||||
assertEq(dt4.getDate(), 1);
|
||||
});
|
||||
|
||||
// bug 1284507
|
||||
inTimeZone("Atlantic/Azores", () => {
|
||||
let dt1 = new Date(2017, Month.March, 25, 0, 0, 0);
|
||||
assertDateTime(dt1, "Sat Mar 25 2017 00:00:00 GMT-0100 (AZOT)");
|
||||
|
||||
let dt2 = new Date(2016, Month.October, 30, 0, 0, 0);
|
||||
assertDateTime(dt2, "Sun Oct 30 2016 00:00:00 GMT+0000 (AZOST)");
|
||||
|
||||
let dt3 = new Date(2016, Month.October, 30, 23, 0, 0);
|
||||
assertDateTime(dt3, "Sun Oct 30 2016 23:00:00 GMT-0100 (AZOT)");
|
||||
});
|
||||
|
||||
// bug 1303306
|
||||
inTimeZone("America/New_York", () => {
|
||||
let dt = new Date(2016, Month.September, 15, 16, 14, 48);
|
||||
assertDateTime(dt, "Thu Sep 15 2016 16:14:48 GMT-0400 (EDT)");
|
||||
});
|
||||
|
||||
// bug 1317364
|
||||
inTimeZone("America/Los_Angeles", () => {
|
||||
let dt = new Date(2016, Month.March, 13, 2, 30, 0, 0);
|
||||
assertDateTime(dt, "Sun Mar 13 2016 03:30:00 GMT-0700 (PDT)");
|
||||
|
||||
let dt2 = new Date(2016, Month.January, 5, 0, 30, 30, 500);
|
||||
assertDateTime(dt2, "Tue Jan 05 2016 00:30:30 GMT-0800 (PST)");
|
||||
|
||||
let dt3 = new Date(dt2.getTime());
|
||||
dt3.setMonth(dt2.getMonth() + 2);
|
||||
dt3.setDate(dt2.getDate() + 7 + 1);
|
||||
dt3.setHours(dt2.getHours() + 2);
|
||||
|
||||
assertEq(dt3.getHours(), 3);
|
||||
});
|
||||
|
||||
// bug 1335818
|
||||
inTimeZone("Asia/Jerusalem", () => {
|
||||
let dt1 = new Date(2013, Month.March, 22, 1, 0, 0, 0);
|
||||
assertDateTime(dt1, "Fri Mar 22 2013 01:00:00 GMT+0200 (IST)");
|
||||
|
||||
let dt2 = new Date(2013, Month.March, 22, 2, 0, 0, 0);
|
||||
assertDateTime(dt2, "Fri Mar 22 2013 02:00:00 GMT+0200 (IST)");
|
||||
|
||||
let dt3 = new Date(2013, Month.March, 22, 3, 0, 0, 0);
|
||||
assertDateTime(dt3, "Fri Mar 22 2013 03:00:00 GMT+0200 (IST)");
|
||||
|
||||
let dt4 = new Date(2013, Month.March, 29, 1, 0, 0, 0);
|
||||
assertDateTime(dt4, "Fri Mar 29 2013 01:00:00 GMT+0200 (IST)");
|
||||
|
||||
let dt5 = new Date(2013, Month.March, 29, 2, 0, 0, 0);
|
||||
assertDateTime(dt5, "Fri Mar 29 2013 03:00:00 GMT+0300 (IDT)");
|
||||
|
||||
let dt6 = new Date(2013, Month.March, 29, 3, 0, 0, 0);
|
||||
assertDateTime(dt6, "Fri Mar 29 2013 03:00:00 GMT+0300 (IDT)");
|
||||
});
|
||||
|
||||
// bug 1355272
|
||||
inTimeZone("America/Los_Angeles", () => {
|
||||
let dt = new Date(2017, Month.April, 10, 17, 25, 07);
|
||||
assertDateTime(dt, "Mon Apr 10 2017 17:25:07 GMT-0700 (PDT)");
|
||||
});
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -90,8 +90,11 @@ UTCToLocalStandardOffsetSeconds()
|
|||
currentNoDST = currentMaybeWithDST;
|
||||
} else {
|
||||
// If |local| respected DST, we need a time broken down into components
|
||||
// ignoring DST. Turn off DST in the broken-down time.
|
||||
local.tm_isdst = 0;
|
||||
// ignoring DST. Turn off DST in the broken-down time. Create a fresh
|
||||
// copy of |local|, because mktime() will reset tm_isdst = 1 and will
|
||||
// adjust tm_hour and tm_hour accordingly.
|
||||
struct tm localNoDST = local;
|
||||
localNoDST.tm_isdst = 0;
|
||||
|
||||
// Compute a |time_t t| corresponding to the broken-down time with DST
|
||||
// off. This has boundary-condition issues (for about the duration of
|
||||
|
@ -99,7 +102,7 @@ UTCToLocalStandardOffsetSeconds()
|
|||
// zone. But 1) errors will be transient; 2) locations rarely change
|
||||
// time zone; and 3) in the absence of an API that provides the time
|
||||
// zone offset directly, this may be the best we can do.
|
||||
currentNoDST = mktime(&local);
|
||||
currentNoDST = mktime(&localNoDST);
|
||||
if (currentNoDST == time_t(-1))
|
||||
return 0;
|
||||
}
|
||||
|
@ -177,6 +180,8 @@ js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
|
|||
if (!ComputeLocalTime(static_cast<time_t>(utcSeconds), &tm))
|
||||
return 0;
|
||||
|
||||
// NB: The offset isn't computed correctly when the standard local offset
|
||||
// at |utcSeconds| is different from |utcToLocalStandardOffsetSeconds|.
|
||||
int32_t dayoff = int32_t((utcSeconds + utcToLocalStandardOffsetSeconds) % SecondsPerDay);
|
||||
int32_t tmoff = tm.tm_sec + (tm.tm_min * SecondsPerMinute) + (tm.tm_hour * SecondsPerHour);
|
||||
|
||||
|
@ -184,6 +189,8 @@ js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
|
|||
|
||||
if (diff < 0)
|
||||
diff += SecondsPerDay;
|
||||
else if (uint32_t(diff) >= SecondsPerDay)
|
||||
diff -= SecondsPerDay;
|
||||
|
||||
return diff * msPerSecond;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче