LCOV - app.info - js/src/jsdate.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jsdate.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1194 | 829 | 69.4 %
| Date: | 2012-04-07 | Functions: | 105 | 92 | 87.6 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=78:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla Communicator client code, released
          18                 :  * March 31, 1998.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  * Netscape Communications Corporation.
          22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          23                 :  * the Initial Developer. All Rights Reserved.
          24                 :  *
          25                 :  * Contributor(s):
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : /*
          42                 :  * JS date methods.
          43                 :  */
          44                 :
          45                 : /*
          46                 :  * "For example, OS/360 devotes 26 bytes of the permanently
          47                 :  *  resident date-turnover routine to the proper handling of
          48                 :  *  December 31 on leap years (when it is Day 366).  That
          49                 :  *  might have been left to the operator."
          50                 :  *
          51                 :  * Frederick Brooks, 'The Second-System Effect'.
          52                 :  */
          53                 :
          54                 : #include <ctype.h>
          55                 : #include <locale.h>
          56                 : #include <math.h>
          57                 : #include <stdlib.h>
          58                 : #include <string.h>
          59                 :
          60                 : #include "mozilla/Util.h"
          61                 :
          62                 : #include "jstypes.h"
          63                 : #include "jsprf.h"
          64                 : #include "prmjtime.h"
          65                 : #include "jsutil.h"
          66                 : #include "jsapi.h"
          67                 : #include "jsversion.h"
          68                 : #include "jscntxt.h"
          69                 : #include "jsdate.h"
          70                 : #include "jsinterp.h"
          71                 : #include "jsnum.h"
          72                 : #include "jsobj.h"
          73                 : #include "jsstr.h"
          74                 : #include "jslibmath.h"
          75                 :
          76                 : #include "vm/GlobalObject.h"
          77                 : #include "vm/StringBuffer.h"
          78                 :
          79                 : #include "jsinferinlines.h"
          80                 : #include "jsobjinlines.h"
          81                 :
          82                 : #include "vm/MethodGuard-inl.h"
          83                 : #include "vm/Stack-inl.h"
          84                 :
          85                 : using namespace mozilla;
          86                 : using namespace js;
          87                 : using namespace js::types;
          88                 :
          89                 : /*
          90                 :  * The JS 'Date' object is patterned after the Java 'Date' object.
          91                 :  * Here is an script:
          92                 :  *
          93                 :  *    today = new Date();
          94                 :  *
          95                 :  *    print(today.toLocaleString());
          96                 :  *
          97                 :  *    weekDay = today.getDay();
          98                 :  *
          99                 :  *
         100                 :  * These Java (and ECMA-262) methods are supported:
         101                 :  *
         102                 :  *     UTC
         103                 :  *     getDate (getUTCDate)
         104                 :  *     getDay (getUTCDay)
         105                 :  *     getHours (getUTCHours)
         106                 :  *     getMinutes (getUTCMinutes)
         107                 :  *     getMonth (getUTCMonth)
         108                 :  *     getSeconds (getUTCSeconds)
         109                 :  *     getMilliseconds (getUTCMilliseconds)
         110                 :  *     getTime
         111                 :  *     getTimezoneOffset
         112                 :  *     getYear
         113                 :  *     getFullYear (getUTCFullYear)
         114                 :  *     parse
         115                 :  *     setDate (setUTCDate)
         116                 :  *     setHours (setUTCHours)
         117                 :  *     setMinutes (setUTCMinutes)
         118                 :  *     setMonth (setUTCMonth)
         119                 :  *     setSeconds (setUTCSeconds)
         120                 :  *     setMilliseconds (setUTCMilliseconds)
         121                 :  *     setTime
         122                 :  *     setYear (setFullYear, setUTCFullYear)
         123                 :  *     toGMTString (toUTCString)
         124                 :  *     toLocaleString
         125                 :  *     toString
         126                 :  *
         127                 :  *
         128                 :  * These Java methods are not supported
         129                 :  *
         130                 :  *     setDay
         131                 :  *     before
         132                 :  *     after
         133                 :  *     equals
         134                 :  *     hashCode
         135                 :  */
         136                 :
         137                 : /*
         138                 :  * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
         139                 :  * definition and reduce dependence on NSPR.  NSPR is used to get the current
         140                 :  * time in milliseconds, the time zone offset, and the daylight savings time
         141                 :  * offset for a given time.  NSPR is also used for Date.toLocaleString(), for
         142                 :  * locale-specific formatting, and to get a string representing the timezone.
         143                 :  * (Which turns out to be platform-dependent.)
         144                 :  *
         145                 :  * To do:
         146                 :  * (I did some performance tests by timing how long it took to run what
         147                 :  *  I had of the js ECMA conformance tests.)
         148                 :  *
         149                 :  * - look at saving results across multiple calls to supporting
         150                 :  * functions; the toString functions compute some of the same values
         151                 :  * multiple times.  Although - I took a quick stab at this, and I lost
         152                 :  * rather than gained.  (Fractionally.)  Hard to tell what compilers/processors
         153                 :  * are doing these days.
         154                 :  *
         155                 :  * - look at tweaking function return types to return double instead
         156                 :  * of int; this seems to make things run slightly faster sometimes.
         157                 :  * (though it could be architecture-dependent.)  It'd be good to see
         158                 :  * how this does on win32.  (Tried it on irix.)  Types could use a
         159                 :  * general going-over.
         160                 :  */
         161                 :
         162                 : /*
         163                 :  * Supporting functions - ECMA 15.9.1.*
         164                 :  */
         165                 :
         166                 : #define HoursPerDay     24.0
         167                 : #define MinutesPerDay   (HoursPerDay * MinutesPerHour)
         168                 : #define MinutesPerHour  60.0
         169                 : #define SecondsPerDay   (MinutesPerDay * SecondsPerMinute)
         170                 : #define SecondsPerHour  (MinutesPerHour * SecondsPerMinute)
         171                 : #define SecondsPerMinute 60.0
         172                 :
         173                 : #if defined(XP_WIN) || defined(XP_OS2)
         174                 : /* Work around msvc double optimization bug by making these runtime values; if
         175                 :  * they're available at compile time, msvc optimizes division by them by
         176                 :  * computing the reciprocal and multiplying instead of dividing - this loses
         177                 :  * when the reciprocal isn't representable in a double.
         178                 :  */
         179                 : static double msPerSecond = 1000.0;
         180                 : static double msPerDay = SecondsPerDay * 1000.0;
         181                 : static double msPerHour = SecondsPerHour * 1000.0;
         182                 : static double msPerMinute = SecondsPerMinute * 1000.0;
         183                 : #else
         184                 : #define msPerDay        (SecondsPerDay * msPerSecond)
         185                 : #define msPerHour       (SecondsPerHour * msPerSecond)
         186                 : #define msPerMinute     (SecondsPerMinute * msPerSecond)
         187                 : #define msPerSecond     1000.0
         188                 : #endif
         189                 :
         190                 : #define Day(t)          floor((t) / msPerDay)
         191                 :
         192                 : static double
         193               9 : TimeWithinDay(double t)
         194                 : {
         195                 :     double result;
         196               9 :     result = fmod(t, msPerDay);
         197               9 :     if (result < 0)
         198               0 :         result += msPerDay;
         199               9 :     return result;
         200                 : }
         201                 :
         202                 : static inline bool
         203           69759 : IsLeapYear(int year)
         204                 : {
         205           69759 :     return year % 4 == 0 && (year % 100 || (year % 400 == 0));
         206                 : }
         207                 :
         208                 : static inline int
         209           59985 : DaysInYear(int year)
         210                 : {
         211           59985 :     return IsLeapYear(year) ? 366 : 365;
         212                 : }
         213                 :
         214                 : static inline int
         215             702 : DaysInFebruary(int year)
         216                 : {
         217             702 :     return IsLeapYear(year) ? 29 : 28;
         218                 : }
         219                 :
         220                 : /* math here has to be f.p, because we need
         221                 :  *  floor((1968 - 1969) / 4) == -1
         222                 :  */
         223                 : #define DayFromYear(y)  (365 * ((y)-1970) + floor(((y)-1969)/4.0)            \
         224                 :                          - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
         225                 : #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
         226                 :
         227                 : static int
         228            1188 : YearFromTime(double t)
         229                 : {
         230            1188 :     int y = (int) floor(t /(msPerDay*365.2425)) + 1970;
         231            1188 :     double t2 = (double) TimeFromYear(y);
         232                 :
         233                 :     /*
         234                 :      * Adjust the year if the approximation was wrong.  Since the year was
         235                 :      * computed using the average number of ms per year, it will usually
         236                 :      * be wrong for dates within several hours of a year transition.
         237                 :      */
         238            1188 :     if (t2 > t) {
         239               0 :         y--;
         240                 :     } else {
         241            1188 :         if (t2 + msPerDay * DaysInYear(y) <= t)
         242              27 :             y++;
         243                 :     }
         244            1188 :     return y;
         245                 : }
         246                 :
         247                 : #define DayWithinYear(t, year) ((int) (Day(t) - DayFromYear(year)))
         248                 :
         249                 : /*
         250                 :  * The following array contains the day of year for the first day of
         251                 :  * each month, where index 0 is January, and day 0 is January 1.
         252                 :  */
         253                 : static double firstDayOfMonth[2][13] = {
         254                 :     {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0, 365.0},
         255                 :     {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0, 366.0}
         256                 : };
         257                 :
         258                 : #define DayFromMonth(m, leap) firstDayOfMonth[leap][(int)m]
         259                 :
         260                 : static int
         261               9 : DaysInMonth(int year, int month)
         262                 : {
         263               9 :     JSBool leap = IsLeapYear(year);
         264               9 :     int result = int(DayFromMonth(month, leap) - DayFromMonth(month-1, leap));
         265               9 :     return result;
         266                 : }
         267                 :
         268                 : static int
         269             396 : MonthFromTime(double t)
         270                 : {
         271                 :     int d, step;
         272             396 :     int year = YearFromTime(t);
         273             396 :     d = DayWithinYear(t, year);
         274                 :
         275             396 :     if (d < (step = 31))
         276              45 :         return 0;
         277             351 :     if (d < (step += DaysInFebruary(year)))
         278               9 :         return 1;
         279             342 :     if (d < (step += 31))
         280               0 :         return 2;
         281             342 :     if (d < (step += 30))
         282             324 :         return 3;
         283              18 :     if (d < (step += 31))
         284               0 :         return 4;
         285              18 :     if (d < (step += 30))
         286               0 :         return 5;
         287              18 :     if (d < (step += 31))
         288               0 :         return 6;
         289              18 :     if (d < (step += 31))
         290              18 :         return 7;
         291               0 :     if (d < (step += 30))
         292               0 :         return 8;
         293               0 :     if (d < (step += 31))
         294               0 :         return 9;
         295               0 :     if (d < (step += 30))
         296               0 :         return 10;
         297               0 :     return 11;
         298                 : }
         299                 :
         300                 : static int
         301             396 : DateFromTime(double t)
         302                 : {
         303                 :     int d, step, next;
         304             396 :     int year = YearFromTime(t);
         305             396 :     d = DayWithinYear(t, year);
         306                 :
         307             396 :     if (d <= (next = 30))
         308              45 :         return d + 1;
         309             351 :     step = next;
         310             351 :     if (d <= (next += DaysInFebruary(year)))
         311               9 :         return d - step;
         312             342 :     step = next;
         313             342 :     if (d <= (next += 31))
         314               0 :         return d - step;
         315             342 :     step = next;
         316             342 :     if (d <= (next += 30))
         317             324 :         return d - step;
         318              18 :     step = next;
         319              18 :     if (d <= (next += 31))
         320               0 :         return d - step;
         321              18 :     step = next;
         322              18 :     if (d <= (next += 30))
         323               0 :         return d - step;
         324              18 :     step = next;
         325              18 :     if (d <= (next += 31))
         326               0 :         return d - step;
         327              18 :     step = next;
         328              18 :     if (d <= (next += 31))
         329              18 :         return d - step;
         330               0 :     step = next;
         331               0 :     if (d <= (next += 30))
         332               0 :         return d - step;
         333               0 :     step = next;
         334               0 :     if (d <= (next += 31))
         335               0 :         return d - step;
         336               0 :     step = next;
         337               0 :     if (d <= (next += 30))
         338               0 :         return d - step;
         339               0 :     step = next;
         340               0 :     return d - step;
         341                 : }
         342                 :
         343                 : static int
         344           50067 : WeekDay(double t)
         345                 : {
         346                 :     int result;
         347           50067 :     result = (int) Day(t) + 4;
         348           50067 :     result = result % 7;
         349           50067 :     if (result < 0)
         350               0 :         result += 7;
         351           50067 :     return (int) result;
         352                 : }
         353                 :
         354                 : #define MakeTime(hour, min, sec, ms) \
         355                 : ((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
         356                 :
         357                 : static double
         358            9054 : MakeDay(double year, double month, double date)
         359                 : {
         360                 :     JSBool leap;
         361                 :     double yearday;
         362                 :     double monthday;
         363                 :
         364            9054 :     year += floor(month / 12);
         365                 :
         366            9054 :     month = fmod(month, 12.0);
         367            9054 :     if (month < 0)
         368               0 :         month += 12;
         369                 :
         370            9054 :     leap = IsLeapYear((int) year);
         371                 :
         372            9054 :     yearday = floor(TimeFromYear(year) / msPerDay);
         373            9054 :     monthday = DayFromMonth(month, leap);
         374                 :
         375            9054 :     return yearday + monthday + date - 1;
         376                 : }
         377                 :
         378                 : #define MakeDate(day, time) ((day) * msPerDay + (time))
         379                 :
         380                 : /*
         381                 :  * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
         382                 :  *
         383                 :  * yearStartingWith[0][i] is an example non-leap year where
         384                 :  * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
         385                 :  *
         386                 :  * yearStartingWith[1][i] is an example leap year where
         387                 :  * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
         388                 :  */
         389                 : static int yearStartingWith[2][7] = {
         390                 :     {1978, 1973, 1974, 1975, 1981, 1971, 1977},
         391                 :     {1984, 1996, 1980, 1992, 1976, 1988, 1972}
         392                 : };
         393                 :
         394                 : /*
         395                 :  * Find a year for which any given date will fall on the same weekday.
         396                 :  *
         397                 :  * This function should be used with caution when used other than
         398                 :  * for determining DST; it hasn't been proven not to produce an
         399                 :  * incorrect year for times near year boundaries.
         400                 :  */
         401                 : static int
         402               9 : EquivalentYearForDST(int year)
         403                 : {
         404                 :     int day;
         405                 :
         406               9 :     day = (int) DayFromYear(year) + 4;
         407               9 :     day = day % 7;
         408               9 :     if (day < 0)
         409               9 :         day += 7;
         410                 :
         411               9 :     return yearStartingWith[IsLeapYear(year)][day];
         412                 : }
         413                 :
         414                 : /* LocalTZA gets set by js_InitDateClass() */
         415                 : static double LocalTZA;
         416                 :
         417                 : static double
         418           50274 : DaylightSavingTA(double t, JSContext *cx)
         419                 : {
         420                 :     /* abort if NaN */
         421           50274 :     if (JSDOUBLE_IS_NaN(t))
         422               0 :         return t;
         423                 :
         424                 :     /*
         425                 :      * If earlier than 1970 or after 2038, potentially beyond the ken of
         426                 :      * many OSes, map it to an equivalent year before asking.
         427                 :      */
         428           50274 :     if (t < 0.0 || t > 2145916800000.0) {
         429               9 :         int year = EquivalentYearForDST(YearFromTime(t));
         430               9 :         double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
         431               9 :         t = MakeDate(day, TimeWithinDay(t));
         432                 :     }
         433                 :
         434           50274 :     int64_t timeMilliseconds = static_cast<int64_t>(t);
         435           50274 :     int64_t offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx);
         436           50274 :     return static_cast<double>(offsetMilliseconds);
         437                 : }
         438                 :
         439                 : static double
         440           50085 : AdjustTime(double date, JSContext *cx)
         441                 : {
         442           50085 :     double t = DaylightSavingTA(date, cx) + LocalTZA;
         443           50085 :     t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
         444           50085 :     return t;
         445                 : }
         446                 :
         447                 : static double
         448           49968 : LocalTime(double t, JSContext *cx)
         449                 : {
         450           49968 :     return t + AdjustTime(t, cx);
         451                 : }
         452                 :
         453                 : static double
         454              36 : UTC(double t, JSContext *cx)
         455                 : {
         456              36 :     return t - AdjustTime(t - LocalTZA, cx);
         457                 : }
         458                 :
         459                 : static int
         460             396 : HourFromTime(double t)
         461                 : {
         462             396 :     int result = (int) fmod(floor(t/msPerHour), HoursPerDay);
         463             396 :     if (result < 0)
         464               9 :         result += (int)HoursPerDay;
         465             396 :     return result;
         466                 : }
         467                 :
         468                 : static int
         469             396 : MinFromTime(double t)
         470                 : {
         471             396 :     int result = (int) fmod(floor(t / msPerMinute), MinutesPerHour);
         472             396 :     if (result < 0)
         473               0 :         result += (int)MinutesPerHour;
         474             396 :     return result;
         475                 : }
         476                 :
         477                 : static int
         478             369 : SecFromTime(double t)
         479                 : {
         480             369 :     int result = (int) fmod(floor(t / msPerSecond), SecondsPerMinute);
         481             369 :     if (result < 0)
         482               0 :         result += (int)SecondsPerMinute;
         483             369 :     return result;
         484                 : }
         485                 :
         486                 : static int
         487             279 : msFromTime(double t)
         488                 : {
         489             279 :     int result = (int) fmod(t, msPerSecond);
         490             279 :     if (result < 0)
         491               0 :         result += (int)msPerSecond;
         492             279 :     return result;
         493                 : }
         494                 :
         495                 : /**
         496                 :  * end of ECMA 'support' functions
         497                 :  */
         498                 :
         499                 : static JSBool
         500               0 : date_convert(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
         501                 : {
         502               0 :     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
         503               0 :     JS_ASSERT(obj->isDate());
         504                 :
         505               0 :     return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
         506                 : }
         507                 :
         508                 : /*
         509                 :  * Other Support routines and definitions
         510                 :  */
         511                 :
         512                 : Class js::DateClass = {
         513                 :     js_Date_str,
         514                 :     JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
         515                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
         516                 :     JS_PropertyStub,         /* addProperty */
         517                 :     JS_PropertyStub,         /* delProperty */
         518                 :     JS_PropertyStub,         /* getProperty */
         519                 :     JS_StrictPropertyStub,   /* setProperty */
         520                 :     JS_EnumerateStub,
         521                 :     JS_ResolveStub,
         522                 :     date_convert
         523                 : };
         524                 :
         525                 : /* for use by date_parse */
         526                 :
         527                 : static const char* wtb[] = {
         528                 :     "am", "pm",
         529                 :     "monday", "tuesday", "wednesday", "thursday", "friday",
         530                 :     "saturday", "sunday",
         531                 :     "january", "february", "march", "april", "may", "june",
         532                 :     "july", "august", "september", "october", "november", "december",
         533                 :     "gmt", "ut", "utc",
         534                 :     "est", "edt",
         535                 :     "cst", "cdt",
         536                 :     "mst", "mdt",
         537                 :     "pst", "pdt"
         538                 :     /* time zone table needs to be expanded */
         539                 : };
         540                 :
         541                 : static int ttb[] = {
         542                 :     -1, -2, 0, 0, 0, 0, 0, 0, 0,       /* AM/PM */
         543                 :     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
         544                 :     10000 + 0, 10000 + 0, 10000 + 0,   /* GMT/UT/UTC */
         545                 :     10000 + 5 * 60, 10000 + 4 * 60,    /* EST/EDT */
         546                 :     10000 + 6 * 60, 10000 + 5 * 60,    /* CST/CDT */
         547                 :     10000 + 7 * 60, 10000 + 6 * 60,    /* MST/MDT */
         548                 :     10000 + 8 * 60, 10000 + 7 * 60     /* PST/PDT */
         549                 : };
         550                 :
         551                 : /* helper for date_parse */
         552                 : static JSBool
         553          207000 : date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
         554                 :                    int count, int ignoreCase)
         555                 : {
         556          207000 :     JSBool result = JS_FALSE;
         557                 :     /* return true if matches, otherwise, false */
         558                 :
         559          495000 :     while (count > 0 && s1[s1off] && s2[s2off]) {
         560          279000 :         if (ignoreCase) {
         561          279000 :             if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off]))
         562          198000 :                 break;
         563                 :         } else {
         564               0 :             if ((jschar)s1[s1off] != s2[s2off]) {
         565               0 :                 break;
         566                 :             }
         567                 :         }
         568           81000 :         s1off++;
         569           81000 :         s2off++;
         570           81000 :         count--;
         571                 :     }
         572                 :
         573          207000 :     if (count == 0) {
         574            9000 :         result = JS_TRUE;
         575                 :     }
         576                 :
         577          207000 :     return result;
         578                 : }
         579                 :
         580                 : /* find UTC time from given date... no 1900 correction! */
         581                 : static double
         582            9045 : date_msecFromDate(double year, double mon, double mday, double hour,
         583                 :                   double min, double sec, double msec)
         584                 : {
         585                 :     double day;
         586                 :     double msec_time;
         587                 :     double result;
         588                 :
         589            9045 :     day = MakeDay(year, mon, mday);
         590            9045 :     msec_time = MakeTime(hour, min, sec, msec);
         591            9045 :     result = MakeDate(day, msec_time);
         592            9045 :     return result;
         593                 : }
         594                 :
         595                 : /* compute the time in msec (unclipped) from the given args */
         596                 : #define MAXARGS        7
         597                 :
         598                 : static JSBool
         599              27 : date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
         600                 : {
         601                 :     unsigned loop;
         602                 :     double array[MAXARGS];
         603                 :     double msec_time;
         604                 :
         605             153 :     for (loop = 0; loop < MAXARGS; loop++) {
         606             135 :         if (loop < args.length()) {
         607                 :             double d;
         608             126 :             if (!ToNumber(cx, args[loop], &d))
         609               0 :                 return JS_FALSE;
         610                 :             /* return NaN if any arg is not finite */
         611             126 :             if (!JSDOUBLE_IS_FINITE(d)) {
         612               9 :                 *rval = js_NaN;
         613               9 :                 return JS_TRUE;
         614                 :             }
         615             117 :             array[loop] = js_DoubleToInteger(d);
         616                 :         } else {
         617               9 :             if (loop == 2) {
         618               0 :                 array[loop] = 1; /* Default the date argument to 1. */
         619                 :             } else {
         620               9 :                 array[loop] = 0;
         621                 :             }
         622                 :         }
         623                 :     }
         624                 :
         625                 :     /* adjust 2-digit years into the 20th century */
         626              18 :     if (array[0] >= 0 && array[0] <= 99)
         627               0 :         array[0] += 1900;
         628                 :
         629                 :     msec_time = date_msecFromDate(array[0], array[1], array[2],
         630              18 :                                   array[3], array[4], array[5], array[6]);
         631              18 :     *rval = msec_time;
         632              18 :     return JS_TRUE;
         633                 : }
         634                 :
         635                 : /*
         636                 :  * See ECMA 15.9.4.[3-10];
         637                 :  */
         638                 : static JSBool
         639              18 : date_UTC(JSContext *cx, unsigned argc, Value *vp)
         640                 : {
         641              18 :     CallArgs args = CallArgsFromVp(argc, vp);
         642                 :
         643                 :     double msec_time;
         644              18 :     if (!date_msecFromArgs(cx, args, &msec_time))
         645               0 :         return JS_FALSE;
         646                 :
         647              18 :     msec_time = TIMECLIP(msec_time);
         648                 :
         649              18 :     args.rval().setNumber(msec_time);
         650              18 :     return JS_TRUE;
         651                 : }
         652                 :
         653                 : /*
         654                 :  * Read and convert decimal digits from s[*i] into *result
         655                 :  * while *i < limit.
         656                 :  *
         657                 :  * Succeed if any digits are converted. Advance *i only
         658                 :  * as digits are consumed.
         659                 :  */
         660                 : static JSBool
         661            9045 : digits(size_t *result, const jschar *s, size_t *i, size_t limit)
         662                 : {
         663            9045 :     size_t init = *i;
         664            9045 :     *result = 0;
         665           36378 :     while (*i < limit &&
         666           18198 :            ('0' <= s[*i] && s[*i] <= '9')) {
         667              90 :         *result *= 10;
         668              90 :         *result += (s[*i] - '0');
         669              90 :         ++(*i);
         670                 :     }
         671            9045 :     return (*i != init);
         672                 : }
         673                 :
         674                 : /*
         675                 :  * Read and convert decimal digits to the right of a decimal point,
         676                 :  * representing a fractional integer, from s[*i] into *result
         677                 :  * while *i < limit.
         678                 :  *
         679                 :  * Succeed if any digits are converted. Advance *i only
         680                 :  * as digits are consumed.
         681                 :  */
         682                 : static JSBool
         683               0 : fractional(double *result, const jschar *s, size_t *i, size_t limit)
         684                 : {
         685               0 :     double factor = 0.1;
         686               0 :     size_t init = *i;
         687               0 :     *result = 0.0;
         688               0 :     while (*i < limit &&
         689               0 :            ('0' <= s[*i] && s[*i] <= '9')) {
         690               0 :         *result += (s[*i] - '0') * factor;
         691               0 :         factor *= 0.1;
         692               0 :         ++(*i);
         693                 :     }
         694               0 :     return (*i != init);
         695                 : }
         696                 :
         697                 : /*
         698                 :  * Read and convert exactly n decimal digits from s[*i]
         699                 :  * to s[min(*i+n,limit)] into *result.
         700                 :  *
         701                 :  * Succeed if exactly n digits are converted. Advance *i only
         702                 :  * on success.
         703                 :  */
         704                 : static JSBool
         705            9045 : ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
         706                 : {
         707            9045 :     size_t init = *i;
         708                 :
         709            9045 :     if (digits(result, s, i, JS_MIN(limit, init+n)))
         710              45 :         return ((*i - init) == n);
         711                 :
         712            9000 :     *i = init;
         713            9000 :     return JS_FALSE;
         714                 : }
         715                 :
         716                 : /*
         717                 :  * Parse a string in one of the date-time formats given by the W3C
         718                 :  * "NOTE-datetime" specification. These formats make up a restricted
         719                 :  * profile of the ISO 8601 format. Quoted here:
         720                 :  *
         721                 :  *   The formats are as follows. Exactly the components shown here
         722                 :  *   must be present, with exactly this punctuation. Note that the "T"
         723                 :  *   appears literally in the string, to indicate the beginning of the
         724                 :  *   time element, as specified in ISO 8601.
         725                 :  *
         726                 :  *   Any combination of the date formats with the time formats is
         727                 :  *   allowed, and also either the date or the time can be missing.
         728                 :  *
         729                 :  *   The specification is silent on the meaning when fields are
         730                 :  *   ommitted so the interpretations are a guess, but hopefully a
         731                 :  *   reasonable one. We default the month to January, the day to the
         732                 :  *   1st, and hours minutes and seconds all to 0. If the date is
         733                 :  *   missing entirely then we assume 1970-01-01 so that the time can
         734                 :  *   be aded to a date later. If the time is missing then we assume
         735                 :  *   00:00 UTC.  If the time is present but the time zone field is
         736                 :  *   missing then we use local time.
         737                 :  *
         738                 :  * Date part:
         739                 :  *
         740                 :  *  Year:
         741                 :  *     YYYY (eg 1997)
         742                 :  *
         743                 :  *  Year and month:
         744                 :  *     YYYY-MM (eg 1997-07)
         745                 :  *
         746                 :  *  Complete date:
         747                 :  *     YYYY-MM-DD (eg 1997-07-16)
         748                 :  *
         749                 :  * Time part:
         750                 :  *
         751                 :  *  Hours and minutes:
         752                 :  *     Thh:mmTZD (eg T19:20+01:00)
         753                 :  *
         754                 :  *  Hours, minutes and seconds:
         755                 :  *     Thh:mm:ssTZD (eg T19:20:30+01:00)
         756                 :  *
         757                 :  *  Hours, minutes, seconds and a decimal fraction of a second:
         758                 :  *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
         759                 :  *
         760                 :  * where:
         761                 :  *
         762                 :  *   YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
         763                 :  *   MM   = two-digit month (01=January, etc.)
         764                 :  *   DD   = two-digit day of month (01 through 31)
         765                 :  *   hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
         766                 :  *   mm   = two digits of minute (00 through 59)
         767                 :  *   ss   = two digits of second (00 through 59)
         768                 :  *   s    = one or more digits representing a decimal fraction of a second
         769                 :  *   TZD  = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
         770                 :  */
         771                 :
         772                 : static JSBool
         773            9027 : date_parseISOString(JSLinearString *str, double *result, JSContext *cx)
         774                 : {
         775                 :     double msec;
         776                 :
         777                 :     const jschar *s;
         778                 :     size_t limit;
         779            9027 :     size_t i = 0;
         780            9027 :     int tzMul = 1;
         781            9027 :     int dateMul = 1;
         782            9027 :     size_t year = 1970;
         783            9027 :     size_t month = 1;
         784            9027 :     size_t day = 1;
         785            9027 :     size_t hour = 0;
         786            9027 :     size_t min = 0;
         787            9027 :     size_t sec = 0;
         788            9027 :     double frac = 0;
         789            9027 :     bool isLocalTime = JS_FALSE;
         790            9027 :     size_t tzHour = 0;
         791            9027 :     size_t tzMin = 0;
         792                 :
         793                 : #define PEEK(ch) (i < limit && s[i] == ch)
         794                 :
         795                 : #define NEED(ch)                                                     \
         796                 :     JS_BEGIN_MACRO                                                   \
         797                 :         if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
         798                 :     JS_END_MACRO
         799                 :
         800                 : #define DONE_DATE_UNLESS(ch)                                            \
         801                 :     JS_BEGIN_MACRO                                                      \
         802                 :         if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
         803                 :     JS_END_MACRO
         804                 :
         805                 : #define DONE_UNLESS(ch)                                            \
         806                 :     JS_BEGIN_MACRO                                                 \
         807                 :         if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
         808                 :     JS_END_MACRO
         809                 :
         810                 : #define NEED_NDIGITS(n, field)                                      \
         811                 :     JS_BEGIN_MACRO                                                  \
         812                 :         if (!ndigits(n, &field, s, &i, limit)) { goto syntax; }     \
         813                 :     JS_END_MACRO
         814                 :
         815            9027 :     s = str->chars();
         816            9027 :     limit = str->length();
         817                 :
         818            9027 :     if (PEEK('+') || PEEK('-')) {
         819               0 :         if (PEEK('-'))
         820               0 :             dateMul = -1;
         821               0 :         ++i;
         822               0 :         NEED_NDIGITS(6, year);
         823            9027 :     } else if (!PEEK('T')) {
         824            9027 :         NEED_NDIGITS(4, year);
         825                 :     }
         826               9 :     DONE_DATE_UNLESS('-');
         827               9 :     NEED_NDIGITS(2, month);
         828               9 :     DONE_DATE_UNLESS('-');
         829               9 :     NEED_NDIGITS(2, day);
         830                 :
         831                 :  done_date:
         832               9 :     DONE_UNLESS('T');
         833               0 :     NEED_NDIGITS(2, hour);
         834               0 :     NEED(':');
         835               0 :     NEED_NDIGITS(2, min);
         836                 :
         837               0 :     if (PEEK(':')) {
         838               0 :         ++i;
         839               0 :         NEED_NDIGITS(2, sec);
         840               0 :         if (PEEK('.')) {
         841               0 :             ++i;
         842               0 :             if (!fractional(&frac, s, &i, limit))
         843               0 :                 goto syntax;
         844                 :         }
         845                 :     }
         846                 :
         847               0 :     if (PEEK('Z')) {
         848               0 :         ++i;
         849               0 :     } else if (PEEK('+') || PEEK('-')) {
         850               0 :         if (PEEK('-'))
         851               0 :             tzMul = -1;
         852               0 :         ++i;
         853               0 :         NEED_NDIGITS(2, tzHour);
         854                 :         /*
         855                 :          * Non-standard extension to the ISO date format (permitted by ES5):
         856                 :          * allow "-0700" as a time zone offset, not just "-07:00".
         857                 :          */
         858               0 :         if (PEEK(':'))
         859               0 :           ++i;
         860               0 :         NEED_NDIGITS(2, tzMin);
         861                 :     } else {
         862               0 :         isLocalTime = JS_TRUE;
         863                 :     }
         864                 :
         865                 :  done:
         866              18 :     if (year > 275943 // ceil(1e8/365) + 1970
         867                 :         || (month == 0 || month > 12)
         868               9 :         || (day == 0 || day > size_t(DaysInMonth(year,month)))
         869                 :         || hour > 24
         870                 :         || ((hour == 24) && (min > 0 || sec > 0))
         871                 :         || min > 59
         872                 :         || sec > 59
         873                 :         || tzHour > 23
         874                 :         || tzMin > 59)
         875               0 :         goto syntax;
         876                 :
         877               9 :     if (i != limit)
         878               0 :         goto syntax;
         879                 :
         880               9 :     month -= 1; /* convert month to 0-based */
         881                 :
         882                 :     msec = date_msecFromDate(dateMul * (double)year, month, day,
         883                 :                              hour, min, sec,
         884               9 :                              frac * 1000.0);;
         885                 :
         886               9 :     if (isLocalTime) {
         887               0 :         msec = UTC(msec, cx);
         888                 :     } else {
         889                 :         msec -= ((tzMul) * ((tzHour * msPerHour)
         890               9 :                             + (tzMin * msPerMinute)));
         891                 :     }
         892                 :
         893               9 :     if (msec < -8.64e15 || msec > 8.64e15)
         894                 :         goto syntax;
         895                 :
         896               9 :     *result = msec;
         897                 :
         898               9 :     return JS_TRUE;
         899                 :
         900                 :  syntax:
         901                 :     /* syntax error */
         902            9018 :     *result = 0;
         903            9018 :     return JS_FALSE;
         904                 :
         905                 : #undef PEEK
         906                 : #undef NEED
         907                 : #undef DONE_UNLESS
         908                 : #undef NEED_NDIGITS
         909                 : }
         910                 :
         911                 : static JSBool
         912            9027 : date_parseString(JSLinearString *str, double *result, JSContext *cx)
         913                 : {
         914                 :     double msec;
         915                 :
         916                 :     const jschar *s;
         917                 :     size_t limit;
         918            9027 :     size_t i = 0;
         919            9027 :     int year = -1;
         920            9027 :     int mon = -1;
         921            9027 :     int mday = -1;
         922            9027 :     int hour = -1;
         923            9027 :     int min = -1;
         924            9027 :     int sec = -1;
         925            9027 :     int c = -1;
         926            9027 :     int n = -1;
         927            9027 :     int tzoffset = -1;
         928            9027 :     int prevc = 0;
         929            9027 :     JSBool seenplusminus = JS_FALSE;
         930                 :     int temp;
         931            9027 :     JSBool seenmonthname = JS_FALSE;
         932                 :
         933            9027 :     if (date_parseISOString(str, result, cx))
         934               9 :         return JS_TRUE;
         935                 :
         936            9018 :     s = str->chars();
         937            9018 :     limit = str->length();
         938            9018 :     if (limit == 0)
         939               0 :         goto syntax;
         940          144234 :     while (i < limit) {
         941          126198 :         c = s[i];
         942          126198 :         i++;
         943          126198 :         if (c <= ' ' || c == ',' || c == '-') {
         944           36018 :             if (c == '-' && '0' <= s[i] && s[i] <= '9') {
         945               0 :               prevc = c;
         946                 :             }
         947           36018 :             continue;
         948                 :         }
         949           90180 :         if (c == '(') { /* comments) */
         950               0 :             int depth = 1;
         951               0 :             while (i < limit) {
         952               0 :                 c = s[i];
         953               0 :                 i++;
         954               0 :                 if (c == '(') depth++;
         955               0 :                 else if (c == ')')
         956               0 :                     if (--depth <= 0)
         957               0 :                         break;
         958                 :             }
         959               0 :             continue;
         960                 :         }
         961           90180 :         if ('0' <= c && c <= '9') {
         962           54108 :             n = c - '0';
         963          189306 :             while (i < limit && '0' <= (c = s[i]) && c <= '9') {
         964           81090 :                 n = n * 10 + c - '0';
         965           81090 :                 i++;
         966                 :             }
         967                 :
         968                 :             /* allow TZA before the year, so
         969                 :              * 'Wed Nov 05 21:49:11 GMT-0800 1997'
         970                 :              * works */
         971                 :
         972                 :             /* uses of seenplusminus allow : in TZA, so Java
         973                 :              * no-timezone style of GMT+4:30 works
         974                 :              */
         975                 :
         976           54108 :             if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
         977                 :                 /* make ':' case below change tzoffset */
         978            9000 :                 seenplusminus = JS_TRUE;
         979                 :
         980                 :                 /* offset */
         981            9000 :                 if (n < 24)
         982            9000 :                     n = n * 60; /* EG. "GMT-3" */
         983                 :                 else
         984               0 :                     n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
         985            9000 :                 if (prevc == '+')       /* plus means east of GMT */
         986            9000 :                     n = -n;
         987            9000 :                 if (tzoffset != 0 && tzoffset != -1)
         988               0 :                     goto syntax;
         989            9000 :                 tzoffset = n;
         990           45108 :             } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
         991              36 :                 if (c <= ' ' || c == ',' || c == '/' || i >= limit)
         992              18 :                     year = n;
         993                 :                 else
         994                 :                     goto syntax;
         995           45090 :             } else if (c == ':') {
         996           18036 :                 if (hour < 0)
         997            9018 :                     hour = /*byte*/ n;
         998            9018 :                 else if (min < 0)
         999            9018 :                     min = /*byte*/ n;
        1000                 :                 else
        1001               0 :                     goto syntax;
        1002           27054 :             } else if (c == '/') {
        1003                 :                 /* until it is determined that mon is the actual
        1004                 :                    month, keep it as 1-based rather than 0-based */
        1005              36 :                 if (mon < 0)
        1006              18 :                     mon = /*byte*/ n;
        1007              18 :                 else if (mday < 0)
        1008              18 :                     mday = /*byte*/ n;
        1009                 :                 else
        1010               0 :                     goto syntax;
        1011           27018 :             } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
        1012                 :                 goto syntax;
        1013           27018 :             } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */
        1014               0 :                 if (tzoffset < 0)
        1015               0 :                     tzoffset -= n;
        1016                 :                 else
        1017               0 :                     tzoffset += n;
        1018           27018 :             } else if (hour >= 0 && min < 0) {
        1019               0 :                 min = /*byte*/ n;
        1020           27018 :             } else if (prevc == ':' && min >= 0 && sec < 0) {
        1021            9018 :                 sec = /*byte*/ n;
        1022           18000 :             } else if (mon < 0) {
        1023               0 :                 mon = /*byte*/n;
        1024           18000 :             } else if (mon >= 0 && mday < 0) {
        1025            9000 :                 mday = /*byte*/ n;
        1026            9000 :             } else if (mon >= 0 && mday >= 0 && year < 0) {
        1027            9000 :                 year = n;
        1028                 :             } else {
        1029                 :                 goto syntax;
        1030                 :             }
        1031           54108 :             prevc = 0;
        1032           36072 :         } else if (c == '/' || c == ':' || c == '+' || c == '-') {
        1033           27072 :             prevc = c;
        1034                 :         } else {
        1035            9000 :             size_t st = i - 1;
        1036                 :             int k;
        1037           72000 :             while (i < limit) {
        1038           63000 :                 c = s[i];
        1039           63000 :                 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
        1040            9000 :                     break;
        1041           54000 :                 i++;
        1042                 :             }
        1043            9000 :             if (i <= st + 1)
        1044               0 :                 goto syntax;
        1045          216000 :             for (k = ArrayLength(wtb); --k >= 0;)
        1046          207000 :                 if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
        1047            9000 :                     int action = ttb[k];
        1048            9000 :                     if (action != 0) {
        1049            9000 :                         if (action < 0) {
        1050                 :                             /*
        1051                 :                              * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
        1052                 :                              * 12:30, instead of blindly adding 12 if PM.
        1053                 :                              */
        1054               0 :                             JS_ASSERT(action == -1 || action == -2);
        1055               0 :                             if (hour > 12 || hour < 0) {
        1056                 :                                 goto syntax;
        1057                 :                             } else {
        1058               0 :                                 if (action == -1 && hour == 12) { /* am */
        1059               0 :                                     hour = 0;
        1060               0 :                                 } else if (action == -2 && hour != 12) { /* pm */
        1061               0 :                                     hour += 12;
        1062                 :                                 }
        1063                 :                             }
        1064            9000 :                         } else if (action <= 13) { /* month! */
        1065                 :                             /* Adjust mon to be 1-based until the final values
        1066                 :                                for mon, mday and year are adjusted below */
        1067            9000 :                             if (seenmonthname) {
        1068               0 :                                 goto syntax;
        1069                 :                             }
        1070            9000 :                             seenmonthname = JS_TRUE;
        1071            9000 :                             temp = /*byte*/ (action - 2) + 1;
        1072                 :
        1073            9000 :                             if (mon < 0) {
        1074            9000 :                                 mon = temp;
        1075               0 :                             } else if (mday < 0) {
        1076               0 :                                 mday = mon;
        1077               0 :                                 mon = temp;
        1078               0 :                             } else if (year < 0) {
        1079               0 :                                 year = mon;
        1080               0 :                                 mon = temp;
        1081                 :                             } else {
        1082               0 :                                 goto syntax;
        1083                 :                             }
        1084                 :                         } else {
        1085               0 :                             tzoffset = action - 10000;
        1086                 :                         }
        1087                 :                     }
        1088            9000 :                     break;
        1089                 :                 }
        1090            9000 :             if (k < 0)
        1091               0 :                 goto syntax;
        1092            9000 :             prevc = 0;
        1093                 :         }
        1094                 :     }
        1095            9018 :     if (year < 0 || mon < 0 || mday < 0)
        1096                 :         goto syntax;
        1097                 :     /*
        1098                 :       Case 1. The input string contains an English month name.
        1099                 :               The form of the string can be month f l, or f month l, or
        1100                 :               f l month which each evaluate to the same date.
        1101                 :               If f and l are both greater than or equal to 70, or
        1102                 :               both less than 70, the date is invalid.
        1103                 :               The year is taken to be the greater of the values f, l.
        1104                 :               If the year is greater than or equal to 70 and less than 100,
        1105                 :               it is considered to be the number of years after 1900.
        1106                 :       Case 2. The input string is of the form "f/m/l" where f, m and l are
        1107                 :               integers, e.g. 7/16/45.
        1108                 :               Adjust the mon, mday and year values to achieve 100% MSIE
        1109                 :               compatibility.
        1110                 :               a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
        1111                 :                  i.  If year < 100, it is the number of years after 1900
        1112                 :                  ii. If year >= 100, it is the number of years after 0.
        1113                 :               b. If 70 <= f < 100
        1114                 :                  i.  If m < 70, f/m/l is interpreted as
        1115                 :                      year/month/day where year is the number of years after
        1116                 :                      1900.
        1117                 :                  ii. If m >= 70, the date is invalid.
        1118                 :               c. If f >= 100
        1119                 :                  i.  If m < 70, f/m/l is interpreted as
        1120                 :                      year/month/day where year is the number of years after 0.
        1121                 :                  ii. If m >= 70, the date is invalid.
        1122                 :     */
        1123            9018 :     if (seenmonthname) {
        1124            9000 :         if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
        1125                 :             goto syntax;
        1126                 :         }
        1127            9000 :         if (mday > year) {
        1128               0 :             temp = year;
        1129               0 :             year = mday;
        1130               0 :             mday = temp;
        1131                 :         }
        1132            9000 :         if (year >= 70 && year < 100) {
        1133               0 :             year += 1900;
        1134                 :         }
        1135              18 :     } else if (mon < 70) { /* (a) month/day/year */
        1136              18 :         if (year < 100) {
        1137               0 :             year += 1900;
        1138                 :         }
        1139               0 :     } else if (mon < 100) { /* (b) year/month/day */
        1140               0 :         if (mday < 70) {
        1141               0 :             temp = year;
        1142               0 :             year = mon + 1900;
        1143               0 :             mon = mday;
        1144               0 :             mday = temp;
        1145                 :         } else {
        1146               0 :             goto syntax;
        1147                 :         }
        1148                 :     } else { /* (c) year/month/day */
        1149               0 :         if (mday < 70) {
        1150               0 :             temp = year;
        1151               0 :             year = mon;
        1152               0 :             mon = mday;
        1153               0 :             mday = temp;
        1154                 :         } else {
        1155               0 :             goto syntax;
        1156                 :         }
        1157                 :     }
        1158            9018 :     mon -= 1; /* convert month to 0-based */
        1159            9018 :     if (sec < 0)
        1160               0 :         sec = 0;
        1161            9018 :     if (min < 0)
        1162               0 :         min = 0;
        1163            9018 :     if (hour < 0)
        1164               0 :         hour = 0;
        1165                 :
        1166            9018 :     msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
        1167                 :
        1168            9018 :     if (tzoffset == -1) { /* no time zone specified, have to use local */
        1169              18 :         msec = UTC(msec, cx);
        1170                 :     } else {
        1171            9000 :         msec += tzoffset * msPerMinute;
        1172                 :     }
        1173                 :
        1174            9018 :     *result = msec;
        1175            9018 :     return JS_TRUE;
        1176                 :
        1177                 : syntax:
        1178                 :     /* syntax error */
        1179               0 :     *result = 0;
        1180               0 :     return JS_FALSE;
        1181                 : }
        1182                 :
        1183                 : static JSBool
        1184               0 : date_parse(JSContext *cx, unsigned argc, Value *vp)
        1185                 : {
        1186                 :     JSString *str;
        1187                 :     double result;
        1188                 :
        1189               0 :     if (argc == 0) {
        1190               0 :         vp->setDouble(js_NaN);
        1191               0 :         return true;
        1192                 :     }
        1193               0 :     str = ToString(cx, vp[2]);
        1194               0 :     if (!str)
        1195               0 :         return JS_FALSE;
        1196               0 :     vp[2].setString(str);
        1197               0 :     JSLinearString *linearStr = str->ensureLinear(cx);
        1198               0 :     if (!linearStr)
        1199               0 :         return false;
        1200                 :
        1201               0 :     if (!date_parseString(linearStr, &result, cx)) {
        1202               0 :         vp->setDouble(js_NaN);
        1203               0 :         return true;
        1204                 :     }
        1205                 :
        1206               0 :     result = TIMECLIP(result);
        1207               0 :     vp->setNumber(result);
        1208               0 :     return true;
        1209                 : }
        1210                 :
        1211                 : static inline double
        1212            1449 : NowAsMillis()
        1213                 : {
        1214            1449 :     return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
        1215                 : }
        1216                 :
        1217                 : static JSBool
        1218              90 : date_now(JSContext *cx, unsigned argc, Value *vp)
        1219                 : {
        1220              90 :     vp->setDouble(NowAsMillis());
        1221              90 :     return JS_TRUE;
        1222                 : }
        1223                 :
        1224                 : /*
        1225                 :  * Set UTC time to a given time and invalidate cached local time.
        1226                 :  */
        1227                 : static JSBool
        1228           52158 : SetUTCTime(JSContext *cx, JSObject *obj, double t, Value *vp = NULL)
        1229                 : {
        1230           52158 :     JS_ASSERT(obj->isDate());
        1231                 :
        1232          469422 :     for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
        1233                 :          ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
        1234                 :          ind++) {
        1235          417264 :         obj->setSlot(ind, UndefinedValue());
        1236                 :     }
        1237                 :
        1238           52158 :     obj->setDateUTCTime(DoubleValue(t));
        1239           52158 :     if (vp)
        1240           40941 :         vp->setDouble(t);
        1241           52158 :     return true;
        1242                 : }
        1243                 :
        1244                 : static void
        1245            1146 : SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
        1246                 : {
        1247            1146 :     double NaN = cx->runtime->NaNValue.getDoubleRef();
        1248            1146 :     SetUTCTime(cx, obj, NaN, vp);
        1249            1146 : }
        1250                 :
        1251                 : /*
        1252                 :  * Cache the local time, year, month, and so forth of the object.
        1253                 :  * If UTC time is not finite (e.g., NaN), the local time
        1254                 :  * slots will be set to the UTC time without conversion.
        1255                 :  */
        1256                 : static bool
        1257           49770 : FillLocalTimes(JSContext *cx, JSObject *obj)
        1258                 : {
        1259           49770 :     JS_ASSERT(obj->isDate());
        1260                 :
        1261           49770 :     double utcTime = obj->getDateUTCTime().toNumber();
        1262                 :
        1263           49770 :     if (!JSDOUBLE_IS_FINITE(utcTime)) {
        1264               0 :         for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
        1265                 :              ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
        1266                 :              ind++) {
        1267               0 :             obj->setSlot(ind, DoubleValue(utcTime));
        1268                 :         }
        1269               0 :         return true;
        1270                 :     }
        1271                 :
        1272           49770 :     double localTime = LocalTime(utcTime, cx);
        1273                 :
        1274           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
        1275                 :
        1276           49770 :     int year = (int) floor(localTime /(msPerDay*365.2425)) + 1970;
        1277           49770 :     double yearStartTime = (double) TimeFromYear(year);
        1278                 :
        1279                 :     /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
        1280                 :     int yearDays;
        1281           49770 :     if (yearStartTime > localTime) {
        1282            9027 :         year--;
        1283            9027 :         yearStartTime -= (msPerDay * DaysInYear(year));
        1284            9027 :         yearDays = DaysInYear(year);
        1285                 :     } else {
        1286           40743 :         yearDays = DaysInYear(year);
        1287           40743 :         double nextStart = yearStartTime + (msPerDay * yearDays);
        1288           40743 :         if (nextStart <= localTime) {
        1289               0 :             year++;
        1290               0 :             yearStartTime = nextStart;
        1291               0 :             yearDays = DaysInYear(year);
        1292                 :         }
        1293                 :     }
        1294                 :
        1295           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
        1296                 :
        1297           49770 :     uint64_t yearTime = uint64_t(localTime - yearStartTime);
        1298           49770 :     int yearSeconds = uint32_t(yearTime / 1000);
        1299                 :
        1300           49770 :     int day = yearSeconds / int(SecondsPerDay);
        1301                 :
        1302           49770 :     int step = -1, next = 30;
        1303                 :     int month;
        1304                 :
        1305                 :     do {
        1306           49770 :         if (day <= next) {
        1307            3708 :             month = 0;
        1308            3708 :             break;
        1309                 :         }
        1310           46062 :         step = next;
        1311           46062 :         next += ((yearDays == 366) ? 29 : 28);
        1312           46062 :         if (day <= next) {
        1313            3402 :             month = 1;
        1314            3402 :             break;
        1315                 :         }
        1316           42660 :         step = next;
        1317           42660 :         if (day <= (next += 31)) {
        1318            3726 :             month = 2;
        1319            3726 :             break;
        1320                 :         }
        1321           38934 :         step = next;
        1322           38934 :         if (day <= (next += 30)) {
        1323            3861 :             month = 3;
        1324            3861 :             break;
        1325                 :         }
        1326           35073 :         step = next;
        1327           35073 :         if (day <= (next += 31)) {
        1328            3438 :             month = 4;
        1329            3438 :             break;
        1330                 :         }
        1331           31635 :         step = next;
        1332           31635 :         if (day <= (next += 30)) {
        1333            3321 :             month = 5;
        1334            3321 :             break;
        1335                 :         }
        1336           28314 :         step = next;
        1337           28314 :         if (day <= (next += 31)) {
        1338            3447 :             month = 6;
        1339            3447 :             break;
        1340                 :         }
        1341           24867 :         step = next;
        1342           24867 :         if (day <= (next += 31)) {
        1343            3447 :             month = 7;
        1344            3447 :             break;
        1345                 :         }
        1346           21420 :         step = next;
        1347           21420 :         if (day <= (next += 30)) {
        1348            3078 :             month = 8;
        1349            3078 :             break;
        1350                 :         }
        1351           18342 :         step = next;
        1352           18342 :         if (day <= (next += 31)) {
        1353            3141 :             month = 9;
        1354            3141 :             break;
        1355                 :         }
        1356           15201 :         step = next;
        1357           15201 :         if (day <= (next += 30)) {
        1358            3051 :             month = 10;
        1359            3051 :             break;
        1360                 :         }
        1361           12150 :         step = next;
        1362           12150 :         month = 11;
        1363                 :     } while (0);
        1364                 :
        1365           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
        1366           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
        1367                 :
        1368           49770 :     int weekday = WeekDay(localTime);
        1369                 :
        1370           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
        1371                 :
        1372           49770 :     int seconds = yearSeconds % 60;
        1373                 :
        1374           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
        1375                 :
        1376           49770 :     int minutes = (yearSeconds / 60) % 60;
        1377                 :
        1378           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
        1379                 :
        1380           49770 :     int hours = (yearSeconds / (60 * 60)) % 24;
        1381                 :
        1382           49770 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
        1383                 :
        1384           49770 :     return true;
        1385                 : }
        1386                 :
        1387                 : /* Cache the local times in obj, if necessary. */
        1388                 : static inline bool
        1389          514746 : GetAndCacheLocalTime(JSContext *cx, JSObject *obj)
        1390                 : {
        1391          514746 :     JS_ASSERT(obj->isDate());
        1392                 :
        1393                 :     /* If the local time is undefined, we need to fill in the cached values. */
        1394          514746 :     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
        1395           49770 :         if (!FillLocalTimes(cx, obj))
        1396               0 :             return false;
        1397                 :     }
        1398          514746 :     return true;
        1399                 : }
        1400                 :
        1401                 : static inline bool
        1402              27 : GetAndCacheLocalTime(JSContext *cx, JSObject *obj, double *time)
        1403                 : {
        1404              27 :     if (!obj || !GetAndCacheLocalTime(cx, obj))
        1405               0 :         return false;
        1406                 :
        1407              27 :     *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
        1408              27 :     return true;
        1409                 : }
        1410                 :
        1411                 : /*
        1412                 :  * See ECMA 15.9.5.4 thru 15.9.5.23
        1413                 :  */
        1414                 : static JSBool
        1415           40599 : date_getTime(JSContext *cx, unsigned argc, Value *vp)
        1416                 : {
        1417           40599 :     CallArgs args = CallArgsFromVp(argc, vp);
        1418                 :
        1419                 :     bool ok;
        1420           40599 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &ok);
        1421           40599 :     if (!obj)
        1422              63 :         return ok;
        1423                 :
        1424           40536 :     args.rval() = obj->getDateUTCTime();
        1425           40536 :     return true;
        1426                 : }
        1427                 :
        1428                 : static JSBool
        1429            9090 : date_getYear(JSContext *cx, unsigned argc, Value *vp)
        1430                 : {
        1431            9090 :     CallArgs args = CallArgsFromVp(argc, vp);
        1432                 :
        1433                 :     bool ok;
        1434            9090 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getYear, &DateClass, &ok);
        1435            9090 :     if (!obj)
        1436              63 :         return ok;
        1437                 :
        1438            9027 :     if (!GetAndCacheLocalTime(cx, obj))
        1439               0 :         return false;
        1440                 :
        1441            9027 :     Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
        1442            9027 :     if (yearVal.isInt32()) {
        1443                 :         /* Follow ECMA-262 to the letter, contrary to IE JScript. */
        1444            9027 :         int year = yearVal.toInt32() - 1900;
        1445            9027 :         args.rval().setInt32(year);
        1446                 :     } else {
        1447               0 :         args.rval() = yearVal;
        1448                 :     }
        1449                 :
        1450            9027 :     return true;
        1451                 : }
        1452                 :
        1453                 : static JSBool
        1454           81090 : date_getFullYear(JSContext *cx, unsigned argc, Value *vp)
        1455                 : {
        1456           81090 :     CallArgs args = CallArgsFromVp(argc, vp);
        1457                 :
        1458                 :     bool ok;
        1459           81090 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &ok);
        1460           81090 :     if (!obj)
        1461              63 :         return ok;
        1462                 :
        1463           81027 :     if (!GetAndCacheLocalTime(cx, obj))
        1464               0 :         return false;
        1465                 :
        1466           81027 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
        1467           81027 :     return true;
        1468                 : }
        1469                 :
        1470                 : static JSBool
        1471              90 : date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
        1472                 : {
        1473              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1474                 :
        1475                 :     bool ok;
        1476              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &ok);
        1477              90 :     if (!obj)
        1478              63 :         return ok;
        1479                 :
        1480              27 :     double result = obj->getDateUTCTime().toNumber();
        1481              27 :     if (JSDOUBLE_IS_FINITE(result))
        1482              27 :         result = YearFromTime(result);
        1483                 :
        1484              27 :     args.rval().setNumber(result);
        1485              27 :     return true;
        1486                 : }
        1487                 :
        1488                 : static JSBool
        1489           85590 : date_getMonth(JSContext *cx, unsigned argc, Value *vp)
        1490                 : {
        1491           85590 :     CallArgs args = CallArgsFromVp(argc, vp);
        1492                 :
        1493                 :     bool ok;
        1494           85590 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &ok);
        1495           85590 :     if (!obj)
        1496              63 :         return ok;
        1497                 :
        1498           85527 :     if (!GetAndCacheLocalTime(cx, obj))
        1499               0 :         return false;
        1500                 :
        1501           85527 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
        1502           85527 :     return true;
        1503                 : }
        1504                 :
        1505                 : static JSBool
        1506              90 : date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
        1507                 : {
        1508              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1509                 :
        1510                 :     bool ok;
        1511              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &ok);
        1512              90 :     if (!obj)
        1513              63 :         return ok;
        1514                 :
        1515              27 :     double result = obj->getDateUTCTime().toNumber();
        1516              27 :     if (JSDOUBLE_IS_FINITE(result))
        1517              27 :         result = MonthFromTime(result);
        1518                 :
        1519              27 :     args.rval().setNumber(result);
        1520              27 :     return true;
        1521                 : }
        1522                 :
        1523                 : static JSBool
        1524           90090 : date_getDate(JSContext *cx, unsigned argc, Value *vp)
        1525                 : {
        1526           90090 :     CallArgs args = CallArgsFromVp(argc, vp);
        1527                 :
        1528                 :     bool ok;
        1529           90090 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &ok);
        1530           90090 :     if (!obj)
        1531              63 :         return ok;
        1532                 :
        1533           90027 :     if (!GetAndCacheLocalTime(cx, obj))
        1534               0 :         return false;
        1535                 :
        1536           90027 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
        1537           90027 :     return true;
        1538                 : }
        1539                 :
        1540                 : static JSBool
        1541              90 : date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
        1542                 : {
        1543              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1544                 :
        1545                 :     bool ok;
        1546              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &ok);
        1547              90 :     if (!obj)
        1548              63 :         return ok;
        1549                 :
        1550              27 :     double result = obj->getDateUTCTime().toNumber();
        1551              27 :     if (JSDOUBLE_IS_FINITE(result))
        1552              27 :         result = DateFromTime(result);
        1553                 :
        1554              27 :     args.rval().setNumber(result);
        1555              27 :     return true;
        1556                 : }
        1557                 :
        1558                 : static JSBool
        1559           40590 : date_getDay(JSContext *cx, unsigned argc, Value *vp)
        1560                 : {
        1561           40590 :     CallArgs args = CallArgsFromVp(argc, vp);
        1562                 :
        1563                 :     bool ok;
        1564           40590 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getDay, &DateClass, &ok);
        1565           40590 :     if (!obj)
        1566              63 :         return ok;
        1567                 :
        1568           40527 :     if (!GetAndCacheLocalTime(cx, obj))
        1569               0 :         return false;
        1570                 :
        1571           40527 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
        1572           40527 :     return true;
        1573                 : }
        1574                 :
        1575                 : static JSBool
        1576              90 : date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
        1577                 : {
        1578              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1579                 :
        1580                 :     bool ok;
        1581              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &ok);
        1582              90 :     if (!obj)
        1583              63 :         return ok;
        1584                 :
        1585              27 :     double result = obj->getDateUTCTime().toNumber();
        1586              27 :     if (JSDOUBLE_IS_FINITE(result))
        1587              27 :         result = WeekDay(result);
        1588                 :
        1589              27 :     args.rval().setNumber(result);
        1590              27 :     return true;
        1591                 : }
        1592                 :
        1593                 : static JSBool
        1594          118566 : date_getHours(JSContext *cx, unsigned argc, Value *vp)
        1595                 : {
        1596          118566 :     CallArgs args = CallArgsFromVp(argc, vp);
        1597                 :
        1598                 :     bool ok;
        1599          118566 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &ok);
        1600          118566 :     if (!obj)
        1601              63 :         return ok;
        1602                 :
        1603          118503 :     if (!GetAndCacheLocalTime(cx, obj))
        1604               0 :         return false;
        1605                 :
        1606          118503 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
        1607          118503 :     return true;
        1608                 : }
        1609                 :
        1610                 : static JSBool
        1611              90 : date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
        1612                 : {
        1613              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1614                 :
        1615                 :     bool ok;
        1616              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &ok);
        1617              90 :     if (!obj)
        1618              63 :         return ok;
        1619                 :
        1620              27 :     double result = obj->getDateUTCTime().toNumber();
        1621              27 :     if (JSDOUBLE_IS_FINITE(result))
        1622              27 :         result = HourFromTime(result);
        1623                 :
        1624              27 :     args.rval().setNumber(result);
        1625              27 :     return JS_TRUE;
        1626                 : }
        1627                 :
        1628                 : static JSBool
        1629           45090 : date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
        1630                 : {
        1631           45090 :     CallArgs args = CallArgsFromVp(argc, vp);
        1632                 :
        1633                 :     bool ok;
        1634           45090 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &ok);
        1635           45090 :     if (!obj)
        1636              63 :         return ok;
        1637                 :
        1638           45027 :     if (!GetAndCacheLocalTime(cx, obj))
        1639               0 :         return false;
        1640                 :
        1641           45027 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
        1642           45027 :     return true;
        1643                 : }
        1644                 :
        1645                 : static JSBool
        1646              90 : date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
        1647                 : {
        1648              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1649                 :
        1650                 :     bool ok;
        1651              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &ok);
        1652              90 :     if (!obj)
        1653              63 :         return ok;
        1654                 :
        1655              27 :     double result = obj->getDateUTCTime().toNumber();
        1656              27 :     if (JSDOUBLE_IS_FINITE(result))
        1657              27 :         result = MinFromTime(result);
        1658                 :
        1659              27 :     args.rval().setNumber(result);
        1660              27 :     return true;
        1661                 : }
        1662                 :
        1663                 : /* Date.getSeconds is mapped to getUTCSeconds */
        1664                 :
        1665                 : static JSBool
        1666           45180 : date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
        1667                 : {
        1668           45180 :     CallArgs args = CallArgsFromVp(argc, vp);
        1669                 :
        1670                 :     bool ok;
        1671           45180 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &ok);
        1672           45180 :     if (!obj)
        1673             126 :         return ok;
        1674                 :
        1675           45054 :     if (!GetAndCacheLocalTime(cx, obj))
        1676               0 :         return false;
        1677                 :
        1678           45054 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
        1679           45054 :     return true;
        1680                 : }
        1681                 :
        1682                 : /* Date.getMilliseconds is mapped to getUTCMilliseconds */
        1683                 :
        1684                 : static JSBool
        1685               0 : date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
        1686                 : {
        1687               0 :     CallArgs args = CallArgsFromVp(argc, vp);
        1688                 :
        1689                 :     bool ok;
        1690               0 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &ok);
        1691               0 :     if (!obj)
        1692               0 :         return ok;
        1693                 :
        1694               0 :     double result = obj->getDateUTCTime().toNumber();
        1695               0 :     if (JSDOUBLE_IS_FINITE(result))
        1696               0 :         result = msFromTime(result);
        1697                 :
        1698               0 :     args.rval().setNumber(result);
        1699               0 :     return true;
        1700                 : }
        1701                 :
        1702                 : static JSBool
        1703              90 : date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
        1704                 : {
        1705              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1706                 :
        1707                 :     bool ok;
        1708              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &ok);
        1709              90 :     if (!obj)
        1710              63 :         return ok;
        1711                 :
        1712              27 :     double utctime = obj->getDateUTCTime().toNumber();
        1713                 :
        1714                 :     double localtime;
        1715              27 :     if (!GetAndCacheLocalTime(cx, obj, &localtime))
        1716               0 :         return false;
        1717                 :
        1718                 :     /*
        1719                 :      * Return the time zone offset in minutes for the current locale that is
        1720                 :      * appropriate for this time. This value would be a constant except for
        1721                 :      * daylight savings time.
        1722                 :      */
        1723              27 :     double result = (utctime - localtime) / msPerMinute;
        1724              27 :     args.rval().setNumber(result);
        1725              27 :     return true;
        1726                 : }
        1727                 :
        1728                 : static JSBool
        1729           40590 : date_setTime(JSContext *cx, unsigned argc, Value *vp)
        1730                 : {
        1731           40590 :     CallArgs args = CallArgsFromVp(argc, vp);
        1732                 :
        1733                 :     bool ok;
        1734           40590 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_setTime, &DateClass, &ok);
        1735           40590 :     if (!obj)
        1736              63 :         return ok;
        1737                 :
        1738           40527 :     if (args.length() == 0) {
        1739              27 :         SetDateToNaN(cx, obj, &args.rval());
        1740              27 :         return true;
        1741                 :     }
        1742                 :
        1743                 :     double result;
        1744           40500 :     if (!ToNumber(cx, args[0], &result))
        1745               0 :         return false;
        1746                 :
        1747           40500 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
        1748                 : }
        1749                 :
        1750                 : static JSBool
        1751             729 : date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsigned argc, Value *vp)
        1752                 : {
        1753             729 :     CallArgs args = CallArgsFromVp(argc, vp);
        1754                 :
        1755                 :     bool ok;
        1756             729 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
        1757             729 :     if (!obj)
        1758             504 :         return ok;
        1759                 :
        1760             225 :     double result = obj->getDateUTCTime().toNumber();
        1761                 :
        1762                 :     /* just return NaN if the date is already NaN */
        1763             225 :     if (!JSDOUBLE_IS_FINITE(result)) {
        1764               0 :         args.rval().setNumber(result);
        1765               0 :         return true;
        1766                 :     }
        1767                 :
        1768                 :     /*
        1769                 :      * Satisfy the ECMA rule that if a function is called with
        1770                 :      * fewer arguments than the specified formal arguments, the
        1771                 :      * remaining arguments are set to undefined.  Seems like all
        1772                 :      * the Date.setWhatever functions in ECMA are only varargs
        1773                 :      * beyond the first argument; this should be set to undefined
        1774                 :      * if it's not given.  This means that "d = new Date();
        1775                 :      * d.setMilliseconds()" returns NaN.  Blech.
        1776                 :      */
        1777             225 :     if (args.length() == 0) {
        1778             216 :         SetDateToNaN(cx, obj, &args.rval());
        1779             216 :         return true;
        1780                 :     }
        1781                 :
        1782               9 :     unsigned numNums = Min(args.length(), maxargs);
        1783               9 :     JS_ASSERT(numNums <= 4);
        1784                 :     double nums[4];
        1785              18 :     for (unsigned i = 0; i < numNums; i++) {
        1786               9 :         if (!ToNumber(cx, args[i], &nums[i]))
        1787               0 :             return false;
        1788               9 :         if (!JSDOUBLE_IS_FINITE(nums[i])) {
        1789               0 :             SetDateToNaN(cx, obj, &args.rval());
        1790               0 :             return true;
        1791                 :         }
        1792               9 :         nums[i] = js_DoubleToInteger(nums[i]);
        1793                 :     }
        1794                 :
        1795                 :     double lorutime;  /* Local or UTC version of *date */
        1796               9 :     if (local)
        1797               9 :         lorutime = LocalTime(result, cx);
        1798                 :     else
        1799               0 :         lorutime = result;
        1800                 :
        1801               9 :     double *argp = nums;
        1802               9 :     double *stop = argp + numNums;
        1803                 :     double hour;
        1804               9 :     if (maxargs >= 4 && argp < stop)
        1805               0 :         hour = *argp++;
        1806                 :     else
        1807               9 :         hour = HourFromTime(lorutime);
        1808                 :
        1809                 :     double min;
        1810               9 :     if (maxargs >= 3 && argp < stop)
        1811               0 :         min = *argp++;
        1812                 :     else
        1813               9 :         min = MinFromTime(lorutime);
        1814                 :
        1815                 :     double sec;
        1816               9 :     if (maxargs >= 2 && argp < stop)
        1817               0 :         sec = *argp++;
        1818                 :     else
        1819               9 :         sec = SecFromTime(lorutime);
        1820                 :
        1821                 :     double msec;
        1822               9 :     if (maxargs >= 1 && argp < stop)
        1823               9 :         msec = *argp;
        1824                 :     else
        1825               0 :         msec = msFromTime(lorutime);
        1826                 :
        1827               9 :     double msec_time = MakeTime(hour, min, sec, msec);
        1828               9 :     result = MakeDate(Day(lorutime), msec_time);
        1829                 :
        1830               9 :     if (local)
        1831               9 :         result = UTC(result, cx);
        1832                 :
        1833               9 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
        1834                 : }
        1835                 :
        1836                 : static JSBool
        1837              99 : date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp)
        1838                 : {
        1839              99 :     return date_makeTime(cx, date_setMilliseconds, 1, JS_TRUE, argc, vp);
        1840                 : }
        1841                 :
        1842                 : static JSBool
        1843              90 : date_setUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
        1844                 : {
        1845              90 :     return date_makeTime(cx, date_setUTCMilliseconds, 1, JS_FALSE, argc, vp);
        1846                 : }
        1847                 :
        1848                 : static JSBool
        1849              90 : date_setSeconds(JSContext *cx, unsigned argc, Value *vp)
        1850                 : {
        1851              90 :     return date_makeTime(cx, date_setSeconds, 2, JS_TRUE, argc, vp);
        1852                 : }
        1853                 :
        1854                 : static JSBool
        1855              90 : date_setUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
        1856                 : {
        1857              90 :     return date_makeTime(cx, date_setUTCSeconds, 2, JS_FALSE, argc, vp);
        1858                 : }
        1859                 :
        1860                 : static JSBool
        1861              90 : date_setMinutes(JSContext *cx, unsigned argc, Value *vp)
        1862                 : {
        1863              90 :     return date_makeTime(cx, date_setMinutes, 3, JS_TRUE, argc, vp);
        1864                 : }
        1865                 :
        1866                 : static JSBool
        1867              90 : date_setUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
        1868                 : {
        1869              90 :     return date_makeTime(cx, date_setUTCMinutes, 3, JS_FALSE, argc, vp);
        1870                 : }
        1871                 :
        1872                 : static JSBool
        1873              90 : date_setHours(JSContext *cx, unsigned argc, Value *vp)
        1874                 : {
        1875              90 :     return date_makeTime(cx, date_setHours, 4, JS_TRUE, argc, vp);
        1876                 : }
        1877                 :
        1878                 : static JSBool
        1879              90 : date_setUTCHours(JSContext *cx, unsigned argc, Value *vp)
        1880                 : {
        1881              90 :     return date_makeTime(cx, date_setUTCHours, 4, JS_FALSE, argc, vp);
        1882                 : }
        1883                 :
        1884                 : static JSBool
        1885             540 : date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsigned argc, Value *vp)
        1886                 : {
        1887             540 :     CallArgs args = CallArgsFromVp(argc, vp);
        1888                 :
        1889                 :     bool ok;
        1890             540 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
        1891             540 :     if (!obj)
        1892             378 :         return ok;
        1893                 :
        1894             162 :     double result = obj->getDateUTCTime().toNumber();
        1895                 :
        1896                 :     /* see complaint about ECMA in date_MakeTime */
        1897             162 :     if (args.length() == 0) {
        1898             162 :         SetDateToNaN(cx, obj, &args.rval());
        1899             162 :         return true;
        1900                 :     }
        1901                 :
        1902               0 :     unsigned numNums = Min(args.length(), maxargs);
        1903               0 :     JS_ASSERT(1 <= numNums && numNums <= 3);
        1904                 :     double nums[3];
        1905               0 :     for (unsigned i = 0; i < numNums; i++) {
        1906               0 :         if (!ToNumber(cx, args[i], &nums[i]))
        1907               0 :             return JS_FALSE;
        1908               0 :         if (!JSDOUBLE_IS_FINITE(nums[i])) {
        1909               0 :             SetDateToNaN(cx, obj, &args.rval());
        1910               0 :             return true;
        1911                 :         }
        1912               0 :         nums[i] = js_DoubleToInteger(nums[i]);
        1913                 :     }
        1914                 :
        1915                 :     /*
        1916                 :      * return NaN if date is NaN and we're not setting the year, If we are, use
        1917                 :      * 0 as the time.
        1918                 :      */
        1919                 :     double lorutime; /* local or UTC version of *date */
        1920               0 :     if (!(JSDOUBLE_IS_FINITE(result))) {
        1921               0 :         if (maxargs < 3) {
        1922               0 :             args.rval().setDouble(result);
        1923               0 :             return true;
        1924                 :         }
        1925               0 :         lorutime = +0.;
        1926                 :     } else {
        1927               0 :         lorutime = local ? LocalTime(result, cx) : result;
        1928                 :     }
        1929                 :
        1930               0 :     double *argp = nums;
        1931               0 :     double *stop = argp + numNums;
        1932                 :     double year;
        1933               0 :     if (maxargs >= 3 && argp < stop)
        1934               0 :         year = *argp++;
        1935                 :     else
        1936               0 :         year = YearFromTime(lorutime);
        1937                 :
        1938                 :     double month;
        1939               0 :     if (maxargs >= 2 && argp < stop)
        1940               0 :         month = *argp++;
        1941                 :     else
        1942               0 :         month = MonthFromTime(lorutime);
        1943                 :
        1944                 :     double day;
        1945               0 :     if (maxargs >= 1 && argp < stop)
        1946               0 :         day = *argp++;
        1947                 :     else
        1948               0 :         day = DateFromTime(lorutime);
        1949                 :
        1950               0 :     day = MakeDay(year, month, day); /* day within year */
        1951               0 :     result = MakeDate(day, TimeWithinDay(lorutime));
        1952                 :
        1953               0 :     if (local)
        1954               0 :         result = UTC(result, cx);
        1955                 :
        1956               0 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
        1957                 : }
        1958                 :
        1959                 : static JSBool
        1960              90 : date_setDate(JSContext *cx, unsigned argc, Value *vp)
        1961                 : {
        1962              90 :     return date_makeDate(cx, date_setDate, 1, JS_TRUE, argc, vp);
        1963                 : }
        1964                 :
        1965                 : static JSBool
        1966              90 : date_setUTCDate(JSContext *cx, unsigned argc, Value *vp)
        1967                 : {
        1968              90 :     return date_makeDate(cx, date_setUTCDate, 1, JS_FALSE, argc, vp);
        1969                 : }
        1970                 :
        1971                 : static JSBool
        1972              90 : date_setMonth(JSContext *cx, unsigned argc, Value *vp)
        1973                 : {
        1974              90 :     return date_makeDate(cx, date_setMonth, 2, JS_TRUE, argc, vp);
        1975                 : }
        1976                 :
        1977                 : static JSBool
        1978              90 : date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp)
        1979                 : {
        1980              90 :     return date_makeDate(cx, date_setUTCMonth, 2, JS_FALSE, argc, vp);
        1981                 : }
        1982                 :
        1983                 : static JSBool
        1984              90 : date_setFullYear(JSContext *cx, unsigned argc, Value *vp)
        1985                 : {
        1986              90 :     return date_makeDate(cx, date_setFullYear, 3, JS_TRUE, argc, vp);
        1987                 : }
        1988                 :
        1989                 : static JSBool
        1990              90 : date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
        1991                 : {
        1992              90 :     return date_makeDate(cx, date_setUTCFullYear, 3, JS_FALSE, argc, vp);
        1993                 : }
        1994                 :
        1995                 : static JSBool
        1996              90 : date_setYear(JSContext *cx, unsigned argc, Value *vp)
        1997                 : {
        1998              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        1999                 :
        2000                 :     bool ok;
        2001              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok);
        2002              90 :     if (!obj)
        2003              63 :         return ok;
        2004                 :
        2005              27 :     if (args.length() == 0) {
        2006                 :         /* Call this only after verifying that obj.[[Class]] = "Date". */
        2007              27 :         SetDateToNaN(cx, obj, &args.rval());
        2008              27 :         return true;
        2009                 :     }
        2010                 :
        2011               0 :     double result = obj->getDateUTCTime().toNumber();
        2012                 :
        2013                 :     double year;
        2014               0 :     if (!ToNumber(cx, args[0], &year))
        2015               0 :         return false;
        2016               0 :     if (!JSDOUBLE_IS_FINITE(year)) {
        2017               0 :         SetDateToNaN(cx, obj, &args.rval());
        2018               0 :         return true;
        2019                 :     }
        2020               0 :     year = js_DoubleToInteger(year);
        2021               0 :     if (year >= 0 && year <= 99)
        2022               0 :         year += 1900;
        2023                 :
        2024               0 :     double t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
        2025               0 :     double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
        2026               0 :     result = MakeDate(day, TimeWithinDay(t));
        2027               0 :     result = UTC(result, cx);
        2028                 :
        2029               0 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
        2030                 : }
        2031                 :
        2032                 : /* constants for toString, toUTCString */
        2033                 : static char js_NaN_date_str[] = "Invalid Date";
        2034                 : static const char* days[] =
        2035                 : {
        2036                 :    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
        2037                 : };
        2038                 : static const char* months[] =
        2039                 : {
        2040                 :    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
        2041                 : };
        2042                 :
        2043                 :
        2044                 : // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
        2045                 : // requires a PRMJTime... which only has 16-bit years.  Sub-ECMA.
        2046                 : static void
        2047              27 : print_gmt_string(char* buf, size_t size, double utctime)
        2048                 : {
        2049                 :     JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
        2050              27 :                 days[WeekDay(utctime)],
        2051                 :                 DateFromTime(utctime),
        2052              27 :                 months[MonthFromTime(utctime)],
        2053                 :                 YearFromTime(utctime),
        2054                 :                 HourFromTime(utctime),
        2055                 :                 MinFromTime(utctime),
        2056              81 :                 SecFromTime(utctime));
        2057              27 : }
        2058                 :
        2059                 : static void
        2060              90 : print_iso_string(char* buf, size_t size, double utctime)
        2061                 : {
        2062                 :     JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
        2063                 :                 YearFromTime(utctime),
        2064              90 :                 MonthFromTime(utctime) + 1,
        2065                 :                 DateFromTime(utctime),
        2066                 :                 HourFromTime(utctime),
        2067                 :                 MinFromTime(utctime),
        2068                 :                 SecFromTime(utctime),
        2069             180 :                 msFromTime(utctime));
        2070              90 : }
        2071                 :
        2072                 : static JSBool
        2073             252 : date_utc_format(JSContext *cx, Native native, CallArgs args,
        2074                 :                 void (*printFunc)(char*, size_t, double))
        2075                 : {
        2076                 :     bool ok;
        2077             252 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
        2078             252 :     if (!obj)
        2079             126 :         return ok;
        2080                 :
        2081             126 :     double utctime = obj->getDateUTCTime().toNumber();
        2082                 :
        2083                 :     char buf[100];
        2084             126 :     if (!JSDOUBLE_IS_FINITE(utctime)) {
        2085               9 :         if (printFunc == print_iso_string) {
        2086               9 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DATE);
        2087               9 :             return false;
        2088                 :         }
        2089                 :
        2090               0 :         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
        2091                 :     } else {
        2092             117 :         (*printFunc)(buf, sizeof buf, utctime);
        2093                 :     }
        2094                 :
        2095             117 :     JSString *str = JS_NewStringCopyZ(cx, buf);
        2096             117 :     if (!str)
        2097               0 :         return false;
        2098             117 :     args.rval().setString(str);
        2099             117 :     return true;
        2100                 : }
        2101                 :
        2102                 : static JSBool
        2103              90 : date_toGMTString(JSContext *cx, unsigned argc, Value *vp)
        2104                 : {
        2105              90 :     return date_utc_format(cx, date_toGMTString, CallArgsFromVp(argc, vp), print_gmt_string);
        2106                 : }
        2107                 :
        2108                 : static JSBool
        2109             162 : date_toISOString(JSContext *cx, unsigned argc, Value *vp)
        2110                 : {
        2111             162 :     return date_utc_format(cx, date_toISOString, CallArgsFromVp(argc, vp), print_iso_string);
        2112                 : }
        2113                 :
        2114                 : /* ES5 15.9.5.44. */
        2115                 : static JSBool
        2116               0 : date_toJSON(JSContext *cx, unsigned argc, Value *vp)
        2117                 : {
        2118                 :     /* Step 1. */
        2119               0 :     JSObject *obj = ToObject(cx, &vp[1]);
        2120               0 :     if (!obj)
        2121               0 :         return false;
        2122                 :
        2123                 :     /* Step 2. */
        2124               0 :     Value tv = ObjectValue(*obj);
        2125               0 :     if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
        2126               0 :         return false;
        2127                 :
        2128                 :     /* Step 3. */
        2129               0 :     if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
        2130               0 :         vp->setNull();
        2131               0 :         return true;
        2132                 :     }
        2133                 :
        2134                 :     /* Step 4. */
        2135               0 :     Value &toISO = vp[0];
        2136               0 :     if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
        2137               0 :         return false;
        2138                 :
        2139                 :     /* Step 5. */
        2140               0 :     if (!js_IsCallable(toISO)) {
        2141                 :         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
        2142               0 :                                      JSMSG_BAD_TOISOSTRING_PROP);
        2143               0 :         return false;
        2144                 :     }
        2145                 :
        2146                 :     /* Step 6. */
        2147               0 :     InvokeArgsGuard args;
        2148               0 :     if (!cx->stack.pushInvokeArgs(cx, 0, &args))
        2149               0 :         return false;
        2150                 :
        2151               0 :     args.calleev() = toISO;
        2152               0 :     args.thisv().setObject(*obj);
        2153                 :
        2154               0 :     if (!Invoke(cx, args))
        2155               0 :         return false;
        2156               0 :     *vp = args.rval();
        2157               0 :     return true;
        2158                 : }
        2159                 :
        2160                 : /* for Date.toLocaleString; interface to PRMJTime date struct.
        2161                 :  */
        2162                 : static void
        2163             189 : new_explode(double timeval, PRMJTime *split, JSContext *cx)
        2164                 : {
        2165             189 :     int year = YearFromTime(timeval);
        2166                 :
        2167             189 :     split->tm_usec = int32_t(msFromTime(timeval)) * 1000;
        2168             189 :     split->tm_sec = int8_t(SecFromTime(timeval));
        2169             189 :     split->tm_min = int8_t(MinFromTime(timeval));
        2170             189 :     split->tm_hour = int8_t(HourFromTime(timeval));
        2171             189 :     split->tm_mday = int8_t(DateFromTime(timeval));
        2172             189 :     split->tm_mon = int8_t(MonthFromTime(timeval));
        2173             189 :     split->tm_wday = int8_t(WeekDay(timeval));
        2174             189 :     split->tm_year = year;
        2175             189 :     split->tm_yday = int16_t(DayWithinYear(timeval, year));
        2176                 :
        2177                 :     /* not sure how this affects things, but it doesn't seem
        2178                 :        to matter. */
        2179             189 :     split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0);
        2180             189 : }
        2181                 :
        2182                 : typedef enum formatspec {
        2183                 :     FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
        2184                 : } formatspec;
        2185                 :
        2186                 : /* helper function */
        2187                 : static JSBool
        2188              81 : date_format(JSContext *cx, double date, formatspec format, CallReceiver call)
        2189                 : {
        2190                 :     char buf[100];
        2191                 :     JSString *str;
        2192                 :     char tzbuf[100];
        2193                 :     JSBool usetz;
        2194                 :     size_t i, tzlen;
        2195                 :     PRMJTime split;
        2196                 :
        2197              81 :     if (!JSDOUBLE_IS_FINITE(date)) {
        2198               0 :         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
        2199                 :     } else {
        2200              81 :         double local = LocalTime(date, cx);
        2201                 :
        2202                 :         /* offset from GMT in minutes.  The offset includes daylight savings,
        2203                 :            if it applies. */
        2204              81 :         int minutes = (int) floor(AdjustTime(date, cx) / msPerMinute);
        2205                 :
        2206                 :         /* map 510 minutes to 0830 hours */
        2207              81 :         int offset = (minutes / 60) * 100 + minutes % 60;
        2208                 :
        2209                 :         /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
        2210                 :          * printed as 'GMT-0800' rather than as 'PST' to avoid
        2211                 :          * operating-system dependence on strftime (which
        2212                 :          * PRMJ_FormatTimeUSEnglish calls, for %Z only.)  win32 prints
        2213                 :          * PST as 'Pacific Standard Time.'  This way we always know
        2214                 :          * what we're getting, and can parse it if we produce it.
        2215                 :          * The OS TZA string is included as a comment.
        2216                 :          */
        2217                 :
        2218                 :         /* get a timezone string from the OS to include as a
        2219                 :            comment. */
        2220              81 :         new_explode(date, &split, cx);
        2221              81 :         if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
        2222                 :
        2223                 :             /* Decide whether to use the resulting timezone string.
        2224                 :              *
        2225                 :              * Reject it if it contains any non-ASCII, non-alphanumeric
        2226                 :              * characters.  It's then likely in some other character
        2227                 :              * encoding, and we probably won't display it correctly.
        2228                 :              */
        2229              81 :             usetz = JS_TRUE;
        2230              81 :             tzlen = strlen(tzbuf);
        2231              81 :             if (tzlen > 100) {
        2232               0 :                 usetz = JS_FALSE;
        2233                 :             } else {
        2234             486 :                 for (i = 0; i < tzlen; i++) {
        2235             405 :                     jschar c = tzbuf[i];
        2236             810 :                     if (c > 127 ||
        2237             567 :                         !(isalpha(c) || isdigit(c) ||
        2238             162 :                           c == ' ' || c == '(' || c == ')')) {
        2239               0 :                         usetz = JS_FALSE;
        2240                 :                     }
        2241                 :                 }
        2242                 :             }
        2243                 :
        2244                 :             /* Also reject it if it's not parenthesized or if it's '()'. */
        2245              81 :             if (tzbuf[0] != '(' || tzbuf[1] == ')')
        2246               0 :                 usetz = JS_FALSE;
        2247                 :         } else
        2248               0 :             usetz = JS_FALSE;
        2249                 :
        2250              81 :         switch (format) {
        2251                 :           case FORMATSPEC_FULL:
        2252                 :             /*
        2253                 :              * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
        2254                 :              * requires a PRMJTime... which only has 16-bit years.  Sub-ECMA.
        2255                 :              */
        2256                 :             /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
        2257                 :             JS_snprintf(buf, sizeof buf,
        2258                 :                         "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
        2259              27 :                         days[WeekDay(local)],
        2260              27 :                         months[MonthFromTime(local)],
        2261                 :                         DateFromTime(local),
        2262                 :                         YearFromTime(local),
        2263                 :                         HourFromTime(local),
        2264                 :                         MinFromTime(local),
        2265                 :                         SecFromTime(local),
        2266                 :                         offset,
        2267                 :                         usetz ? " " : "",
        2268              81 :                         usetz ? tzbuf : "");
        2269              27 :             break;
        2270                 :           case FORMATSPEC_DATE:
        2271                 :             /* Tue Oct 31 2000 */
        2272                 :             JS_snprintf(buf, sizeof buf,
        2273                 :                         "%s %s %.2d %.4d",
        2274              27 :                         days[WeekDay(local)],
        2275              27 :                         months[MonthFromTime(local)],
        2276                 :                         DateFromTime(local),
        2277              81 :                         YearFromTime(local));
        2278              27 :             break;
        2279                 :           case FORMATSPEC_TIME:
        2280                 :             /* 09:41:40 GMT-0800 (PST) */
        2281                 :             JS_snprintf(buf, sizeof buf,
        2282                 :                         "%.2d:%.2d:%.2d GMT%+.4d%s%s",
        2283                 :                         HourFromTime(local),
        2284                 :                         MinFromTime(local),
        2285                 :                         SecFromTime(local),
        2286                 :                         offset,
        2287                 :                         usetz ? " " : "",
        2288              27 :                         usetz ? tzbuf : "");
        2289              27 :             break;
        2290                 :         }
        2291                 :     }
        2292                 :
        2293              81 :     str = JS_NewStringCopyZ(cx, buf);
        2294              81 :     if (!str)
        2295               0 :         return JS_FALSE;
        2296              81 :     call.rval().setString(str);
        2297              81 :     return JS_TRUE;
        2298                 : }
        2299                 :
        2300                 : static bool
        2301             108 : ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *format)
        2302                 : {
        2303             108 :     double utctime = obj->getDateUTCTime().toNumber();
        2304                 :
        2305                 :     char buf[100];
        2306             108 :     if (!JSDOUBLE_IS_FINITE(utctime)) {
        2307               0 :         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
        2308                 :     } else {
        2309                 :         int result_len;
        2310             108 :         double local = LocalTime(utctime, cx);
        2311                 :         PRMJTime split;
        2312             108 :         new_explode(local, &split, cx);
        2313                 :
        2314                 :         /* let PRMJTime format it.       */
        2315             108 :         result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
        2316                 :
        2317                 :         /* If it failed, default to toString. */
        2318             108 :         if (result_len == 0)
        2319               0 :             return date_format(cx, utctime, FORMATSPEC_FULL, call);
        2320                 :
        2321                 :         /* Hacked check against undesired 2-digit year 00/00/00 form. */
        2322             135 :         if (strcmp(format, "%x") == 0 && result_len >= 6 &&
        2323                 :             /* Format %x means use OS settings, which may have 2-digit yr, so
        2324                 :                hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
        2325              27 :             !isdigit(buf[result_len - 3]) &&
        2326               0 :             isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
        2327                 :             /* ...but not if starts with 4-digit year, like 2022/3/11. */
        2328               0 :             !(isdigit(buf[0]) && isdigit(buf[1]) &&
        2329               0 :               isdigit(buf[2]) && isdigit(buf[3]))) {
        2330               0 :             JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
        2331               0 :                         "%d", js_DateGetYear(cx, obj));
        2332                 :         }
        2333                 :
        2334                 :     }
        2335                 :
        2336             108 :     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
        2337               0 :         return cx->localeCallbacks->localeToUnicode(cx, buf, &call.rval());
        2338                 :
        2339             108 :     JSString *str = JS_NewStringCopyZ(cx, buf);
        2340             108 :     if (!str)
        2341               0 :         return false;
        2342             108 :     call.rval().setString(str);
        2343             108 :     return true;
        2344                 : }
        2345                 :
        2346                 : /*
        2347                 :  * NB: Because of NonGenericMethodGuard, the calling native return immediately
        2348                 :  * after calling date_toLocaleHelper, even if it returns 'true'.
        2349                 :  */
        2350                 : static JSBool
        2351             360 : date_toLocaleHelper(JSContext *cx, unsigned argc, Value *vp, Native native, const char *format)
        2352                 : {
        2353             360 :     CallArgs args = CallArgsFromVp(argc, vp);
        2354                 :
        2355                 :     bool ok;
        2356             360 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
        2357             360 :     if (!obj)
        2358             252 :         return ok;
        2359                 :
        2360             108 :     return ToLocaleHelper(cx, args, obj, format);
        2361                 : }
        2362                 :
        2363                 : static JSBool
        2364             180 : date_toLocaleStringHelper(JSContext *cx, Native native, unsigned argc, Value *vp)
        2365                 : {
        2366                 :     /*
        2367                 :      * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
        2368                 :      * with msvc; '%#c' requests that a full year be used in the result string.
        2369                 :      */
        2370                 :     return date_toLocaleHelper(cx, argc, vp, native,
        2371                 : #if defined(_WIN32) && !defined(__MWERKS__)
        2372                 :                                    "%#c"
        2373                 : #else
        2374                 :                                    "%c"
        2375                 : #endif
        2376             180 :                                );
        2377                 : }
        2378                 :
        2379                 : static JSBool
        2380              90 : date_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
        2381                 : {
        2382              90 :     return date_toLocaleStringHelper(cx, date_toLocaleString, argc, vp);
        2383                 : }
        2384                 :
        2385                 : static JSBool
        2386              90 : date_toLocaleDateString(JSContext *cx, unsigned argc, Value *vp)
        2387                 : {
        2388                 :     /*
        2389                 :      * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
        2390                 :      * with msvc; '%#x' requests that a full year be used in the result string.
        2391                 :      */
        2392                 :     return date_toLocaleHelper(cx, argc, vp, date_toLocaleDateString,
        2393                 : #if defined(_WIN32) && !defined(__MWERKS__)
        2394                 :                                    "%#x"
        2395                 : #else
        2396                 :                                    "%x"
        2397                 : #endif
        2398              90 :                                );
        2399                 : }
        2400                 :
        2401                 : static JSBool
        2402              90 : date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp)
        2403                 : {
        2404              90 :     return date_toLocaleHelper(cx, argc, vp, date_toLocaleTimeString, "%X");
        2405                 : }
        2406                 :
        2407                 : static JSBool
        2408              90 : date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
        2409                 : {
        2410              90 :     if (argc == 0)
        2411              90 :         return date_toLocaleStringHelper(cx, date_toLocaleFormat, argc, vp);
        2412                 :
        2413               0 :     CallArgs args = CallArgsFromVp(argc, vp);
        2414                 :
        2415                 :     bool ok;
        2416               0 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &ok);
        2417               0 :     if (!obj)
        2418               0 :         return ok;
        2419                 :
        2420               0 :     JSString *fmt = ToString(cx, args[0]);
        2421               0 :     if (!fmt)
        2422               0 :         return false;
        2423                 :
        2424               0 :     args[0].setString(fmt);
        2425               0 :     JSAutoByteString fmtbytes(cx, fmt);
        2426               0 :     if (!fmtbytes)
        2427               0 :         return false;
        2428                 :
        2429               0 :     return ToLocaleHelper(cx, args, obj, fmtbytes.ptr());
        2430                 : }
        2431                 :
        2432                 : static JSBool
        2433              90 : date_toTimeString(JSContext *cx, unsigned argc, Value *vp)
        2434                 : {
        2435              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        2436                 :
        2437                 :     bool ok;
        2438              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toTimeString, &DateClass, &ok);
        2439              90 :     if (!obj)
        2440              63 :         return ok;
        2441                 :
        2442              27 :     return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_TIME, args);
        2443                 : }
        2444                 :
        2445                 : static JSBool
        2446              90 : date_toDateString(JSContext *cx, unsigned argc, Value *vp)
        2447                 : {
        2448              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        2449                 :
        2450                 :     bool ok;
        2451              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toDateString, &DateClass, &ok);
        2452              90 :     if (!obj)
        2453              63 :         return ok;
        2454                 :
        2455              27 :     return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_DATE, args);
        2456                 : }
        2457                 :
        2458                 : #if JS_HAS_TOSOURCE
        2459                 : static JSBool
        2460              90 : date_toSource(JSContext *cx, unsigned argc, Value *vp)
        2461                 : {
        2462              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        2463                 :
        2464                 :     bool ok;
        2465              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &ok);
        2466              90 :     if (!obj)
        2467              63 :         return ok;
        2468                 :
        2469              54 :     StringBuffer sb(cx);
        2470              54 :     if (!sb.append("(new Date(") || !NumberValueToStringBuffer(cx, obj->getDateUTCTime(), sb) ||
        2471              27 :         !sb.append("))"))
        2472                 :     {
        2473               0 :         return false;
        2474                 :     }
        2475                 :
        2476              27 :     JSString *str = sb.finishString();
        2477              27 :     if (!str)
        2478               0 :         return false;
        2479              27 :     args.rval().setString(str);
        2480              27 :     return true;
        2481                 : }
        2482                 : #endif
        2483                 :
        2484                 : static JSBool
        2485              90 : date_toString(JSContext *cx, unsigned argc, Value *vp)
        2486                 : {
        2487              90 :     CallArgs args = CallArgsFromVp(argc, vp);
        2488                 :
        2489                 :     bool ok;
        2490              90 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toString, &DateClass, &ok);
        2491              90 :     if (!obj)
        2492              63 :         return ok;
        2493                 :
        2494              27 :     return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
        2495                 : }
        2496                 :
        2497                 : static JSBool
        2498             135 : date_valueOf(JSContext *cx, unsigned argc, Value *vp)
        2499                 : {
        2500             135 :     CallArgs args = CallArgsFromVp(argc, vp);
        2501                 :
        2502                 :     bool ok;
        2503             135 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &ok);
        2504             135 :     if (!obj)
        2505              63 :         return ok;
        2506                 :
        2507                 :     /* If called directly with no arguments, convert to a time number. */
        2508              72 :     if (argc == 0) {
        2509              72 :         args.rval() = obj->getDateUTCTime();
        2510              72 :         return true;
        2511                 :     }
        2512                 :
        2513                 :     /* Convert to number only if the hint was given, otherwise favor string. */
        2514               0 :     JSString *str = ToString(cx, args[0]);
        2515               0 :     if (!str)
        2516               0 :         return false;
        2517               0 :     JSLinearString *linear_str = str->ensureLinear(cx);
        2518               0 :     if (!linear_str)
        2519               0 :         return false;
        2520               0 :     JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
        2521               0 :     if (EqualStrings(linear_str, number_str)) {
        2522               0 :         args.rval() = obj->getDateUTCTime();
        2523               0 :         return true;
        2524                 :     }
        2525               0 :     return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
        2526                 : }
        2527                 :
        2528                 : static JSFunctionSpec date_static_methods[] = {
        2529                 :     JS_FN("UTC",                 date_UTC,                MAXARGS,0),
        2530                 :     JS_FN("parse",               date_parse,              1,0),
        2531                 :     JS_FN("now",                 date_now,                0,0),
        2532                 :     JS_FS_END
        2533                 : };
        2534                 :
        2535                 : static JSFunctionSpec date_methods[] = {
        2536                 :     JS_FN("getTime",             date_getTime,            0,0),
        2537                 :     JS_FN("getTimezoneOffset",   date_getTimezoneOffset,  0,0),
        2538                 :     JS_FN("getYear",             date_getYear,            0,0),
        2539                 :     JS_FN("getFullYear",         date_getFullYear,        0,0),
        2540                 :     JS_FN("getUTCFullYear",      date_getUTCFullYear,     0,0),
        2541                 :     JS_FN("getMonth",            date_getMonth,           0,0),
        2542                 :     JS_FN("getUTCMonth",         date_getUTCMonth,        0,0),
        2543                 :     JS_FN("getDate",             date_getDate,            0,0),
        2544                 :     JS_FN("getUTCDate",          date_getUTCDate,         0,0),
        2545                 :     JS_FN("getDay",              date_getDay,             0,0),
        2546                 :     JS_FN("getUTCDay",           date_getUTCDay,          0,0),
        2547                 :     JS_FN("getHours",            date_getHours,           0,0),
        2548                 :     JS_FN("getUTCHours",         date_getUTCHours,        0,0),
        2549                 :     JS_FN("getMinutes",          date_getMinutes,         0,0),
        2550                 :     JS_FN("getUTCMinutes",       date_getUTCMinutes,      0,0),
        2551                 :     JS_FN("getSeconds",          date_getUTCSeconds,      0,0),
        2552                 :     JS_FN("getUTCSeconds",       date_getUTCSeconds,      0,0),
        2553                 :     JS_FN("getMilliseconds",     date_getUTCMilliseconds, 0,0),
        2554                 :     JS_FN("getUTCMilliseconds",  date_getUTCMilliseconds, 0,0),
        2555                 :     JS_FN("setTime",             date_setTime,            1,0),
        2556                 :     JS_FN("setYear",             date_setYear,            1,0),
        2557                 :     JS_FN("setFullYear",         date_setFullYear,        3,0),
        2558                 :     JS_FN("setUTCFullYear",      date_setUTCFullYear,     3,0),
        2559                 :     JS_FN("setMonth",            date_setMonth,           2,0),
        2560                 :     JS_FN("setUTCMonth",         date_setUTCMonth,        2,0),
        2561                 :     JS_FN("setDate",             date_setDate,            1,0),
        2562                 :     JS_FN("setUTCDate",          date_setUTCDate,         1,0),
        2563                 :     JS_FN("setHours",            date_setHours,           4,0),
        2564                 :     JS_FN("setUTCHours",         date_setUTCHours,        4,0),
        2565                 :     JS_FN("setMinutes",          date_setMinutes,         3,0),
        2566                 :     JS_FN("setUTCMinutes",       date_setUTCMinutes,      3,0),
        2567                 :     JS_FN("setSeconds",          date_setSeconds,         2,0),
        2568                 :     JS_FN("setUTCSeconds",       date_setUTCSeconds,      2,0),
        2569                 :     JS_FN("setMilliseconds",     date_setMilliseconds,    1,0),
        2570                 :     JS_FN("setUTCMilliseconds",  date_setUTCMilliseconds, 1,0),
        2571                 :     JS_FN("toUTCString",         date_toGMTString,        0,0),
        2572                 :     JS_FN(js_toLocaleString_str, date_toLocaleString,     0,0),
        2573                 :     JS_FN("toLocaleDateString",  date_toLocaleDateString, 0,0),
        2574                 :     JS_FN("toLocaleTimeString",  date_toLocaleTimeString, 0,0),
        2575                 :     JS_FN("toLocaleFormat",      date_toLocaleFormat,     0,0),
        2576                 :     JS_FN("toDateString",        date_toDateString,       0,0),
        2577                 :     JS_FN("toTimeString",        date_toTimeString,       0,0),
        2578                 :     JS_FN("toISOString",         date_toISOString,        0,0),
        2579                 :     JS_FN(js_toJSON_str,         date_toJSON,             1,0),
        2580                 : #if JS_HAS_TOSOURCE
        2581                 :     JS_FN(js_toSource_str,       date_toSource,           0,0),
        2582                 : #endif
        2583                 :     JS_FN(js_toString_str,       date_toString,           0,0),
        2584                 :     JS_FN(js_valueOf_str,        date_valueOf,            0,0),
        2585                 :     JS_FS_END
        2586                 : };
        2587                 :
        2588                 : JSBool
        2589           10503 : js_Date(JSContext *cx, unsigned argc, Value *vp)
        2590                 : {
        2591           10503 :     CallArgs args = CallArgsFromVp(argc, vp);
        2592                 :
        2593                 :     /* Date called as function. */
        2594           10503 :     if (!IsConstructing(args))
        2595               0 :         return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args);
        2596                 :
        2597                 :     /* Date called as constructor. */
        2598                 :     double d;
        2599           10503 :     if (args.length() == 0) {
        2600            1359 :         d = NowAsMillis();
        2601            9144 :     } else if (args.length() == 1) {
        2602            9135 :         if (!args[0].isString()) {
        2603                 :             /* the argument is a millisecond number */
        2604             108 :             if (!ToNumber(cx, args[0], &d))
        2605               0 :                 return false;
        2606             108 :             d = TIMECLIP(d);
        2607                 :         } else {
        2608                 :             /* the argument is a string; parse it. */
        2609            9027 :             JSString *str = ToString(cx, args[0]);
        2610            9027 :             if (!str)
        2611               0 :                 return false;
        2612            9027 :             args[0].setString(str);
        2613            9027 :             JSLinearString *linearStr = str->ensureLinear(cx);
        2614            9027 :             if (!linearStr)
        2615               0 :                 return false;
        2616                 :
        2617            9027 :             if (!date_parseString(linearStr, &d, cx))
        2618               0 :                 d = js_NaN;
        2619                 :             else
        2620            9027 :                 d = TIMECLIP(d);
        2621                 :         }
        2622                 :     } else {
        2623                 :         double msec_time;
        2624               9 :         if (!date_msecFromArgs(cx, args, &msec_time))
        2625               0 :             return false;
        2626                 :
        2627               9 :         if (JSDOUBLE_IS_FINITE(msec_time)) {
        2628               9 :             msec_time = UTC(msec_time, cx);
        2629               9 :             msec_time = TIMECLIP(msec_time);
        2630                 :         }
        2631               9 :         d = msec_time;
        2632                 :     }
        2633                 :
        2634           10503 :     JSObject *obj = js_NewDateObjectMsec(cx, d);
        2635           10503 :     if (!obj)
        2636               0 :         return false;
        2637                 :
        2638           10503 :     args.rval().setObject(*obj);
        2639           10503 :     return true;
        2640                 : }
        2641                 :
        2642                 : JSObject *
        2643             714 : js_InitDateClass(JSContext *cx, JSObject *obj)
        2644                 : {
        2645             714 :     JS_ASSERT(obj->isNative());
        2646                 :
        2647                 :     /* Set the static LocalTZA. */
        2648             714 :     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
        2649                 :
        2650             714 :     GlobalObject *global = &obj->asGlobal();
        2651                 :
        2652             714 :     JSObject *dateProto = global->createBlankPrototype(cx, &DateClass);
        2653             714 :     if (!dateProto)
        2654               0 :         return NULL;
        2655             714 :     SetDateToNaN(cx, dateProto);
        2656                 :
        2657             714 :     JSFunction *ctor = global->createConstructor(cx, js_Date, CLASS_ATOM(cx, Date), MAXARGS);
        2658             714 :     if (!ctor)
        2659               0 :         return NULL;
        2660                 :
        2661             714 :     if (!LinkConstructorAndPrototype(cx, ctor, dateProto))
        2662               0 :         return NULL;
        2663                 :
        2664             714 :     if (!DefinePropertiesAndBrand(cx, ctor, NULL, date_static_methods))
        2665               0 :         return NULL;
        2666                 :
        2667                 :     /*
        2668                 :      * Define all Date.prototype.* functions, then brand for trace-jitted code.
        2669                 :      * Date.prototype.toGMTString has the same initial value as
        2670                 :      * Date.prototype.toUTCString.
        2671                 :      */
        2672             714 :     if (!JS_DefineFunctions(cx, dateProto, date_methods))
        2673               0 :         return NULL;
        2674                 :     Value toUTCStringFun;
        2675             714 :     jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
        2676             714 :     jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
        2677            1428 :     if (!js_GetProperty(cx, dateProto, toUTCStringId, &toUTCStringFun) ||
        2678                 :         !js_DefineProperty(cx, dateProto, toGMTStringId, &toUTCStringFun,
        2679             714 :                            JS_PropertyStub, JS_StrictPropertyStub, 0))
        2680                 :     {
        2681               0 :         return NULL;
        2682                 :     }
        2683                 :
        2684             714 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_Date, ctor, dateProto))
        2685               0 :         return NULL;
        2686                 :
        2687             714 :     return dateProto;
        2688                 : }
        2689                 :
        2690                 : JS_FRIEND_API(JSObject *)
        2691           10503 : js_NewDateObjectMsec(JSContext *cx, double msec_time)
        2692                 : {
        2693           10503 :     JSObject *obj = NewBuiltinClassInstance(cx, &DateClass);
        2694           10503 :     if (!obj)
        2695               0 :         return NULL;
        2696           10503 :     if (!SetUTCTime(cx, obj, msec_time))
        2697               0 :         return NULL;
        2698           10503 :     return obj;
        2699                 : }
        2700                 :
        2701                 : JS_FRIEND_API(JSObject *)
        2702               0 : js_NewDateObject(JSContext* cx, int year, int mon, int mday,
        2703                 :                  int hour, int min, int sec)
        2704                 : {
        2705                 :     JSObject *obj;
        2706                 :     double msec_time;
        2707                 :
        2708               0 :     JS_ASSERT(mon < 12);
        2709               0 :     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
        2710               0 :     obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
        2711               0 :     return obj;
        2712                 : }
        2713                 :
        2714                 : JS_FRIEND_API(JSBool)
        2715               0 : js_DateIsValid(JSContext *cx, JSObject* obj)
        2716                 : {
        2717               0 :     return obj->isDate() && !JSDOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
        2718                 : }
        2719                 :
        2720                 : JS_FRIEND_API(int)
        2721               0 : js_DateGetYear(JSContext *cx, JSObject* obj)
        2722                 : {
        2723                 :     double localtime;
        2724                 :
        2725                 :     /* Preserve legacy API behavior of returning 0 for invalid dates. */
        2726               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
        2727               0 :         JSDOUBLE_IS_NaN(localtime)) {
        2728               0 :         return 0;
        2729                 :     }
        2730                 :
        2731               0 :     return (int) YearFromTime(localtime);
        2732                 : }
        2733                 :
        2734                 : JS_FRIEND_API(int)
        2735               0 : js_DateGetMonth(JSContext *cx, JSObject* obj)
        2736                 : {
        2737                 :     double localtime;
        2738                 :
        2739               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
        2740               0 :         JSDOUBLE_IS_NaN(localtime)) {
        2741               0 :         return 0;
        2742                 :     }
        2743                 :
        2744               0 :     return (int) MonthFromTime(localtime);
        2745                 : }
        2746                 :
        2747                 : JS_FRIEND_API(int)
        2748               0 : js_DateGetDate(JSContext *cx, JSObject* obj)
        2749                 : {
        2750                 :     double localtime;
        2751                 :
        2752               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
        2753               0 :         JSDOUBLE_IS_NaN(localtime)) {
        2754               0 :         return 0;
        2755                 :     }
        2756                 :
        2757               0 :     return (int) DateFromTime(localtime);
        2758                 : }
        2759                 :
        2760                 : JS_FRIEND_API(int)
        2761               0 : js_DateGetHours(JSContext *cx, JSObject* obj)
        2762                 : {
        2763                 :     double localtime;
        2764                 :
        2765               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
        2766               0 :         JSDOUBLE_IS_NaN(localtime)) {
        2767               0 :         return 0;
        2768                 :     }
        2769                 :
        2770               0 :     return (int) HourFromTime(localtime);
        2771                 : }
        2772                 :
        2773                 : JS_FRIEND_API(int)
        2774               0 : js_DateGetMinutes(JSContext *cx, JSObject* obj)
        2775                 : {
        2776                 :     double localtime;
        2777                 :
        2778               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
        2779               0 :         JSDOUBLE_IS_NaN(localtime)) {
        2780               0 :         return 0;
        2781                 :     }
        2782                 :
        2783               0 :     return (int) MinFromTime(localtime);
        2784                 : }
        2785                 :
        2786                 : JS_FRIEND_API(int)
        2787               0 : js_DateGetSeconds(JSContext *cx, JSObject* obj)
        2788                 : {
        2789               0 :     if (!obj->isDate())
        2790               0 :         return 0;
        2791                 :
        2792               0 :     double utctime = obj->getDateUTCTime().toNumber();
        2793               0 :     if (JSDOUBLE_IS_NaN(utctime))
        2794               0 :         return 0;
        2795               0 :     return (int) SecFromTime(utctime);
        2796                 : }
        2797                 :
        2798                 : JS_FRIEND_API(double)
        2799               9 : js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
        2800                 : {
        2801               9 :     return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0;
        2802                 : }
        2803                 :
        2804                 : #ifdef JS_THREADSAFE
        2805                 : #include "prinrval.h"
        2806                 :
        2807                 : JS_FRIEND_API(uint32_t)
        2808           18666 : js_IntervalNow()
        2809                 : {
        2810           18666 :     return uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
        2811                 : }
        2812                 :
        2813                 : #else /* !JS_THREADSAFE */
        2814                 :
        2815                 : JS_FRIEND_API(uint32_t)
        2816                 : js_IntervalNow()
        2817                 : {
        2818                 :     return uint32_t(PRMJ_Now() / PRMJ_USEC_PER_MSEC);
        2819                 : }
        2820                 : #endif

Generated by: LCOV version 1.7