LCOV - code coverage report
Current view: directory - js/src - jsdate.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1194 981 82.2 %
Date: 2012-06-02 Functions: 105 96 91.4 %

       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                 : 
      78                 : #include "jsinferinlines.h"
      79                 : #include "jsobjinlines.h"
      80                 : 
      81                 : #include "vm/MethodGuard-inl.h"
      82                 : #include "vm/Stack-inl.h"
      83                 : #include "vm/StringBuffer-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              24 : TimeWithinDay(double t)
     194                 : {
     195                 :     double result;
     196              24 :     result = fmod(t, msPerDay);
     197              24 :     if (result < 0)
     198               1 :         result += msPerDay;
     199              24 :     return result;
     200                 : }
     201                 : 
     202                 : static inline bool
     203           94695 : IsLeapYear(int year)
     204                 : {
     205           94695 :     return year % 4 == 0 && (year % 100 || (year % 400 == 0));
     206                 : }
     207                 : 
     208                 : static inline int
     209           76042 : DaysInYear(int year)
     210                 : {
     211           76042 :     return IsLeapYear(year) ? 366 : 365;
     212                 : }
     213                 : 
     214                 : static inline int
     215            9052 : DaysInFebruary(int year)
     216                 : {
     217            9052 :     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           13805 : YearFromTime(double t)
     229                 : {
     230           13805 :     int y = (int) floor(t /(msPerDay*365.2425)) + 1970;
     231           13805 :     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           13805 :     if (t2 > t) {
     239               0 :         y--;
     240                 :     } else {
     241           13805 :         if (t2 + msPerDay * DaysInYear(y) <= t)
     242              27 :             y++;
     243                 :     }
     244           13805 :     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             213 : DaysInMonth(int year, int month)
     262                 : {
     263             213 :     JSBool leap = IsLeapYear(year);
     264             213 :     int result = int(DayFromMonth(month, leap) - DayFromMonth(month-1, leap));
     265             213 :     return result;
     266                 : }
     267                 : 
     268                 : static int
     269            4600 : MonthFromTime(double t)
     270                 : {
     271                 :     int d, step;
     272            4600 :     int year = YearFromTime(t);
     273            4600 :     d = DayWithinYear(t, year);
     274                 : 
     275            4600 :     if (d < (step = 31))
     276              74 :         return 0;
     277            4526 :     if (d < (step += DaysInFebruary(year)))
     278              20 :         return 1;
     279            4506 :     if (d < (step += 31))
     280              15 :         return 2;
     281            4491 :     if (d < (step += 30))
     282              66 :         return 3;
     283            4425 :     if (d < (step += 31))
     284             164 :         return 4;
     285            4261 :     if (d < (step += 30))
     286            4179 :         return 5;
     287              82 :     if (d < (step += 31))
     288               0 :         return 6;
     289              82 :     if (d < (step += 31))
     290              18 :         return 7;
     291              64 :     if (d < (step += 30))
     292              15 :         return 8;
     293              49 :     if (d < (step += 31))
     294               0 :         return 9;
     295              49 :     if (d < (step += 30))
     296               3 :         return 10;
     297              46 :     return 11;
     298                 : }
     299                 : 
     300                 : static int
     301            4600 : DateFromTime(double t)
     302                 : {
     303                 :     int d, step, next;
     304            4600 :     int year = YearFromTime(t);
     305            4600 :     d = DayWithinYear(t, year);
     306                 : 
     307            4600 :     if (d <= (next = 30))
     308              74 :         return d + 1;
     309            4526 :     step = next;
     310            4526 :     if (d <= (next += DaysInFebruary(year)))
     311              20 :         return d - step;
     312            4506 :     step = next;
     313            4506 :     if (d <= (next += 31))
     314              15 :         return d - step;
     315            4491 :     step = next;
     316            4491 :     if (d <= (next += 30))
     317              66 :         return d - step;
     318            4425 :     step = next;
     319            4425 :     if (d <= (next += 31))
     320             164 :         return d - step;
     321            4261 :     step = next;
     322            4261 :     if (d <= (next += 30))
     323            4179 :         return d - step;
     324              82 :     step = next;
     325              82 :     if (d <= (next += 31))
     326               0 :         return d - step;
     327              82 :     step = next;
     328              82 :     if (d <= (next += 31))
     329              18 :         return d - step;
     330              64 :     step = next;
     331              64 :     if (d <= (next += 30))
     332              15 :         return d - step;
     333              49 :     step = next;
     334              49 :     if (d <= (next += 31))
     335               0 :         return d - step;
     336              49 :     step = next;
     337              49 :     if (d <= (next += 30))
     338               3 :         return d - step;
     339              46 :     step = next;
     340              46 :     return d - step;
     341                 : }
     342                 : 
     343                 : static int
     344           57701 : WeekDay(double t)
     345                 : {
     346                 :     int result;
     347           57701 :     result = (int) Day(t) + 4;
     348           57701 :     result = result % 7;
     349           57701 :     if (result < 0)
     350               0 :         result += 7;
     351           57701 :     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            9377 : MakeDay(double year, double month, double date)
     359                 : {
     360                 :     JSBool leap;
     361                 :     double yearday;
     362                 :     double monthday;
     363                 : 
     364            9377 :     year += floor(month / 12);
     365                 : 
     366            9377 :     month = fmod(month, 12.0);
     367            9377 :     if (month < 0)
     368               0 :         month += 12;
     369                 : 
     370            9377 :     leap = IsLeapYear((int) year);
     371                 : 
     372            9377 :     yearday = floor(TimeFromYear(year) / msPerDay);
     373            9377 :     monthday = DayFromMonth(month, leap);
     374                 : 
     375            9377 :     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              11 : EquivalentYearForDST(int year)
     403                 : {
     404                 :     int day;
     405                 : 
     406              11 :     day = (int) DayFromYear(year) + 4;
     407              11 :     day = day % 7;
     408              11 :     if (day < 0)
     409              10 :         day += 7;
     410                 : 
     411              11 :     return yearStartingWith[IsLeapYear(year)][day];
     412                 : }
     413                 : 
     414                 : /* LocalTZA gets set by js_InitDateClass() */
     415                 : static double LocalTZA;
     416                 : 
     417                 : static double
     418           55701 : DaylightSavingTA(double t, JSContext *cx)
     419                 : {
     420                 :     /* abort if NaN */
     421           55701 :     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           55701 :     if (t < 0.0 || t > 2145916800000.0) {
     429              11 :         int year = EquivalentYearForDST(YearFromTime(t));
     430              11 :         double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
     431              11 :         t = MakeDate(day, TimeWithinDay(t));
     432                 :     }
     433                 : 
     434           55701 :     int64_t timeMilliseconds = static_cast<int64_t>(t);
     435           55701 :     int64_t offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx);
     436           55701 :     return static_cast<double>(offsetMilliseconds);
     437                 : }
     438                 : 
     439                 : static double
     440           54968 : AdjustTime(double date, JSContext *cx)
     441                 : {
     442           54968 :     double t = DaylightSavingTA(date, cx) + LocalTZA;
     443           54968 :     t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
     444           54968 :     return t;
     445                 : }
     446                 : 
     447                 : static double
     448           54248 : LocalTime(double t, JSContext *cx)
     449                 : {
     450           54248 :     return t + AdjustTime(t, cx);
     451                 : }
     452                 : 
     453                 : static double
     454             454 : UTC(double t, JSContext *cx)
     455                 : {
     456             454 :     return t - AdjustTime(t - LocalTZA, cx);
     457                 : }
     458                 : 
     459                 : static int
     460            4802 : HourFromTime(double t)
     461                 : {
     462            4802 :     int result = (int) fmod(floor(t/msPerHour), HoursPerDay);
     463            4802 :     if (result < 0)
     464               9 :         result += (int)HoursPerDay;
     465            4802 :     return result;
     466                 : }
     467                 : 
     468                 : static int
     469            4803 : MinFromTime(double t)
     470                 : {
     471            4803 :     int result = (int) fmod(floor(t / msPerMinute), MinutesPerHour);
     472            4803 :     if (result < 0)
     473               0 :         result += (int)MinutesPerHour;
     474            4803 :     return result;
     475                 : }
     476                 : 
     477                 : static int
     478            1444 : SecFromTime(double t)
     479                 : {
     480            1444 :     int result = (int) fmod(floor(t / msPerSecond), SecondsPerMinute);
     481            1444 :     if (result < 0)
     482               0 :         result += (int)SecondsPerMinute;
     483            1444 :     return result;
     484                 : }
     485                 : 
     486                 : static int
     487            1040 : msFromTime(double t)
     488                 : {
     489            1040 :     int result = (int) fmod(t, msPerSecond);
     490            1040 :     if (result < 0)
     491               0 :         result += (int)msPerSecond;
     492            1040 :     return result;
     493                 : }
     494                 : 
     495                 : /**
     496                 :  * end of ECMA 'support' functions
     497                 :  */
     498                 : 
     499                 : static JSBool
     500             450 : date_convert(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
     501                 : {
     502             450 :     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
     503             450 :     JS_ASSERT(obj->isDate());
     504                 : 
     505             450 :     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          210497 : date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
     554                 :                    int count, int ignoreCase)
     555                 : {
     556          210497 :     JSBool result = JS_FALSE;
     557                 :     /* return true if matches, otherwise, false */
     558                 : 
     559          502786 :     while (count > 0 && s1[s1off] && s2[s2off]) {
     560          283102 :         if (ignoreCase) {
     561          283102 :             if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off]))
     562          201310 :                 break;
     563                 :         } else {
     564               0 :             if ((jschar)s1[s1off] != s2[s2off]) {
     565               0 :                 break;
     566                 :             }
     567                 :         }
     568           81792 :         s1off++;
     569           81792 :         s2off++;
     570           81792 :         count--;
     571                 :     }
     572                 : 
     573          210497 :     if (count == 0) {
     574            9187 :         result = JS_TRUE;
     575                 :     }
     576                 : 
     577          210497 :     return result;
     578                 : }
     579                 : 
     580                 : /* find UTC time from given date... no 1900 correction! */
     581                 : static double
     582            9353 : 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            9353 :     day = MakeDay(year, mon, mday);
     590            9353 :     msec_time = MakeTime(hour, min, sec, msec);
     591            9353 :     result = MakeDate(day, msec_time);
     592            9353 :     return result;
     593                 : }
     594                 : 
     595                 : /* compute the time in msec (unclipped) from the given args */
     596                 : #define MAXARGS        7
     597                 : 
     598                 : static JSBool
     599              66 : date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
     600                 : {
     601                 :     unsigned loop;
     602                 :     double array[MAXARGS];
     603                 :     double msec_time;
     604                 : 
     605             465 :     for (loop = 0; loop < MAXARGS; loop++) {
     606             408 :         if (loop < args.length()) {
     607                 :             double d;
     608             311 :             if (!ToNumber(cx, args[loop], &d))
     609               0 :                 return JS_FALSE;
     610                 :             /* return NaN if any arg is not finite */
     611             311 :             if (!JSDOUBLE_IS_FINITE(d)) {
     612               9 :                 *rval = js_NaN;
     613               9 :                 return JS_TRUE;
     614                 :             }
     615             302 :             array[loop] = js_DoubleToInteger(d);
     616                 :         } else {
     617              97 :             if (loop == 2) {
     618               0 :                 array[loop] = 1; /* Default the date argument to 1. */
     619                 :             } else {
     620              97 :                 array[loop] = 0;
     621                 :             }
     622                 :         }
     623                 :     }
     624                 : 
     625                 :     /* adjust 2-digit years into the 20th century */
     626              57 :     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              57 :                                   array[3], array[4], array[5], array[6]);
     631              57 :     *rval = msec_time;
     632              57 :     return JS_TRUE;
     633                 : }
     634                 : 
     635                 : /*
     636                 :  * See ECMA 15.9.4.[3-10];
     637                 :  */
     638                 : static JSBool
     639              21 : date_UTC(JSContext *cx, unsigned argc, Value *vp)
     640                 : {
     641              21 :     CallArgs args = CallArgsFromVp(argc, vp);
     642                 : 
     643                 :     double msec_time;
     644              21 :     if (!date_msecFromArgs(cx, args, &msec_time))
     645               0 :         return JS_FALSE;
     646                 : 
     647              21 :     msec_time = TIMECLIP(msec_time);
     648                 : 
     649              21 :     args.rval().setNumber(msec_time);
     650              21 :     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           10191 : digits(size_t *result, const jschar *s, size_t *i, size_t limit)
     662                 : {
     663           10191 :     size_t init = *i;
     664           10191 :     *result = 0;
     665           46519 :     while (*i < limit &&
     666           23477 :            ('0' <= s[*i] && s[*i] <= '9')) {
     667            2660 :         *result *= 10;
     668            2660 :         *result += (s[*i] - '0');
     669            2660 :         ++(*i);
     670                 :     }
     671           10191 :     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               5 : fractional(double *result, const jschar *s, size_t *i, size_t limit)
     684                 : {
     685               5 :     double factor = 0.1;
     686               5 :     size_t init = *i;
     687               5 :     *result = 0.0;
     688              46 :     while (*i < limit &&
     689              24 :            ('0' <= s[*i] && s[*i] <= '9')) {
     690              12 :         *result += (s[*i] - '0') * factor;
     691              12 :         factor *= 0.1;
     692              12 :         ++(*i);
     693                 :     }
     694               5 :     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           10191 : ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
     706                 : {
     707           10191 :     size_t init = *i;
     708                 : 
     709           10191 :     if (digits(result, s, i, JS_MIN(limit, init+n)))
     710            1125 :         return ((*i - init) == n);
     711                 : 
     712            9066 :     *i = init;
     713            9066 :     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            9301 : date_parseISOString(JSLinearString *str, double *result, JSContext *cx)
     774                 : {
     775                 :     double msec;
     776                 : 
     777                 :     const jschar *s;
     778                 :     size_t limit;
     779            9301 :     size_t i = 0;
     780            9301 :     int tzMul = 1;
     781            9301 :     int dateMul = 1;
     782            9301 :     size_t year = 1970;
     783            9301 :     size_t month = 1;
     784            9301 :     size_t day = 1;
     785            9301 :     size_t hour = 0;
     786            9301 :     size_t min = 0;
     787            9301 :     size_t sec = 0;
     788            9301 :     double frac = 0;
     789            9301 :     bool isLocalTime = JS_FALSE;
     790            9301 :     size_t tzHour = 0;
     791            9301 :     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            9301 :     s = str->chars();
     816            9301 :     limit = str->length();
     817                 : 
     818            9301 :     if (PEEK('+') || PEEK('-')) {
     819               0 :         if (PEEK('-'))
     820               0 :             dateMul = -1;
     821               0 :         ++i;
     822               0 :         NEED_NDIGITS(6, year);
     823            9301 :     } else if (!PEEK('T')) {
     824            9283 :         NEED_NDIGITS(4, year);
     825                 :     }
     826             234 :     DONE_DATE_UNLESS('-');
     827             140 :     NEED_NDIGITS(2, month);
     828             140 :     DONE_DATE_UNLESS('-');
     829             140 :     NEED_NDIGITS(2, day);
     830                 : 
     831                 :  done_date:
     832             234 :     DONE_UNLESS('T');
     833             146 :     NEED_NDIGITS(2, hour);
     834             125 :     NEED(':');
     835             125 :     NEED_NDIGITS(2, min);
     836                 : 
     837             125 :     if (PEEK(':')) {
     838             125 :         ++i;
     839             125 :         NEED_NDIGITS(2, sec);
     840             125 :         if (PEEK('.')) {
     841               5 :             ++i;
     842               5 :             if (!fractional(&frac, s, &i, limit))
     843               0 :                 goto syntax;
     844                 :         }
     845                 :     }
     846                 : 
     847             125 :     if (PEEK('Z')) {
     848               3 :         ++i;
     849             122 :     } else if (PEEK('+') || PEEK('-')) {
     850             116 :         if (PEEK('-'))
     851             116 :             tzMul = -1;
     852             116 :         ++i;
     853             116 :         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             116 :         if (PEEK(':'))
     859             116 :           ++i;
     860             116 :         NEED_NDIGITS(2, tzMin);
     861                 :     } else {
     862               6 :         isLocalTime = JS_TRUE;
     863                 :     }
     864                 : 
     865                 :  done:
     866             426 :     if (year > 275943 // ceil(1e8/365) + 1970
     867                 :         || (month == 0 || month > 12)
     868             213 :         || (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             213 :     if (i != limit)
     878              76 :         goto syntax;
     879                 : 
     880             137 :     month -= 1; /* convert month to 0-based */
     881                 : 
     882                 :     msec = date_msecFromDate(dateMul * (double)year, month, day,
     883                 :                              hour, min, sec,
     884             137 :                              frac * 1000.0);;
     885                 : 
     886             137 :     if (isLocalTime) {
     887               6 :         msec = UTC(msec, cx);
     888                 :     } else {
     889                 :         msec -= ((tzMul) * ((tzHour * msPerHour)
     890             131 :                             + (tzMin * msPerMinute)));
     891                 :     }
     892                 : 
     893             137 :     if (msec < -8.64e15 || msec > 8.64e15)
     894                 :         goto syntax;
     895                 : 
     896             137 :     *result = msec;
     897                 : 
     898             137 :     return JS_TRUE;
     899                 : 
     900                 :  syntax:
     901                 :     /* syntax error */
     902            9164 :     *result = 0;
     903            9164 :     return JS_FALSE;
     904                 : 
     905                 : #undef PEEK
     906                 : #undef NEED
     907                 : #undef DONE_UNLESS
     908                 : #undef NEED_NDIGITS
     909                 : }
     910                 : 
     911                 : static JSBool
     912            9301 : date_parseString(JSLinearString *str, double *result, JSContext *cx)
     913                 : {
     914                 :     double msec;
     915                 : 
     916                 :     const jschar *s;
     917                 :     size_t limit;
     918            9301 :     size_t i = 0;
     919            9301 :     int year = -1;
     920            9301 :     int mon = -1;
     921            9301 :     int mday = -1;
     922            9301 :     int hour = -1;
     923            9301 :     int min = -1;
     924            9301 :     int sec = -1;
     925            9301 :     int c = -1;
     926            9301 :     int n = -1;
     927            9301 :     int tzoffset = -1;
     928            9301 :     int prevc = 0;
     929            9301 :     JSBool seenplusminus = JS_FALSE;
     930                 :     int temp;
     931            9301 :     JSBool seenmonthname = JS_FALSE;
     932                 : 
     933            9301 :     if (date_parseISOString(str, result, cx))
     934             137 :         return JS_TRUE;
     935                 : 
     936            9164 :     s = str->chars();
     937            9164 :     limit = str->length();
     938            9164 :     if (limit == 0)
     939               0 :         goto syntax;
     940          146053 :     while (i < limit) {
     941          127730 :         c = s[i];
     942          127730 :         i++;
     943          127730 :         if (c <= ' ' || c == ',' || c == '-') {
     944           36449 :             if (c == '-' && '0' <= s[i] && s[i] <= '9') {
     945              50 :               prevc = c;
     946                 :             }
     947           36449 :             continue;
     948                 :         }
     949           91281 :         if (c == '(') { /* comments) */
     950              43 :             int depth = 1;
     951             215 :             while (i < limit) {
     952             172 :                 c = s[i];
     953             172 :                 i++;
     954             172 :                 if (c == '(') depth++;
     955             172 :                 else if (c == ')')
     956              43 :                     if (--depth <= 0)
     957              43 :                         break;
     958                 :             }
     959              43 :             continue;
     960                 :         }
     961           91238 :         if ('0' <= c && c <= '9') {
     962           54704 :             n = c - '0';
     963          191467 :             while (i < limit && '0' <= (c = s[i]) && c <= '9') {
     964           82059 :                 n = n * 10 + c - '0';
     965           82059 :                 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           54704 :             if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
     977                 :                 /* make ':' case below change tzoffset */
     978            9051 :                 seenplusminus = JS_TRUE;
     979                 : 
     980                 :                 /* offset */
     981            9051 :                 if (n < 24)
     982            9007 :                     n = n * 60; /* EG. "GMT-3" */
     983                 :                 else
     984              44 :                     n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
     985            9051 :                 if (prevc == '+')       /* plus means east of GMT */
     986            9001 :                     n = -n;
     987            9051 :                 if (tzoffset != 0 && tzoffset != -1)
     988               3 :                     goto syntax;
     989            9048 :                 tzoffset = n;
     990           45653 :             } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
     991             186 :                 if (c <= ' ' || c == ',' || c == '/' || i >= limit)
     992              93 :                     year = n;
     993                 :                 else
     994                 :                     goto syntax;
     995           45560 :             } else if (c == ':') {
     996           18158 :                 if (hour < 0)
     997            9079 :                     hour = /*byte*/ n;
     998            9079 :                 else if (min < 0)
     999            9079 :                     min = /*byte*/ n;
    1000                 :                 else
    1001               0 :                     goto syntax;
    1002           27402 :             } 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             186 :                 if (mon < 0)
    1006              93 :                     mon = /*byte*/ n;
    1007              93 :                 else if (mday < 0)
    1008              93 :                     mday = /*byte*/ n;
    1009                 :                 else
    1010               0 :                     goto syntax;
    1011           27216 :             } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
    1012                 :                 goto syntax;
    1013           27215 :             } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */
    1014               2 :                 if (tzoffset < 0)
    1015               0 :                     tzoffset -= n;
    1016                 :                 else
    1017               1 :                     tzoffset += n;
    1018           27214 :             } else if (hour >= 0 && min < 0) {
    1019               0 :                 min = /*byte*/ n;
    1020           27214 :             } else if (prevc == ':' && min >= 0 && sec < 0) {
    1021            9079 :                 sec = /*byte*/ n;
    1022           18135 :             } else if (mon < 0) {
    1023              22 :                 mon = /*byte*/n;
    1024           18113 :             } else if (mon >= 0 && mday < 0) {
    1025            9047 :                 mday = /*byte*/ n;
    1026            9066 :             } else if (mon >= 0 && mday >= 0 && year < 0) {
    1027            9066 :                 year = n;
    1028                 :             } else {
    1029                 :                 goto syntax;
    1030                 :             }
    1031           54700 :             prevc = 0;
    1032           36534 :         } else if (c == '/' || c == ':' || c == '+' || c == '-') {
    1033           27346 :             prevc = c;
    1034                 :         } else {
    1035            9188 :             size_t st = i - 1;
    1036                 :             int k;
    1037           72779 :             while (i < limit) {
    1038           63574 :                 c = s[i];
    1039           63574 :                 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
    1040            9171 :                     break;
    1041           54403 :                 i++;
    1042                 :             }
    1043            9188 :             if (i <= st + 1)
    1044               0 :                 goto syntax;
    1045          219686 :             for (k = ArrayLength(wtb); --k >= 0;)
    1046          210497 :                 if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
    1047            9187 :                     int action = ttb[k];
    1048            9187 :                     if (action != 0) {
    1049            9126 :                         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            9126 :                         } 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            9066 :                             if (seenmonthname) {
    1068               0 :                                 goto syntax;
    1069                 :                             }
    1070            9066 :                             seenmonthname = JS_TRUE;
    1071            9066 :                             temp = /*byte*/ (action - 2) + 1;
    1072                 : 
    1073            9066 :                             if (mon < 0) {
    1074            9047 :                                 mon = temp;
    1075              19 :                             } else if (mday < 0) {
    1076              19 :                                 mday = mon;
    1077              19 :                                 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              60 :                             tzoffset = action - 10000;
    1086                 :                         }
    1087                 :                     }
    1088            9187 :                     break;
    1089                 :                 }
    1090            9188 :             if (k < 0)
    1091               1 :                 goto syntax;
    1092            9187 :             prevc = 0;
    1093                 :         }
    1094                 :     }
    1095            9159 :     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            9159 :     if (seenmonthname) {
    1124            9066 :         if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
    1125                 :             goto syntax;
    1126                 :         }
    1127            9066 :         if (mday > year) {
    1128               0 :             temp = year;
    1129               0 :             year = mday;
    1130               0 :             mday = temp;
    1131                 :         }
    1132            9066 :         if (year >= 70 && year < 100) {
    1133               0 :             year += 1900;
    1134                 :         }
    1135              93 :     } else if (mon < 70) { /* (a) month/day/year */
    1136              18 :         if (year < 100) {
    1137               0 :             year += 1900;
    1138                 :         }
    1139              75 :     } 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              75 :         if (mday < 70) {
    1150              75 :             temp = year;
    1151              75 :             year = mon;
    1152              75 :             mon = mday;
    1153              75 :             mday = temp;
    1154                 :         } else {
    1155               0 :             goto syntax;
    1156                 :         }
    1157                 :     }
    1158            9159 :     mon -= 1; /* convert month to 0-based */
    1159            9159 :     if (sec < 0)
    1160              80 :         sec = 0;
    1161            9159 :     if (min < 0)
    1162              80 :         min = 0;
    1163            9159 :     if (hour < 0)
    1164              80 :         hour = 0;
    1165                 : 
    1166            9159 :     msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
    1167                 : 
    1168            9159 :     if (tzoffset == -1) { /* no time zone specified, have to use local */
    1169              97 :         msec = UTC(msec, cx);
    1170                 :     } else {
    1171            9062 :         msec += tzoffset * msPerMinute;
    1172                 :     }
    1173                 : 
    1174            9159 :     *result = msec;
    1175            9159 :     return JS_TRUE;
    1176                 : 
    1177                 : syntax:
    1178                 :     /* syntax error */
    1179               5 :     *result = 0;
    1180               5 :     return JS_FALSE;
    1181                 : }
    1182                 : 
    1183                 : static JSBool
    1184              43 : date_parse(JSContext *cx, unsigned argc, Value *vp)
    1185                 : {
    1186                 :     JSString *str;
    1187                 :     double result;
    1188                 : 
    1189              43 :     if (argc == 0) {
    1190               0 :         vp->setDouble(js_NaN);
    1191               0 :         return true;
    1192                 :     }
    1193              43 :     str = ToString(cx, vp[2]);
    1194              43 :     if (!str)
    1195               0 :         return JS_FALSE;
    1196              43 :     vp[2].setString(str);
    1197              43 :     JSLinearString *linearStr = str->ensureLinear(cx);
    1198              43 :     if (!linearStr)
    1199               0 :         return false;
    1200                 : 
    1201              43 :     if (!date_parseString(linearStr, &result, cx)) {
    1202               0 :         vp->setDouble(js_NaN);
    1203               0 :         return true;
    1204                 :     }
    1205                 : 
    1206              43 :     result = TIMECLIP(result);
    1207              43 :     vp->setNumber(result);
    1208              43 :     return true;
    1209                 : }
    1210                 : 
    1211                 : static inline double
    1212           37506 : NowAsMillis()
    1213                 : {
    1214           37506 :     return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
    1215                 : }
    1216                 : 
    1217                 : static JSBool
    1218           35483 : date_now(JSContext *cx, unsigned argc, Value *vp)
    1219                 : {
    1220           35483 :     vp->setDouble(NowAsMillis());
    1221           35483 :     return JS_TRUE;
    1222                 : }
    1223                 : 
    1224                 : /*
    1225                 :  * Set UTC time to a given time and invalidate cached local time.
    1226                 :  */
    1227                 : static JSBool
    1228           58881 : SetUTCTime(JSContext *cx, JSObject *obj, double t, Value *vp = NULL)
    1229                 : {
    1230           58881 :     JS_ASSERT(obj->isDate());
    1231                 : 
    1232          529929 :     for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
    1233                 :          ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
    1234                 :          ind++) {
    1235          471048 :         obj->setSlot(ind, UndefinedValue());
    1236                 :     }
    1237                 : 
    1238           58881 :     obj->setDateUTCTime(DoubleValue(t));
    1239           58881 :     if (vp)
    1240           41238 :         vp->setDouble(t);
    1241           58881 :     return true;
    1242                 : }
    1243                 : 
    1244                 : static void
    1245            2810 : SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
    1246                 : {
    1247            2810 :     double NaN = cx->runtime->NaNValue.getDoubleRef();
    1248            2810 :     SetUTCTime(cx, obj, NaN, vp);
    1249            2810 : }
    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           53209 : FillLocalTimes(JSContext *cx, JSObject *obj)
    1258                 : {
    1259           53209 :     JS_ASSERT(obj->isDate());
    1260                 : 
    1261           53209 :     double utcTime = obj->getDateUTCTime().toNumber();
    1262                 : 
    1263           53209 :     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           53209 :     double localTime = LocalTime(utcTime, cx);
    1273                 : 
    1274           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
    1275                 : 
    1276           53209 :     int year = (int) floor(localTime /(msPerDay*365.2425)) + 1970;
    1277           53209 :     double yearStartTime = (double) TimeFromYear(year);
    1278                 : 
    1279                 :     /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
    1280                 :     int yearDays;
    1281           53209 :     if (yearStartTime > localTime) {
    1282            9028 :         year--;
    1283            9028 :         yearStartTime -= (msPerDay * DaysInYear(year));
    1284            9028 :         yearDays = DaysInYear(year);
    1285                 :     } else {
    1286           44181 :         yearDays = DaysInYear(year);
    1287           44181 :         double nextStart = yearStartTime + (msPerDay * yearDays);
    1288           44181 :         if (nextStart <= localTime) {
    1289               0 :             year++;
    1290               0 :             yearStartTime = nextStart;
    1291               0 :             yearDays = DaysInYear(year);
    1292                 :         }
    1293                 :     }
    1294                 : 
    1295           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
    1296                 : 
    1297           53209 :     uint64_t yearTime = uint64_t(localTime - yearStartTime);
    1298           53209 :     int yearSeconds = uint32_t(yearTime / 1000);
    1299                 : 
    1300           53209 :     int day = yearSeconds / int(SecondsPerDay);
    1301                 : 
    1302           53209 :     int step = -1, next = 30;
    1303                 :     int month;
    1304                 : 
    1305                 :     do {
    1306           53209 :         if (day <= next) {
    1307            3712 :             month = 0;
    1308            3712 :             break;
    1309                 :         }
    1310           49497 :         step = next;
    1311           49497 :         next += ((yearDays == 366) ? 29 : 28);
    1312           49497 :         if (day <= next) {
    1313            3406 :             month = 1;
    1314            3406 :             break;
    1315                 :         }
    1316           46091 :         step = next;
    1317           46091 :         if (day <= (next += 31)) {
    1318            3730 :             month = 2;
    1319            3730 :             break;
    1320                 :         }
    1321           42361 :         step = next;
    1322           42361 :         if (day <= (next += 30)) {
    1323            3595 :             month = 3;
    1324            3595 :             break;
    1325                 :         }
    1326           38766 :         step = next;
    1327           38766 :         if (day <= (next += 31)) {
    1328            3450 :             month = 4;
    1329            3450 :             break;
    1330                 :         }
    1331           35316 :         step = next;
    1332           35316 :         if (day <= (next += 30)) {
    1333            6984 :             month = 5;
    1334            6984 :             break;
    1335                 :         }
    1336           28332 :         step = next;
    1337           28332 :         if (day <= (next += 31)) {
    1338            3447 :             month = 6;
    1339            3447 :             break;
    1340                 :         }
    1341           24885 :         step = next;
    1342           24885 :         if (day <= (next += 31)) {
    1343            3447 :             month = 7;
    1344            3447 :             break;
    1345                 :         }
    1346           21438 :         step = next;
    1347           21438 :         if (day <= (next += 30)) {
    1348            3078 :             month = 8;
    1349            3078 :             break;
    1350                 :         }
    1351           18360 :         step = next;
    1352           18360 :         if (day <= (next += 31)) {
    1353            3141 :             month = 9;
    1354            3141 :             break;
    1355                 :         }
    1356           15219 :         step = next;
    1357           15219 :         if (day <= (next += 30)) {
    1358            3051 :             month = 10;
    1359            3051 :             break;
    1360                 :         }
    1361           12168 :         step = next;
    1362           12168 :         month = 11;
    1363                 :     } while (0);
    1364                 : 
    1365           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
    1366           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
    1367                 : 
    1368           53209 :     int weekday = WeekDay(localTime);
    1369                 : 
    1370           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
    1371                 : 
    1372           53209 :     int seconds = yearSeconds % 60;
    1373                 : 
    1374           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
    1375                 : 
    1376           53209 :     int minutes = (yearSeconds / 60) % 60;
    1377                 : 
    1378           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
    1379                 : 
    1380           53209 :     int hours = (yearSeconds / (60 * 60)) % 24;
    1381                 : 
    1382           53209 :     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
    1383                 : 
    1384           53209 :     return true;
    1385                 : }
    1386                 : 
    1387                 : /* Cache the local times in obj, if necessary. */
    1388                 : static inline bool
    1389          518254 : GetAndCacheLocalTime(JSContext *cx, JSObject *obj)
    1390                 : {
    1391          518254 :     JS_ASSERT(obj->isDate());
    1392                 : 
    1393                 :     /* If the local time is undefined, we need to fill in the cached values. */
    1394          518254 :     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
    1395           53209 :         if (!FillLocalTimes(cx, obj))
    1396               0 :             return false;
    1397                 :     }
    1398          518254 :     return true;
    1399                 : }
    1400                 : 
    1401                 : static inline bool
    1402             115 : GetAndCacheLocalTime(JSContext *cx, JSObject *obj, double *time)
    1403                 : {
    1404             115 :     if (!obj || !GetAndCacheLocalTime(cx, obj))
    1405               0 :         return false;
    1406                 : 
    1407             115 :     *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
    1408             115 :     return true;
    1409                 : }
    1410                 : 
    1411                 : /*
    1412                 :  * See ECMA 15.9.5.4 thru 15.9.5.23
    1413                 :  */
    1414                 : static JSBool
    1415           41728 : date_getTime(JSContext *cx, unsigned argc, Value *vp)
    1416                 : {
    1417           41728 :     CallArgs args = CallArgsFromVp(argc, vp);
    1418                 : 
    1419                 :     bool ok;
    1420           41728 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &ok);
    1421           41728 :     if (!obj)
    1422              63 :         return ok;
    1423                 : 
    1424           41665 :     args.rval() = obj->getDateUTCTime();
    1425           41665 :     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           81118 : date_getFullYear(JSContext *cx, unsigned argc, Value *vp)
    1455                 : {
    1456           81118 :     CallArgs args = CallArgsFromVp(argc, vp);
    1457                 : 
    1458                 :     bool ok;
    1459           81118 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &ok);
    1460           81118 :     if (!obj)
    1461              63 :         return ok;
    1462                 : 
    1463           81055 :     if (!GetAndCacheLocalTime(cx, obj))
    1464               0 :         return false;
    1465                 : 
    1466           81055 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
    1467           81055 :     return true;
    1468                 : }
    1469                 : 
    1470                 : static JSBool
    1471            3422 : date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
    1472                 : {
    1473            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1474                 : 
    1475                 :     bool ok;
    1476            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &ok);
    1477            3422 :     if (!obj)
    1478              63 :         return ok;
    1479                 : 
    1480            3359 :     double result = obj->getDateUTCTime().toNumber();
    1481            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1482            3359 :         result = YearFromTime(result);
    1483                 : 
    1484            3359 :     args.rval().setNumber(result);
    1485            3359 :     return true;
    1486                 : }
    1487                 : 
    1488                 : static JSBool
    1489           85612 : date_getMonth(JSContext *cx, unsigned argc, Value *vp)
    1490                 : {
    1491           85612 :     CallArgs args = CallArgsFromVp(argc, vp);
    1492                 : 
    1493                 :     bool ok;
    1494           85612 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &ok);
    1495           85612 :     if (!obj)
    1496              63 :         return ok;
    1497                 : 
    1498           85549 :     if (!GetAndCacheLocalTime(cx, obj))
    1499               0 :         return false;
    1500                 : 
    1501           85549 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
    1502           85549 :     return true;
    1503                 : }
    1504                 : 
    1505                 : static JSBool
    1506            3422 : date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
    1507                 : {
    1508            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1509                 : 
    1510                 :     bool ok;
    1511            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &ok);
    1512            3422 :     if (!obj)
    1513              63 :         return ok;
    1514                 : 
    1515            3359 :     double result = obj->getDateUTCTime().toNumber();
    1516            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1517            3359 :         result = MonthFromTime(result);
    1518                 : 
    1519            3359 :     args.rval().setNumber(result);
    1520            3359 :     return true;
    1521                 : }
    1522                 : 
    1523                 : static JSBool
    1524           90107 : date_getDate(JSContext *cx, unsigned argc, Value *vp)
    1525                 : {
    1526           90107 :     CallArgs args = CallArgsFromVp(argc, vp);
    1527                 : 
    1528                 :     bool ok;
    1529           90107 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &ok);
    1530           90107 :     if (!obj)
    1531              63 :         return ok;
    1532                 : 
    1533           90044 :     if (!GetAndCacheLocalTime(cx, obj))
    1534               0 :         return false;
    1535                 : 
    1536           90044 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
    1537           90044 :     return true;
    1538                 : }
    1539                 : 
    1540                 : static JSBool
    1541            3422 : date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
    1542                 : {
    1543            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1544                 : 
    1545                 :     bool ok;
    1546            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &ok);
    1547            3422 :     if (!obj)
    1548              63 :         return ok;
    1549                 : 
    1550            3359 :     double result = obj->getDateUTCTime().toNumber();
    1551            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1552            3359 :         result = DateFromTime(result);
    1553                 : 
    1554            3359 :     args.rval().setNumber(result);
    1555            3359 :     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            3422 : date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
    1577                 : {
    1578            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1579                 : 
    1580                 :     bool ok;
    1581            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &ok);
    1582            3422 :     if (!obj)
    1583              63 :         return ok;
    1584                 : 
    1585            3359 :     double result = obj->getDateUTCTime().toNumber();
    1586            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1587            3359 :         result = WeekDay(result);
    1588                 : 
    1589            3359 :     args.rval().setNumber(result);
    1590            3359 :     return true;
    1591                 : }
    1592                 : 
    1593                 : static JSBool
    1594          118577 : date_getHours(JSContext *cx, unsigned argc, Value *vp)
    1595                 : {
    1596          118577 :     CallArgs args = CallArgsFromVp(argc, vp);
    1597                 : 
    1598                 :     bool ok;
    1599          118577 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &ok);
    1600          118577 :     if (!obj)
    1601              63 :         return ok;
    1602                 : 
    1603          118514 :     if (!GetAndCacheLocalTime(cx, obj))
    1604               0 :         return false;
    1605                 : 
    1606          118514 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
    1607          118514 :     return true;
    1608                 : }
    1609                 : 
    1610                 : static JSBool
    1611            3422 : date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
    1612                 : {
    1613            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1614                 : 
    1615                 :     bool ok;
    1616            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &ok);
    1617            3422 :     if (!obj)
    1618              63 :         return ok;
    1619                 : 
    1620            3359 :     double result = obj->getDateUTCTime().toNumber();
    1621            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1622            3359 :         result = HourFromTime(result);
    1623                 : 
    1624            3359 :     args.rval().setNumber(result);
    1625            3359 :     return JS_TRUE;
    1626                 : }
    1627                 : 
    1628                 : static JSBool
    1629           45100 : date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
    1630                 : {
    1631           45100 :     CallArgs args = CallArgsFromVp(argc, vp);
    1632                 : 
    1633                 :     bool ok;
    1634           45100 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &ok);
    1635           45100 :     if (!obj)
    1636              63 :         return ok;
    1637                 : 
    1638           45037 :     if (!GetAndCacheLocalTime(cx, obj))
    1639               0 :         return false;
    1640                 : 
    1641           45037 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
    1642           45037 :     return true;
    1643                 : }
    1644                 : 
    1645                 : static JSBool
    1646            3422 : date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
    1647                 : {
    1648            3422 :     CallArgs args = CallArgsFromVp(argc, vp);
    1649                 : 
    1650                 :     bool ok;
    1651            3422 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &ok);
    1652            3422 :     if (!obj)
    1653              63 :         return ok;
    1654                 : 
    1655            3359 :     double result = obj->getDateUTCTime().toNumber();
    1656            3359 :     if (JSDOUBLE_IS_FINITE(result))
    1657            3359 :         result = MinFromTime(result);
    1658                 : 
    1659            3359 :     args.rval().setNumber(result);
    1660            3359 :     return true;
    1661                 : }
    1662                 : 
    1663                 : /* Date.getSeconds is mapped to getUTCSeconds */
    1664                 : 
    1665                 : static JSBool
    1666           48512 : date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
    1667                 : {
    1668           48512 :     CallArgs args = CallArgsFromVp(argc, vp);
    1669                 : 
    1670                 :     bool ok;
    1671           48512 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &ok);
    1672           48512 :     if (!obj)
    1673             126 :         return ok;
    1674                 : 
    1675           48386 :     if (!GetAndCacheLocalTime(cx, obj))
    1676               0 :         return false;
    1677                 : 
    1678           48386 :     args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
    1679           48386 :     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             178 : date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
    1704                 : {
    1705             178 :     CallArgs args = CallArgsFromVp(argc, vp);
    1706                 : 
    1707                 :     bool ok;
    1708             178 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &ok);
    1709             178 :     if (!obj)
    1710              63 :         return ok;
    1711                 : 
    1712             115 :     double utctime = obj->getDateUTCTime().toNumber();
    1713                 : 
    1714                 :     double localtime;
    1715             115 :     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             115 :     double result = (utctime - localtime) / msPerMinute;
    1724             115 :     args.rval().setNumber(result);
    1725             115 :     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            1013 : date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsigned argc, Value *vp)
    1752                 : {
    1753            1013 :     CallArgs args = CallArgsFromVp(argc, vp);
    1754                 : 
    1755                 :     bool ok;
    1756            1013 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
    1757            1013 :     if (!obj)
    1758             504 :         return ok;
    1759                 : 
    1760             509 :     double result = obj->getDateUTCTime().toNumber();
    1761                 : 
    1762                 :     /* just return NaN if the date is already NaN */
    1763             509 :     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             509 :     if (args.length() == 0) {
    1778             216 :         SetDateToNaN(cx, obj, &args.rval());
    1779             216 :         return true;
    1780                 :     }
    1781                 : 
    1782             293 :     unsigned numNums = Min(args.length(), maxargs);
    1783             293 :     JS_ASSERT(numNums <= 4);
    1784                 :     double nums[4];
    1785             586 :     for (unsigned i = 0; i < numNums; i++) {
    1786             293 :         if (!ToNumber(cx, args[i], &nums[i]))
    1787               0 :             return false;
    1788             293 :         if (!JSDOUBLE_IS_FINITE(nums[i])) {
    1789               0 :             SetDateToNaN(cx, obj, &args.rval());
    1790               0 :             return true;
    1791                 :         }
    1792             293 :         nums[i] = js_DoubleToInteger(nums[i]);
    1793                 :     }
    1794                 : 
    1795                 :     double lorutime;  /* Local or UTC version of *date */
    1796             293 :     if (local)
    1797             293 :         lorutime = LocalTime(result, cx);
    1798                 :     else
    1799               0 :         lorutime = result;
    1800                 : 
    1801             293 :     double *argp = nums;
    1802             293 :     double *stop = argp + numNums;
    1803                 :     double hour;
    1804             293 :     if (maxargs >= 4 && argp < stop)
    1805              73 :         hour = *argp++;
    1806                 :     else
    1807             220 :         hour = HourFromTime(lorutime);
    1808                 : 
    1809                 :     double min;
    1810             293 :     if (maxargs >= 3 && argp < stop)
    1811              72 :         min = *argp++;
    1812                 :     else
    1813             221 :         min = MinFromTime(lorutime);
    1814                 : 
    1815                 :     double sec;
    1816             293 :     if (maxargs >= 2 && argp < stop)
    1817              72 :         sec = *argp++;
    1818                 :     else
    1819             221 :         sec = SecFromTime(lorutime);
    1820                 : 
    1821                 :     double msec;
    1822             293 :     if (maxargs >= 1 && argp < stop)
    1823              76 :         msec = *argp;
    1824                 :     else
    1825             217 :         msec = msFromTime(lorutime);
    1826                 : 
    1827             293 :     double msec_time = MakeTime(hour, min, sec, msec);
    1828             293 :     result = MakeDate(Day(lorutime), msec_time);
    1829                 : 
    1830             293 :     if (local)
    1831             293 :         result = UTC(result, cx);
    1832                 : 
    1833             293 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
    1834                 : }
    1835                 : 
    1836                 : static JSBool
    1837             166 : date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp)
    1838                 : {
    1839             166 :     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             162 : date_setSeconds(JSContext *cx, unsigned argc, Value *vp)
    1850                 : {
    1851             162 :     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             162 : date_setMinutes(JSContext *cx, unsigned argc, Value *vp)
    1862                 : {
    1863             162 :     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             163 : date_setHours(JSContext *cx, unsigned argc, Value *vp)
    1874                 : {
    1875             163 :     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             552 : date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsigned argc, Value *vp)
    1886                 : {
    1887             552 :     CallArgs args = CallArgsFromVp(argc, vp);
    1888                 : 
    1889                 :     bool ok;
    1890             552 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
    1891             552 :     if (!obj)
    1892             378 :         return ok;
    1893                 : 
    1894             174 :     double result = obj->getDateUTCTime().toNumber();
    1895                 : 
    1896                 :     /* see complaint about ECMA in date_MakeTime */
    1897             174 :     if (args.length() == 0) {
    1898             162 :         SetDateToNaN(cx, obj, &args.rval());
    1899             162 :         return true;
    1900                 :     }
    1901                 : 
    1902              12 :     unsigned numNums = Min(args.length(), maxargs);
    1903              12 :     JS_ASSERT(1 <= numNums && numNums <= 3);
    1904                 :     double nums[3];
    1905              24 :     for (unsigned i = 0; i < numNums; i++) {
    1906              12 :         if (!ToNumber(cx, args[i], &nums[i]))
    1907               0 :             return JS_FALSE;
    1908              12 :         if (!JSDOUBLE_IS_FINITE(nums[i])) {
    1909               0 :             SetDateToNaN(cx, obj, &args.rval());
    1910               0 :             return true;
    1911                 :         }
    1912              12 :         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              12 :     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              12 :         lorutime = local ? LocalTime(result, cx) : result;
    1928                 :     }
    1929                 : 
    1930              12 :     double *argp = nums;
    1931              12 :     double *stop = argp + numNums;
    1932                 :     double year;
    1933              12 :     if (maxargs >= 3 && argp < stop)
    1934               0 :         year = *argp++;
    1935                 :     else
    1936              12 :         year = YearFromTime(lorutime);
    1937                 : 
    1938                 :     double month;
    1939              12 :     if (maxargs >= 2 && argp < stop)
    1940               6 :         month = *argp++;
    1941                 :     else
    1942               6 :         month = MonthFromTime(lorutime);
    1943                 : 
    1944                 :     double day;
    1945              12 :     if (maxargs >= 1 && argp < stop)
    1946               6 :         day = *argp++;
    1947                 :     else
    1948               6 :         day = DateFromTime(lorutime);
    1949                 : 
    1950              12 :     day = MakeDay(year, month, day); /* day within year */
    1951              12 :     result = MakeDate(day, TimeWithinDay(lorutime));
    1952                 : 
    1953              12 :     if (local)
    1954              12 :         result = UTC(result, cx);
    1955                 : 
    1956              12 :     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
    1957                 : }
    1958                 : 
    1959                 : static JSBool
    1960              96 : date_setDate(JSContext *cx, unsigned argc, Value *vp)
    1961                 : {
    1962              96 :     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              96 : date_setMonth(JSContext *cx, unsigned argc, Value *vp)
    1973                 : {
    1974              96 :     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              91 : date_setYear(JSContext *cx, unsigned argc, Value *vp)
    1997                 : {
    1998              91 :     CallArgs args = CallArgsFromVp(argc, vp);
    1999                 : 
    2000                 :     bool ok;
    2001              91 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok);
    2002              91 :     if (!obj)
    2003              63 :         return ok;
    2004                 : 
    2005              28 :     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               1 :     double result = obj->getDateUTCTime().toNumber();
    2012                 : 
    2013                 :     double year;
    2014               1 :     if (!ToNumber(cx, args[0], &year))
    2015               0 :         return false;
    2016               1 :     if (!JSDOUBLE_IS_FINITE(year)) {
    2017               0 :         SetDateToNaN(cx, obj, &args.rval());
    2018               0 :         return true;
    2019                 :     }
    2020               1 :     year = js_DoubleToInteger(year);
    2021               1 :     if (year >= 0 && year <= 99)
    2022               0 :         year += 1900;
    2023                 : 
    2024               1 :     double t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
    2025               1 :     double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
    2026               1 :     result = MakeDate(day, TimeWithinDay(t));
    2027               1 :     result = UTC(result, cx);
    2028                 : 
    2029               1 :     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             161 : 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             161 :                 days[WeekDay(utctime)],
    2051                 :                 DateFromTime(utctime),
    2052             161 :                 months[MonthFromTime(utctime)],
    2053                 :                 YearFromTime(utctime),
    2054                 :                 HourFromTime(utctime),
    2055                 :                 MinFromTime(utctime),
    2056             483 :                 SecFromTime(utctime));
    2057             161 : }
    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             386 : date_utc_format(JSContext *cx, Native native, CallArgs args,
    2074                 :                 void (*printFunc)(char*, size_t, double))
    2075                 : {
    2076                 :     bool ok;
    2077             386 :     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
    2078             386 :     if (!obj)
    2079             126 :         return ok;
    2080                 : 
    2081             260 :     double utctime = obj->getDateUTCTime().toNumber();
    2082                 : 
    2083                 :     char buf[100];
    2084             260 :     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             251 :         (*printFunc)(buf, sizeof buf, utctime);
    2093                 :     }
    2094                 : 
    2095             251 :     JSString *str = JS_NewStringCopyZ(cx, buf);
    2096             251 :     if (!str)
    2097               0 :         return false;
    2098             251 :     args.rval().setString(str);
    2099             251 :     return true;
    2100                 : }
    2101                 : 
    2102                 : static JSBool
    2103             224 : date_toGMTString(JSContext *cx, unsigned argc, Value *vp)
    2104                 : {
    2105             224 :     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             733 : new_explode(double timeval, PRMJTime *split, JSContext *cx)
    2164                 : {
    2165             733 :     int year = YearFromTime(timeval);
    2166                 : 
    2167             733 :     split->tm_usec = int32_t(msFromTime(timeval)) * 1000;
    2168             733 :     split->tm_sec = int8_t(SecFromTime(timeval));
    2169             733 :     split->tm_min = int8_t(MinFromTime(timeval));
    2170             733 :     split->tm_hour = int8_t(HourFromTime(timeval));
    2171             733 :     split->tm_mday = int8_t(DateFromTime(timeval));
    2172             733 :     split->tm_mon = int8_t(MonthFromTime(timeval));
    2173             733 :     split->tm_wday = int8_t(WeekDay(timeval));
    2174             733 :     split->tm_year = year;
    2175             733 :     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             733 :     split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0);
    2180             733 : }
    2181                 : 
    2182                 : typedef enum formatspec {
    2183                 :     FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
    2184                 : } formatspec;
    2185                 : 
    2186                 : /* helper function */
    2187                 : static JSBool
    2188             266 : 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             266 :     if (!JSDOUBLE_IS_FINITE(date)) {
    2198               0 :         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
    2199                 :     } else {
    2200             266 :         double local = LocalTime(date, cx);
    2201                 : 
    2202                 :         /* offset from GMT in minutes.  The offset includes daylight savings,
    2203                 :            if it applies. */
    2204             266 :         int minutes = (int) floor(AdjustTime(date, cx) / msPerMinute);
    2205                 : 
    2206                 :         /* map 510 minutes to 0830 hours */
    2207             266 :         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             266 :         new_explode(date, &split, cx);
    2221             266 :         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             266 :             usetz = JS_TRUE;
    2230             266 :             tzlen = strlen(tzbuf);
    2231             266 :             if (tzlen > 100) {
    2232               0 :                 usetz = JS_FALSE;
    2233                 :             } else {
    2234            1596 :                 for (i = 0; i < tzlen; i++) {
    2235            1330 :                     jschar c = tzbuf[i];
    2236            2660 :                     if (c > 127 ||
    2237            1862 :                         !(isalpha(c) || isdigit(c) ||
    2238             532 :                           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             266 :             if (tzbuf[0] != '(' || tzbuf[1] == ')')
    2246               0 :                 usetz = JS_FALSE;
    2247                 :         } else
    2248               0 :             usetz = JS_FALSE;
    2249                 : 
    2250             266 :         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             212 :                         days[WeekDay(local)],
    2260             212 :                         months[MonthFromTime(local)],
    2261                 :                         DateFromTime(local),
    2262                 :                         YearFromTime(local),
    2263                 :                         HourFromTime(local),
    2264                 :                         MinFromTime(local),
    2265                 :                         SecFromTime(local),
    2266                 :                         offset,
    2267                 :                         usetz ? " " : "",
    2268             636 :                         usetz ? tzbuf : "");
    2269             212 :             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             266 :     str = JS_NewStringCopyZ(cx, buf);
    2294             266 :     if (!str)
    2295               0 :         return JS_FALSE;
    2296             266 :     call.rval().setString(str);
    2297             266 :     return JS_TRUE;
    2298                 : }
    2299                 : 
    2300                 : static bool
    2301             467 : ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *format)
    2302                 : {
    2303             467 :     double utctime = obj->getDateUTCTime().toNumber();
    2304                 : 
    2305                 :     char buf[100];
    2306             467 :     if (!JSDOUBLE_IS_FINITE(utctime)) {
    2307               0 :         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
    2308                 :     } else {
    2309                 :         int result_len;
    2310             467 :         double local = LocalTime(utctime, cx);
    2311                 :         PRMJTime split;
    2312             467 :         new_explode(local, &split, cx);
    2313                 : 
    2314                 :         /* let PRMJTime format it.       */
    2315             467 :         result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
    2316                 : 
    2317                 :         /* If it failed, default to toString. */
    2318             467 :         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             494 :         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             467 :     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
    2337             359 :         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             449 : date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
    2409                 : {
    2410             449 :     if (argc == 0)
    2411              90 :         return date_toLocaleStringHelper(cx, date_toLocaleFormat, argc, vp);
    2412                 : 
    2413             359 :     CallArgs args = CallArgsFromVp(argc, vp);
    2414                 : 
    2415                 :     bool ok;
    2416             359 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &ok);
    2417             359 :     if (!obj)
    2418               0 :         return ok;
    2419                 : 
    2420             359 :     JSString *fmt = ToString(cx, args[0]);
    2421             359 :     if (!fmt)
    2422               0 :         return false;
    2423                 : 
    2424             359 :     args[0].setString(fmt);
    2425             718 :     JSAutoByteString fmtbytes(cx, fmt);
    2426             359 :     if (!fmtbytes)
    2427               0 :         return false;
    2428                 : 
    2429             359 :     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              92 : date_toSource(JSContext *cx, unsigned argc, Value *vp)
    2461                 : {
    2462              92 :     CallArgs args = CallArgsFromVp(argc, vp);
    2463                 : 
    2464                 :     bool ok;
    2465              92 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &ok);
    2466              92 :     if (!obj)
    2467              63 :         return ok;
    2468                 : 
    2469              58 :     StringBuffer sb(cx);
    2470              58 :     if (!sb.append("(new Date(") || !NumberValueToStringBuffer(cx, obj->getDateUTCTime(), sb) ||
    2471              29 :         !sb.append("))"))
    2472                 :     {
    2473               0 :         return false;
    2474                 :     }
    2475                 : 
    2476              29 :     JSString *str = sb.finishString();
    2477              29 :     if (!str)
    2478               0 :         return false;
    2479              29 :     args.rval().setString(str);
    2480              29 :     return true;
    2481                 : }
    2482                 : #endif
    2483                 : 
    2484                 : static JSBool
    2485             273 : date_toString(JSContext *cx, unsigned argc, Value *vp)
    2486                 : {
    2487             273 :     CallArgs args = CallArgsFromVp(argc, vp);
    2488                 : 
    2489                 :     bool ok;
    2490             273 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_toString, &DateClass, &ok);
    2491             273 :     if (!obj)
    2492              63 :         return ok;
    2493                 : 
    2494             210 :     return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args);
    2495                 : }
    2496                 : 
    2497                 : static JSBool
    2498             536 : date_valueOf(JSContext *cx, unsigned argc, Value *vp)
    2499                 : {
    2500             536 :     CallArgs args = CallArgsFromVp(argc, vp);
    2501                 : 
    2502                 :     bool ok;
    2503             536 :     JSObject *obj = NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &ok);
    2504             536 :     if (!obj)
    2505              63 :         return ok;
    2506                 : 
    2507                 :     /* If called directly with no arguments, convert to a time number. */
    2508             473 :     if (argc == 0) {
    2509             473 :         args.rval() = obj->getDateUTCTime();
    2510             473 :         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           15209 : js_Date(JSContext *cx, unsigned argc, Value *vp)
    2590                 : {
    2591           15209 :     CallArgs args = CallArgsFromVp(argc, vp);
    2592                 : 
    2593                 :     /* Date called as function. */
    2594           15209 :     if (!IsConstructing(args))
    2595               2 :         return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args);
    2596                 : 
    2597                 :     /* Date called as constructor. */
    2598                 :     double d;
    2599           15207 :     if (args.length() == 0) {
    2600            2021 :         d = NowAsMillis();
    2601           13186 :     } else if (args.length() == 1) {
    2602           13141 :         if (!args[0].isString()) {
    2603                 :             /* the argument is a millisecond number */
    2604            3883 :             if (!ToNumber(cx, args[0], &d))
    2605               0 :                 return false;
    2606            3883 :             d = TIMECLIP(d);
    2607                 :         } else {
    2608                 :             /* the argument is a string; parse it. */
    2609            9258 :             JSString *str = ToString(cx, args[0]);
    2610            9258 :             if (!str)
    2611               0 :                 return false;
    2612            9258 :             args[0].setString(str);
    2613            9258 :             JSLinearString *linearStr = str->ensureLinear(cx);
    2614            9258 :             if (!linearStr)
    2615               0 :                 return false;
    2616                 : 
    2617            9258 :             if (!date_parseString(linearStr, &d, cx))
    2618               5 :                 d = js_NaN;
    2619                 :             else
    2620            9253 :                 d = TIMECLIP(d);
    2621                 :         }
    2622                 :     } else {
    2623                 :         double msec_time;
    2624              45 :         if (!date_msecFromArgs(cx, args, &msec_time))
    2625               0 :             return false;
    2626                 : 
    2627              45 :         if (JSDOUBLE_IS_FINITE(msec_time)) {
    2628              45 :             msec_time = UTC(msec_time, cx);
    2629              45 :             msec_time = TIMECLIP(msec_time);
    2630                 :         }
    2631              45 :         d = msec_time;
    2632                 :     }
    2633                 : 
    2634           15207 :     JSObject *obj = js_NewDateObjectMsec(cx, d);
    2635           15207 :     if (!obj)
    2636               0 :         return false;
    2637                 : 
    2638           15207 :     args.rval().setObject(*obj);
    2639           15207 :     return true;
    2640                 : }
    2641                 : 
    2642                 : JSObject *
    2643            2378 : js_InitDateClass(JSContext *cx, JSObject *obj)
    2644                 : {
    2645            2378 :     JS_ASSERT(obj->isNative());
    2646                 : 
    2647                 :     /* Set the static LocalTZA. */
    2648            2378 :     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
    2649                 : 
    2650            2378 :     GlobalObject *global = &obj->asGlobal();
    2651                 : 
    2652            2378 :     JSObject *dateProto = global->createBlankPrototype(cx, &DateClass);
    2653            2378 :     if (!dateProto)
    2654               0 :         return NULL;
    2655            2378 :     SetDateToNaN(cx, dateProto);
    2656                 : 
    2657                 :     JSFunction *ctor = global->createConstructor(cx, js_Date, &DateClass,
    2658            2378 :                                                  CLASS_ATOM(cx, Date), MAXARGS);
    2659            2378 :     if (!ctor)
    2660               0 :         return NULL;
    2661                 : 
    2662            2378 :     if (!LinkConstructorAndPrototype(cx, ctor, dateProto))
    2663               0 :         return NULL;
    2664                 : 
    2665            2378 :     if (!DefinePropertiesAndBrand(cx, ctor, NULL, date_static_methods))
    2666               0 :         return NULL;
    2667                 : 
    2668                 :     /*
    2669                 :      * Define all Date.prototype.* functions, then brand for trace-jitted code.
    2670                 :      * Date.prototype.toGMTString has the same initial value as
    2671                 :      * Date.prototype.toUTCString.
    2672                 :      */
    2673            2378 :     if (!JS_DefineFunctions(cx, dateProto, date_methods))
    2674               0 :         return NULL;
    2675                 :     Value toUTCStringFun;
    2676            2378 :     jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
    2677            2378 :     jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
    2678            4756 :     if (!js_GetProperty(cx, dateProto, toUTCStringId, &toUTCStringFun) ||
    2679                 :         !js_DefineProperty(cx, dateProto, toGMTStringId, &toUTCStringFun,
    2680            2378 :                            JS_PropertyStub, JS_StrictPropertyStub, 0))
    2681                 :     {
    2682               0 :         return NULL;
    2683                 :     }
    2684                 : 
    2685            2378 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_Date, ctor, dateProto))
    2686               0 :         return NULL;
    2687                 : 
    2688            2378 :     return dateProto;
    2689                 : }
    2690                 : 
    2691                 : JS_FRIEND_API(JSObject *)
    2692           15265 : js_NewDateObjectMsec(JSContext *cx, double msec_time)
    2693                 : {
    2694           15265 :     JSObject *obj = NewBuiltinClassInstance(cx, &DateClass);
    2695           15265 :     if (!obj)
    2696               0 :         return NULL;
    2697           15265 :     if (!SetUTCTime(cx, obj, msec_time))
    2698               0 :         return NULL;
    2699           15265 :     return obj;
    2700                 : }
    2701                 : 
    2702                 : JS_FRIEND_API(JSObject *)
    2703               0 : js_NewDateObject(JSContext* cx, int year, int mon, int mday,
    2704                 :                  int hour, int min, int sec)
    2705                 : {
    2706                 :     JSObject *obj;
    2707                 :     double msec_time;
    2708                 : 
    2709               0 :     JS_ASSERT(mon < 12);
    2710               0 :     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
    2711               0 :     obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
    2712               0 :     return obj;
    2713                 : }
    2714                 : 
    2715                 : JS_FRIEND_API(JSBool)
    2716               5 : js_DateIsValid(JSContext *cx, JSObject* obj)
    2717                 : {
    2718               5 :     return obj->isDate() && !JSDOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
    2719                 : }
    2720                 : 
    2721                 : JS_FRIEND_API(int)
    2722               0 : js_DateGetYear(JSContext *cx, JSObject* obj)
    2723                 : {
    2724                 :     double localtime;
    2725                 : 
    2726                 :     /* Preserve legacy API behavior of returning 0 for invalid dates. */
    2727               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
    2728               0 :         JSDOUBLE_IS_NaN(localtime)) {
    2729               0 :         return 0;
    2730                 :     }
    2731                 : 
    2732               0 :     return (int) YearFromTime(localtime);
    2733                 : }
    2734                 : 
    2735                 : JS_FRIEND_API(int)
    2736               0 : js_DateGetMonth(JSContext *cx, JSObject* obj)
    2737                 : {
    2738                 :     double localtime;
    2739                 : 
    2740               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
    2741               0 :         JSDOUBLE_IS_NaN(localtime)) {
    2742               0 :         return 0;
    2743                 :     }
    2744                 : 
    2745               0 :     return (int) MonthFromTime(localtime);
    2746                 : }
    2747                 : 
    2748                 : JS_FRIEND_API(int)
    2749               0 : js_DateGetDate(JSContext *cx, JSObject* obj)
    2750                 : {
    2751                 :     double localtime;
    2752                 : 
    2753               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
    2754               0 :         JSDOUBLE_IS_NaN(localtime)) {
    2755               0 :         return 0;
    2756                 :     }
    2757                 : 
    2758               0 :     return (int) DateFromTime(localtime);
    2759                 : }
    2760                 : 
    2761                 : JS_FRIEND_API(int)
    2762               0 : js_DateGetHours(JSContext *cx, JSObject* obj)
    2763                 : {
    2764                 :     double localtime;
    2765                 : 
    2766               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
    2767               0 :         JSDOUBLE_IS_NaN(localtime)) {
    2768               0 :         return 0;
    2769                 :     }
    2770                 : 
    2771               0 :     return (int) HourFromTime(localtime);
    2772                 : }
    2773                 : 
    2774                 : JS_FRIEND_API(int)
    2775               0 : js_DateGetMinutes(JSContext *cx, JSObject* obj)
    2776                 : {
    2777                 :     double localtime;
    2778                 : 
    2779               0 :     if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
    2780               0 :         JSDOUBLE_IS_NaN(localtime)) {
    2781               0 :         return 0;
    2782                 :     }
    2783                 : 
    2784               0 :     return (int) MinFromTime(localtime);
    2785                 : }
    2786                 : 
    2787                 : JS_FRIEND_API(int)
    2788               0 : js_DateGetSeconds(JSContext *cx, JSObject* obj)
    2789                 : {
    2790               0 :     if (!obj->isDate()) 
    2791               0 :         return 0;
    2792                 :     
    2793               0 :     double utctime = obj->getDateUTCTime().toNumber();
    2794               0 :     if (JSDOUBLE_IS_NaN(utctime))
    2795               0 :         return 0;
    2796               0 :     return (int) SecFromTime(utctime);
    2797                 : }
    2798                 : 
    2799                 : JS_FRIEND_API(double)
    2800             862 : js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
    2801                 : {
    2802             862 :     return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0;
    2803                 : }
    2804                 : 
    2805                 : #ifdef JS_THREADSAFE
    2806                 : #include "prinrval.h"
    2807                 : 
    2808                 : JS_FRIEND_API(uint32_t)
    2809           18405 : js_IntervalNow()
    2810                 : {
    2811           18405 :     return uint32_t(PR_IntervalToMilliseconds(PR_IntervalNow()));
    2812                 : }
    2813                 : 
    2814                 : #else /* !JS_THREADSAFE */
    2815                 : 
    2816                 : JS_FRIEND_API(uint32_t)
    2817                 : js_IntervalNow()
    2818                 : {
    2819                 :     return uint32_t(PRMJ_Now() / PRMJ_USEC_PER_MSEC);
    2820                 : }
    2821                 : #endif

Generated by: LCOV version 1.7