js/src/jsdate.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsdate.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3182 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * JS date methods.
    1.12 + *
    1.13 + * "For example, OS/360 devotes 26 bytes of the permanently
    1.14 + *  resident date-turnover routine to the proper handling of
    1.15 + *  December 31 on leap years (when it is Day 366).  That
    1.16 + *  might have been left to the operator."
    1.17 + *
    1.18 + * Frederick Brooks, 'The Second-System Effect'.
    1.19 + */
    1.20 +
    1.21 +#include "jsdate.h"
    1.22 +
    1.23 +#include "mozilla/ArrayUtils.h"
    1.24 +#include "mozilla/FloatingPoint.h"
    1.25 +
    1.26 +#include <ctype.h>
    1.27 +#include <math.h>
    1.28 +#include <string.h>
    1.29 +
    1.30 +#include "jsapi.h"
    1.31 +#include "jscntxt.h"
    1.32 +#include "jsnum.h"
    1.33 +#include "jsobj.h"
    1.34 +#include "jsprf.h"
    1.35 +#include "jsstr.h"
    1.36 +#include "jstypes.h"
    1.37 +#include "jsutil.h"
    1.38 +#include "prmjtime.h"
    1.39 +
    1.40 +#include "js/Date.h"
    1.41 +#include "vm/DateTime.h"
    1.42 +#include "vm/GlobalObject.h"
    1.43 +#include "vm/Interpreter.h"
    1.44 +#include "vm/NumericConversions.h"
    1.45 +#include "vm/String.h"
    1.46 +#include "vm/StringBuffer.h"
    1.47 +
    1.48 +#include "jsobjinlines.h"
    1.49 +
    1.50 +using namespace js;
    1.51 +using namespace js::types;
    1.52 +
    1.53 +using mozilla::ArrayLength;
    1.54 +using mozilla::IsFinite;
    1.55 +using mozilla::IsNaN;
    1.56 +using JS::GenericNaN;
    1.57 +
    1.58 +/*
    1.59 + * The JS 'Date' object is patterned after the Java 'Date' object.
    1.60 + * Here is a script:
    1.61 + *
    1.62 + *    today = new Date();
    1.63 + *
    1.64 + *    print(today.toLocaleString());
    1.65 + *
    1.66 + *    weekDay = today.getDay();
    1.67 + *
    1.68 + *
    1.69 + * These Java (and ECMA-262) methods are supported:
    1.70 + *
    1.71 + *     UTC
    1.72 + *     getDate (getUTCDate)
    1.73 + *     getDay (getUTCDay)
    1.74 + *     getHours (getUTCHours)
    1.75 + *     getMinutes (getUTCMinutes)
    1.76 + *     getMonth (getUTCMonth)
    1.77 + *     getSeconds (getUTCSeconds)
    1.78 + *     getMilliseconds (getUTCMilliseconds)
    1.79 + *     getTime
    1.80 + *     getTimezoneOffset
    1.81 + *     getYear
    1.82 + *     getFullYear (getUTCFullYear)
    1.83 + *     parse
    1.84 + *     setDate (setUTCDate)
    1.85 + *     setHours (setUTCHours)
    1.86 + *     setMinutes (setUTCMinutes)
    1.87 + *     setMonth (setUTCMonth)
    1.88 + *     setSeconds (setUTCSeconds)
    1.89 + *     setMilliseconds (setUTCMilliseconds)
    1.90 + *     setTime
    1.91 + *     setYear (setFullYear, setUTCFullYear)
    1.92 + *     toGMTString (toUTCString)
    1.93 + *     toLocaleString
    1.94 + *     toString
    1.95 + *
    1.96 + *
    1.97 + * These Java methods are not supported
    1.98 + *
    1.99 + *     setDay
   1.100 + *     before
   1.101 + *     after
   1.102 + *     equals
   1.103 + *     hashCode
   1.104 + */
   1.105 +
   1.106 +static inline double
   1.107 +Day(double t)
   1.108 +{
   1.109 +    return floor(t / msPerDay);
   1.110 +}
   1.111 +
   1.112 +static double
   1.113 +TimeWithinDay(double t)
   1.114 +{
   1.115 +    double result = fmod(t, msPerDay);
   1.116 +    if (result < 0)
   1.117 +        result += msPerDay;
   1.118 +    return result;
   1.119 +}
   1.120 +
   1.121 +/* ES5 15.9.1.3. */
   1.122 +static inline bool
   1.123 +IsLeapYear(double year)
   1.124 +{
   1.125 +    JS_ASSERT(ToInteger(year) == year);
   1.126 +    return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0);
   1.127 +}
   1.128 +
   1.129 +static inline double
   1.130 +DaysInYear(double year)
   1.131 +{
   1.132 +    if (!IsFinite(year))
   1.133 +        return GenericNaN();
   1.134 +    return IsLeapYear(year) ? 366 : 365;
   1.135 +}
   1.136 +
   1.137 +static inline double
   1.138 +DayFromYear(double y)
   1.139 +{
   1.140 +    return 365 * (y - 1970) +
   1.141 +           floor((y - 1969) / 4.0) -
   1.142 +           floor((y - 1901) / 100.0) +
   1.143 +           floor((y - 1601) / 400.0);
   1.144 +}
   1.145 +
   1.146 +static inline double
   1.147 +TimeFromYear(double y)
   1.148 +{
   1.149 +    return DayFromYear(y) * msPerDay;
   1.150 +}
   1.151 +
   1.152 +static double
   1.153 +YearFromTime(double t)
   1.154 +{
   1.155 +    if (!IsFinite(t))
   1.156 +        return GenericNaN();
   1.157 +
   1.158 +    JS_ASSERT(ToInteger(t) == t);
   1.159 +
   1.160 +    double y = floor(t / (msPerDay * 365.2425)) + 1970;
   1.161 +    double t2 = TimeFromYear(y);
   1.162 +
   1.163 +    /*
   1.164 +     * Adjust the year if the approximation was wrong.  Since the year was
   1.165 +     * computed using the average number of ms per year, it will usually
   1.166 +     * be wrong for dates within several hours of a year transition.
   1.167 +     */
   1.168 +    if (t2 > t) {
   1.169 +        y--;
   1.170 +    } else {
   1.171 +        if (t2 + msPerDay * DaysInYear(y) <= t)
   1.172 +            y++;
   1.173 +    }
   1.174 +    return y;
   1.175 +}
   1.176 +
   1.177 +static inline int
   1.178 +DaysInFebruary(double year)
   1.179 +{
   1.180 +    return IsLeapYear(year) ? 29 : 28;
   1.181 +}
   1.182 +
   1.183 +/* ES5 15.9.1.4. */
   1.184 +static inline double
   1.185 +DayWithinYear(double t, double year)
   1.186 +{
   1.187 +    JS_ASSERT_IF(IsFinite(t), YearFromTime(t) == year);
   1.188 +    return Day(t) - DayFromYear(year);
   1.189 +}
   1.190 +
   1.191 +static double
   1.192 +MonthFromTime(double t)
   1.193 +{
   1.194 +    if (!IsFinite(t))
   1.195 +        return GenericNaN();
   1.196 +
   1.197 +    double year = YearFromTime(t);
   1.198 +    double d = DayWithinYear(t, year);
   1.199 +
   1.200 +    int step;
   1.201 +    if (d < (step = 31))
   1.202 +        return 0;
   1.203 +    if (d < (step += DaysInFebruary(year)))
   1.204 +        return 1;
   1.205 +    if (d < (step += 31))
   1.206 +        return 2;
   1.207 +    if (d < (step += 30))
   1.208 +        return 3;
   1.209 +    if (d < (step += 31))
   1.210 +        return 4;
   1.211 +    if (d < (step += 30))
   1.212 +        return 5;
   1.213 +    if (d < (step += 31))
   1.214 +        return 6;
   1.215 +    if (d < (step += 31))
   1.216 +        return 7;
   1.217 +    if (d < (step += 30))
   1.218 +        return 8;
   1.219 +    if (d < (step += 31))
   1.220 +        return 9;
   1.221 +    if (d < (step += 30))
   1.222 +        return 10;
   1.223 +    return 11;
   1.224 +}
   1.225 +
   1.226 +/* ES5 15.9.1.5. */
   1.227 +static double
   1.228 +DateFromTime(double t)
   1.229 +{
   1.230 +    if (!IsFinite(t))
   1.231 +        return GenericNaN();
   1.232 +
   1.233 +    double year = YearFromTime(t);
   1.234 +    double d = DayWithinYear(t, year);
   1.235 +
   1.236 +    int next;
   1.237 +    if (d <= (next = 30))
   1.238 +        return d + 1;
   1.239 +    int step = next;
   1.240 +    if (d <= (next += DaysInFebruary(year)))
   1.241 +        return d - step;
   1.242 +    step = next;
   1.243 +    if (d <= (next += 31))
   1.244 +        return d - step;
   1.245 +    step = next;
   1.246 +    if (d <= (next += 30))
   1.247 +        return d - step;
   1.248 +    step = next;
   1.249 +    if (d <= (next += 31))
   1.250 +        return d - step;
   1.251 +    step = next;
   1.252 +    if (d <= (next += 30))
   1.253 +        return d - step;
   1.254 +    step = next;
   1.255 +    if (d <= (next += 31))
   1.256 +        return d - step;
   1.257 +    step = next;
   1.258 +    if (d <= (next += 31))
   1.259 +        return d - step;
   1.260 +    step = next;
   1.261 +    if (d <= (next += 30))
   1.262 +        return d - step;
   1.263 +    step = next;
   1.264 +    if (d <= (next += 31))
   1.265 +        return d - step;
   1.266 +    step = next;
   1.267 +    if (d <= (next += 30))
   1.268 +        return d - step;
   1.269 +    step = next;
   1.270 +    return d - step;
   1.271 +}
   1.272 +
   1.273 +/* ES5 15.9.1.6. */
   1.274 +static int
   1.275 +WeekDay(double t)
   1.276 +{
   1.277 +    /*
   1.278 +     * We can't assert TimeClip(t) == t because we call this function with
   1.279 +     * local times, which can be offset outside TimeClip's permitted range.
   1.280 +     */
   1.281 +    JS_ASSERT(ToInteger(t) == t);
   1.282 +    int result = (int(Day(t)) + 4) % 7;
   1.283 +    if (result < 0)
   1.284 +        result += 7;
   1.285 +    return result;
   1.286 +}
   1.287 +
   1.288 +static inline int
   1.289 +DayFromMonth(int month, bool isLeapYear)
   1.290 +{
   1.291 +    /*
   1.292 +     * The following array contains the day of year for the first day of
   1.293 +     * each month, where index 0 is January, and day 0 is January 1.
   1.294 +     */
   1.295 +    static const int firstDayOfMonth[2][13] = {
   1.296 +        {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
   1.297 +        {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
   1.298 +    };
   1.299 +
   1.300 +    JS_ASSERT(0 <= month && month <= 12);
   1.301 +    return firstDayOfMonth[isLeapYear][month];
   1.302 +}
   1.303 +
   1.304 +template<typename T>
   1.305 +static inline int
   1.306 +DayFromMonth(T month, bool isLeapYear) MOZ_DELETE;
   1.307 +
   1.308 +/* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
   1.309 +static double
   1.310 +MakeDay(double year, double month, double date)
   1.311 +{
   1.312 +    /* Step 1. */
   1.313 +    if (!IsFinite(year) || !IsFinite(month) || !IsFinite(date))
   1.314 +        return GenericNaN();
   1.315 +
   1.316 +    /* Steps 2-4. */
   1.317 +    double y = ToInteger(year);
   1.318 +    double m = ToInteger(month);
   1.319 +    double dt = ToInteger(date);
   1.320 +
   1.321 +    /* Step 5. */
   1.322 +    double ym = y + floor(m / 12);
   1.323 +
   1.324 +    /* Step 6. */
   1.325 +    int mn = int(fmod(m, 12.0));
   1.326 +    if (mn < 0)
   1.327 +        mn += 12;
   1.328 +
   1.329 +    /* Steps 7-8. */
   1.330 +    bool leap = IsLeapYear(ym);
   1.331 +
   1.332 +    double yearday = floor(TimeFromYear(ym) / msPerDay);
   1.333 +    double monthday = DayFromMonth(mn, leap);
   1.334 +
   1.335 +    return yearday + monthday + dt - 1;
   1.336 +}
   1.337 +
   1.338 +/* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
   1.339 +static inline double
   1.340 +MakeDate(double day, double time)
   1.341 +{
   1.342 +    /* Step 1. */
   1.343 +    if (!IsFinite(day) || !IsFinite(time))
   1.344 +        return GenericNaN();
   1.345 +
   1.346 +    /* Step 2. */
   1.347 +    return day * msPerDay + time;
   1.348 +}
   1.349 +
   1.350 +JS_PUBLIC_API(double)
   1.351 +JS::MakeDate(double year, unsigned month, unsigned day)
   1.352 +{
   1.353 +    return TimeClip(::MakeDate(MakeDay(year, month, day), 0));
   1.354 +}
   1.355 +
   1.356 +JS_PUBLIC_API(double)
   1.357 +JS::YearFromTime(double time)
   1.358 +{
   1.359 +    return ::YearFromTime(time);
   1.360 +}
   1.361 +
   1.362 +JS_PUBLIC_API(double)
   1.363 +JS::MonthFromTime(double time)
   1.364 +{
   1.365 +    return ::MonthFromTime(time);
   1.366 +}
   1.367 +
   1.368 +JS_PUBLIC_API(double)
   1.369 +JS::DayFromTime(double time)
   1.370 +{
   1.371 +    return DateFromTime(time);
   1.372 +}
   1.373 +
   1.374 +/*
   1.375 + * Find a year for which any given date will fall on the same weekday.
   1.376 + *
   1.377 + * This function should be used with caution when used other than
   1.378 + * for determining DST; it hasn't been proven not to produce an
   1.379 + * incorrect year for times near year boundaries.
   1.380 + */
   1.381 +static int
   1.382 +EquivalentYearForDST(int year)
   1.383 +{
   1.384 +    /*
   1.385 +     * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
   1.386 +     *
   1.387 +     * yearStartingWith[0][i] is an example non-leap year where
   1.388 +     * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
   1.389 +     *
   1.390 +     * yearStartingWith[1][i] is an example leap year where
   1.391 +     * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
   1.392 +     */
   1.393 +    static const int yearStartingWith[2][7] = {
   1.394 +        {1978, 1973, 1974, 1975, 1981, 1971, 1977},
   1.395 +        {1984, 1996, 1980, 1992, 1976, 1988, 1972}
   1.396 +    };
   1.397 +
   1.398 +    int day = int(DayFromYear(year) + 4) % 7;
   1.399 +    if (day < 0)
   1.400 +        day += 7;
   1.401 +
   1.402 +    return yearStartingWith[IsLeapYear(year)][day];
   1.403 +}
   1.404 +
   1.405 +/* ES5 15.9.1.8. */
   1.406 +static double
   1.407 +DaylightSavingTA(double t, DateTimeInfo *dtInfo)
   1.408 +{
   1.409 +    if (!IsFinite(t))
   1.410 +        return GenericNaN();
   1.411 +
   1.412 +    /*
   1.413 +     * If earlier than 1970 or after 2038, potentially beyond the ken of
   1.414 +     * many OSes, map it to an equivalent year before asking.
   1.415 +     */
   1.416 +    if (t < 0.0 || t > 2145916800000.0) {
   1.417 +        int year = EquivalentYearForDST(int(YearFromTime(t)));
   1.418 +        double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
   1.419 +        t = MakeDate(day, TimeWithinDay(t));
   1.420 +    }
   1.421 +
   1.422 +    int64_t utcMilliseconds = static_cast<int64_t>(t);
   1.423 +    int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(utcMilliseconds);
   1.424 +    return static_cast<double>(offsetMilliseconds);
   1.425 +}
   1.426 +
   1.427 +static double
   1.428 +AdjustTime(double date, DateTimeInfo *dtInfo)
   1.429 +{
   1.430 +    double t = DaylightSavingTA(date, dtInfo) + dtInfo->localTZA();
   1.431 +    t = (dtInfo->localTZA() >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
   1.432 +    return t;
   1.433 +}
   1.434 +
   1.435 +/* ES5 15.9.1.9. */
   1.436 +static double
   1.437 +LocalTime(double t, DateTimeInfo *dtInfo)
   1.438 +{
   1.439 +    return t + AdjustTime(t, dtInfo);
   1.440 +}
   1.441 +
   1.442 +static double
   1.443 +UTC(double t, DateTimeInfo *dtInfo)
   1.444 +{
   1.445 +    return t - AdjustTime(t - dtInfo->localTZA(), dtInfo);
   1.446 +}
   1.447 +
   1.448 +/* ES5 15.9.1.10. */
   1.449 +static double
   1.450 +HourFromTime(double t)
   1.451 +{
   1.452 +    double result = fmod(floor(t/msPerHour), HoursPerDay);
   1.453 +    if (result < 0)
   1.454 +        result += HoursPerDay;
   1.455 +    return result;
   1.456 +}
   1.457 +
   1.458 +static double
   1.459 +MinFromTime(double t)
   1.460 +{
   1.461 +    double result = fmod(floor(t / msPerMinute), MinutesPerHour);
   1.462 +    if (result < 0)
   1.463 +        result += MinutesPerHour;
   1.464 +    return result;
   1.465 +}
   1.466 +
   1.467 +static double
   1.468 +SecFromTime(double t)
   1.469 +{
   1.470 +    double result = fmod(floor(t / msPerSecond), SecondsPerMinute);
   1.471 +    if (result < 0)
   1.472 +        result += SecondsPerMinute;
   1.473 +    return result;
   1.474 +}
   1.475 +
   1.476 +static double
   1.477 +msFromTime(double t)
   1.478 +{
   1.479 +    double result = fmod(t, msPerSecond);
   1.480 +    if (result < 0)
   1.481 +        result += msPerSecond;
   1.482 +    return result;
   1.483 +}
   1.484 +
   1.485 +/* ES5 15.9.1.11. */
   1.486 +static double
   1.487 +MakeTime(double hour, double min, double sec, double ms)
   1.488 +{
   1.489 +    /* Step 1. */
   1.490 +    if (!IsFinite(hour) ||
   1.491 +        !IsFinite(min) ||
   1.492 +        !IsFinite(sec) ||
   1.493 +        !IsFinite(ms))
   1.494 +    {
   1.495 +        return GenericNaN();
   1.496 +    }
   1.497 +
   1.498 +    /* Step 2. */
   1.499 +    double h = ToInteger(hour);
   1.500 +
   1.501 +    /* Step 3. */
   1.502 +    double m = ToInteger(min);
   1.503 +
   1.504 +    /* Step 4. */
   1.505 +    double s = ToInteger(sec);
   1.506 +
   1.507 +    /* Step 5. */
   1.508 +    double milli = ToInteger(ms);
   1.509 +
   1.510 +    /* Steps 6-7. */
   1.511 +    return h * msPerHour + m * msPerMinute + s * msPerSecond + milli;
   1.512 +}
   1.513 +
   1.514 +/**
   1.515 + * end of ECMA 'support' functions
   1.516 + */
   1.517 +
   1.518 +static bool
   1.519 +date_convert(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp)
   1.520 +{
   1.521 +    JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
   1.522 +    JS_ASSERT(obj->is<DateObject>());
   1.523 +
   1.524 +    return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
   1.525 +}
   1.526 +
   1.527 +/* for use by date_parse */
   1.528 +
   1.529 +static const char* const wtb[] = {
   1.530 +    "am", "pm",
   1.531 +    "monday", "tuesday", "wednesday", "thursday", "friday",
   1.532 +    "saturday", "sunday",
   1.533 +    "january", "february", "march", "april", "may", "june",
   1.534 +    "july", "august", "september", "october", "november", "december",
   1.535 +    "gmt", "ut", "utc",
   1.536 +    "est", "edt",
   1.537 +    "cst", "cdt",
   1.538 +    "mst", "mdt",
   1.539 +    "pst", "pdt"
   1.540 +    /* time zone table needs to be expanded */
   1.541 +};
   1.542 +
   1.543 +static const int ttb[] = {
   1.544 +    -1, -2, 0, 0, 0, 0, 0, 0, 0,       /* AM/PM */
   1.545 +    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
   1.546 +    10000 + 0, 10000 + 0, 10000 + 0,   /* GMT/UT/UTC */
   1.547 +    10000 + 5 * 60, 10000 + 4 * 60,    /* EST/EDT */
   1.548 +    10000 + 6 * 60, 10000 + 5 * 60,    /* CST/CDT */
   1.549 +    10000 + 7 * 60, 10000 + 6 * 60,    /* MST/MDT */
   1.550 +    10000 + 8 * 60, 10000 + 7 * 60     /* PST/PDT */
   1.551 +};
   1.552 +
   1.553 +/* helper for date_parse */
   1.554 +static bool
   1.555 +date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
   1.556 +                   int count, int ignoreCase)
   1.557 +{
   1.558 +    bool result = false;
   1.559 +    /* return true if matches, otherwise, false */
   1.560 +
   1.561 +    while (count > 0 && s1[s1off] && s2[s2off]) {
   1.562 +        if (ignoreCase) {
   1.563 +            if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off]))
   1.564 +                break;
   1.565 +        } else {
   1.566 +            if ((jschar)s1[s1off] != s2[s2off]) {
   1.567 +                break;
   1.568 +            }
   1.569 +        }
   1.570 +        s1off++;
   1.571 +        s2off++;
   1.572 +        count--;
   1.573 +    }
   1.574 +
   1.575 +    if (count == 0) {
   1.576 +        result = true;
   1.577 +    }
   1.578 +
   1.579 +    return result;
   1.580 +}
   1.581 +
   1.582 +/* find UTC time from given date... no 1900 correction! */
   1.583 +static double
   1.584 +date_msecFromDate(double year, double mon, double mday, double hour,
   1.585 +                  double min, double sec, double msec)
   1.586 +{
   1.587 +    return MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, msec));
   1.588 +}
   1.589 +
   1.590 +/* compute the time in msec (unclipped) from the given args */
   1.591 +#define MAXARGS        7
   1.592 +
   1.593 +static bool
   1.594 +date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
   1.595 +{
   1.596 +    unsigned loop;
   1.597 +    double array[MAXARGS];
   1.598 +    double msec_time;
   1.599 +
   1.600 +    for (loop = 0; loop < MAXARGS; loop++) {
   1.601 +        if (loop < args.length()) {
   1.602 +            double d;
   1.603 +            if (!ToNumber(cx, args[loop], &d))
   1.604 +                return false;
   1.605 +            /* return NaN if any arg is not finite */
   1.606 +            if (!IsFinite(d)) {
   1.607 +                *rval = GenericNaN();
   1.608 +                return true;
   1.609 +            }
   1.610 +            array[loop] = ToInteger(d);
   1.611 +        } else {
   1.612 +            if (loop == 2) {
   1.613 +                array[loop] = 1; /* Default the date argument to 1. */
   1.614 +            } else {
   1.615 +                array[loop] = 0;
   1.616 +            }
   1.617 +        }
   1.618 +    }
   1.619 +
   1.620 +    /* adjust 2-digit years into the 20th century */
   1.621 +    if (array[0] >= 0 && array[0] <= 99)
   1.622 +        array[0] += 1900;
   1.623 +
   1.624 +    msec_time = date_msecFromDate(array[0], array[1], array[2],
   1.625 +                                  array[3], array[4], array[5], array[6]);
   1.626 +    *rval = msec_time;
   1.627 +    return true;
   1.628 +}
   1.629 +
   1.630 +/*
   1.631 + * See ECMA 15.9.4.[3-10];
   1.632 + */
   1.633 +static bool
   1.634 +date_UTC(JSContext *cx, unsigned argc, Value *vp)
   1.635 +{
   1.636 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.637 +
   1.638 +    double msec_time;
   1.639 +    if (!date_msecFromArgs(cx, args, &msec_time))
   1.640 +        return false;
   1.641 +
   1.642 +    msec_time = TimeClip(msec_time);
   1.643 +
   1.644 +    args.rval().setNumber(msec_time);
   1.645 +    return true;
   1.646 +}
   1.647 +
   1.648 +/*
   1.649 + * Read and convert decimal digits from s[*i] into *result
   1.650 + * while *i < limit.
   1.651 + *
   1.652 + * Succeed if any digits are converted. Advance *i only
   1.653 + * as digits are consumed.
   1.654 + */
   1.655 +static bool
   1.656 +digits(size_t *result, const jschar *s, size_t *i, size_t limit)
   1.657 +{
   1.658 +    size_t init = *i;
   1.659 +    *result = 0;
   1.660 +    while (*i < limit &&
   1.661 +           ('0' <= s[*i] && s[*i] <= '9')) {
   1.662 +        *result *= 10;
   1.663 +        *result += (s[*i] - '0');
   1.664 +        ++(*i);
   1.665 +    }
   1.666 +    return *i != init;
   1.667 +}
   1.668 +
   1.669 +/*
   1.670 + * Read and convert decimal digits to the right of a decimal point,
   1.671 + * representing a fractional integer, from s[*i] into *result
   1.672 + * while *i < limit.
   1.673 + *
   1.674 + * Succeed if any digits are converted. Advance *i only
   1.675 + * as digits are consumed.
   1.676 + */
   1.677 +static bool
   1.678 +fractional(double *result, const jschar *s, size_t *i, size_t limit)
   1.679 +{
   1.680 +    double factor = 0.1;
   1.681 +    size_t init = *i;
   1.682 +    *result = 0.0;
   1.683 +    while (*i < limit &&
   1.684 +           ('0' <= s[*i] && s[*i] <= '9')) {
   1.685 +        *result += (s[*i] - '0') * factor;
   1.686 +        factor *= 0.1;
   1.687 +        ++(*i);
   1.688 +    }
   1.689 +    return *i != init;
   1.690 +}
   1.691 +
   1.692 +/*
   1.693 + * Read and convert exactly n decimal digits from s[*i]
   1.694 + * to s[min(*i+n,limit)] into *result.
   1.695 + *
   1.696 + * Succeed if exactly n digits are converted. Advance *i only
   1.697 + * on success.
   1.698 + */
   1.699 +static bool
   1.700 +ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
   1.701 +{
   1.702 +    size_t init = *i;
   1.703 +
   1.704 +    if (digits(result, s, i, Min(limit, init+n)))
   1.705 +        return (*i - init) == n;
   1.706 +
   1.707 +    *i = init;
   1.708 +    return false;
   1.709 +}
   1.710 +
   1.711 +static int
   1.712 +DaysInMonth(int year, int month)
   1.713 +{
   1.714 +    bool leap = IsLeapYear(year);
   1.715 +    int result = int(DayFromMonth(month, leap) - DayFromMonth(month - 1, leap));
   1.716 +    return result;
   1.717 +}
   1.718 +
   1.719 +/*
   1.720 + * Parse a string in one of the date-time formats given by the W3C
   1.721 + * "NOTE-datetime" specification. These formats make up a restricted
   1.722 + * profile of the ISO 8601 format. Quoted here:
   1.723 + *
   1.724 + *   The formats are as follows. Exactly the components shown here
   1.725 + *   must be present, with exactly this punctuation. Note that the "T"
   1.726 + *   appears literally in the string, to indicate the beginning of the
   1.727 + *   time element, as specified in ISO 8601.
   1.728 + *
   1.729 + *   Any combination of the date formats with the time formats is
   1.730 + *   allowed, and also either the date or the time can be missing.
   1.731 + *
   1.732 + *   The specification is silent on the meaning when fields are
   1.733 + *   ommitted so the interpretations are a guess, but hopefully a
   1.734 + *   reasonable one. We default the month to January, the day to the
   1.735 + *   1st, and hours minutes and seconds all to 0. If the date is
   1.736 + *   missing entirely then we assume 1970-01-01 so that the time can
   1.737 + *   be aded to a date later. If the time is missing then we assume
   1.738 + *   00:00 UTC.  If the time is present but the time zone field is
   1.739 + *   missing then we use local time.
   1.740 + *
   1.741 + * Date part:
   1.742 + *
   1.743 + *  Year:
   1.744 + *     YYYY (eg 1997)
   1.745 + *
   1.746 + *  Year and month:
   1.747 + *     YYYY-MM (eg 1997-07)
   1.748 + *
   1.749 + *  Complete date:
   1.750 + *     YYYY-MM-DD (eg 1997-07-16)
   1.751 + *
   1.752 + * Time part:
   1.753 + *
   1.754 + *  Hours and minutes:
   1.755 + *     Thh:mmTZD (eg T19:20+01:00)
   1.756 + *
   1.757 + *  Hours, minutes and seconds:
   1.758 + *     Thh:mm:ssTZD (eg T19:20:30+01:00)
   1.759 + *
   1.760 + *  Hours, minutes, seconds and a decimal fraction of a second:
   1.761 + *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
   1.762 + *
   1.763 + * where:
   1.764 + *
   1.765 + *   YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
   1.766 + *   MM   = two-digit month (01=January, etc.)
   1.767 + *   DD   = two-digit day of month (01 through 31)
   1.768 + *   hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
   1.769 + *   mm   = two digits of minute (00 through 59)
   1.770 + *   ss   = two digits of second (00 through 59)
   1.771 + *   s    = one or more digits representing a decimal fraction of a second
   1.772 + *   TZD  = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
   1.773 + */
   1.774 +
   1.775 +static bool
   1.776 +date_parseISOString(JSLinearString *str, double *result, DateTimeInfo *dtInfo)
   1.777 +{
   1.778 +    double msec;
   1.779 +
   1.780 +    const jschar *s;
   1.781 +    size_t limit;
   1.782 +    size_t i = 0;
   1.783 +    int tzMul = 1;
   1.784 +    int dateMul = 1;
   1.785 +    size_t year = 1970;
   1.786 +    size_t month = 1;
   1.787 +    size_t day = 1;
   1.788 +    size_t hour = 0;
   1.789 +    size_t min = 0;
   1.790 +    size_t sec = 0;
   1.791 +    double frac = 0;
   1.792 +    bool isLocalTime = false;
   1.793 +    size_t tzHour = 0;
   1.794 +    size_t tzMin = 0;
   1.795 +
   1.796 +#define PEEK(ch) (i < limit && s[i] == ch)
   1.797 +
   1.798 +#define NEED(ch)                                                     \
   1.799 +    JS_BEGIN_MACRO                                                   \
   1.800 +        if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
   1.801 +    JS_END_MACRO
   1.802 +
   1.803 +#define DONE_DATE_UNLESS(ch)                                            \
   1.804 +    JS_BEGIN_MACRO                                                      \
   1.805 +        if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
   1.806 +    JS_END_MACRO
   1.807 +
   1.808 +#define DONE_UNLESS(ch)                                            \
   1.809 +    JS_BEGIN_MACRO                                                 \
   1.810 +        if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
   1.811 +    JS_END_MACRO
   1.812 +
   1.813 +#define NEED_NDIGITS(n, field)                                      \
   1.814 +    JS_BEGIN_MACRO                                                  \
   1.815 +        if (!ndigits(n, &field, s, &i, limit)) { goto syntax; }     \
   1.816 +    JS_END_MACRO
   1.817 +
   1.818 +    s = str->chars();
   1.819 +    limit = str->length();
   1.820 +
   1.821 +    if (PEEK('+') || PEEK('-')) {
   1.822 +        if (PEEK('-'))
   1.823 +            dateMul = -1;
   1.824 +        ++i;
   1.825 +        NEED_NDIGITS(6, year);
   1.826 +    } else if (!PEEK('T')) {
   1.827 +        NEED_NDIGITS(4, year);
   1.828 +    }
   1.829 +    DONE_DATE_UNLESS('-');
   1.830 +    NEED_NDIGITS(2, month);
   1.831 +    DONE_DATE_UNLESS('-');
   1.832 +    NEED_NDIGITS(2, day);
   1.833 +
   1.834 + done_date:
   1.835 +    DONE_UNLESS('T');
   1.836 +    NEED_NDIGITS(2, hour);
   1.837 +    NEED(':');
   1.838 +    NEED_NDIGITS(2, min);
   1.839 +
   1.840 +    if (PEEK(':')) {
   1.841 +        ++i;
   1.842 +        NEED_NDIGITS(2, sec);
   1.843 +        if (PEEK('.')) {
   1.844 +            ++i;
   1.845 +            if (!fractional(&frac, s, &i, limit))
   1.846 +                goto syntax;
   1.847 +        }
   1.848 +    }
   1.849 +
   1.850 +    if (PEEK('Z')) {
   1.851 +        ++i;
   1.852 +    } else if (PEEK('+') || PEEK('-')) {
   1.853 +        if (PEEK('-'))
   1.854 +            tzMul = -1;
   1.855 +        ++i;
   1.856 +        NEED_NDIGITS(2, tzHour);
   1.857 +        /*
   1.858 +         * Non-standard extension to the ISO date format (permitted by ES5):
   1.859 +         * allow "-0700" as a time zone offset, not just "-07:00".
   1.860 +         */
   1.861 +        if (PEEK(':'))
   1.862 +          ++i;
   1.863 +        NEED_NDIGITS(2, tzMin);
   1.864 +    } else {
   1.865 +        isLocalTime = true;
   1.866 +    }
   1.867 +
   1.868 + done:
   1.869 +    if (year > 275943 // ceil(1e8/365) + 1970
   1.870 +        || (month == 0 || month > 12)
   1.871 +        || (day == 0 || day > size_t(DaysInMonth(year,month)))
   1.872 +        || hour > 24
   1.873 +        || ((hour == 24) && (min > 0 || sec > 0))
   1.874 +        || min > 59
   1.875 +        || sec > 59
   1.876 +        || tzHour > 23
   1.877 +        || tzMin > 59)
   1.878 +        goto syntax;
   1.879 +
   1.880 +    if (i != limit)
   1.881 +        goto syntax;
   1.882 +
   1.883 +    month -= 1; /* convert month to 0-based */
   1.884 +
   1.885 +    msec = date_msecFromDate(dateMul * (double)year, month, day,
   1.886 +                             hour, min, sec,
   1.887 +                             frac * 1000.0);;
   1.888 +
   1.889 +    if (isLocalTime) {
   1.890 +        msec = UTC(msec, dtInfo);
   1.891 +    } else {
   1.892 +        msec -= ((tzMul) * ((tzHour * msPerHour)
   1.893 +                            + (tzMin * msPerMinute)));
   1.894 +    }
   1.895 +
   1.896 +    if (msec < -8.64e15 || msec > 8.64e15)
   1.897 +        goto syntax;
   1.898 +
   1.899 +    *result = msec;
   1.900 +
   1.901 +    return true;
   1.902 +
   1.903 + syntax:
   1.904 +    /* syntax error */
   1.905 +    *result = 0;
   1.906 +    return false;
   1.907 +
   1.908 +#undef PEEK
   1.909 +#undef NEED
   1.910 +#undef DONE_UNLESS
   1.911 +#undef NEED_NDIGITS
   1.912 +}
   1.913 +
   1.914 +static bool
   1.915 +date_parseString(JSLinearString *str, double *result, DateTimeInfo *dtInfo)
   1.916 +{
   1.917 +    double msec;
   1.918 +
   1.919 +    const jschar *s;
   1.920 +    size_t limit;
   1.921 +    size_t i = 0;
   1.922 +    int year = -1;
   1.923 +    int mon = -1;
   1.924 +    int mday = -1;
   1.925 +    int hour = -1;
   1.926 +    int min = -1;
   1.927 +    int sec = -1;
   1.928 +    int c = -1;
   1.929 +    int n = -1;
   1.930 +    int tzoffset = -1;
   1.931 +    int prevc = 0;
   1.932 +    bool seenplusminus = false;
   1.933 +    int temp;
   1.934 +    bool seenmonthname = false;
   1.935 +
   1.936 +    if (date_parseISOString(str, result, dtInfo))
   1.937 +        return true;
   1.938 +
   1.939 +    s = str->chars();
   1.940 +    limit = str->length();
   1.941 +    if (limit == 0)
   1.942 +        goto syntax;
   1.943 +    while (i < limit) {
   1.944 +        c = s[i];
   1.945 +        i++;
   1.946 +        if (c <= ' ' || c == ',' || c == '-') {
   1.947 +            if (c == '-' && '0' <= s[i] && s[i] <= '9') {
   1.948 +              prevc = c;
   1.949 +            }
   1.950 +            continue;
   1.951 +        }
   1.952 +        if (c == '(') { /* comments) */
   1.953 +            int depth = 1;
   1.954 +            while (i < limit) {
   1.955 +                c = s[i];
   1.956 +                i++;
   1.957 +                if (c == '(') depth++;
   1.958 +                else if (c == ')')
   1.959 +                    if (--depth <= 0)
   1.960 +                        break;
   1.961 +            }
   1.962 +            continue;
   1.963 +        }
   1.964 +        if ('0' <= c && c <= '9') {
   1.965 +            n = c - '0';
   1.966 +            while (i < limit && '0' <= (c = s[i]) && c <= '9') {
   1.967 +                n = n * 10 + c - '0';
   1.968 +                i++;
   1.969 +            }
   1.970 +
   1.971 +            /* allow TZA before the year, so
   1.972 +             * 'Wed Nov 05 21:49:11 GMT-0800 1997'
   1.973 +             * works */
   1.974 +
   1.975 +            /* uses of seenplusminus allow : in TZA, so Java
   1.976 +             * no-timezone style of GMT+4:30 works
   1.977 +             */
   1.978 +
   1.979 +            if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
   1.980 +                /* make ':' case below change tzoffset */
   1.981 +                seenplusminus = true;
   1.982 +
   1.983 +                /* offset */
   1.984 +                if (n < 24)
   1.985 +                    n = n * 60; /* EG. "GMT-3" */
   1.986 +                else
   1.987 +                    n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
   1.988 +                if (prevc == '+')       /* plus means east of GMT */
   1.989 +                    n = -n;
   1.990 +                if (tzoffset != 0 && tzoffset != -1)
   1.991 +                    goto syntax;
   1.992 +                tzoffset = n;
   1.993 +            } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
   1.994 +                if (c <= ' ' || c == ',' || c == '/' || i >= limit)
   1.995 +                    year = n;
   1.996 +                else
   1.997 +                    goto syntax;
   1.998 +            } else if (c == ':') {
   1.999 +                if (hour < 0)
  1.1000 +                    hour = /*byte*/ n;
  1.1001 +                else if (min < 0)
  1.1002 +                    min = /*byte*/ n;
  1.1003 +                else
  1.1004 +                    goto syntax;
  1.1005 +            } else if (c == '/') {
  1.1006 +                /* until it is determined that mon is the actual
  1.1007 +                   month, keep it as 1-based rather than 0-based */
  1.1008 +                if (mon < 0)
  1.1009 +                    mon = /*byte*/ n;
  1.1010 +                else if (mday < 0)
  1.1011 +                    mday = /*byte*/ n;
  1.1012 +                else
  1.1013 +                    goto syntax;
  1.1014 +            } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
  1.1015 +                goto syntax;
  1.1016 +            } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */
  1.1017 +                if (tzoffset < 0)
  1.1018 +                    tzoffset -= n;
  1.1019 +                else
  1.1020 +                    tzoffset += n;
  1.1021 +            } else if (hour >= 0 && min < 0) {
  1.1022 +                min = /*byte*/ n;
  1.1023 +            } else if (prevc == ':' && min >= 0 && sec < 0) {
  1.1024 +                sec = /*byte*/ n;
  1.1025 +            } else if (mon < 0) {
  1.1026 +                mon = /*byte*/n;
  1.1027 +            } else if (mon >= 0 && mday < 0) {
  1.1028 +                mday = /*byte*/ n;
  1.1029 +            } else if (mon >= 0 && mday >= 0 && year < 0) {
  1.1030 +                year = n;
  1.1031 +            } else {
  1.1032 +                goto syntax;
  1.1033 +            }
  1.1034 +            prevc = 0;
  1.1035 +        } else if (c == '/' || c == ':' || c == '+' || c == '-') {
  1.1036 +            prevc = c;
  1.1037 +        } else {
  1.1038 +            size_t st = i - 1;
  1.1039 +            int k;
  1.1040 +            while (i < limit) {
  1.1041 +                c = s[i];
  1.1042 +                if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
  1.1043 +                    break;
  1.1044 +                i++;
  1.1045 +            }
  1.1046 +            if (i <= st + 1)
  1.1047 +                goto syntax;
  1.1048 +            for (k = ArrayLength(wtb); --k >= 0;)
  1.1049 +                if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
  1.1050 +                    int action = ttb[k];
  1.1051 +                    if (action != 0) {
  1.1052 +                        if (action < 0) {
  1.1053 +                            /*
  1.1054 +                             * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
  1.1055 +                             * 12:30, instead of blindly adding 12 if PM.
  1.1056 +                             */
  1.1057 +                            JS_ASSERT(action == -1 || action == -2);
  1.1058 +                            if (hour > 12 || hour < 0) {
  1.1059 +                                goto syntax;
  1.1060 +                            } else {
  1.1061 +                                if (action == -1 && hour == 12) { /* am */
  1.1062 +                                    hour = 0;
  1.1063 +                                } else if (action == -2 && hour != 12) { /* pm */
  1.1064 +                                    hour += 12;
  1.1065 +                                }
  1.1066 +                            }
  1.1067 +                        } else if (action <= 13) { /* month! */
  1.1068 +                            /* Adjust mon to be 1-based until the final values
  1.1069 +                               for mon, mday and year are adjusted below */
  1.1070 +                            if (seenmonthname) {
  1.1071 +                                goto syntax;
  1.1072 +                            }
  1.1073 +                            seenmonthname = true;
  1.1074 +                            temp = /*byte*/ (action - 2) + 1;
  1.1075 +
  1.1076 +                            if (mon < 0) {
  1.1077 +                                mon = temp;
  1.1078 +                            } else if (mday < 0) {
  1.1079 +                                mday = mon;
  1.1080 +                                mon = temp;
  1.1081 +                            } else if (year < 0) {
  1.1082 +                                year = mon;
  1.1083 +                                mon = temp;
  1.1084 +                            } else {
  1.1085 +                                goto syntax;
  1.1086 +                            }
  1.1087 +                        } else {
  1.1088 +                            tzoffset = action - 10000;
  1.1089 +                        }
  1.1090 +                    }
  1.1091 +                    break;
  1.1092 +                }
  1.1093 +            if (k < 0)
  1.1094 +                goto syntax;
  1.1095 +            prevc = 0;
  1.1096 +        }
  1.1097 +    }
  1.1098 +    if (year < 0 || mon < 0 || mday < 0)
  1.1099 +        goto syntax;
  1.1100 +    /*
  1.1101 +      Case 1. The input string contains an English month name.
  1.1102 +              The form of the string can be month f l, or f month l, or
  1.1103 +              f l month which each evaluate to the same date.
  1.1104 +              If f and l are both greater than or equal to 70, or
  1.1105 +              both less than 70, the date is invalid.
  1.1106 +              The year is taken to be the greater of the values f, l.
  1.1107 +              If the year is greater than or equal to 70 and less than 100,
  1.1108 +              it is considered to be the number of years after 1900.
  1.1109 +      Case 2. The input string is of the form "f/m/l" where f, m and l are
  1.1110 +              integers, e.g. 7/16/45.
  1.1111 +              Adjust the mon, mday and year values to achieve 100% MSIE
  1.1112 +              compatibility.
  1.1113 +              a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
  1.1114 +                 i.  If year < 100, it is the number of years after 1900
  1.1115 +                 ii. If year >= 100, it is the number of years after 0.
  1.1116 +              b. If 70 <= f < 100
  1.1117 +                 i.  If m < 70, f/m/l is interpreted as
  1.1118 +                     year/month/day where year is the number of years after
  1.1119 +                     1900.
  1.1120 +                 ii. If m >= 70, the date is invalid.
  1.1121 +              c. If f >= 100
  1.1122 +                 i.  If m < 70, f/m/l is interpreted as
  1.1123 +                     year/month/day where year is the number of years after 0.
  1.1124 +                 ii. If m >= 70, the date is invalid.
  1.1125 +    */
  1.1126 +    if (seenmonthname) {
  1.1127 +        if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
  1.1128 +            goto syntax;
  1.1129 +        }
  1.1130 +        if (mday > year) {
  1.1131 +            temp = year;
  1.1132 +            year = mday;
  1.1133 +            mday = temp;
  1.1134 +        }
  1.1135 +        if (year >= 70 && year < 100) {
  1.1136 +            year += 1900;
  1.1137 +        }
  1.1138 +    } else if (mon < 70) { /* (a) month/day/year */
  1.1139 +        if (year < 100) {
  1.1140 +            year += 1900;
  1.1141 +        }
  1.1142 +    } else if (mon < 100) { /* (b) year/month/day */
  1.1143 +        if (mday < 70) {
  1.1144 +            temp = year;
  1.1145 +            year = mon + 1900;
  1.1146 +            mon = mday;
  1.1147 +            mday = temp;
  1.1148 +        } else {
  1.1149 +            goto syntax;
  1.1150 +        }
  1.1151 +    } else { /* (c) year/month/day */
  1.1152 +        if (mday < 70) {
  1.1153 +            temp = year;
  1.1154 +            year = mon;
  1.1155 +            mon = mday;
  1.1156 +            mday = temp;
  1.1157 +        } else {
  1.1158 +            goto syntax;
  1.1159 +        }
  1.1160 +    }
  1.1161 +    mon -= 1; /* convert month to 0-based */
  1.1162 +    if (sec < 0)
  1.1163 +        sec = 0;
  1.1164 +    if (min < 0)
  1.1165 +        min = 0;
  1.1166 +    if (hour < 0)
  1.1167 +        hour = 0;
  1.1168 +
  1.1169 +    msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
  1.1170 +
  1.1171 +    if (tzoffset == -1) { /* no time zone specified, have to use local */
  1.1172 +        msec = UTC(msec, dtInfo);
  1.1173 +    } else {
  1.1174 +        msec += tzoffset * msPerMinute;
  1.1175 +    }
  1.1176 +
  1.1177 +    *result = msec;
  1.1178 +    return true;
  1.1179 +
  1.1180 +syntax:
  1.1181 +    /* syntax error */
  1.1182 +    *result = 0;
  1.1183 +    return false;
  1.1184 +}
  1.1185 +
  1.1186 +static bool
  1.1187 +date_parse(JSContext *cx, unsigned argc, Value *vp)
  1.1188 +{
  1.1189 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1190 +    if (args.length() == 0) {
  1.1191 +        args.rval().setNaN();
  1.1192 +        return true;
  1.1193 +    }
  1.1194 +
  1.1195 +    JSString *str = ToString<CanGC>(cx, args[0]);
  1.1196 +    if (!str)
  1.1197 +        return false;
  1.1198 +
  1.1199 +    JSLinearString *linearStr = str->ensureLinear(cx);
  1.1200 +    if (!linearStr)
  1.1201 +        return false;
  1.1202 +
  1.1203 +    double result;
  1.1204 +    if (!date_parseString(linearStr, &result, &cx->runtime()->dateTimeInfo)) {
  1.1205 +        args.rval().setNaN();
  1.1206 +        return true;
  1.1207 +    }
  1.1208 +
  1.1209 +    result = TimeClip(result);
  1.1210 +    args.rval().setNumber(result);
  1.1211 +    return true;
  1.1212 +}
  1.1213 +
  1.1214 +static inline double
  1.1215 +NowAsMillis()
  1.1216 +{
  1.1217 +    return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
  1.1218 +}
  1.1219 +
  1.1220 +static bool
  1.1221 +date_now(JSContext *cx, unsigned argc, Value *vp)
  1.1222 +{
  1.1223 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1224 +    args.rval().setDouble(NowAsMillis());
  1.1225 +    return true;
  1.1226 +}
  1.1227 +
  1.1228 +void
  1.1229 +DateObject::setUTCTime(double t, Value *vp)
  1.1230 +{
  1.1231 +    for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++)
  1.1232 +        setReservedSlot(ind, UndefinedValue());
  1.1233 +
  1.1234 +    setFixedSlot(UTC_TIME_SLOT, DoubleValue(t));
  1.1235 +    if (vp)
  1.1236 +        vp->setDouble(t);
  1.1237 +}
  1.1238 +
  1.1239 +void
  1.1240 +DateObject::fillLocalTimeSlots(DateTimeInfo *dtInfo)
  1.1241 +{
  1.1242 +    /* Check if the cache is already populated. */
  1.1243 +    if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() &&
  1.1244 +        getReservedSlot(TZA_SLOT).toDouble() == dtInfo->localTZA())
  1.1245 +    {
  1.1246 +        return;
  1.1247 +    }
  1.1248 +
  1.1249 +    /* Remember timezone used to generate the local cache. */
  1.1250 +    setReservedSlot(TZA_SLOT, DoubleValue(dtInfo->localTZA()));
  1.1251 +
  1.1252 +    double utcTime = UTCTime().toNumber();
  1.1253 +
  1.1254 +    if (!IsFinite(utcTime)) {
  1.1255 +        for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++)
  1.1256 +            setReservedSlot(ind, DoubleValue(utcTime));
  1.1257 +        return;
  1.1258 +    }
  1.1259 +
  1.1260 +    double localTime = LocalTime(utcTime, dtInfo);
  1.1261 +
  1.1262 +    setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime));
  1.1263 +
  1.1264 +    int year = (int) floor(localTime /(msPerDay * 365.2425)) + 1970;
  1.1265 +    double yearStartTime = TimeFromYear(year);
  1.1266 +
  1.1267 +    /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
  1.1268 +    int yearDays;
  1.1269 +    if (yearStartTime > localTime) {
  1.1270 +        year--;
  1.1271 +        yearStartTime -= (msPerDay * DaysInYear(year));
  1.1272 +        yearDays = DaysInYear(year);
  1.1273 +    } else {
  1.1274 +        yearDays = DaysInYear(year);
  1.1275 +        double nextStart = yearStartTime + (msPerDay * yearDays);
  1.1276 +        if (nextStart <= localTime) {
  1.1277 +            year++;
  1.1278 +            yearStartTime = nextStart;
  1.1279 +            yearDays = DaysInYear(year);
  1.1280 +        }
  1.1281 +    }
  1.1282 +
  1.1283 +    setReservedSlot(LOCAL_YEAR_SLOT, Int32Value(year));
  1.1284 +
  1.1285 +    uint64_t yearTime = uint64_t(localTime - yearStartTime);
  1.1286 +    int yearSeconds = uint32_t(yearTime / 1000);
  1.1287 +
  1.1288 +    int day = yearSeconds / int(SecondsPerDay);
  1.1289 +
  1.1290 +    int step = -1, next = 30;
  1.1291 +    int month;
  1.1292 +
  1.1293 +    do {
  1.1294 +        if (day <= next) {
  1.1295 +            month = 0;
  1.1296 +            break;
  1.1297 +        }
  1.1298 +        step = next;
  1.1299 +        next += ((yearDays == 366) ? 29 : 28);
  1.1300 +        if (day <= next) {
  1.1301 +            month = 1;
  1.1302 +            break;
  1.1303 +        }
  1.1304 +        step = next;
  1.1305 +        if (day <= (next += 31)) {
  1.1306 +            month = 2;
  1.1307 +            break;
  1.1308 +        }
  1.1309 +        step = next;
  1.1310 +        if (day <= (next += 30)) {
  1.1311 +            month = 3;
  1.1312 +            break;
  1.1313 +        }
  1.1314 +        step = next;
  1.1315 +        if (day <= (next += 31)) {
  1.1316 +            month = 4;
  1.1317 +            break;
  1.1318 +        }
  1.1319 +        step = next;
  1.1320 +        if (day <= (next += 30)) {
  1.1321 +            month = 5;
  1.1322 +            break;
  1.1323 +        }
  1.1324 +        step = next;
  1.1325 +        if (day <= (next += 31)) {
  1.1326 +            month = 6;
  1.1327 +            break;
  1.1328 +        }
  1.1329 +        step = next;
  1.1330 +        if (day <= (next += 31)) {
  1.1331 +            month = 7;
  1.1332 +            break;
  1.1333 +        }
  1.1334 +        step = next;
  1.1335 +        if (day <= (next += 30)) {
  1.1336 +            month = 8;
  1.1337 +            break;
  1.1338 +        }
  1.1339 +        step = next;
  1.1340 +        if (day <= (next += 31)) {
  1.1341 +            month = 9;
  1.1342 +            break;
  1.1343 +        }
  1.1344 +        step = next;
  1.1345 +        if (day <= (next += 30)) {
  1.1346 +            month = 10;
  1.1347 +            break;
  1.1348 +        }
  1.1349 +        step = next;
  1.1350 +        month = 11;
  1.1351 +    } while (0);
  1.1352 +
  1.1353 +    setReservedSlot(LOCAL_MONTH_SLOT, Int32Value(month));
  1.1354 +    setReservedSlot(LOCAL_DATE_SLOT, Int32Value(day - step));
  1.1355 +
  1.1356 +    int weekday = WeekDay(localTime);
  1.1357 +    setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday));
  1.1358 +
  1.1359 +    int seconds = yearSeconds % 60;
  1.1360 +    setReservedSlot(LOCAL_SECONDS_SLOT, Int32Value(seconds));
  1.1361 +
  1.1362 +    int minutes = (yearSeconds / 60) % 60;
  1.1363 +    setReservedSlot(LOCAL_MINUTES_SLOT, Int32Value(minutes));
  1.1364 +
  1.1365 +    int hours = (yearSeconds / (60 * 60)) % 24;
  1.1366 +    setReservedSlot(LOCAL_HOURS_SLOT, Int32Value(hours));
  1.1367 +}
  1.1368 +
  1.1369 +inline double
  1.1370 +DateObject::cachedLocalTime(DateTimeInfo *dtInfo)
  1.1371 +{
  1.1372 +    fillLocalTimeSlots(dtInfo);
  1.1373 +    return getReservedSlot(LOCAL_TIME_SLOT).toDouble();
  1.1374 +}
  1.1375 +
  1.1376 +MOZ_ALWAYS_INLINE bool
  1.1377 +IsDate(HandleValue v)
  1.1378 +{
  1.1379 +    return v.isObject() && v.toObject().is<DateObject>();
  1.1380 +}
  1.1381 +
  1.1382 +/*
  1.1383 + * See ECMA 15.9.5.4 thru 15.9.5.23
  1.1384 + */
  1.1385 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1386 +DateObject::getTime_impl(JSContext *cx, CallArgs args)
  1.1387 +{
  1.1388 +    args.rval().set(args.thisv().toObject().as<DateObject>().UTCTime());
  1.1389 +    return true;
  1.1390 +}
  1.1391 +
  1.1392 +static bool
  1.1393 +date_getTime(JSContext *cx, unsigned argc, Value *vp)
  1.1394 +{
  1.1395 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1396 +    return CallNonGenericMethod<IsDate, DateObject::getTime_impl>(cx, args);
  1.1397 +}
  1.1398 +
  1.1399 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1400 +DateObject::getYear_impl(JSContext *cx, CallArgs args)
  1.1401 +{
  1.1402 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1403 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1404 +
  1.1405 +    Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT);
  1.1406 +    if (yearVal.isInt32()) {
  1.1407 +        /* Follow ECMA-262 to the letter, contrary to IE JScript. */
  1.1408 +        int year = yearVal.toInt32() - 1900;
  1.1409 +        args.rval().setInt32(year);
  1.1410 +    } else {
  1.1411 +        args.rval().set(yearVal);
  1.1412 +    }
  1.1413 +
  1.1414 +    return true;
  1.1415 +}
  1.1416 +
  1.1417 +static bool
  1.1418 +date_getYear(JSContext *cx, unsigned argc, Value *vp)
  1.1419 +{
  1.1420 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1421 +    return CallNonGenericMethod<IsDate, DateObject::getYear_impl>(cx, args);
  1.1422 +}
  1.1423 +
  1.1424 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1425 +DateObject::getFullYear_impl(JSContext *cx, CallArgs args)
  1.1426 +{
  1.1427 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1428 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1429 +
  1.1430 +    args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT));
  1.1431 +    return true;
  1.1432 +}
  1.1433 +
  1.1434 +static bool
  1.1435 +date_getFullYear(JSContext *cx, unsigned argc, Value *vp)
  1.1436 +{
  1.1437 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1438 +    return CallNonGenericMethod<IsDate, DateObject::getFullYear_impl>(cx, args);
  1.1439 +}
  1.1440 +
  1.1441 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1442 +DateObject::getUTCFullYear_impl(JSContext *cx, CallArgs args)
  1.1443 +{
  1.1444 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1445 +    if (IsFinite(result))
  1.1446 +        result = YearFromTime(result);
  1.1447 +
  1.1448 +    args.rval().setNumber(result);
  1.1449 +    return true;
  1.1450 +}
  1.1451 +
  1.1452 +static bool
  1.1453 +date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
  1.1454 +{
  1.1455 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1456 +    return CallNonGenericMethod<IsDate, DateObject::getUTCFullYear_impl>(cx, args);
  1.1457 +}
  1.1458 +
  1.1459 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1460 +DateObject::getMonth_impl(JSContext *cx, CallArgs args)
  1.1461 +{
  1.1462 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1463 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1464 +
  1.1465 +    args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT));
  1.1466 +    return true;
  1.1467 +}
  1.1468 +
  1.1469 +static bool
  1.1470 +date_getMonth(JSContext *cx, unsigned argc, Value *vp)
  1.1471 +{
  1.1472 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1473 +    return CallNonGenericMethod<IsDate, DateObject::getMonth_impl>(cx, args);
  1.1474 +}
  1.1475 +
  1.1476 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1477 +DateObject::getUTCMonth_impl(JSContext *cx, CallArgs args)
  1.1478 +{
  1.1479 +    double d = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1480 +    args.rval().setNumber(MonthFromTime(d));
  1.1481 +    return true;
  1.1482 +}
  1.1483 +
  1.1484 +static bool
  1.1485 +date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
  1.1486 +{
  1.1487 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1488 +    return CallNonGenericMethod<IsDate, DateObject::getUTCMonth_impl>(cx, args);
  1.1489 +}
  1.1490 +
  1.1491 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1492 +DateObject::getDate_impl(JSContext *cx, CallArgs args)
  1.1493 +{
  1.1494 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1495 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1496 +
  1.1497 +    args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT));
  1.1498 +    return true;
  1.1499 +}
  1.1500 +
  1.1501 +static bool
  1.1502 +date_getDate(JSContext *cx, unsigned argc, Value *vp)
  1.1503 +{
  1.1504 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1505 +    return CallNonGenericMethod<IsDate, DateObject::getDate_impl>(cx, args);
  1.1506 +}
  1.1507 +
  1.1508 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1509 +DateObject::getUTCDate_impl(JSContext *cx, CallArgs args)
  1.1510 +{
  1.1511 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1512 +    if (IsFinite(result))
  1.1513 +        result = DateFromTime(result);
  1.1514 +
  1.1515 +    args.rval().setNumber(result);
  1.1516 +    return true;
  1.1517 +}
  1.1518 +
  1.1519 +static bool
  1.1520 +date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
  1.1521 +{
  1.1522 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1523 +    return CallNonGenericMethod<IsDate, DateObject::getUTCDate_impl>(cx, args);
  1.1524 +}
  1.1525 +
  1.1526 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1527 +DateObject::getDay_impl(JSContext *cx, CallArgs args)
  1.1528 +{
  1.1529 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1530 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1531 +
  1.1532 +    args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT));
  1.1533 +    return true;
  1.1534 +}
  1.1535 +
  1.1536 +static bool
  1.1537 +date_getDay(JSContext *cx, unsigned argc, Value *vp)
  1.1538 +{
  1.1539 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1540 +    return CallNonGenericMethod<IsDate, DateObject::getDay_impl>(cx, args);
  1.1541 +}
  1.1542 +
  1.1543 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1544 +DateObject::getUTCDay_impl(JSContext *cx, CallArgs args)
  1.1545 +{
  1.1546 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1547 +    if (IsFinite(result))
  1.1548 +        result = WeekDay(result);
  1.1549 +
  1.1550 +    args.rval().setNumber(result);
  1.1551 +    return true;
  1.1552 +}
  1.1553 +
  1.1554 +static bool
  1.1555 +date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
  1.1556 +{
  1.1557 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1558 +    return CallNonGenericMethod<IsDate, DateObject::getUTCDay_impl>(cx, args);
  1.1559 +}
  1.1560 +
  1.1561 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1562 +DateObject::getHours_impl(JSContext *cx, CallArgs args)
  1.1563 +{
  1.1564 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1565 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1566 +
  1.1567 +    args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT));
  1.1568 +    return true;
  1.1569 +}
  1.1570 +
  1.1571 +static bool
  1.1572 +date_getHours(JSContext *cx, unsigned argc, Value *vp)
  1.1573 +{
  1.1574 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1575 +    return CallNonGenericMethod<IsDate, DateObject::getHours_impl>(cx, args);
  1.1576 +}
  1.1577 +
  1.1578 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1579 +DateObject::getUTCHours_impl(JSContext *cx, CallArgs args)
  1.1580 +{
  1.1581 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1582 +    if (IsFinite(result))
  1.1583 +        result = HourFromTime(result);
  1.1584 +
  1.1585 +    args.rval().setNumber(result);
  1.1586 +    return true;
  1.1587 +}
  1.1588 +
  1.1589 +static bool
  1.1590 +date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
  1.1591 +{
  1.1592 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1593 +    return CallNonGenericMethod<IsDate, DateObject::getUTCHours_impl>(cx, args);
  1.1594 +}
  1.1595 +
  1.1596 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1597 +DateObject::getMinutes_impl(JSContext *cx, CallArgs args)
  1.1598 +{
  1.1599 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1600 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1601 +
  1.1602 +    args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT));
  1.1603 +    return true;
  1.1604 +}
  1.1605 +
  1.1606 +static bool
  1.1607 +date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
  1.1608 +{
  1.1609 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1610 +    return CallNonGenericMethod<IsDate, DateObject::getMinutes_impl>(cx, args);
  1.1611 +}
  1.1612 +
  1.1613 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1614 +DateObject::getUTCMinutes_impl(JSContext *cx, CallArgs args)
  1.1615 +{
  1.1616 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1617 +    if (IsFinite(result))
  1.1618 +        result = MinFromTime(result);
  1.1619 +
  1.1620 +    args.rval().setNumber(result);
  1.1621 +    return true;
  1.1622 +}
  1.1623 +
  1.1624 +static bool
  1.1625 +date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
  1.1626 +{
  1.1627 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1628 +    return CallNonGenericMethod<IsDate, DateObject::getUTCMinutes_impl>(cx, args);
  1.1629 +}
  1.1630 +
  1.1631 +/* Date.getSeconds is mapped to getUTCSeconds */
  1.1632 +
  1.1633 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1634 +DateObject::getUTCSeconds_impl(JSContext *cx, CallArgs args)
  1.1635 +{
  1.1636 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1637 +    dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
  1.1638 +
  1.1639 +    args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT));
  1.1640 +    return true;
  1.1641 +}
  1.1642 +
  1.1643 +static bool
  1.1644 +date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
  1.1645 +{
  1.1646 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1647 +    return CallNonGenericMethod<IsDate, DateObject::getUTCSeconds_impl>(cx, args);
  1.1648 +}
  1.1649 +
  1.1650 +/* Date.getMilliseconds is mapped to getUTCMilliseconds */
  1.1651 +
  1.1652 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1653 +DateObject::getUTCMilliseconds_impl(JSContext *cx, CallArgs args)
  1.1654 +{
  1.1655 +    double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.1656 +    if (IsFinite(result))
  1.1657 +        result = msFromTime(result);
  1.1658 +
  1.1659 +    args.rval().setNumber(result);
  1.1660 +    return true;
  1.1661 +}
  1.1662 +
  1.1663 +static bool
  1.1664 +date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
  1.1665 +{
  1.1666 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1667 +    return CallNonGenericMethod<IsDate, DateObject::getUTCMilliseconds_impl>(cx, args);
  1.1668 +}
  1.1669 +
  1.1670 +/* static */ MOZ_ALWAYS_INLINE bool
  1.1671 +DateObject::getTimezoneOffset_impl(JSContext *cx, CallArgs args)
  1.1672 +{
  1.1673 +    DateObject *dateObj = &args.thisv().toObject().as<DateObject>();
  1.1674 +    double utctime = dateObj->UTCTime().toNumber();
  1.1675 +    double localtime = dateObj->cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.1676 +
  1.1677 +    /*
  1.1678 +     * Return the time zone offset in minutes for the current locale that is
  1.1679 +     * appropriate for this time. This value would be a constant except for
  1.1680 +     * daylight savings time.
  1.1681 +     */
  1.1682 +    double result = (utctime - localtime) / msPerMinute;
  1.1683 +    args.rval().setNumber(result);
  1.1684 +    return true;
  1.1685 +}
  1.1686 +
  1.1687 +static bool
  1.1688 +date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
  1.1689 +{
  1.1690 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1691 +    return CallNonGenericMethod<IsDate, DateObject::getTimezoneOffset_impl>(cx, args);
  1.1692 +}
  1.1693 +
  1.1694 +MOZ_ALWAYS_INLINE bool
  1.1695 +date_setTime_impl(JSContext *cx, CallArgs args)
  1.1696 +{
  1.1697 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1698 +    if (args.length() == 0) {
  1.1699 +        dateObj->setUTCTime(GenericNaN(), args.rval().address());
  1.1700 +        return true;
  1.1701 +    }
  1.1702 +
  1.1703 +    double result;
  1.1704 +    if (!ToNumber(cx, args[0], &result))
  1.1705 +        return false;
  1.1706 +
  1.1707 +    dateObj->setUTCTime(TimeClip(result), args.rval().address());
  1.1708 +    return true;
  1.1709 +}
  1.1710 +
  1.1711 +static bool
  1.1712 +date_setTime(JSContext *cx, unsigned argc, Value *vp)
  1.1713 +{
  1.1714 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1715 +    return CallNonGenericMethod<IsDate, date_setTime_impl>(cx, args);
  1.1716 +}
  1.1717 +
  1.1718 +static bool
  1.1719 +GetMsecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *millis)
  1.1720 +{
  1.1721 +    if (args.length() <= i) {
  1.1722 +        *millis = msFromTime(t);
  1.1723 +        return true;
  1.1724 +    }
  1.1725 +    return ToNumber(cx, args[i], millis);
  1.1726 +}
  1.1727 +
  1.1728 +static bool
  1.1729 +GetSecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *sec)
  1.1730 +{
  1.1731 +    if (args.length() <= i) {
  1.1732 +        *sec = SecFromTime(t);
  1.1733 +        return true;
  1.1734 +    }
  1.1735 +    return ToNumber(cx, args[i], sec);
  1.1736 +}
  1.1737 +
  1.1738 +static bool
  1.1739 +GetMinsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *mins)
  1.1740 +{
  1.1741 +    if (args.length() <= i) {
  1.1742 +        *mins = MinFromTime(t);
  1.1743 +        return true;
  1.1744 +    }
  1.1745 +    return ToNumber(cx, args[i], mins);
  1.1746 +}
  1.1747 +
  1.1748 +/* ES5 15.9.5.28. */
  1.1749 +MOZ_ALWAYS_INLINE bool
  1.1750 +date_setMilliseconds_impl(JSContext *cx, CallArgs args)
  1.1751 +{
  1.1752 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1753 +
  1.1754 +    /* Step 1. */
  1.1755 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.1756 +
  1.1757 +    /* Step 2. */
  1.1758 +    double milli;
  1.1759 +    if (!ToNumber(cx, args.get(0), &milli))
  1.1760 +        return false;
  1.1761 +    double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
  1.1762 +
  1.1763 +    /* Step 3. */
  1.1764 +    double u = TimeClip(UTC(MakeDate(Day(t), time), &cx->runtime()->dateTimeInfo));
  1.1765 +
  1.1766 +    /* Steps 4-5. */
  1.1767 +    dateObj->setUTCTime(u, args.rval().address());
  1.1768 +    return true;
  1.1769 +}
  1.1770 +
  1.1771 +static bool
  1.1772 +date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp)
  1.1773 +{
  1.1774 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1775 +    return CallNonGenericMethod<IsDate, date_setMilliseconds_impl>(cx, args);
  1.1776 +}
  1.1777 +
  1.1778 +/* ES5 15.9.5.29. */
  1.1779 +MOZ_ALWAYS_INLINE bool
  1.1780 +date_setUTCMilliseconds_impl(JSContext *cx, CallArgs args)
  1.1781 +{
  1.1782 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1783 +
  1.1784 +    /* Step 1. */
  1.1785 +    double t = dateObj->UTCTime().toNumber();
  1.1786 +
  1.1787 +    /* Step 2. */
  1.1788 +    double milli;
  1.1789 +    if (!ToNumber(cx, args.get(0), &milli))
  1.1790 +        return false;
  1.1791 +    double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
  1.1792 +
  1.1793 +    /* Step 3. */
  1.1794 +    double v = TimeClip(MakeDate(Day(t), time));
  1.1795 +
  1.1796 +    /* Steps 4-5. */
  1.1797 +    dateObj->setUTCTime(v, args.rval().address());
  1.1798 +    return true;
  1.1799 +}
  1.1800 +
  1.1801 +static bool
  1.1802 +date_setUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
  1.1803 +{
  1.1804 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1805 +    return CallNonGenericMethod<IsDate, date_setUTCMilliseconds_impl>(cx, args);
  1.1806 +}
  1.1807 +
  1.1808 +/* ES5 15.9.5.30. */
  1.1809 +MOZ_ALWAYS_INLINE bool
  1.1810 +date_setSeconds_impl(JSContext *cx, CallArgs args)
  1.1811 +{
  1.1812 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1813 +
  1.1814 +    /* Step 1. */
  1.1815 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.1816 +
  1.1817 +    /* Step 2. */
  1.1818 +    double s;
  1.1819 +    if (!ToNumber(cx, args.get(0), &s))
  1.1820 +        return false;
  1.1821 +
  1.1822 +    /* Step 3. */
  1.1823 +    double milli;
  1.1824 +    if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
  1.1825 +        return false;
  1.1826 +
  1.1827 +    /* Step 4. */
  1.1828 +    double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
  1.1829 +
  1.1830 +    /* Step 5. */
  1.1831 +    double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
  1.1832 +
  1.1833 +    /* Steps 6-7. */
  1.1834 +    dateObj->setUTCTime(u, args.rval().address());
  1.1835 +    return true;
  1.1836 +}
  1.1837 +
  1.1838 +/* ES5 15.9.5.31. */
  1.1839 +static bool
  1.1840 +date_setSeconds(JSContext *cx, unsigned argc, Value *vp)
  1.1841 +{
  1.1842 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1843 +    return CallNonGenericMethod<IsDate, date_setSeconds_impl>(cx, args);
  1.1844 +}
  1.1845 +
  1.1846 +MOZ_ALWAYS_INLINE bool
  1.1847 +date_setUTCSeconds_impl(JSContext *cx, CallArgs args)
  1.1848 +{
  1.1849 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1850 +
  1.1851 +    /* Step 1. */
  1.1852 +    double t = dateObj->UTCTime().toNumber();
  1.1853 +
  1.1854 +    /* Step 2. */
  1.1855 +    double s;
  1.1856 +    if (!ToNumber(cx, args.get(0), &s))
  1.1857 +        return false;
  1.1858 +
  1.1859 +    /* Step 3. */
  1.1860 +    double milli;
  1.1861 +    if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
  1.1862 +        return false;
  1.1863 +
  1.1864 +    /* Step 4. */
  1.1865 +    double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
  1.1866 +
  1.1867 +    /* Step 5. */
  1.1868 +    double v = TimeClip(date);
  1.1869 +
  1.1870 +    /* Steps 6-7. */
  1.1871 +    dateObj->setUTCTime(v, args.rval().address());
  1.1872 +    return true;
  1.1873 +}
  1.1874 +
  1.1875 +/* ES5 15.9.5.32. */
  1.1876 +static bool
  1.1877 +date_setUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
  1.1878 +{
  1.1879 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1880 +    return CallNonGenericMethod<IsDate, date_setUTCSeconds_impl>(cx, args);
  1.1881 +}
  1.1882 +
  1.1883 +MOZ_ALWAYS_INLINE bool
  1.1884 +date_setMinutes_impl(JSContext *cx, CallArgs args)
  1.1885 +{
  1.1886 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1887 +
  1.1888 +    /* Step 1. */
  1.1889 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.1890 +
  1.1891 +    /* Step 2. */
  1.1892 +    double m;
  1.1893 +    if (!ToNumber(cx, args.get(0), &m))
  1.1894 +        return false;
  1.1895 +
  1.1896 +    /* Step 3. */
  1.1897 +    double s;
  1.1898 +    if (!GetSecsOrDefault(cx, args, 1, t, &s))
  1.1899 +        return false;
  1.1900 +
  1.1901 +    /* Step 4. */
  1.1902 +    double milli;
  1.1903 +    if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
  1.1904 +        return false;
  1.1905 +
  1.1906 +    /* Step 5. */
  1.1907 +    double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
  1.1908 +
  1.1909 +    /* Step 6. */
  1.1910 +    double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
  1.1911 +
  1.1912 +    /* Steps 7-8. */
  1.1913 +    dateObj->setUTCTime(u, args.rval().address());
  1.1914 +    return true;
  1.1915 +}
  1.1916 +
  1.1917 +/* ES5 15.9.5.33. */
  1.1918 +static bool
  1.1919 +date_setMinutes(JSContext *cx, unsigned argc, Value *vp)
  1.1920 +{
  1.1921 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1922 +    return CallNonGenericMethod<IsDate, date_setMinutes_impl>(cx, args);
  1.1923 +}
  1.1924 +
  1.1925 +MOZ_ALWAYS_INLINE bool
  1.1926 +date_setUTCMinutes_impl(JSContext *cx, CallArgs args)
  1.1927 +{
  1.1928 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1929 +
  1.1930 +    /* Step 1. */
  1.1931 +    double t = dateObj->UTCTime().toNumber();
  1.1932 +
  1.1933 +    /* Step 2. */
  1.1934 +    double m;
  1.1935 +    if (!ToNumber(cx, args.get(0), &m))
  1.1936 +        return false;
  1.1937 +
  1.1938 +    /* Step 3. */
  1.1939 +    double s;
  1.1940 +    if (!GetSecsOrDefault(cx, args, 1, t, &s))
  1.1941 +        return false;
  1.1942 +
  1.1943 +    /* Step 4. */
  1.1944 +    double milli;
  1.1945 +    if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
  1.1946 +        return false;
  1.1947 +
  1.1948 +    /* Step 5. */
  1.1949 +    double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
  1.1950 +
  1.1951 +    /* Step 6. */
  1.1952 +    double v = TimeClip(date);
  1.1953 +
  1.1954 +    /* Steps 7-8. */
  1.1955 +    dateObj->setUTCTime(v, args.rval().address());
  1.1956 +    return true;
  1.1957 +}
  1.1958 +
  1.1959 +/* ES5 15.9.5.34. */
  1.1960 +static bool
  1.1961 +date_setUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
  1.1962 +{
  1.1963 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.1964 +    return CallNonGenericMethod<IsDate, date_setUTCMinutes_impl>(cx, args);
  1.1965 +}
  1.1966 +
  1.1967 +MOZ_ALWAYS_INLINE bool
  1.1968 +date_setHours_impl(JSContext *cx, CallArgs args)
  1.1969 +{
  1.1970 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.1971 +
  1.1972 +    /* Step 1. */
  1.1973 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.1974 +
  1.1975 +    /* Step 2. */
  1.1976 +    double h;
  1.1977 +    if (!ToNumber(cx, args.get(0), &h))
  1.1978 +        return false;
  1.1979 +
  1.1980 +    /* Step 3. */
  1.1981 +    double m;
  1.1982 +    if (!GetMinsOrDefault(cx, args, 1, t, &m))
  1.1983 +        return false;
  1.1984 +
  1.1985 +    /* Step 4. */
  1.1986 +    double s;
  1.1987 +    if (!GetSecsOrDefault(cx, args, 2, t, &s))
  1.1988 +        return false;
  1.1989 +
  1.1990 +    /* Step 5. */
  1.1991 +    double milli;
  1.1992 +    if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
  1.1993 +        return false;
  1.1994 +
  1.1995 +    /* Step 6. */
  1.1996 +    double date = MakeDate(Day(t), MakeTime(h, m, s, milli));
  1.1997 +
  1.1998 +    /* Step 6. */
  1.1999 +    double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
  1.2000 +
  1.2001 +    /* Steps 7-8. */
  1.2002 +    dateObj->setUTCTime(u, args.rval().address());
  1.2003 +    return true;
  1.2004 +}
  1.2005 +
  1.2006 +/* ES5 15.9.5.35. */
  1.2007 +static bool
  1.2008 +date_setHours(JSContext *cx, unsigned argc, Value *vp)
  1.2009 +{
  1.2010 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2011 +    return CallNonGenericMethod<IsDate, date_setHours_impl>(cx, args);
  1.2012 +}
  1.2013 +
  1.2014 +MOZ_ALWAYS_INLINE bool
  1.2015 +date_setUTCHours_impl(JSContext *cx, CallArgs args)
  1.2016 +{
  1.2017 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2018 +
  1.2019 +    /* Step 1. */
  1.2020 +    double t = dateObj->UTCTime().toNumber();
  1.2021 +
  1.2022 +    /* Step 2. */
  1.2023 +    double h;
  1.2024 +    if (!ToNumber(cx, args.get(0), &h))
  1.2025 +        return false;
  1.2026 +
  1.2027 +    /* Step 3. */
  1.2028 +    double m;
  1.2029 +    if (!GetMinsOrDefault(cx, args, 1, t, &m))
  1.2030 +        return false;
  1.2031 +
  1.2032 +    /* Step 4. */
  1.2033 +    double s;
  1.2034 +    if (!GetSecsOrDefault(cx, args, 2, t, &s))
  1.2035 +        return false;
  1.2036 +
  1.2037 +    /* Step 5. */
  1.2038 +    double milli;
  1.2039 +    if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
  1.2040 +        return false;
  1.2041 +
  1.2042 +    /* Step 6. */
  1.2043 +    double newDate = MakeDate(Day(t), MakeTime(h, m, s, milli));
  1.2044 +
  1.2045 +    /* Step 7. */
  1.2046 +    double v = TimeClip(newDate);
  1.2047 +
  1.2048 +    /* Steps 8-9. */
  1.2049 +    dateObj->setUTCTime(v, args.rval().address());
  1.2050 +    return true;
  1.2051 +}
  1.2052 +
  1.2053 +/* ES5 15.9.5.36. */
  1.2054 +static bool
  1.2055 +date_setUTCHours(JSContext *cx, unsigned argc, Value *vp)
  1.2056 +{
  1.2057 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2058 +    return CallNonGenericMethod<IsDate, date_setUTCHours_impl>(cx, args);
  1.2059 +}
  1.2060 +
  1.2061 +MOZ_ALWAYS_INLINE bool
  1.2062 +date_setDate_impl(JSContext *cx, CallArgs args)
  1.2063 +{
  1.2064 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2065 +
  1.2066 +    /* Step 1. */
  1.2067 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.2068 +
  1.2069 +    /* Step 2. */
  1.2070 +    double date;
  1.2071 +    if (!ToNumber(cx, args.get(0), &date))
  1.2072 +        return false;
  1.2073 +
  1.2074 +    /* Step 3. */
  1.2075 +    double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
  1.2076 +
  1.2077 +    /* Step 4. */
  1.2078 +    double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
  1.2079 +
  1.2080 +    /* Steps 5-6. */
  1.2081 +    dateObj->setUTCTime(u, args.rval().address());
  1.2082 +    return true;
  1.2083 +}
  1.2084 +
  1.2085 +/* ES5 15.9.5.37. */
  1.2086 +static bool
  1.2087 +date_setDate(JSContext *cx, unsigned argc, Value *vp)
  1.2088 +{
  1.2089 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2090 +    return CallNonGenericMethod<IsDate, date_setDate_impl>(cx, args);
  1.2091 +}
  1.2092 +
  1.2093 +MOZ_ALWAYS_INLINE bool
  1.2094 +date_setUTCDate_impl(JSContext *cx, CallArgs args)
  1.2095 +{
  1.2096 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2097 +
  1.2098 +    /* Step 1. */
  1.2099 +    double t = dateObj->UTCTime().toNumber();
  1.2100 +
  1.2101 +    /* Step 2. */
  1.2102 +    double date;
  1.2103 +    if (!ToNumber(cx, args.get(0), &date))
  1.2104 +        return false;
  1.2105 +
  1.2106 +    /* Step 3. */
  1.2107 +    double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
  1.2108 +
  1.2109 +    /* Step 4. */
  1.2110 +    double v = TimeClip(newDate);
  1.2111 +
  1.2112 +    /* Steps 5-6. */
  1.2113 +    dateObj->setUTCTime(v, args.rval().address());
  1.2114 +    return true;
  1.2115 +}
  1.2116 +
  1.2117 +static bool
  1.2118 +date_setUTCDate(JSContext *cx, unsigned argc, Value *vp)
  1.2119 +{
  1.2120 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2121 +    return CallNonGenericMethod<IsDate, date_setUTCDate_impl>(cx, args);
  1.2122 +}
  1.2123 +
  1.2124 +static bool
  1.2125 +GetDateOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *date)
  1.2126 +{
  1.2127 +    if (args.length() <= i) {
  1.2128 +        *date = DateFromTime(t);
  1.2129 +        return true;
  1.2130 +    }
  1.2131 +    return ToNumber(cx, args[i], date);
  1.2132 +}
  1.2133 +
  1.2134 +static bool
  1.2135 +GetMonthOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *month)
  1.2136 +{
  1.2137 +    if (args.length() <= i) {
  1.2138 +        *month = MonthFromTime(t);
  1.2139 +        return true;
  1.2140 +    }
  1.2141 +    return ToNumber(cx, args[i], month);
  1.2142 +}
  1.2143 +
  1.2144 +/* ES5 15.9.5.38. */
  1.2145 +MOZ_ALWAYS_INLINE bool
  1.2146 +date_setMonth_impl(JSContext *cx, CallArgs args)
  1.2147 +{
  1.2148 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2149 +
  1.2150 +    /* Step 1. */
  1.2151 +    double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
  1.2152 +
  1.2153 +    /* Step 2. */
  1.2154 +    double m;
  1.2155 +    if (!ToNumber(cx, args.get(0), &m))
  1.2156 +        return false;
  1.2157 +
  1.2158 +    /* Step 3. */
  1.2159 +    double date;
  1.2160 +    if (!GetDateOrDefault(cx, args, 1, t, &date))
  1.2161 +        return false;
  1.2162 +
  1.2163 +    /* Step 4. */
  1.2164 +    double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t));
  1.2165 +
  1.2166 +    /* Step 5. */
  1.2167 +    double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
  1.2168 +
  1.2169 +    /* Steps 6-7. */
  1.2170 +    dateObj->setUTCTime(u, args.rval().address());
  1.2171 +    return true;
  1.2172 +}
  1.2173 +
  1.2174 +static bool
  1.2175 +date_setMonth(JSContext *cx, unsigned argc, Value *vp)
  1.2176 +{
  1.2177 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2178 +    return CallNonGenericMethod<IsDate, date_setMonth_impl>(cx, args);
  1.2179 +}
  1.2180 +
  1.2181 +/* ES5 15.9.5.39. */
  1.2182 +MOZ_ALWAYS_INLINE bool
  1.2183 +date_setUTCMonth_impl(JSContext *cx, CallArgs args)
  1.2184 +{
  1.2185 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2186 +
  1.2187 +    /* Step 1. */
  1.2188 +    double t = dateObj->UTCTime().toNumber();
  1.2189 +
  1.2190 +    /* Step 2. */
  1.2191 +    double m;
  1.2192 +    if (!ToNumber(cx, args.get(0), &m))
  1.2193 +        return false;
  1.2194 +
  1.2195 +    /* Step 3. */
  1.2196 +    double date;
  1.2197 +    if (!GetDateOrDefault(cx, args, 1, t, &date))
  1.2198 +        return false;
  1.2199 +
  1.2200 +    /* Step 4. */
  1.2201 +    double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t));
  1.2202 +
  1.2203 +    /* Step 5. */
  1.2204 +    double v = TimeClip(newDate);
  1.2205 +
  1.2206 +    /* Steps 6-7. */
  1.2207 +    dateObj->setUTCTime(v, args.rval().address());
  1.2208 +    return true;
  1.2209 +}
  1.2210 +
  1.2211 +static bool
  1.2212 +date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp)
  1.2213 +{
  1.2214 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2215 +    return CallNonGenericMethod<IsDate, date_setUTCMonth_impl>(cx, args);
  1.2216 +}
  1.2217 +
  1.2218 +static double
  1.2219 +ThisLocalTimeOrZero(Handle<DateObject*> dateObj, DateTimeInfo *dtInfo)
  1.2220 +{
  1.2221 +    double t = dateObj->UTCTime().toNumber();
  1.2222 +    if (IsNaN(t))
  1.2223 +        return +0;
  1.2224 +    return LocalTime(t, dtInfo);
  1.2225 +}
  1.2226 +
  1.2227 +static double
  1.2228 +ThisUTCTimeOrZero(Handle<DateObject*> dateObj)
  1.2229 +{
  1.2230 +    double t = dateObj->as<DateObject>().UTCTime().toNumber();
  1.2231 +    return IsNaN(t) ? +0 : t;
  1.2232 +}
  1.2233 +
  1.2234 +/* ES5 15.9.5.40. */
  1.2235 +MOZ_ALWAYS_INLINE bool
  1.2236 +date_setFullYear_impl(JSContext *cx, CallArgs args)
  1.2237 +{
  1.2238 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2239 +
  1.2240 +    /* Step 1. */
  1.2241 +    double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo);
  1.2242 +
  1.2243 +    /* Step 2. */
  1.2244 +    double y;
  1.2245 +    if (!ToNumber(cx, args.get(0), &y))
  1.2246 +        return false;
  1.2247 +
  1.2248 +    /* Step 3. */
  1.2249 +    double m;
  1.2250 +    if (!GetMonthOrDefault(cx, args, 1, t, &m))
  1.2251 +        return false;
  1.2252 +
  1.2253 +    /* Step 4. */
  1.2254 +    double date;
  1.2255 +    if (!GetDateOrDefault(cx, args, 2, t, &date))
  1.2256 +        return false;
  1.2257 +
  1.2258 +    /* Step 5. */
  1.2259 +    double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t));
  1.2260 +
  1.2261 +    /* Step 6. */
  1.2262 +    double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
  1.2263 +
  1.2264 +    /* Steps 7-8. */
  1.2265 +    dateObj->setUTCTime(u, args.rval().address());
  1.2266 +    return true;
  1.2267 +}
  1.2268 +
  1.2269 +static bool
  1.2270 +date_setFullYear(JSContext *cx, unsigned argc, Value *vp)
  1.2271 +{
  1.2272 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2273 +    return CallNonGenericMethod<IsDate, date_setFullYear_impl>(cx, args);
  1.2274 +}
  1.2275 +
  1.2276 +/* ES5 15.9.5.41. */
  1.2277 +MOZ_ALWAYS_INLINE bool
  1.2278 +date_setUTCFullYear_impl(JSContext *cx, CallArgs args)
  1.2279 +{
  1.2280 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2281 +
  1.2282 +    /* Step 1. */
  1.2283 +    double t = ThisUTCTimeOrZero(dateObj);
  1.2284 +
  1.2285 +    /* Step 2. */
  1.2286 +    double y;
  1.2287 +    if (!ToNumber(cx, args.get(0), &y))
  1.2288 +        return false;
  1.2289 +
  1.2290 +    /* Step 3. */
  1.2291 +    double m;
  1.2292 +    if (!GetMonthOrDefault(cx, args, 1, t, &m))
  1.2293 +        return false;
  1.2294 +
  1.2295 +    /* Step 4. */
  1.2296 +    double date;
  1.2297 +    if (!GetDateOrDefault(cx, args, 2, t, &date))
  1.2298 +        return false;
  1.2299 +
  1.2300 +    /* Step 5. */
  1.2301 +    double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t));
  1.2302 +
  1.2303 +    /* Step 6. */
  1.2304 +    double v = TimeClip(newDate);
  1.2305 +
  1.2306 +    /* Steps 7-8. */
  1.2307 +    dateObj->setUTCTime(v, args.rval().address());
  1.2308 +    return true;
  1.2309 +}
  1.2310 +
  1.2311 +static bool
  1.2312 +date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
  1.2313 +{
  1.2314 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2315 +    return CallNonGenericMethod<IsDate, date_setUTCFullYear_impl>(cx, args);
  1.2316 +}
  1.2317 +
  1.2318 +/* ES5 Annex B.2.5. */
  1.2319 +MOZ_ALWAYS_INLINE bool
  1.2320 +date_setYear_impl(JSContext *cx, CallArgs args)
  1.2321 +{
  1.2322 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2323 +
  1.2324 +    /* Step 1. */
  1.2325 +    double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo);
  1.2326 +
  1.2327 +    /* Step 2. */
  1.2328 +    double y;
  1.2329 +    if (!ToNumber(cx, args.get(0), &y))
  1.2330 +        return false;
  1.2331 +
  1.2332 +    /* Step 3. */
  1.2333 +    if (IsNaN(y)) {
  1.2334 +        dateObj->setUTCTime(GenericNaN(), args.rval().address());
  1.2335 +        return true;
  1.2336 +    }
  1.2337 +
  1.2338 +    /* Step 4. */
  1.2339 +    double yint = ToInteger(y);
  1.2340 +    if (0 <= yint && yint <= 99)
  1.2341 +        yint += 1900;
  1.2342 +
  1.2343 +    /* Step 5. */
  1.2344 +    double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t));
  1.2345 +
  1.2346 +    /* Step 6. */
  1.2347 +    double u = UTC(MakeDate(day, TimeWithinDay(t)), &cx->runtime()->dateTimeInfo);
  1.2348 +
  1.2349 +    /* Steps 7-8. */
  1.2350 +    dateObj->setUTCTime(TimeClip(u), args.rval().address());
  1.2351 +    return true;
  1.2352 +}
  1.2353 +
  1.2354 +static bool
  1.2355 +date_setYear(JSContext *cx, unsigned argc, Value *vp)
  1.2356 +{
  1.2357 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2358 +    return CallNonGenericMethod<IsDate, date_setYear_impl>(cx, args);
  1.2359 +}
  1.2360 +
  1.2361 +/* constants for toString, toUTCString */
  1.2362 +static const char js_NaN_date_str[] = "Invalid Date";
  1.2363 +static const char * const days[] =
  1.2364 +{
  1.2365 +   "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  1.2366 +};
  1.2367 +static const char * const months[] =
  1.2368 +{
  1.2369 +   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1.2370 +};
  1.2371 +
  1.2372 +
  1.2373 +// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
  1.2374 +// requires a PRMJTime... which only has 16-bit years.  Sub-ECMA.
  1.2375 +static void
  1.2376 +print_gmt_string(char* buf, size_t size, double utctime)
  1.2377 +{
  1.2378 +    JS_ASSERT(TimeClip(utctime) == utctime);
  1.2379 +    JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
  1.2380 +                days[int(WeekDay(utctime))],
  1.2381 +                int(DateFromTime(utctime)),
  1.2382 +                months[int(MonthFromTime(utctime))],
  1.2383 +                int(YearFromTime(utctime)),
  1.2384 +                int(HourFromTime(utctime)),
  1.2385 +                int(MinFromTime(utctime)),
  1.2386 +                int(SecFromTime(utctime)));
  1.2387 +}
  1.2388 +
  1.2389 +static void
  1.2390 +print_iso_string(char* buf, size_t size, double utctime)
  1.2391 +{
  1.2392 +    JS_ASSERT(TimeClip(utctime) == utctime);
  1.2393 +    JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
  1.2394 +                int(YearFromTime(utctime)),
  1.2395 +                int(MonthFromTime(utctime)) + 1,
  1.2396 +                int(DateFromTime(utctime)),
  1.2397 +                int(HourFromTime(utctime)),
  1.2398 +                int(MinFromTime(utctime)),
  1.2399 +                int(SecFromTime(utctime)),
  1.2400 +                int(msFromTime(utctime)));
  1.2401 +}
  1.2402 +
  1.2403 +/* ES5 B.2.6. */
  1.2404 +MOZ_ALWAYS_INLINE bool
  1.2405 +date_toGMTString_impl(JSContext *cx, CallArgs args)
  1.2406 +{
  1.2407 +    double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.2408 +
  1.2409 +    char buf[100];
  1.2410 +    if (!IsFinite(utctime))
  1.2411 +        JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1.2412 +    else
  1.2413 +        print_gmt_string(buf, sizeof buf, utctime);
  1.2414 +
  1.2415 +    JSString *str = JS_NewStringCopyZ(cx, buf);
  1.2416 +    if (!str)
  1.2417 +        return false;
  1.2418 +    args.rval().setString(str);
  1.2419 +    return true;
  1.2420 +}
  1.2421 +
  1.2422 +/* ES5 15.9.5.43. */
  1.2423 +static bool
  1.2424 +date_toGMTString(JSContext *cx, unsigned argc, Value *vp)
  1.2425 +{
  1.2426 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2427 +    return CallNonGenericMethod<IsDate, date_toGMTString_impl>(cx, args);
  1.2428 +}
  1.2429 +
  1.2430 +MOZ_ALWAYS_INLINE bool
  1.2431 +date_toISOString_impl(JSContext *cx, CallArgs args)
  1.2432 +{
  1.2433 +    double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
  1.2434 +    if (!IsFinite(utctime)) {
  1.2435 +        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_DATE);
  1.2436 +        return false;
  1.2437 +    }
  1.2438 +
  1.2439 +    char buf[100];
  1.2440 +    print_iso_string(buf, sizeof buf, utctime);
  1.2441 +
  1.2442 +    JSString *str = JS_NewStringCopyZ(cx, buf);
  1.2443 +    if (!str)
  1.2444 +        return false;
  1.2445 +    args.rval().setString(str);
  1.2446 +    return true;
  1.2447 +
  1.2448 +}
  1.2449 +
  1.2450 +static bool
  1.2451 +date_toISOString(JSContext *cx, unsigned argc, Value *vp)
  1.2452 +{
  1.2453 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2454 +    return CallNonGenericMethod<IsDate, date_toISOString_impl>(cx, args);
  1.2455 +}
  1.2456 +
  1.2457 +/* ES5 15.9.5.44. */
  1.2458 +static bool
  1.2459 +date_toJSON(JSContext *cx, unsigned argc, Value *vp)
  1.2460 +{
  1.2461 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2462 +
  1.2463 +    /* Step 1. */
  1.2464 +    RootedObject obj(cx, ToObject(cx, args.thisv()));
  1.2465 +    if (!obj)
  1.2466 +        return false;
  1.2467 +
  1.2468 +    /* Step 2. */
  1.2469 +    RootedValue tv(cx, ObjectValue(*obj));
  1.2470 +    if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
  1.2471 +        return false;
  1.2472 +
  1.2473 +    /* Step 3. */
  1.2474 +    if (tv.isDouble() && !IsFinite(tv.toDouble())) {
  1.2475 +        args.rval().setNull();
  1.2476 +        return true;
  1.2477 +    }
  1.2478 +
  1.2479 +    /* Step 4. */
  1.2480 +    RootedValue toISO(cx);
  1.2481 +    if (!JSObject::getProperty(cx, obj, obj, cx->names().toISOString, &toISO))
  1.2482 +        return false;
  1.2483 +
  1.2484 +    /* Step 5. */
  1.2485 +    if (!js_IsCallable(toISO)) {
  1.2486 +        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
  1.2487 +                                     JSMSG_BAD_TOISOSTRING_PROP);
  1.2488 +        return false;
  1.2489 +    }
  1.2490 +
  1.2491 +    /* Step 6. */
  1.2492 +    InvokeArgs args2(cx);
  1.2493 +    if (!args2.init(0))
  1.2494 +        return false;
  1.2495 +
  1.2496 +    args2.setCallee(toISO);
  1.2497 +    args2.setThis(ObjectValue(*obj));
  1.2498 +
  1.2499 +    if (!Invoke(cx, args2))
  1.2500 +        return false;
  1.2501 +    args.rval().set(args2.rval());
  1.2502 +    return true;
  1.2503 +}
  1.2504 +
  1.2505 +/* for Date.toLocaleFormat; interface to PRMJTime date struct.
  1.2506 + */
  1.2507 +static void
  1.2508 +new_explode(double timeval, PRMJTime *split, DateTimeInfo *dtInfo)
  1.2509 +{
  1.2510 +    double year = YearFromTime(timeval);
  1.2511 +
  1.2512 +    split->tm_usec = int32_t(msFromTime(timeval)) * 1000;
  1.2513 +    split->tm_sec = int8_t(SecFromTime(timeval));
  1.2514 +    split->tm_min = int8_t(MinFromTime(timeval));
  1.2515 +    split->tm_hour = int8_t(HourFromTime(timeval));
  1.2516 +    split->tm_mday = int8_t(DateFromTime(timeval));
  1.2517 +    split->tm_mon = int8_t(MonthFromTime(timeval));
  1.2518 +    split->tm_wday = int8_t(WeekDay(timeval));
  1.2519 +    split->tm_year = year;
  1.2520 +    split->tm_yday = int16_t(DayWithinYear(timeval, year));
  1.2521 +
  1.2522 +    /* not sure how this affects things, but it doesn't seem
  1.2523 +       to matter. */
  1.2524 +    split->tm_isdst = (DaylightSavingTA(timeval, dtInfo) != 0);
  1.2525 +}
  1.2526 +
  1.2527 +typedef enum formatspec {
  1.2528 +    FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
  1.2529 +} formatspec;
  1.2530 +
  1.2531 +/* helper function */
  1.2532 +static bool
  1.2533 +date_format(JSContext *cx, double date, formatspec format, MutableHandleValue rval)
  1.2534 +{
  1.2535 +    char buf[100];
  1.2536 +    char tzbuf[100];
  1.2537 +    bool usetz;
  1.2538 +    size_t i, tzlen;
  1.2539 +    PRMJTime split;
  1.2540 +
  1.2541 +    if (!IsFinite(date)) {
  1.2542 +        JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1.2543 +    } else {
  1.2544 +        JS_ASSERT(TimeClip(date) == date);
  1.2545 +
  1.2546 +        double local = LocalTime(date, &cx->runtime()->dateTimeInfo);
  1.2547 +
  1.2548 +        /* offset from GMT in minutes.  The offset includes daylight savings,
  1.2549 +           if it applies. */
  1.2550 +        int minutes = (int) floor(AdjustTime(date, &cx->runtime()->dateTimeInfo) / msPerMinute);
  1.2551 +
  1.2552 +        /* map 510 minutes to 0830 hours */
  1.2553 +        int offset = (minutes / 60) * 100 + minutes % 60;
  1.2554 +
  1.2555 +        /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
  1.2556 +         * printed as 'GMT-0800' rather than as 'PST' to avoid
  1.2557 +         * operating-system dependence on strftime (which
  1.2558 +         * PRMJ_FormatTimeUSEnglish calls, for %Z only.)  win32 prints
  1.2559 +         * PST as 'Pacific Standard Time.'  This way we always know
  1.2560 +         * what we're getting, and can parse it if we produce it.
  1.2561 +         * The OS TZA string is included as a comment.
  1.2562 +         */
  1.2563 +
  1.2564 +        /* get a timezone string from the OS to include as a
  1.2565 +           comment. */
  1.2566 +        new_explode(date, &split, &cx->runtime()->dateTimeInfo);
  1.2567 +        if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
  1.2568 +
  1.2569 +            /* Decide whether to use the resulting timezone string.
  1.2570 +             *
  1.2571 +             * Reject it if it contains any non-ASCII, non-alphanumeric
  1.2572 +             * characters.  It's then likely in some other character
  1.2573 +             * encoding, and we probably won't display it correctly.
  1.2574 +             */
  1.2575 +            usetz = true;
  1.2576 +            tzlen = strlen(tzbuf);
  1.2577 +            if (tzlen > 100) {
  1.2578 +                usetz = false;
  1.2579 +            } else {
  1.2580 +                for (i = 0; i < tzlen; i++) {
  1.2581 +                    jschar c = tzbuf[i];
  1.2582 +                    if (c > 127 ||
  1.2583 +                        !(isalpha(c) || isdigit(c) ||
  1.2584 +                          c == ' ' || c == '(' || c == ')')) {
  1.2585 +                        usetz = false;
  1.2586 +                    }
  1.2587 +                }
  1.2588 +            }
  1.2589 +
  1.2590 +            /* Also reject it if it's not parenthesized or if it's '()'. */
  1.2591 +            if (tzbuf[0] != '(' || tzbuf[1] == ')')
  1.2592 +                usetz = false;
  1.2593 +        } else
  1.2594 +            usetz = false;
  1.2595 +
  1.2596 +        switch (format) {
  1.2597 +          case FORMATSPEC_FULL:
  1.2598 +            /*
  1.2599 +             * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
  1.2600 +             * requires a PRMJTime... which only has 16-bit years.  Sub-ECMA.
  1.2601 +             */
  1.2602 +            /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
  1.2603 +            JS_snprintf(buf, sizeof buf,
  1.2604 +                        "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
  1.2605 +                        days[int(WeekDay(local))],
  1.2606 +                        months[int(MonthFromTime(local))],
  1.2607 +                        int(DateFromTime(local)),
  1.2608 +                        int(YearFromTime(local)),
  1.2609 +                        int(HourFromTime(local)),
  1.2610 +                        int(MinFromTime(local)),
  1.2611 +                        int(SecFromTime(local)),
  1.2612 +                        offset,
  1.2613 +                        usetz ? " " : "",
  1.2614 +                        usetz ? tzbuf : "");
  1.2615 +            break;
  1.2616 +          case FORMATSPEC_DATE:
  1.2617 +            /* Tue Oct 31 2000 */
  1.2618 +            JS_snprintf(buf, sizeof buf,
  1.2619 +                        "%s %s %.2d %.4d",
  1.2620 +                        days[int(WeekDay(local))],
  1.2621 +                        months[int(MonthFromTime(local))],
  1.2622 +                        int(DateFromTime(local)),
  1.2623 +                        int(YearFromTime(local)));
  1.2624 +            break;
  1.2625 +          case FORMATSPEC_TIME:
  1.2626 +            /* 09:41:40 GMT-0800 (PST) */
  1.2627 +            JS_snprintf(buf, sizeof buf,
  1.2628 +                        "%.2d:%.2d:%.2d GMT%+.4d%s%s",
  1.2629 +                        int(HourFromTime(local)),
  1.2630 +                        int(MinFromTime(local)),
  1.2631 +                        int(SecFromTime(local)),
  1.2632 +                        offset,
  1.2633 +                        usetz ? " " : "",
  1.2634 +                        usetz ? tzbuf : "");
  1.2635 +            break;
  1.2636 +        }
  1.2637 +    }
  1.2638 +
  1.2639 +    JSString *str = JS_NewStringCopyZ(cx, buf);
  1.2640 +    if (!str)
  1.2641 +        return false;
  1.2642 +    rval.setString(str);
  1.2643 +    return true;
  1.2644 +}
  1.2645 +
  1.2646 +static bool
  1.2647 +ToLocaleFormatHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandleValue rval)
  1.2648 +{
  1.2649 +    double utctime = obj->as<DateObject>().UTCTime().toNumber();
  1.2650 +
  1.2651 +    char buf[100];
  1.2652 +    if (!IsFinite(utctime)) {
  1.2653 +        JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1.2654 +    } else {
  1.2655 +        int result_len;
  1.2656 +        double local = LocalTime(utctime, &cx->runtime()->dateTimeInfo);
  1.2657 +        PRMJTime split;
  1.2658 +        new_explode(local, &split, &cx->runtime()->dateTimeInfo);
  1.2659 +
  1.2660 +        /* Let PRMJTime format it. */
  1.2661 +        result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
  1.2662 +
  1.2663 +        /* If it failed, default to toString. */
  1.2664 +        if (result_len == 0)
  1.2665 +            return date_format(cx, utctime, FORMATSPEC_FULL, rval);
  1.2666 +
  1.2667 +        /* Hacked check against undesired 2-digit year 00/00/00 form. */
  1.2668 +        if (strcmp(format, "%x") == 0 && result_len >= 6 &&
  1.2669 +            /* Format %x means use OS settings, which may have 2-digit yr, so
  1.2670 +               hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
  1.2671 +            !isdigit(buf[result_len - 3]) &&
  1.2672 +            isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
  1.2673 +            /* ...but not if starts with 4-digit year, like 2022/3/11. */
  1.2674 +            !(isdigit(buf[0]) && isdigit(buf[1]) &&
  1.2675 +              isdigit(buf[2]) && isdigit(buf[3]))) {
  1.2676 +            JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
  1.2677 +                        "%d", js_DateGetYear(cx, obj));
  1.2678 +        }
  1.2679 +
  1.2680 +    }
  1.2681 +
  1.2682 +    if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode)
  1.2683 +        return cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, rval);
  1.2684 +
  1.2685 +    JSString *str = JS_NewStringCopyZ(cx, buf);
  1.2686 +    if (!str)
  1.2687 +        return false;
  1.2688 +    rval.setString(str);
  1.2689 +    return true;
  1.2690 +}
  1.2691 +
  1.2692 +#if !EXPOSE_INTL_API
  1.2693 +static bool
  1.2694 +ToLocaleStringHelper(JSContext *cx, Handle<DateObject*> dateObj, MutableHandleValue rval)
  1.2695 +{
  1.2696 +    /*
  1.2697 +     * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
  1.2698 +     * with msvc; '%#c' requests that a full year be used in the result string.
  1.2699 +     */
  1.2700 +    return ToLocaleFormatHelper(cx, dateObj,
  1.2701 +#if defined(_WIN32) && !defined(__MWERKS__)
  1.2702 +                          "%#c"
  1.2703 +#else
  1.2704 +                          "%c"
  1.2705 +#endif
  1.2706 +                         , rval);
  1.2707 +}
  1.2708 +
  1.2709 +/* ES5 15.9.5.5. */
  1.2710 +MOZ_ALWAYS_INLINE bool
  1.2711 +date_toLocaleString_impl(JSContext *cx, CallArgs args)
  1.2712 +{
  1.2713 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2714 +    return ToLocaleStringHelper(cx, dateObj, args.rval());
  1.2715 +}
  1.2716 +
  1.2717 +static bool
  1.2718 +date_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
  1.2719 +{
  1.2720 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2721 +    return CallNonGenericMethod<IsDate, date_toLocaleString_impl>(cx, args);
  1.2722 +}
  1.2723 +
  1.2724 +/* ES5 15.9.5.6. */
  1.2725 +MOZ_ALWAYS_INLINE bool
  1.2726 +date_toLocaleDateString_impl(JSContext *cx, CallArgs args)
  1.2727 +{
  1.2728 +    /*
  1.2729 +     * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
  1.2730 +     * with msvc; '%#x' requests that a full year be used in the result string.
  1.2731 +     */
  1.2732 +    static const char format[] =
  1.2733 +#if defined(_WIN32) && !defined(__MWERKS__)
  1.2734 +                                   "%#x"
  1.2735 +#else
  1.2736 +                                   "%x"
  1.2737 +#endif
  1.2738 +                                   ;
  1.2739 +
  1.2740 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2741 +    return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
  1.2742 +}
  1.2743 +
  1.2744 +static bool
  1.2745 +date_toLocaleDateString(JSContext *cx, unsigned argc, Value *vp)
  1.2746 +{
  1.2747 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2748 +    return CallNonGenericMethod<IsDate, date_toLocaleDateString_impl>(cx, args);
  1.2749 +}
  1.2750 +
  1.2751 +/* ES5 15.9.5.7. */
  1.2752 +MOZ_ALWAYS_INLINE bool
  1.2753 +date_toLocaleTimeString_impl(JSContext *cx, CallArgs args)
  1.2754 +{
  1.2755 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2756 +    return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval());
  1.2757 +}
  1.2758 +
  1.2759 +static bool
  1.2760 +date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp)
  1.2761 +{
  1.2762 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2763 +    return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args);
  1.2764 +}
  1.2765 +#endif /* !EXPOSE_INTL_API */
  1.2766 +
  1.2767 +MOZ_ALWAYS_INLINE bool
  1.2768 +date_toLocaleFormat_impl(JSContext *cx, CallArgs args)
  1.2769 +{
  1.2770 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2771 +
  1.2772 +    if (args.length() == 0) {
  1.2773 +        /*
  1.2774 +         * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
  1.2775 +         * with msvc; '%#c' requests that a full year be used in the result string.
  1.2776 +         */
  1.2777 +        return ToLocaleFormatHelper(cx, dateObj,
  1.2778 +#if defined(_WIN32) && !defined(__MWERKS__)
  1.2779 +                              "%#c"
  1.2780 +#else
  1.2781 +                              "%c"
  1.2782 +#endif
  1.2783 +                             , args.rval());
  1.2784 +    }
  1.2785 +
  1.2786 +    RootedString fmt(cx, ToString<CanGC>(cx, args[0]));
  1.2787 +    if (!fmt)
  1.2788 +        return false;
  1.2789 +
  1.2790 +    JSAutoByteString fmtbytes(cx, fmt);
  1.2791 +    if (!fmtbytes)
  1.2792 +        return false;
  1.2793 +
  1.2794 +    return ToLocaleFormatHelper(cx, dateObj, fmtbytes.ptr(), args.rval());
  1.2795 +}
  1.2796 +
  1.2797 +static bool
  1.2798 +date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
  1.2799 +{
  1.2800 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2801 +    return CallNonGenericMethod<IsDate, date_toLocaleFormat_impl>(cx, args);
  1.2802 +}
  1.2803 +
  1.2804 +/* ES5 15.9.5.4. */
  1.2805 +MOZ_ALWAYS_INLINE bool
  1.2806 +date_toTimeString_impl(JSContext *cx, CallArgs args)
  1.2807 +{
  1.2808 +    return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
  1.2809 +                       FORMATSPEC_TIME, args.rval());
  1.2810 +}
  1.2811 +
  1.2812 +static bool
  1.2813 +date_toTimeString(JSContext *cx, unsigned argc, Value *vp)
  1.2814 +{
  1.2815 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2816 +    return CallNonGenericMethod<IsDate, date_toTimeString_impl>(cx, args);
  1.2817 +}
  1.2818 +
  1.2819 +/* ES5 15.9.5.3. */
  1.2820 +MOZ_ALWAYS_INLINE bool
  1.2821 +date_toDateString_impl(JSContext *cx, CallArgs args)
  1.2822 +{
  1.2823 +    return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
  1.2824 +                       FORMATSPEC_DATE, args.rval());
  1.2825 +}
  1.2826 +
  1.2827 +static bool
  1.2828 +date_toDateString(JSContext *cx, unsigned argc, Value *vp)
  1.2829 +{
  1.2830 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2831 +    return CallNonGenericMethod<IsDate, date_toDateString_impl>(cx, args);
  1.2832 +}
  1.2833 +
  1.2834 +#if JS_HAS_TOSOURCE
  1.2835 +MOZ_ALWAYS_INLINE bool
  1.2836 +date_toSource_impl(JSContext *cx, CallArgs args)
  1.2837 +{
  1.2838 +    StringBuffer sb(cx);
  1.2839 +    if (!sb.append("(new Date(") ||
  1.2840 +        !NumberValueToStringBuffer(cx, args.thisv().toObject().as<DateObject>().UTCTime(), sb) ||
  1.2841 +        !sb.append("))"))
  1.2842 +    {
  1.2843 +        return false;
  1.2844 +    }
  1.2845 +
  1.2846 +    JSString *str = sb.finishString();
  1.2847 +    if (!str)
  1.2848 +        return false;
  1.2849 +    args.rval().setString(str);
  1.2850 +    return true;
  1.2851 +}
  1.2852 +
  1.2853 +static bool
  1.2854 +date_toSource(JSContext *cx, unsigned argc, Value *vp)
  1.2855 +{
  1.2856 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2857 +    return CallNonGenericMethod<IsDate, date_toSource_impl>(cx, args);
  1.2858 +}
  1.2859 +#endif
  1.2860 +
  1.2861 +MOZ_ALWAYS_INLINE bool
  1.2862 +date_toString_impl(JSContext *cx, CallArgs args)
  1.2863 +{
  1.2864 +    return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
  1.2865 +                       FORMATSPEC_FULL, args.rval());
  1.2866 +}
  1.2867 +
  1.2868 +static bool
  1.2869 +date_toString(JSContext *cx, unsigned argc, Value *vp)
  1.2870 +{
  1.2871 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2872 +    return CallNonGenericMethod<IsDate, date_toString_impl>(cx, args);
  1.2873 +}
  1.2874 +
  1.2875 +MOZ_ALWAYS_INLINE bool
  1.2876 +date_valueOf_impl(JSContext *cx, CallArgs args)
  1.2877 +{
  1.2878 +    Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
  1.2879 +    args.rval().set(dateObj->UTCTime());
  1.2880 +    return true;
  1.2881 +}
  1.2882 +
  1.2883 +static bool
  1.2884 +date_valueOf(JSContext *cx, unsigned argc, Value *vp)
  1.2885 +{
  1.2886 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2887 +    return CallNonGenericMethod<IsDate, date_valueOf_impl>(cx, args);
  1.2888 +}
  1.2889 +
  1.2890 +static const JSFunctionSpec date_static_methods[] = {
  1.2891 +    JS_FN("UTC",                 date_UTC,                MAXARGS,0),
  1.2892 +    JS_FN("parse",               date_parse,              1,0),
  1.2893 +    JS_FN("now",                 date_now,                0,0),
  1.2894 +    JS_FS_END
  1.2895 +};
  1.2896 +
  1.2897 +static const JSFunctionSpec date_methods[] = {
  1.2898 +    JS_FN("getTime",             date_getTime,            0,0),
  1.2899 +    JS_FN("getTimezoneOffset",   date_getTimezoneOffset,  0,0),
  1.2900 +    JS_FN("getYear",             date_getYear,            0,0),
  1.2901 +    JS_FN("getFullYear",         date_getFullYear,        0,0),
  1.2902 +    JS_FN("getUTCFullYear",      date_getUTCFullYear,     0,0),
  1.2903 +    JS_FN("getMonth",            date_getMonth,           0,0),
  1.2904 +    JS_FN("getUTCMonth",         date_getUTCMonth,        0,0),
  1.2905 +    JS_FN("getDate",             date_getDate,            0,0),
  1.2906 +    JS_FN("getUTCDate",          date_getUTCDate,         0,0),
  1.2907 +    JS_FN("getDay",              date_getDay,             0,0),
  1.2908 +    JS_FN("getUTCDay",           date_getUTCDay,          0,0),
  1.2909 +    JS_FN("getHours",            date_getHours,           0,0),
  1.2910 +    JS_FN("getUTCHours",         date_getUTCHours,        0,0),
  1.2911 +    JS_FN("getMinutes",          date_getMinutes,         0,0),
  1.2912 +    JS_FN("getUTCMinutes",       date_getUTCMinutes,      0,0),
  1.2913 +    JS_FN("getSeconds",          date_getUTCSeconds,      0,0),
  1.2914 +    JS_FN("getUTCSeconds",       date_getUTCSeconds,      0,0),
  1.2915 +    JS_FN("getMilliseconds",     date_getUTCMilliseconds, 0,0),
  1.2916 +    JS_FN("getUTCMilliseconds",  date_getUTCMilliseconds, 0,0),
  1.2917 +    JS_FN("setTime",             date_setTime,            1,0),
  1.2918 +    JS_FN("setYear",             date_setYear,            1,0),
  1.2919 +    JS_FN("setFullYear",         date_setFullYear,        3,0),
  1.2920 +    JS_FN("setUTCFullYear",      date_setUTCFullYear,     3,0),
  1.2921 +    JS_FN("setMonth",            date_setMonth,           2,0),
  1.2922 +    JS_FN("setUTCMonth",         date_setUTCMonth,        2,0),
  1.2923 +    JS_FN("setDate",             date_setDate,            1,0),
  1.2924 +    JS_FN("setUTCDate",          date_setUTCDate,         1,0),
  1.2925 +    JS_FN("setHours",            date_setHours,           4,0),
  1.2926 +    JS_FN("setUTCHours",         date_setUTCHours,        4,0),
  1.2927 +    JS_FN("setMinutes",          date_setMinutes,         3,0),
  1.2928 +    JS_FN("setUTCMinutes",       date_setUTCMinutes,      3,0),
  1.2929 +    JS_FN("setSeconds",          date_setSeconds,         2,0),
  1.2930 +    JS_FN("setUTCSeconds",       date_setUTCSeconds,      2,0),
  1.2931 +    JS_FN("setMilliseconds",     date_setMilliseconds,    1,0),
  1.2932 +    JS_FN("setUTCMilliseconds",  date_setUTCMilliseconds, 1,0),
  1.2933 +    JS_FN("toUTCString",         date_toGMTString,        0,0),
  1.2934 +    JS_FN("toLocaleFormat",      date_toLocaleFormat,     0,0),
  1.2935 +#if EXPOSE_INTL_API
  1.2936 +    JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0,0),
  1.2937 +    JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0),
  1.2938 +    JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0),
  1.2939 +#else
  1.2940 +    JS_FN(js_toLocaleString_str, date_toLocaleString,     0,0),
  1.2941 +    JS_FN("toLocaleDateString",  date_toLocaleDateString, 0,0),
  1.2942 +    JS_FN("toLocaleTimeString",  date_toLocaleTimeString, 0,0),
  1.2943 +#endif
  1.2944 +    JS_FN("toDateString",        date_toDateString,       0,0),
  1.2945 +    JS_FN("toTimeString",        date_toTimeString,       0,0),
  1.2946 +    JS_FN("toISOString",         date_toISOString,        0,0),
  1.2947 +    JS_FN(js_toJSON_str,         date_toJSON,             1,0),
  1.2948 +#if JS_HAS_TOSOURCE
  1.2949 +    JS_FN(js_toSource_str,       date_toSource,           0,0),
  1.2950 +#endif
  1.2951 +    JS_FN(js_toString_str,       date_toString,           0,0),
  1.2952 +    JS_FN(js_valueOf_str,        date_valueOf,            0,0),
  1.2953 +    JS_FS_END
  1.2954 +};
  1.2955 +
  1.2956 +bool
  1.2957 +js_Date(JSContext *cx, unsigned argc, Value *vp)
  1.2958 +{
  1.2959 +    CallArgs args = CallArgsFromVp(argc, vp);
  1.2960 +
  1.2961 +    /* Date called as function. */
  1.2962 +    if (!args.isConstructing())
  1.2963 +        return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args.rval());
  1.2964 +
  1.2965 +    /* Date called as constructor. */
  1.2966 +    double d;
  1.2967 +    if (args.length() == 0) {
  1.2968 +        /* ES5 15.9.3.3. */
  1.2969 +        d = NowAsMillis();
  1.2970 +    } else if (args.length() == 1) {
  1.2971 +        /* ES5 15.9.3.2. */
  1.2972 +
  1.2973 +        /* Step 1. */
  1.2974 +        if (!ToPrimitive(cx, args[0]))
  1.2975 +            return false;
  1.2976 +
  1.2977 +        if (args[0].isString()) {
  1.2978 +            /* Step 2. */
  1.2979 +            JSString *str = args[0].toString();
  1.2980 +            if (!str)
  1.2981 +                return false;
  1.2982 +
  1.2983 +            JSLinearString *linearStr = str->ensureLinear(cx);
  1.2984 +            if (!linearStr)
  1.2985 +                return false;
  1.2986 +
  1.2987 +            if (!date_parseString(linearStr, &d, &cx->runtime()->dateTimeInfo))
  1.2988 +                d = GenericNaN();
  1.2989 +            else
  1.2990 +                d = TimeClip(d);
  1.2991 +        } else {
  1.2992 +            /* Step 3. */
  1.2993 +            if (!ToNumber(cx, args[0], &d))
  1.2994 +                return false;
  1.2995 +            d = TimeClip(d);
  1.2996 +        }
  1.2997 +    } else {
  1.2998 +        double msec_time;
  1.2999 +        if (!date_msecFromArgs(cx, args, &msec_time))
  1.3000 +            return false;
  1.3001 +
  1.3002 +        if (IsFinite(msec_time)) {
  1.3003 +            msec_time = UTC(msec_time, &cx->runtime()->dateTimeInfo);
  1.3004 +            msec_time = TimeClip(msec_time);
  1.3005 +        }
  1.3006 +        d = msec_time;
  1.3007 +    }
  1.3008 +
  1.3009 +    JSObject *obj = js_NewDateObjectMsec(cx, d);
  1.3010 +    if (!obj)
  1.3011 +        return false;
  1.3012 +
  1.3013 +    args.rval().setObject(*obj);
  1.3014 +    return true;
  1.3015 +}
  1.3016 +
  1.3017 +static bool
  1.3018 +FinishDateClassInit(JSContext *cx, HandleObject ctor, HandleObject proto)
  1.3019 +{
  1.3020 +    proto->as<DateObject>().setUTCTime(GenericNaN());
  1.3021 +
  1.3022 +    /*
  1.3023 +     * Date.prototype.toGMTString has the same initial value as
  1.3024 +     * Date.prototype.toUTCString.
  1.3025 +     */
  1.3026 +    RootedValue toUTCStringFun(cx);
  1.3027 +    RootedId toUTCStringId(cx, NameToId(cx->names().toUTCString));
  1.3028 +    RootedId toGMTStringId(cx, NameToId(cx->names().toGMTString));
  1.3029 +    return baseops::GetProperty(cx, proto, toUTCStringId, &toUTCStringFun) &&
  1.3030 +           baseops::DefineGeneric(cx, proto, toGMTStringId, toUTCStringFun,
  1.3031 +                                  JS_PropertyStub, JS_StrictPropertyStub, 0);
  1.3032 +}
  1.3033 +
  1.3034 +const Class DateObject::class_ = {
  1.3035 +    js_Date_str,
  1.3036 +    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
  1.3037 +    JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
  1.3038 +    JS_PropertyStub,         /* addProperty */
  1.3039 +    JS_DeletePropertyStub,   /* delProperty */
  1.3040 +    JS_PropertyStub,         /* getProperty */
  1.3041 +    JS_StrictPropertyStub,   /* setProperty */
  1.3042 +    JS_EnumerateStub,
  1.3043 +    JS_ResolveStub,
  1.3044 +    date_convert,
  1.3045 +    nullptr,                 /* finalize */
  1.3046 +    nullptr,                 /* call */
  1.3047 +    nullptr,                 /* hasInstance */
  1.3048 +    nullptr,                 /* construct */
  1.3049 +    nullptr,                 /* trace */
  1.3050 +    {
  1.3051 +        GenericCreateConstructor<js_Date, NAME_OFFSET(Date), MAXARGS>,
  1.3052 +        GenericCreatePrototype<&DateObject::class_>,
  1.3053 +        date_static_methods,
  1.3054 +        date_methods,
  1.3055 +        FinishDateClassInit
  1.3056 +    }
  1.3057 +};
  1.3058 +
  1.3059 +JS_FRIEND_API(JSObject *)
  1.3060 +js_NewDateObjectMsec(JSContext *cx, double msec_time)
  1.3061 +{
  1.3062 +    JSObject *obj = NewBuiltinClassInstance(cx, &DateObject::class_);
  1.3063 +    if (!obj)
  1.3064 +        return nullptr;
  1.3065 +    obj->as<DateObject>().setUTCTime(msec_time);
  1.3066 +    return obj;
  1.3067 +}
  1.3068 +
  1.3069 +JS_FRIEND_API(JSObject *)
  1.3070 +js_NewDateObject(JSContext *cx, int year, int mon, int mday,
  1.3071 +                 int hour, int min, int sec)
  1.3072 +{
  1.3073 +    JS_ASSERT(mon < 12);
  1.3074 +    double msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
  1.3075 +    return js_NewDateObjectMsec(cx, UTC(msec_time, &cx->runtime()->dateTimeInfo));
  1.3076 +}
  1.3077 +
  1.3078 +JS_FRIEND_API(bool)
  1.3079 +js_DateIsValid(JSObject *obj)
  1.3080 +{
  1.3081 +    return obj->is<DateObject>() && !IsNaN(obj->as<DateObject>().UTCTime().toNumber());
  1.3082 +}
  1.3083 +
  1.3084 +JS_FRIEND_API(int)
  1.3085 +js_DateGetYear(JSContext *cx, JSObject *obj)
  1.3086 +{
  1.3087 +    /* Preserve legacy API behavior of returning 0 for invalid dates. */
  1.3088 +    JS_ASSERT(obj);
  1.3089 +    double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.3090 +    if (IsNaN(localtime))
  1.3091 +        return 0;
  1.3092 +
  1.3093 +    return (int) YearFromTime(localtime);
  1.3094 +}
  1.3095 +
  1.3096 +JS_FRIEND_API(int)
  1.3097 +js_DateGetMonth(JSContext *cx, JSObject *obj)
  1.3098 +{
  1.3099 +    JS_ASSERT(obj);
  1.3100 +    double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.3101 +    if (IsNaN(localtime))
  1.3102 +        return 0;
  1.3103 +
  1.3104 +    return (int) MonthFromTime(localtime);
  1.3105 +}
  1.3106 +
  1.3107 +JS_FRIEND_API(int)
  1.3108 +js_DateGetDate(JSContext *cx, JSObject *obj)
  1.3109 +{
  1.3110 +    JS_ASSERT(obj);
  1.3111 +    double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.3112 +    if (IsNaN(localtime))
  1.3113 +        return 0;
  1.3114 +
  1.3115 +    return (int) DateFromTime(localtime);
  1.3116 +}
  1.3117 +
  1.3118 +JS_FRIEND_API(int)
  1.3119 +js_DateGetHours(JSContext *cx, JSObject *obj)
  1.3120 +{
  1.3121 +    JS_ASSERT(obj);
  1.3122 +    double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.3123 +    if (IsNaN(localtime))
  1.3124 +        return 0;
  1.3125 +
  1.3126 +    return (int) HourFromTime(localtime);
  1.3127 +}
  1.3128 +
  1.3129 +JS_FRIEND_API(int)
  1.3130 +js_DateGetMinutes(JSContext *cx, JSObject *obj)
  1.3131 +{
  1.3132 +    JS_ASSERT(obj);
  1.3133 +    double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
  1.3134 +    if (IsNaN(localtime))
  1.3135 +        return 0;
  1.3136 +
  1.3137 +    return (int) MinFromTime(localtime);
  1.3138 +}
  1.3139 +
  1.3140 +JS_FRIEND_API(int)
  1.3141 +js_DateGetSeconds(JSObject *obj)
  1.3142 +{
  1.3143 +    if (!obj->is<DateObject>())
  1.3144 +        return 0;
  1.3145 +
  1.3146 +    double utctime = obj->as<DateObject>().UTCTime().toNumber();
  1.3147 +    if (IsNaN(utctime))
  1.3148 +        return 0;
  1.3149 +    return (int) SecFromTime(utctime);
  1.3150 +}
  1.3151 +
  1.3152 +JS_FRIEND_API(double)
  1.3153 +js_DateGetMsecSinceEpoch(JSObject *obj)
  1.3154 +{
  1.3155 +    return obj->is<DateObject>() ? obj->as<DateObject>().UTCTime().toNumber() : 0;
  1.3156 +}
  1.3157 +
  1.3158 +
  1.3159 +static const NativeImpl sReadOnlyDateMethods[] = {
  1.3160 +    DateObject::getTime_impl,
  1.3161 +    DateObject::getYear_impl,
  1.3162 +    DateObject::getFullYear_impl,
  1.3163 +    DateObject::getUTCFullYear_impl,
  1.3164 +    DateObject::getMonth_impl,
  1.3165 +    DateObject::getUTCMonth_impl,
  1.3166 +    DateObject::getDate_impl,
  1.3167 +    DateObject::getUTCDate_impl,
  1.3168 +    DateObject::getDay_impl,
  1.3169 +    DateObject::getUTCDay_impl,
  1.3170 +    DateObject::getHours_impl,
  1.3171 +    DateObject::getUTCHours_impl,
  1.3172 +    DateObject::getMinutes_impl,
  1.3173 +    DateObject::getUTCMinutes_impl,
  1.3174 +    DateObject::getUTCSeconds_impl,
  1.3175 +    DateObject::getUTCMilliseconds_impl,
  1.3176 +    DateObject::getTimezoneOffset_impl,
  1.3177 +    date_toGMTString_impl,
  1.3178 +    date_toISOString_impl,
  1.3179 +    date_toLocaleFormat_impl,
  1.3180 +    date_toTimeString_impl,
  1.3181 +    date_toDateString_impl,
  1.3182 +    date_toSource_impl,
  1.3183 +    date_toString_impl,
  1.3184 +    date_valueOf_impl
  1.3185 +};

mercurial