/[jscoverage]/trunk/js/jsdate.cpp
ViewVC logotype

Annotation of /trunk/js/jsdate.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (hide annotations)
Sat Sep 26 23:15:22 2009 UTC (11 years ago) by siliconforks
File size: 69445 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

1 siliconforks 332 /* -*- 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 "jsstddef.h"
55     #include <ctype.h>
56     #include <locale.h>
57     #include <math.h>
58     #include <stdlib.h>
59     #include <string.h>
60     #include "jstypes.h"
61     #include "jsprf.h"
62     #include "prmjtime.h"
63     #include "jsutil.h" /* Added by JSIFY */
64     #include "jsapi.h"
65     #include "jsversion.h"
66 siliconforks 399 #include "jsbuiltins.h"
67 siliconforks 332 #include "jscntxt.h"
68     #include "jsdate.h"
69     #include "jsinterp.h"
70     #include "jsnum.h"
71     #include "jsobj.h"
72     #include "jsstr.h"
73    
74     /*
75     * The JS 'Date' object is patterned after the Java 'Date' object.
76     * Here is an script:
77     *
78     * today = new Date();
79     *
80     * print(today.toLocaleString());
81     *
82     * weekDay = today.getDay();
83     *
84     *
85     * These Java (and ECMA-262) methods are supported:
86     *
87     * UTC
88     * getDate (getUTCDate)
89     * getDay (getUTCDay)
90     * getHours (getUTCHours)
91     * getMinutes (getUTCMinutes)
92     * getMonth (getUTCMonth)
93     * getSeconds (getUTCSeconds)
94     * getMilliseconds (getUTCMilliseconds)
95     * getTime
96     * getTimezoneOffset
97     * getYear
98     * getFullYear (getUTCFullYear)
99     * parse
100     * setDate (setUTCDate)
101     * setHours (setUTCHours)
102     * setMinutes (setUTCMinutes)
103     * setMonth (setUTCMonth)
104     * setSeconds (setUTCSeconds)
105     * setMilliseconds (setUTCMilliseconds)
106     * setTime
107     * setYear (setFullYear, setUTCFullYear)
108     * toGMTString (toUTCString)
109     * toLocaleString
110     * toString
111     *
112     *
113     * These Java methods are not supported
114     *
115     * setDay
116     * before
117     * after
118     * equals
119     * hashCode
120     */
121    
122     /*
123     * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
124     * definition and reduce dependence on NSPR. NSPR is used to get the current
125     * time in milliseconds, the time zone offset, and the daylight savings time
126     * offset for a given time. NSPR is also used for Date.toLocaleString(), for
127     * locale-specific formatting, and to get a string representing the timezone.
128     * (Which turns out to be platform-dependent.)
129     *
130     * To do:
131     * (I did some performance tests by timing how long it took to run what
132     * I had of the js ECMA conformance tests.)
133     *
134     * - look at saving results across multiple calls to supporting
135     * functions; the toString functions compute some of the same values
136     * multiple times. Although - I took a quick stab at this, and I lost
137     * rather than gained. (Fractionally.) Hard to tell what compilers/processors
138     * are doing these days.
139     *
140     * - look at tweaking function return types to return double instead
141     * of int; this seems to make things run slightly faster sometimes.
142     * (though it could be architecture-dependent.) It'd be good to see
143     * how this does on win32. (Tried it on irix.) Types could use a
144     * general going-over.
145     */
146    
147     /*
148     * Supporting functions - ECMA 15.9.1.*
149     */
150    
151     #define HalfTimeDomain 8.64e15
152     #define HoursPerDay 24.0
153     #define MinutesPerDay (HoursPerDay * MinutesPerHour)
154     #define MinutesPerHour 60.0
155     #define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
156     #define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
157     #define SecondsPerMinute 60.0
158    
159     #if defined(XP_WIN) || defined(XP_OS2)
160     /* Work around msvc double optimization bug by making these runtime values; if
161     * they're available at compile time, msvc optimizes division by them by
162     * computing the reciprocal and multiplying instead of dividing - this loses
163     * when the reciprocal isn't representable in a double.
164     */
165     static jsdouble msPerSecond = 1000.0;
166     static jsdouble msPerDay = SecondsPerDay * 1000.0;
167     static jsdouble msPerHour = SecondsPerHour * 1000.0;
168     static jsdouble msPerMinute = SecondsPerMinute * 1000.0;
169     #else
170     #define msPerDay (SecondsPerDay * msPerSecond)
171     #define msPerHour (SecondsPerHour * msPerSecond)
172     #define msPerMinute (SecondsPerMinute * msPerSecond)
173     #define msPerSecond 1000.0
174     #endif
175    
176     #define Day(t) floor((t) / msPerDay)
177    
178     static jsdouble
179     TimeWithinDay(jsdouble t)
180     {
181     jsdouble result;
182     result = fmod(t, msPerDay);
183     if (result < 0)
184     result += msPerDay;
185     return result;
186     }
187    
188     #define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
189     ? 366 : 365)
190    
191     /* math here has to be f.p, because we need
192     * floor((1968 - 1969) / 4) == -1
193     */
194     #define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
195     - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
196     #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
197    
198     static jsint
199     YearFromTime(jsdouble t)
200     {
201     jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
202     jsdouble t2 = (jsdouble) TimeFromYear(y);
203    
204     if (t2 > t) {
205     y--;
206     } else {
207     if (t2 + msPerDay * DaysInYear(y) <= t)
208     y++;
209     }
210     return y;
211     }
212    
213     #define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
214    
215     #define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
216    
217     /*
218     * The following array contains the day of year for the first day of
219     * each month, where index 0 is January, and day 0 is January 1.
220     */
221     static jsdouble firstDayOfMonth[2][12] = {
222     {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
223     {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
224     };
225    
226     #define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
227    
228     static intN
229     MonthFromTime(jsdouble t)
230     {
231     intN d, step;
232     jsint year = YearFromTime(t);
233     d = DayWithinYear(t, year);
234    
235     if (d < (step = 31))
236     return 0;
237     step += (InLeapYear(t) ? 29 : 28);
238     if (d < step)
239     return 1;
240     if (d < (step += 31))
241     return 2;
242     if (d < (step += 30))
243     return 3;
244     if (d < (step += 31))
245     return 4;
246     if (d < (step += 30))
247     return 5;
248     if (d < (step += 31))
249     return 6;
250     if (d < (step += 31))
251     return 7;
252     if (d < (step += 30))
253     return 8;
254     if (d < (step += 31))
255     return 9;
256     if (d < (step += 30))
257     return 10;
258     return 11;
259     }
260    
261     static intN
262     DateFromTime(jsdouble t)
263     {
264     intN d, step, next;
265     jsint year = YearFromTime(t);
266     d = DayWithinYear(t, year);
267    
268     if (d <= (next = 30))
269     return d + 1;
270     step = next;
271     next += (InLeapYear(t) ? 29 : 28);
272     if (d <= next)
273     return d - step;
274     step = next;
275     if (d <= (next += 31))
276     return d - step;
277     step = next;
278     if (d <= (next += 30))
279     return d - step;
280     step = next;
281     if (d <= (next += 31))
282     return d - step;
283     step = next;
284     if (d <= (next += 30))
285     return d - step;
286     step = next;
287     if (d <= (next += 31))
288     return d - step;
289     step = next;
290     if (d <= (next += 31))
291     return d - step;
292     step = next;
293     if (d <= (next += 30))
294     return d - step;
295     step = next;
296     if (d <= (next += 31))
297     return d - step;
298     step = next;
299     if (d <= (next += 30))
300     return d - step;
301     step = next;
302     return d - step;
303     }
304    
305     static intN
306     WeekDay(jsdouble t)
307     {
308     jsint result;
309     result = (jsint) Day(t) + 4;
310     result = result % 7;
311     if (result < 0)
312     result += 7;
313     return (intN) result;
314     }
315    
316     #define MakeTime(hour, min, sec, ms) \
317     ((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
318    
319     static jsdouble
320     MakeDay(jsdouble year, jsdouble month, jsdouble date)
321     {
322     JSBool leap;
323     jsdouble yearday;
324     jsdouble monthday;
325    
326     year += floor(month / 12);
327    
328     month = fmod(month, 12.0);
329     if (month < 0)
330     month += 12;
331    
332     leap = (DaysInYear((jsint) year) == 366);
333    
334     yearday = floor(TimeFromYear(year) / msPerDay);
335     monthday = DayFromMonth(month, leap);
336    
337     return yearday + monthday + date - 1;
338     }
339    
340     #define MakeDate(day, time) ((day) * msPerDay + (time))
341    
342     /*
343     * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
344     *
345     * yearStartingWith[0][i] is an example non-leap year where
346     * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
347     *
348     * yearStartingWith[1][i] is an example leap year where
349     * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
350     */
351     static jsint yearStartingWith[2][7] = {
352     {1978, 1973, 1974, 1975, 1981, 1971, 1977},
353     {1984, 1996, 1980, 1992, 1976, 1988, 1972}
354     };
355    
356     /*
357     * Find a year for which any given date will fall on the same weekday.
358     *
359     * This function should be used with caution when used other than
360     * for determining DST; it hasn't been proven not to produce an
361     * incorrect year for times near year boundaries.
362     */
363     static jsint
364     EquivalentYearForDST(jsint year)
365     {
366     jsint day;
367     JSBool isLeapYear;
368    
369     day = (jsint) DayFromYear(year) + 4;
370     day = day % 7;
371     if (day < 0)
372     day += 7;
373    
374     isLeapYear = (DaysInYear(year) == 366);
375    
376     return yearStartingWith[isLeapYear][day];
377     }
378    
379     /* LocalTZA gets set by js_InitDateClass() */
380     static jsdouble LocalTZA;
381    
382     static jsdouble
383     DaylightSavingTA(jsdouble t)
384     {
385     volatile int64 PR_t;
386     int64 ms2us;
387     int64 offset;
388     jsdouble result;
389    
390     /* abort if NaN */
391     if (JSDOUBLE_IS_NaN(t))
392     return t;
393    
394     /*
395     * If earlier than 1970 or after 2038, potentially beyond the ken of
396     * many OSes, map it to an equivalent year before asking.
397     */
398     if (t < 0.0 || t > 2145916800000.0) {
399     jsint year;
400     jsdouble day;
401    
402     year = EquivalentYearForDST(YearFromTime(t));
403     day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
404     t = MakeDate(day, TimeWithinDay(t));
405     }
406    
407     /* put our t in an LL, and map it to usec for prtime */
408     JSLL_D2L(PR_t, t);
409     JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
410     JSLL_MUL(PR_t, PR_t, ms2us);
411    
412     offset = PRMJ_DSTOffset(PR_t);
413    
414     JSLL_DIV(offset, offset, ms2us);
415     JSLL_L2D(result, offset);
416     return result;
417     }
418    
419 siliconforks 460 static jsdouble
420     AdjustTime(jsdouble date)
421     {
422     jsdouble t = DaylightSavingTA(date) + LocalTZA;
423     t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
424     return t;
425     }
426 siliconforks 332
427     #define LocalTime(t) ((t) + AdjustTime(t))
428    
429     static jsdouble
430     UTC(jsdouble t)
431     {
432     return t - AdjustTime(t - LocalTZA);
433     }
434    
435     static intN
436     HourFromTime(jsdouble t)
437     {
438     intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
439     if (result < 0)
440     result += (intN)HoursPerDay;
441     return result;
442     }
443    
444     static intN
445     MinFromTime(jsdouble t)
446     {
447     intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
448     if (result < 0)
449     result += (intN)MinutesPerHour;
450     return result;
451     }
452    
453     static intN
454     SecFromTime(jsdouble t)
455     {
456     intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
457     if (result < 0)
458     result += (intN)SecondsPerMinute;
459     return result;
460     }
461    
462     static intN
463     msFromTime(jsdouble t)
464     {
465     intN result = (intN) fmod(t, msPerSecond);
466     if (result < 0)
467     result += (intN)msPerSecond;
468     return result;
469     }
470    
471     #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
472     && !((d < 0 ? -d : d) > HalfTimeDomain)) \
473     ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
474    
475     /**
476     * end of ECMA 'support' functions
477     */
478    
479     /*
480     * Other Support routines and definitions
481     */
482    
483     /*
484     * We use the first reseved slot to store UTC time, and the second for caching
485     * the local time. The initial value of the cache entry is NaN.
486     */
487     const uint32 JSSLOT_UTC_TIME = JSSLOT_PRIVATE;
488     const uint32 JSSLOT_LOCAL_TIME = JSSLOT_PRIVATE + 1;
489    
490     const uint32 DATE_RESERVED_SLOTS = 2;
491    
492     JSClass js_DateClass = {
493     js_Date_str,
494     JSCLASS_HAS_RESERVED_SLOTS(DATE_RESERVED_SLOTS) |
495     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
496     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
497     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
498     JSCLASS_NO_OPTIONAL_MEMBERS
499     };
500    
501     /* for use by date_parse */
502    
503     static const char* wtb[] = {
504     "am", "pm",
505     "monday", "tuesday", "wednesday", "thursday", "friday",
506     "saturday", "sunday",
507     "january", "february", "march", "april", "may", "june",
508     "july", "august", "september", "october", "november", "december",
509     "gmt", "ut", "utc",
510     "est", "edt",
511     "cst", "cdt",
512     "mst", "mdt",
513     "pst", "pdt"
514     /* time zone table needs to be expanded */
515     };
516    
517     static int ttb[] = {
518     -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
519     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
520     10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
521     10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
522     10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
523     10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
524     10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
525     };
526    
527     /* helper for date_parse */
528     static JSBool
529     date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
530     int count, int ignoreCase)
531     {
532     JSBool result = JS_FALSE;
533     /* return true if matches, otherwise, false */
534    
535     while (count > 0 && s1[s1off] && s2[s2off]) {
536     if (ignoreCase) {
537     if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
538     break;
539     }
540     } else {
541     if ((jschar)s1[s1off] != s2[s2off]) {
542     break;
543     }
544     }
545     s1off++;
546     s2off++;
547     count--;
548     }
549    
550     if (count == 0) {
551     result = JS_TRUE;
552     }
553    
554     return result;
555     }
556    
557     /* find UTC time from given date... no 1900 correction! */
558     static jsdouble
559     date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
560     jsdouble min, jsdouble sec, jsdouble msec)
561     {
562     jsdouble day;
563     jsdouble msec_time;
564     jsdouble result;
565    
566     day = MakeDay(year, mon, mday);
567     msec_time = MakeTime(hour, min, sec, msec);
568     result = MakeDate(day, msec_time);
569     return result;
570     }
571    
572     /* compute the time in msec (unclipped) from the given args */
573     #define MAXARGS 7
574    
575     static JSBool
576     date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval)
577     {
578     uintN loop;
579     jsdouble array[MAXARGS];
580     jsdouble d;
581     jsdouble msec_time;
582    
583     for (loop = 0; loop < MAXARGS; loop++) {
584     if (loop < argc) {
585     d = js_ValueToNumber(cx, &argv[loop]);
586     if (JSVAL_IS_NULL(argv[loop]))
587     return JS_FALSE;
588     /* return NaN if any arg is not finite */
589     if (!JSDOUBLE_IS_FINITE(d)) {
590     *rval = *cx->runtime->jsNaN;
591     return JS_TRUE;
592     }
593     array[loop] = js_DoubleToInteger(d);
594     } else {
595     if (loop == 2) {
596     array[loop] = 1; /* Default the date argument to 1. */
597     } else {
598     array[loop] = 0;
599     }
600     }
601     }
602    
603     /* adjust 2-digit years into the 20th century */
604     if (array[0] >= 0 && array[0] <= 99)
605     array[0] += 1900;
606    
607     msec_time = date_msecFromDate(array[0], array[1], array[2],
608     array[3], array[4], array[5], array[6]);
609     *rval = msec_time;
610     return JS_TRUE;
611     }
612    
613     /*
614     * See ECMA 15.9.4.[3-10];
615     */
616     static JSBool
617     date_UTC(JSContext *cx, uintN argc, jsval *vp)
618     {
619     jsdouble msec_time;
620    
621     if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
622     return JS_FALSE;
623    
624     msec_time = TIMECLIP(msec_time);
625    
626     return js_NewNumberInRootedValue(cx, msec_time, vp);
627     }
628    
629     static JSBool
630     date_parseString(JSString *str, jsdouble *result)
631     {
632     jsdouble msec;
633    
634     const jschar *s;
635     size_t limit;
636     size_t i = 0;
637     int year = -1;
638     int mon = -1;
639     int mday = -1;
640     int hour = -1;
641     int min = -1;
642     int sec = -1;
643     int c = -1;
644     int n = -1;
645     int tzoffset = -1;
646     int prevc = 0;
647     JSBool seenplusminus = JS_FALSE;
648     int temp;
649     JSBool seenmonthname = JS_FALSE;
650    
651     JSSTRING_CHARS_AND_LENGTH(str, s, limit);
652     if (limit == 0)
653     goto syntax;
654     while (i < limit) {
655     c = s[i];
656     i++;
657     if (c <= ' ' || c == ',' || c == '-') {
658     if (c == '-' && '0' <= s[i] && s[i] <= '9') {
659     prevc = c;
660     }
661     continue;
662     }
663     if (c == '(') { /* comments) */
664     int depth = 1;
665     while (i < limit) {
666     c = s[i];
667     i++;
668     if (c == '(') depth++;
669     else if (c == ')')
670     if (--depth <= 0)
671     break;
672     }
673     continue;
674     }
675     if ('0' <= c && c <= '9') {
676     n = c - '0';
677     while (i < limit && '0' <= (c = s[i]) && c <= '9') {
678     n = n * 10 + c - '0';
679     i++;
680     }
681    
682     /* allow TZA before the year, so
683     * 'Wed Nov 05 21:49:11 GMT-0800 1997'
684     * works */
685    
686     /* uses of seenplusminus allow : in TZA, so Java
687     * no-timezone style of GMT+4:30 works
688     */
689    
690     if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
691     /* make ':' case below change tzoffset */
692     seenplusminus = JS_TRUE;
693    
694     /* offset */
695     if (n < 24)
696     n = n * 60; /* EG. "GMT-3" */
697     else
698     n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
699     if (prevc == '+') /* plus means east of GMT */
700     n = -n;
701     if (tzoffset != 0 && tzoffset != -1)
702     goto syntax;
703     tzoffset = n;
704     } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
705     if (c <= ' ' || c == ',' || c == '/' || i >= limit)
706     year = n;
707     else
708     goto syntax;
709     } else if (c == ':') {
710     if (hour < 0)
711     hour = /*byte*/ n;
712     else if (min < 0)
713     min = /*byte*/ n;
714     else
715     goto syntax;
716     } else if (c == '/') {
717     /* until it is determined that mon is the actual
718     month, keep it as 1-based rather than 0-based */
719     if (mon < 0)
720     mon = /*byte*/ n;
721     else if (mday < 0)
722     mday = /*byte*/ n;
723     else
724     goto syntax;
725     } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
726     goto syntax;
727     } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
728     if (tzoffset < 0)
729     tzoffset -= n;
730     else
731     tzoffset += n;
732     } else if (hour >= 0 && min < 0) {
733     min = /*byte*/ n;
734     } else if (prevc == ':' && min >= 0 && sec < 0) {
735     sec = /*byte*/ n;
736     } else if (mon < 0) {
737     mon = /*byte*/n;
738     } else if (mon >= 0 && mday < 0) {
739     mday = /*byte*/ n;
740     } else if (mon >= 0 && mday >= 0 && year < 0) {
741     year = n;
742     } else {
743     goto syntax;
744     }
745     prevc = 0;
746     } else if (c == '/' || c == ':' || c == '+' || c == '-') {
747     prevc = c;
748     } else {
749     size_t st = i - 1;
750     int k;
751     while (i < limit) {
752     c = s[i];
753     if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
754     break;
755     i++;
756     }
757     if (i <= st + 1)
758     goto syntax;
759     for (k = JS_ARRAY_LENGTH(wtb); --k >= 0;)
760     if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
761     int action = ttb[k];
762     if (action != 0) {
763     if (action < 0) {
764     /*
765     * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
766     * 12:30, instead of blindly adding 12 if PM.
767     */
768     JS_ASSERT(action == -1 || action == -2);
769     if (hour > 12 || hour < 0) {
770     goto syntax;
771     } else {
772     if (action == -1 && hour == 12) { /* am */
773     hour = 0;
774     } else if (action == -2 && hour != 12) { /* pm */
775     hour += 12;
776     }
777     }
778     } else if (action <= 13) { /* month! */
779     /* Adjust mon to be 1-based until the final values
780     for mon, mday and year are adjusted below */
781     if (seenmonthname) {
782     goto syntax;
783     }
784     seenmonthname = JS_TRUE;
785     temp = /*byte*/ (action - 2) + 1;
786    
787     if (mon < 0) {
788     mon = temp;
789     } else if (mday < 0) {
790     mday = mon;
791     mon = temp;
792     } else if (year < 0) {
793     year = mon;
794     mon = temp;
795     } else {
796     goto syntax;
797     }
798     } else {
799     tzoffset = action - 10000;
800     }
801     }
802     break;
803     }
804     if (k < 0)
805     goto syntax;
806     prevc = 0;
807     }
808     }
809     if (year < 0 || mon < 0 || mday < 0)
810     goto syntax;
811     /*
812     Case 1. The input string contains an English month name.
813     The form of the string can be month f l, or f month l, or
814     f l month which each evaluate to the same date.
815     If f and l are both greater than or equal to 70, or
816     both less than 70, the date is invalid.
817     The year is taken to be the greater of the values f, l.
818     If the year is greater than or equal to 70 and less than 100,
819     it is considered to be the number of years after 1900.
820     Case 2. The input string is of the form "f/m/l" where f, m and l are
821     integers, e.g. 7/16/45.
822     Adjust the mon, mday and year values to achieve 100% MSIE
823     compatibility.
824     a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
825     i. If year < 100, it is the number of years after 1900
826     ii. If year >= 100, it is the number of years after 0.
827     b. If 70 <= f < 100
828     i. If m < 70, f/m/l is interpreted as
829     year/month/day where year is the number of years after
830     1900.
831     ii. If m >= 70, the date is invalid.
832     c. If f >= 100
833     i. If m < 70, f/m/l is interpreted as
834     year/month/day where year is the number of years after 0.
835     ii. If m >= 70, the date is invalid.
836     */
837     if (seenmonthname) {
838     if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
839     goto syntax;
840     }
841     if (mday > year) {
842     temp = year;
843     year = mday;
844     mday = temp;
845     }
846     if (year >= 70 && year < 100) {
847     year += 1900;
848     }
849     } else if (mon < 70) { /* (a) month/day/year */
850     if (year < 100) {
851     year += 1900;
852     }
853     } else if (mon < 100) { /* (b) year/month/day */
854     if (mday < 70) {
855     temp = year;
856     year = mon + 1900;
857     mon = mday;
858     mday = temp;
859     } else {
860     goto syntax;
861     }
862     } else { /* (c) year/month/day */
863     if (mday < 70) {
864     temp = year;
865     year = mon;
866     mon = mday;
867     mday = temp;
868     } else {
869     goto syntax;
870     }
871     }
872     mon -= 1; /* convert month to 0-based */
873     if (sec < 0)
874     sec = 0;
875     if (min < 0)
876     min = 0;
877     if (hour < 0)
878     hour = 0;
879     if (tzoffset == -1) { /* no time zone specified, have to use local */
880     jsdouble msec_time;
881     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
882    
883     *result = UTC(msec_time);
884     return JS_TRUE;
885     }
886    
887     msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
888     msec += tzoffset * msPerMinute;
889     *result = msec;
890     return JS_TRUE;
891    
892     syntax:
893     /* syntax error */
894     *result = 0;
895     return JS_FALSE;
896     }
897    
898     static JSBool
899     date_parse(JSContext *cx, uintN argc, jsval *vp)
900     {
901     JSString *str;
902     jsdouble result;
903    
904     if (argc == 0) {
905     *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
906     return JS_TRUE;
907     }
908     str = js_ValueToString(cx, vp[2]);
909     if (!str)
910     return JS_FALSE;
911     vp[2] = STRING_TO_JSVAL(str);
912     if (!date_parseString(str, &result)) {
913     *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
914     return JS_TRUE;
915     }
916    
917     result = TIMECLIP(result);
918     return js_NewNumberInRootedValue(cx, result, vp);
919     }
920    
921 siliconforks 460 static inline jsdouble
922     NowAsMillis()
923     {
924     return (jsdouble) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
925     }
926    
927 siliconforks 399 static JSBool
928     date_now(JSContext *cx, uintN argc, jsval *vp)
929 siliconforks 332 {
930 siliconforks 460 return js_NewDoubleInRootedValue(cx, NowAsMillis(), vp);
931 siliconforks 332 }
932    
933 siliconforks 399 #ifdef JS_TRACER
934     static jsdouble FASTCALL
935     date_now_tn(JSContext*)
936     {
937 siliconforks 460 return NowAsMillis();
938 siliconforks 399 }
939     #endif
940    
941 siliconforks 332 /*
942     * Get UTC time from the date object. Returns false if the object is not
943     * Date type.
944     */
945     static JSBool
946     GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
947     {
948     if (!JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
949     return JS_FALSE;
950     *dp = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]);
951     return JS_TRUE;
952     }
953    
954     /*
955     * Set UTC time slot with a pointer pointing to a jsdouble. This function is
956     * used only for setting UTC time to some predefined values, such as NaN.
957     *
958     * It also invalidates cached local time.
959     */
960     static JSBool
961     SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
962     {
963     if (vp && !JS_InstanceOf(cx, obj, &js_DateClass, vp + 2))
964     return JS_FALSE;
965     JS_ASSERT_IF(!vp, STOBJ_GET_CLASS(obj) == &js_DateClass);
966    
967     /* Invalidate local time cache. */
968     obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
969     obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(dp);
970     return JS_TRUE;
971     }
972    
973     /*
974     * Set UTC time to a given time.
975     */
976     static JSBool
977     SetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble t)
978     {
979     jsdouble *dp = js_NewWeaklyRootedDouble(cx, t);
980     if (!dp)
981     return JS_FALSE;
982     return SetUTCTimePtr(cx, obj, vp, dp);
983     }
984    
985     /*
986     * Get the local time, cache it if necessary. If UTC time is not finite
987     * (e.g., NaN), the local time slot is set to the UTC time without conversion.
988     */
989     static JSBool
990     GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
991     {
992     jsval v;
993     jsdouble result;
994     jsdouble *cached;
995    
996     if (!obj || !JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
997     return JS_FALSE;
998     v = obj->fslots[JSSLOT_LOCAL_TIME];
999    
1000     result = *JSVAL_TO_DOUBLE(v);
1001    
1002     if (JSDOUBLE_IS_NaN(result)) {
1003     if (!GetUTCTime(cx, obj, vp, &result))
1004     return JS_FALSE;
1005    
1006     /* if result is NaN, it couldn't be finite. */
1007     if (JSDOUBLE_IS_FINITE(result))
1008     result = LocalTime(result);
1009    
1010     cached = js_NewWeaklyRootedDouble(cx, result);
1011     if (!cached)
1012     return JS_FALSE;
1013    
1014     obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cached);
1015     }
1016    
1017     *dp = result;
1018     return JS_TRUE;
1019     }
1020    
1021     /*
1022     * See ECMA 15.9.5.4 thru 15.9.5.23
1023     */
1024     static JSBool
1025     date_getTime(JSContext *cx, uintN argc, jsval *vp)
1026     {
1027     jsdouble result;
1028    
1029     return GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result) &&
1030     js_NewNumberInRootedValue(cx, result, vp);
1031     }
1032    
1033     static JSBool
1034     GetYear(JSContext *cx, JSBool fullyear, jsval *vp)
1035     {
1036     jsdouble result;
1037    
1038     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1039     return JS_FALSE;
1040    
1041     if (JSDOUBLE_IS_FINITE(result)) {
1042     result = YearFromTime(result);
1043    
1044     /* Follow ECMA-262 to the letter, contrary to IE JScript. */
1045     if (!fullyear)
1046     result -= 1900;
1047     }
1048    
1049     return js_NewNumberInRootedValue(cx, result, vp);
1050     }
1051    
1052     static JSBool
1053     date_getYear(JSContext *cx, uintN argc, jsval *vp)
1054     {
1055     return GetYear(cx, JS_FALSE, vp);
1056     }
1057    
1058     static JSBool
1059     date_getFullYear(JSContext *cx, uintN argc, jsval *vp)
1060     {
1061     return GetYear(cx, JS_TRUE, vp);
1062     }
1063    
1064     static JSBool
1065     date_getUTCFullYear(JSContext *cx, uintN argc, jsval *vp)
1066     {
1067     jsdouble result;
1068    
1069     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1070     return JS_FALSE;
1071    
1072     if (JSDOUBLE_IS_FINITE(result))
1073     result = YearFromTime(result);
1074    
1075     return js_NewNumberInRootedValue(cx, result, vp);
1076     }
1077    
1078     static JSBool
1079     date_getMonth(JSContext *cx, uintN argc, jsval *vp)
1080     {
1081     jsdouble result;
1082    
1083     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1084     return JS_FALSE;
1085    
1086     if (JSDOUBLE_IS_FINITE(result))
1087     result = MonthFromTime(result);
1088    
1089     return js_NewNumberInRootedValue(cx, result, vp);
1090     }
1091    
1092     static JSBool
1093     date_getUTCMonth(JSContext *cx, uintN argc, jsval *vp)
1094     {
1095     jsdouble result;
1096    
1097     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1098     return JS_FALSE;
1099    
1100     if (JSDOUBLE_IS_FINITE(result))
1101     result = MonthFromTime(result);
1102    
1103     return js_NewNumberInRootedValue(cx, result, vp);
1104     }
1105    
1106     static JSBool
1107     date_getDate(JSContext *cx, uintN argc, jsval *vp)
1108     {
1109     jsdouble result;
1110    
1111     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1112     return JS_FALSE;
1113    
1114     if (JSDOUBLE_IS_FINITE(result))
1115     result = DateFromTime(result);
1116    
1117     return js_NewNumberInRootedValue(cx, result, vp);
1118     }
1119    
1120     static JSBool
1121     date_getUTCDate(JSContext *cx, uintN argc, jsval *vp)
1122     {
1123     jsdouble result;
1124    
1125     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1126     return JS_FALSE;
1127    
1128     if (JSDOUBLE_IS_FINITE(result))
1129     result = DateFromTime(result);
1130    
1131     return js_NewNumberInRootedValue(cx, result, vp);
1132     }
1133    
1134     static JSBool
1135     date_getDay(JSContext *cx, uintN argc, jsval *vp)
1136     {
1137     jsdouble result;
1138    
1139     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1140     return JS_FALSE;
1141    
1142     if (JSDOUBLE_IS_FINITE(result))
1143     result = WeekDay(result);
1144    
1145     return js_NewNumberInRootedValue(cx, result, vp);
1146     }
1147    
1148     static JSBool
1149     date_getUTCDay(JSContext *cx, uintN argc, jsval *vp)
1150     {
1151     jsdouble result;
1152    
1153     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1154     return JS_FALSE;
1155    
1156     if (JSDOUBLE_IS_FINITE(result))
1157     result = WeekDay(result);
1158    
1159     return js_NewNumberInRootedValue(cx, result, vp);
1160     }
1161    
1162     static JSBool
1163     date_getHours(JSContext *cx, uintN argc, jsval *vp)
1164     {
1165     jsdouble result;
1166    
1167     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1168     return JS_FALSE;
1169    
1170     if (JSDOUBLE_IS_FINITE(result))
1171     result = HourFromTime(result);
1172    
1173     return js_NewNumberInRootedValue(cx, result, vp);
1174     }
1175    
1176     static JSBool
1177     date_getUTCHours(JSContext *cx, uintN argc, jsval *vp)
1178     {
1179     jsdouble result;
1180    
1181     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1182     return JS_FALSE;
1183    
1184     if (JSDOUBLE_IS_FINITE(result))
1185     result = HourFromTime(result);
1186    
1187     return js_NewNumberInRootedValue(cx, result, vp);
1188     }
1189    
1190     static JSBool
1191     date_getMinutes(JSContext *cx, uintN argc, jsval *vp)
1192     {
1193     jsdouble result;
1194    
1195     if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1196     return JS_FALSE;
1197    
1198     if (JSDOUBLE_IS_FINITE(result))
1199     result = MinFromTime(result);
1200    
1201     return js_NewNumberInRootedValue(cx, result, vp);
1202     }
1203    
1204     static JSBool
1205     date_getUTCMinutes(JSContext *cx, uintN argc, jsval *vp)
1206     {
1207     jsdouble result;
1208    
1209     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1210     return JS_FALSE;
1211    
1212     if (JSDOUBLE_IS_FINITE(result))
1213     result = MinFromTime(result);
1214    
1215     return js_NewNumberInRootedValue(cx, result, vp);
1216     }
1217    
1218     /* Date.getSeconds is mapped to getUTCSeconds */
1219    
1220     static JSBool
1221     date_getUTCSeconds(JSContext *cx, uintN argc, jsval *vp)
1222     {
1223     jsdouble result;
1224    
1225     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1226     return JS_FALSE;
1227    
1228     if (JSDOUBLE_IS_FINITE(result))
1229     result = SecFromTime(result);
1230    
1231     return js_NewNumberInRootedValue(cx, result, vp);
1232     }
1233    
1234     /* Date.getMilliseconds is mapped to getUTCMilliseconds */
1235    
1236     static JSBool
1237     date_getUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp)
1238     {
1239     jsdouble result;
1240    
1241     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
1242     return JS_FALSE;
1243    
1244     if (JSDOUBLE_IS_FINITE(result))
1245     result = msFromTime(result);
1246    
1247     return js_NewNumberInRootedValue(cx, result, vp);
1248     }
1249    
1250     static JSBool
1251     date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp)
1252     {
1253     JSObject *obj;
1254     jsdouble utctime, localtime, result;
1255    
1256     obj = JS_THIS_OBJECT(cx, vp);
1257     if (!GetUTCTime(cx, obj, vp, &utctime))
1258     return JS_FALSE;
1259     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
1260     return JS_FALSE;
1261    
1262     /*
1263     * Return the time zone offset in minutes for the current locale that is
1264     * appropriate for this time. This value would be a constant except for
1265     * daylight savings time.
1266     */
1267     result = (utctime - localtime) / msPerMinute;
1268     return js_NewNumberInRootedValue(cx, result, vp);
1269     }
1270    
1271     static JSBool
1272     SetDateToNaN(JSContext *cx, jsval *vp)
1273     {
1274     JSObject *obj;
1275    
1276     obj = JS_THIS_OBJECT(cx, vp);
1277     if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN))
1278     return JS_FALSE;
1279     *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
1280     return JS_TRUE;
1281     }
1282    
1283     static JSBool
1284     date_setTime(JSContext *cx, uintN argc, jsval *vp)
1285     {
1286     jsdouble result;
1287    
1288     if (argc == 0)
1289     return SetDateToNaN(cx, vp);
1290     result = js_ValueToNumber(cx, &vp[2]);
1291     if (JSVAL_IS_NULL(vp[2]))
1292     return JS_FALSE;
1293    
1294     result = TIMECLIP(result);
1295    
1296     if (!SetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, result))
1297     return JS_FALSE;
1298    
1299     return js_NewNumberInRootedValue(cx, result, vp);
1300     }
1301    
1302     static JSBool
1303     date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
1304     {
1305     JSObject *obj;
1306     jsval *argv;
1307     uintN i;
1308     jsdouble args[4], *argp, *stop;
1309     jsdouble hour, min, sec, msec;
1310     jsdouble lorutime; /* Local or UTC version of *date */
1311    
1312     jsdouble msec_time;
1313     jsdouble result;
1314    
1315     obj = JS_THIS_OBJECT(cx, vp);
1316     if (!GetUTCTime(cx, obj, vp, &result))
1317     return JS_FALSE;
1318    
1319     /* just return NaN if the date is already NaN */
1320     if (!JSDOUBLE_IS_FINITE(result))
1321     return js_NewNumberInRootedValue(cx, result, vp);
1322    
1323     /*
1324     * Satisfy the ECMA rule that if a function is called with
1325     * fewer arguments than the specified formal arguments, the
1326     * remaining arguments are set to undefined. Seems like all
1327     * the Date.setWhatever functions in ECMA are only varargs
1328     * beyond the first argument; this should be set to undefined
1329     * if it's not given. This means that "d = new Date();
1330     * d.setMilliseconds()" returns NaN. Blech.
1331     */
1332     if (argc == 0)
1333     return SetDateToNaN(cx, vp);
1334     if (argc > maxargs)
1335     argc = maxargs; /* clamp argc */
1336     JS_ASSERT(argc <= 4);
1337    
1338     argv = vp + 2;
1339     for (i = 0; i < argc; i++) {
1340     args[i] = js_ValueToNumber(cx, &argv[i]);
1341     if (JSVAL_IS_NULL(argv[i]))
1342     return JS_FALSE;
1343     if (!JSDOUBLE_IS_FINITE(args[i]))
1344     return SetDateToNaN(cx, vp);
1345     args[i] = js_DoubleToInteger(args[i]);
1346     }
1347    
1348     if (local)
1349     lorutime = LocalTime(result);
1350     else
1351     lorutime = result;
1352    
1353     argp = args;
1354     stop = argp + argc;
1355     if (maxargs >= 4 && argp < stop)
1356     hour = *argp++;
1357     else
1358     hour = HourFromTime(lorutime);
1359    
1360     if (maxargs >= 3 && argp < stop)
1361     min = *argp++;
1362     else
1363     min = MinFromTime(lorutime);
1364    
1365     if (maxargs >= 2 && argp < stop)
1366     sec = *argp++;
1367     else
1368     sec = SecFromTime(lorutime);
1369    
1370     if (maxargs >= 1 && argp < stop)
1371     msec = *argp;
1372     else
1373     msec = msFromTime(lorutime);
1374    
1375     msec_time = MakeTime(hour, min, sec, msec);
1376     result = MakeDate(Day(lorutime), msec_time);
1377    
1378     /* fprintf(stderr, "%f\n", result); */
1379    
1380     if (local)
1381     result = UTC(result);
1382    
1383     /* fprintf(stderr, "%f\n", result); */
1384    
1385     result = TIMECLIP(result);
1386     if (!SetUTCTime(cx, obj, NULL, result))
1387     return JS_FALSE;
1388    
1389     return js_NewNumberInRootedValue(cx, result, vp);
1390     }
1391    
1392     static JSBool
1393     date_setMilliseconds(JSContext *cx, uintN argc, jsval *vp)
1394     {
1395     return date_makeTime(cx, 1, JS_TRUE, argc, vp);
1396     }
1397    
1398     static JSBool
1399     date_setUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp)
1400     {
1401     return date_makeTime(cx, 1, JS_FALSE, argc, vp);
1402     }
1403    
1404     static JSBool
1405     date_setSeconds(JSContext *cx, uintN argc, jsval *vp)
1406     {
1407     return date_makeTime(cx, 2, JS_TRUE, argc, vp);
1408     }
1409    
1410     static JSBool
1411     date_setUTCSeconds(JSContext *cx, uintN argc, jsval *vp)
1412     {
1413     return date_makeTime(cx, 2, JS_FALSE, argc, vp);
1414     }
1415    
1416     static JSBool
1417     date_setMinutes(JSContext *cx, uintN argc, jsval *vp)
1418     {
1419     return date_makeTime(cx, 3, JS_TRUE, argc, vp);
1420     }
1421    
1422     static JSBool
1423     date_setUTCMinutes(JSContext *cx, uintN argc, jsval *vp)
1424     {
1425     return date_makeTime(cx, 3, JS_FALSE, argc, vp);
1426     }
1427    
1428     static JSBool
1429     date_setHours(JSContext *cx, uintN argc, jsval *vp)
1430     {
1431     return date_makeTime(cx, 4, JS_TRUE, argc, vp);
1432     }
1433    
1434     static JSBool
1435     date_setUTCHours(JSContext *cx, uintN argc, jsval *vp)
1436     {
1437     return date_makeTime(cx, 4, JS_FALSE, argc, vp);
1438     }
1439    
1440     static JSBool
1441     date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
1442     {
1443     JSObject *obj;
1444     jsval *argv;
1445     uintN i;
1446     jsdouble lorutime; /* local or UTC version of *date */
1447     jsdouble args[3], *argp, *stop;
1448     jsdouble year, month, day;
1449     jsdouble result;
1450    
1451     obj = JS_THIS_OBJECT(cx, vp);
1452     if (!GetUTCTime(cx, obj, vp, &result))
1453     return JS_FALSE;
1454    
1455     /* see complaint about ECMA in date_MakeTime */
1456     if (argc == 0)
1457     return SetDateToNaN(cx, vp);
1458     if (argc > maxargs)
1459     argc = maxargs; /* clamp argc */
1460     JS_ASSERT(1 <= argc && argc <= 3);
1461    
1462     argv = vp + 2;
1463     for (i = 0; i < argc; i++) {
1464     args[i] = js_ValueToNumber(cx, &argv[i]);
1465     if (JSVAL_IS_NULL(argv[i]))
1466     return JS_FALSE;
1467     if (!JSDOUBLE_IS_FINITE(args[i]))
1468     return SetDateToNaN(cx, vp);
1469     args[i] = js_DoubleToInteger(args[i]);
1470     }
1471    
1472     /* return NaN if date is NaN and we're not setting the year,
1473     * If we are, use 0 as the time. */
1474     if (!(JSDOUBLE_IS_FINITE(result))) {
1475     if (maxargs < 3)
1476     return js_NewNumberInRootedValue(cx, result, vp);
1477     lorutime = +0.;
1478     } else {
1479     lorutime = local ? LocalTime(result) : result;
1480     }
1481    
1482     argp = args;
1483     stop = argp + argc;
1484     if (maxargs >= 3 && argp < stop)
1485     year = *argp++;
1486     else
1487     year = YearFromTime(lorutime);
1488    
1489     if (maxargs >= 2 && argp < stop)
1490     month = *argp++;
1491     else
1492     month = MonthFromTime(lorutime);
1493    
1494     if (maxargs >= 1 && argp < stop)
1495     day = *argp++;
1496     else
1497     day = DateFromTime(lorutime);
1498    
1499     day = MakeDay(year, month, day); /* day within year */
1500     result = MakeDate(day, TimeWithinDay(lorutime));
1501    
1502     if (local)
1503     result = UTC(result);
1504    
1505     result = TIMECLIP(result);
1506     if (!SetUTCTime(cx, obj, NULL, result))
1507     return JS_FALSE;
1508    
1509     return js_NewNumberInRootedValue(cx, result, vp);
1510     }
1511    
1512     static JSBool
1513     date_setDate(JSContext *cx, uintN argc, jsval *vp)
1514     {
1515     return date_makeDate(cx, 1, JS_TRUE, argc, vp);
1516     }
1517    
1518     static JSBool
1519     date_setUTCDate(JSContext *cx, uintN argc, jsval *vp)
1520     {
1521     return date_makeDate(cx, 1, JS_FALSE, argc, vp);
1522     }
1523    
1524     static JSBool
1525     date_setMonth(JSContext *cx, uintN argc, jsval *vp)
1526     {
1527     return date_makeDate(cx, 2, JS_TRUE, argc, vp);
1528     }
1529    
1530     static JSBool
1531     date_setUTCMonth(JSContext *cx, uintN argc, jsval *vp)
1532     {
1533     return date_makeDate(cx, 2, JS_FALSE, argc, vp);
1534     }
1535    
1536     static JSBool
1537     date_setFullYear(JSContext *cx, uintN argc, jsval *vp)
1538     {
1539     return date_makeDate(cx, 3, JS_TRUE, argc, vp);
1540     }
1541    
1542     static JSBool
1543     date_setUTCFullYear(JSContext *cx, uintN argc, jsval *vp)
1544     {
1545     return date_makeDate(cx, 3, JS_FALSE, argc, vp);
1546     }
1547    
1548     static JSBool
1549     date_setYear(JSContext *cx, uintN argc, jsval *vp)
1550     {
1551     JSObject *obj;
1552     jsdouble t;
1553     jsdouble year;
1554     jsdouble day;
1555     jsdouble result;
1556    
1557     obj = JS_THIS_OBJECT(cx, vp);
1558     if (!GetUTCTime(cx, obj, vp, &result))
1559     return JS_FALSE;
1560    
1561     if (argc == 0)
1562     return SetDateToNaN(cx, vp);
1563     year = js_ValueToNumber(cx, &vp[2]);
1564     if (JSVAL_IS_NULL(vp[2]))
1565     return JS_FALSE;
1566     if (!JSDOUBLE_IS_FINITE(year))
1567     return SetDateToNaN(cx, vp);
1568    
1569     year = js_DoubleToInteger(year);
1570    
1571     if (!JSDOUBLE_IS_FINITE(result)) {
1572     t = +0.0;
1573     } else {
1574     t = LocalTime(result);
1575     }
1576    
1577     if (year >= 0 && year <= 99)
1578     year += 1900;
1579    
1580     day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
1581     result = MakeDate(day, TimeWithinDay(t));
1582     result = UTC(result);
1583    
1584     result = TIMECLIP(result);
1585     if (!SetUTCTime(cx, obj, NULL, result))
1586     return JS_FALSE;
1587    
1588     return js_NewNumberInRootedValue(cx, result, vp);
1589     }
1590    
1591     /* constants for toString, toUTCString */
1592     static char js_NaN_date_str[] = "Invalid Date";
1593     static const char* days[] =
1594     {
1595     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1596     };
1597     static const char* months[] =
1598     {
1599     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1600     };
1601    
1602 siliconforks 399
1603     // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1604     // requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1605     static void
1606     print_gmt_string(char* buf, size_t size, jsdouble utctime)
1607     {
1608     JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
1609     days[WeekDay(utctime)],
1610     DateFromTime(utctime),
1611     months[MonthFromTime(utctime)],
1612     YearFromTime(utctime),
1613     HourFromTime(utctime),
1614     MinFromTime(utctime),
1615     SecFromTime(utctime));
1616     }
1617    
1618     static void
1619     print_iso_string(char* buf, size_t size, jsdouble utctime)
1620     {
1621     JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
1622     YearFromTime(utctime),
1623     MonthFromTime(utctime) + 1,
1624     DateFromTime(utctime),
1625     HourFromTime(utctime),
1626     MinFromTime(utctime),
1627     SecFromTime(utctime),
1628     msFromTime(utctime));
1629     }
1630    
1631 siliconforks 332 static JSBool
1632 siliconforks 399 date_utc_format(JSContext *cx, jsval *vp,
1633     void (*printFunc)(char*, size_t, jsdouble))
1634 siliconforks 332 {
1635     char buf[100];
1636     JSString *str;
1637     jsdouble utctime;
1638    
1639     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
1640     return JS_FALSE;
1641    
1642     if (!JSDOUBLE_IS_FINITE(utctime)) {
1643     JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1644     } else {
1645 siliconforks 399 (*printFunc)(buf, sizeof buf, utctime);
1646 siliconforks 332 }
1647     str = JS_NewStringCopyZ(cx, buf);
1648     if (!str)
1649     return JS_FALSE;
1650     *vp = STRING_TO_JSVAL(str);
1651     return JS_TRUE;
1652     }
1653    
1654 siliconforks 399 static JSBool
1655     date_toGMTString(JSContext *cx, uintN argc, jsval *vp)
1656     {
1657     return date_utc_format(cx, vp, print_gmt_string);
1658     }
1659    
1660     static JSBool
1661     date_toISOString(JSContext *cx, uintN argc, jsval *vp)
1662     {
1663     return date_utc_format(cx, vp, print_iso_string);
1664     }
1665    
1666 siliconforks 332 /* for Date.toLocaleString; interface to PRMJTime date struct.
1667     */
1668     static void
1669     new_explode(jsdouble timeval, PRMJTime *split)
1670     {
1671     jsint year = YearFromTime(timeval);
1672    
1673     split->tm_usec = (int32) msFromTime(timeval) * 1000;
1674     split->tm_sec = (int8) SecFromTime(timeval);
1675     split->tm_min = (int8) MinFromTime(timeval);
1676     split->tm_hour = (int8) HourFromTime(timeval);
1677     split->tm_mday = (int8) DateFromTime(timeval);
1678     split->tm_mon = (int8) MonthFromTime(timeval);
1679     split->tm_wday = (int8) WeekDay(timeval);
1680     split->tm_year = year;
1681     split->tm_yday = (int16) DayWithinYear(timeval, year);
1682    
1683     /* not sure how this affects things, but it doesn't seem
1684     to matter. */
1685     split->tm_isdst = (DaylightSavingTA(timeval) != 0);
1686     }
1687    
1688     typedef enum formatspec {
1689     FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
1690     } formatspec;
1691    
1692     /* helper function */
1693     static JSBool
1694     date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
1695     {
1696     char buf[100];
1697     JSString *str;
1698     char tzbuf[100];
1699     JSBool usetz;
1700     size_t i, tzlen;
1701     PRMJTime split;
1702    
1703     if (!JSDOUBLE_IS_FINITE(date)) {
1704     JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1705     } else {
1706     jsdouble local = LocalTime(date);
1707    
1708     /* offset from GMT in minutes. The offset includes daylight savings,
1709     if it applies. */
1710     jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute);
1711    
1712     /* map 510 minutes to 0830 hours */
1713     intN offset = (minutes / 60) * 100 + minutes % 60;
1714    
1715     /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
1716     * printed as 'GMT-0800' rather than as 'PST' to avoid
1717     * operating-system dependence on strftime (which
1718     * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
1719     * PST as 'Pacific Standard Time.' This way we always know
1720     * what we're getting, and can parse it if we produce it.
1721     * The OS TZA string is included as a comment.
1722     */
1723    
1724     /* get a timezone string from the OS to include as a
1725     comment. */
1726     new_explode(date, &split);
1727     if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
1728    
1729     /* Decide whether to use the resulting timezone string.
1730     *
1731     * Reject it if it contains any non-ASCII, non-alphanumeric
1732     * characters. It's then likely in some other character
1733     * encoding, and we probably won't display it correctly.
1734     */
1735     usetz = JS_TRUE;
1736     tzlen = strlen(tzbuf);
1737     if (tzlen > 100) {
1738     usetz = JS_FALSE;
1739     } else {
1740     for (i = 0; i < tzlen; i++) {
1741     jschar c = tzbuf[i];
1742     if (c > 127 ||
1743     !(isalpha(c) || isdigit(c) ||
1744     c == ' ' || c == '(' || c == ')')) {
1745     usetz = JS_FALSE;
1746     }
1747     }
1748     }
1749    
1750     /* Also reject it if it's not parenthesized or if it's '()'. */
1751     if (tzbuf[0] != '(' || tzbuf[1] == ')')
1752     usetz = JS_FALSE;
1753     } else
1754     usetz = JS_FALSE;
1755    
1756     switch (format) {
1757     case FORMATSPEC_FULL:
1758     /*
1759     * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1760     * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1761     */
1762     /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
1763     JS_snprintf(buf, sizeof buf,
1764     "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
1765     days[WeekDay(local)],
1766     months[MonthFromTime(local)],
1767     DateFromTime(local),
1768     YearFromTime(local),
1769     HourFromTime(local),
1770     MinFromTime(local),
1771     SecFromTime(local),
1772     offset,
1773     usetz ? " " : "",
1774     usetz ? tzbuf : "");
1775     break;
1776     case FORMATSPEC_DATE:
1777     /* Tue Oct 31 2000 */
1778     JS_snprintf(buf, sizeof buf,
1779     "%s %s %.2d %.4d",
1780     days[WeekDay(local)],
1781     months[MonthFromTime(local)],
1782     DateFromTime(local),
1783     YearFromTime(local));
1784     break;
1785     case FORMATSPEC_TIME:
1786     /* 09:41:40 GMT-0800 (PST) */
1787     JS_snprintf(buf, sizeof buf,
1788     "%.2d:%.2d:%.2d GMT%+.4d%s%s",
1789     HourFromTime(local),
1790     MinFromTime(local),
1791     SecFromTime(local),
1792     offset,
1793     usetz ? " " : "",
1794     usetz ? tzbuf : "");
1795     break;
1796     }
1797     }
1798    
1799     str = JS_NewStringCopyZ(cx, buf);
1800     if (!str)
1801     return JS_FALSE;
1802     *rval = STRING_TO_JSVAL(str);
1803     return JS_TRUE;
1804     }
1805    
1806     static JSBool
1807     date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp)
1808     {
1809     JSObject *obj;
1810     char buf[100];
1811     JSString *str;
1812     PRMJTime split;
1813     jsdouble utctime;
1814    
1815     obj = JS_THIS_OBJECT(cx, vp);
1816     if (!GetUTCTime(cx, obj, vp, &utctime))
1817     return JS_FALSE;
1818    
1819     if (!JSDOUBLE_IS_FINITE(utctime)) {
1820     JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1821     } else {
1822     intN result_len;
1823     jsdouble local = LocalTime(utctime);
1824     new_explode(local, &split);
1825    
1826     /* let PRMJTime format it. */
1827     result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
1828    
1829     /* If it failed, default to toString. */
1830     if (result_len == 0)
1831     return date_format(cx, utctime, FORMATSPEC_FULL, vp);
1832    
1833     /* Hacked check against undesired 2-digit year 00/00/00 form. */
1834     if (strcmp(format, "%x") == 0 && result_len >= 6 &&
1835     /* Format %x means use OS settings, which may have 2-digit yr, so
1836     hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
1837     !isdigit(buf[result_len - 3]) &&
1838     isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
1839     /* ...but not if starts with 4-digit year, like 2022/3/11. */
1840     !(isdigit(buf[0]) && isdigit(buf[1]) &&
1841     isdigit(buf[2]) && isdigit(buf[3]))) {
1842     JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
1843     "%d", js_DateGetYear(cx, obj));
1844     }
1845    
1846     }
1847    
1848     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
1849     return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
1850    
1851     str = JS_NewStringCopyZ(cx, buf);
1852     if (!str)
1853     return JS_FALSE;
1854     *vp = STRING_TO_JSVAL(str);
1855     return JS_TRUE;
1856     }
1857    
1858     static JSBool
1859     date_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
1860     {
1861     /* Use '%#c' for windows, because '%c' is
1862     * backward-compatible and non-y2k with msvc; '%#c' requests that a
1863     * full year be used in the result string.
1864     */
1865     return date_toLocaleHelper(cx,
1866     #if defined(_WIN32) && !defined(__MWERKS__)
1867     "%#c"
1868     #else
1869     "%c"
1870     #endif
1871     , vp);
1872     }
1873    
1874     static JSBool
1875     date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp)
1876     {
1877     /* Use '%#x' for windows, because '%x' is
1878     * backward-compatible and non-y2k with msvc; '%#x' requests that a
1879     * full year be used in the result string.
1880     */
1881     return date_toLocaleHelper(cx,
1882     #if defined(_WIN32) && !defined(__MWERKS__)
1883     "%#x"
1884     #else
1885     "%x"
1886     #endif
1887     , vp);
1888     }
1889    
1890     static JSBool
1891     date_toLocaleTimeString(JSContext *cx, uintN argc, jsval *vp)
1892     {
1893     return date_toLocaleHelper(cx, "%X", vp);
1894     }
1895    
1896     static JSBool
1897     date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp)
1898     {
1899     JSString *fmt;
1900     const char *fmtbytes;
1901    
1902     if (argc == 0)
1903     return date_toLocaleString(cx, argc, vp);
1904    
1905     fmt = js_ValueToString(cx, vp[2]);
1906     if (!fmt)
1907     return JS_FALSE;
1908     vp[2] = STRING_TO_JSVAL(fmt);
1909     fmtbytes = js_GetStringBytes(cx, fmt);
1910     if (!fmtbytes)
1911     return JS_FALSE;
1912    
1913     return date_toLocaleHelper(cx, fmtbytes, vp);
1914     }
1915    
1916     static JSBool
1917     date_toTimeString(JSContext *cx, uintN argc, jsval *vp)
1918     {
1919     jsdouble utctime;
1920    
1921     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
1922     return JS_FALSE;
1923     return date_format(cx, utctime, FORMATSPEC_TIME, vp);
1924     }
1925    
1926     static JSBool
1927     date_toDateString(JSContext *cx, uintN argc, jsval *vp)
1928     {
1929     jsdouble utctime;
1930    
1931     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
1932     return JS_FALSE;
1933     return date_format(cx, utctime, FORMATSPEC_DATE, vp);
1934     }
1935    
1936     #if JS_HAS_TOSOURCE
1937     #include <string.h>
1938     #include "jsdtoa.h"
1939    
1940     static JSBool
1941     date_toSource(JSContext *cx, uintN argc, jsval *vp)
1942     {
1943     jsdouble utctime;
1944     char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes;
1945     JSString *str;
1946    
1947     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
1948     return JS_FALSE;
1949    
1950     numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime);
1951     if (!numStr) {
1952     JS_ReportOutOfMemory(cx);
1953     return JS_FALSE;
1954     }
1955    
1956     bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
1957     if (!bytes) {
1958     JS_ReportOutOfMemory(cx);
1959     return JS_FALSE;
1960     }
1961    
1962     str = JS_NewString(cx, bytes, strlen(bytes));
1963     if (!str) {
1964     free(bytes);
1965     return JS_FALSE;
1966     }
1967     *vp = STRING_TO_JSVAL(str);
1968     return JS_TRUE;
1969     }
1970     #endif
1971    
1972     static JSBool
1973     date_toString(JSContext *cx, uintN argc, jsval *vp)
1974     {
1975     jsdouble utctime;
1976    
1977     if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
1978     return JS_FALSE;
1979     return date_format(cx, utctime, FORMATSPEC_FULL, vp);
1980     }
1981    
1982 siliconforks 399 #ifdef JS_TRACER
1983     static jsval FASTCALL
1984     date_valueOf_tn(JSContext* cx, JSObject* obj, JSString* str)
1985     {
1986     JS_ASSERT(JS_InstanceOf(cx, obj, &js_DateClass, NULL));
1987     jsdouble t = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]);
1988    
1989     JSString* number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
1990     jsval v;
1991     if (js_EqualStrings(str, number_str)) {
1992     if (!js_NewNumberInRootedValue(cx, t, &v))
1993     return JSVAL_ERROR_COOKIE;
1994     } else {
1995     if (!date_format(cx, t, FORMATSPEC_FULL, &v))
1996     return JSVAL_ERROR_COOKIE;
1997     }
1998     return v;
1999     }
2000     #endif
2001    
2002 siliconforks 332 static JSBool
2003     date_valueOf(JSContext *cx, uintN argc, jsval *vp)
2004     {
2005 siliconforks 399 JSString *str, *number_str;
2006 siliconforks 332
2007     /* It is an error to call date_valueOf on a non-date object, but we don't
2008     * need to check for that explicitly here because every path calls
2009     * GetUTCTime, which does the check.
2010     */
2011    
2012     /* If called directly with no arguments, convert to a time number. */
2013     if (argc == 0)
2014     return date_getTime(cx, argc, vp);
2015    
2016     /* Convert to number only if the hint was given, otherwise favor string. */
2017     str = js_ValueToString(cx, vp[2]);
2018     if (!str)
2019     return JS_FALSE;
2020 siliconforks 399 number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
2021     if (js_EqualStrings(str, number_str))
2022 siliconforks 332 return date_getTime(cx, argc, vp);
2023     return date_toString(cx, argc, vp);
2024     }
2025    
2026 siliconforks 399 // Don't really need an argument here, but we don't support arg-less builtins
2027     JS_DEFINE_TRCINFO_1(date_now,
2028     (1, (static, DOUBLE, date_now_tn, CONTEXT, 0, 0)))
2029    
2030 siliconforks 332 static JSFunctionSpec date_static_methods[] = {
2031     JS_FN("UTC", date_UTC, MAXARGS,0),
2032     JS_FN("parse", date_parse, 1,0),
2033 siliconforks 399 JS_TN("now", date_now, 0,0, date_now_trcinfo),
2034 siliconforks 332 JS_FS_END
2035     };
2036    
2037 siliconforks 399 JS_DEFINE_TRCINFO_1(date_valueOf,
2038 siliconforks 460 (3, (static, JSVAL_RETRY, date_valueOf_tn, CONTEXT, THIS, STRING, 0, 0)))
2039 siliconforks 399
2040 siliconforks 332 static JSFunctionSpec date_methods[] = {
2041     JS_FN("getTime", date_getTime, 0,0),
2042     JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0),
2043     JS_FN("getYear", date_getYear, 0,0),
2044     JS_FN("getFullYear", date_getFullYear, 0,0),
2045     JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0),
2046     JS_FN("getMonth", date_getMonth, 0,0),
2047     JS_FN("getUTCMonth", date_getUTCMonth, 0,0),
2048     JS_FN("getDate", date_getDate, 0,0),
2049     JS_FN("getUTCDate", date_getUTCDate, 0,0),
2050     JS_FN("getDay", date_getDay, 0,0),
2051     JS_FN("getUTCDay", date_getUTCDay, 0,0),
2052     JS_FN("getHours", date_getHours, 0,0),
2053     JS_FN("getUTCHours", date_getUTCHours, 0,0),
2054     JS_FN("getMinutes", date_getMinutes, 0,0),
2055     JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0),
2056     JS_FN("getSeconds", date_getUTCSeconds, 0,0),
2057     JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0),
2058     JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0),
2059     JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0),
2060     JS_FN("setTime", date_setTime, 1,0),
2061     JS_FN("setYear", date_setYear, 1,0),
2062     JS_FN("setFullYear", date_setFullYear, 3,0),
2063     JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0),
2064     JS_FN("setMonth", date_setMonth, 2,0),
2065     JS_FN("setUTCMonth", date_setUTCMonth, 2,0),
2066     JS_FN("setDate", date_setDate, 1,0),
2067     JS_FN("setUTCDate", date_setUTCDate, 1,0),
2068     JS_FN("setHours", date_setHours, 4,0),
2069     JS_FN("setUTCHours", date_setUTCHours, 4,0),
2070     JS_FN("setMinutes", date_setMinutes, 3,0),
2071     JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0),
2072     JS_FN("setSeconds", date_setSeconds, 2,0),
2073     JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0),
2074     JS_FN("setMilliseconds", date_setMilliseconds, 1,0),
2075     JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
2076     JS_FN("toUTCString", date_toGMTString, 0,0),
2077     JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
2078     JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
2079     JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
2080     JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
2081     JS_FN("toDateString", date_toDateString, 0,0),
2082     JS_FN("toTimeString", date_toTimeString, 0,0),
2083 siliconforks 399 JS_FN("toISOString", date_toISOString, 0,0),
2084     JS_FN(js_toJSON_str, date_toISOString, 0,0),
2085    
2086 siliconforks 332 #if JS_HAS_TOSOURCE
2087     JS_FN(js_toSource_str, date_toSource, 0,0),
2088     #endif
2089     JS_FN(js_toString_str, date_toString, 0,0),
2090 siliconforks 399 JS_TN(js_valueOf_str, date_valueOf, 0,0, date_valueOf_trcinfo),
2091 siliconforks 332 JS_FS_END
2092     };
2093    
2094     static jsdouble *
2095     date_constructor(JSContext *cx, JSObject* obj)
2096     {
2097     jsdouble *date;
2098    
2099     date = js_NewWeaklyRootedDouble(cx, 0.0);
2100     if (!date)
2101     return NULL;
2102    
2103     obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date);
2104     obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
2105     return date;
2106     }
2107    
2108 siliconforks 399 JSBool
2109     js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2110 siliconforks 332 {
2111     jsdouble *date;
2112     JSString *str;
2113     jsdouble d;
2114    
2115     /* Date called as function. */
2116 siliconforks 460 if (!JS_IsConstructing(cx))
2117     return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, rval);
2118 siliconforks 332
2119     /* Date called as constructor. */
2120     if (argc == 0) {
2121     date = date_constructor(cx, obj);
2122     if (!date)
2123     return JS_FALSE;
2124 siliconforks 460 *date = NowAsMillis();
2125 siliconforks 332 } else if (argc == 1) {
2126     if (!JSVAL_IS_STRING(argv[0])) {
2127     /* the argument is a millisecond number */
2128     d = js_ValueToNumber(cx, &argv[0]);
2129     if (JSVAL_IS_NULL(argv[0]))
2130     return JS_FALSE;
2131     date = date_constructor(cx, obj);
2132     if (!date)
2133     return JS_FALSE;
2134     *date = TIMECLIP(d);
2135     } else {
2136     /* the argument is a string; parse it. */
2137     date = date_constructor(cx, obj);
2138     if (!date)
2139     return JS_FALSE;
2140    
2141     str = js_ValueToString(cx, argv[0]);
2142     if (!str)
2143     return JS_FALSE;
2144    
2145     if (!date_parseString(str, date))
2146     *date = *cx->runtime->jsNaN;
2147     *date = TIMECLIP(*date);
2148     }
2149     } else {
2150     jsdouble *date;
2151     jsdouble msec_time;
2152    
2153     if (!date_msecFromArgs(cx, argc, argv, &msec_time))
2154     return JS_FALSE;
2155    
2156     date = date_constructor(cx, obj);
2157     if (!date)
2158     return JS_FALSE;
2159    
2160     if (JSDOUBLE_IS_FINITE(msec_time)) {
2161     msec_time = UTC(msec_time);
2162     msec_time = TIMECLIP(msec_time);
2163     }
2164    
2165     *date = msec_time;
2166     }
2167     return JS_TRUE;
2168     }
2169    
2170     JSObject *
2171     js_InitDateClass(JSContext *cx, JSObject *obj)
2172     {
2173     JSObject *proto;
2174     jsdouble *proto_date;
2175    
2176     /* set static LocalTZA */
2177     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
2178 siliconforks 460 proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS,
2179 siliconforks 332 NULL, date_methods, NULL, date_static_methods);
2180     if (!proto)
2181     return NULL;
2182    
2183     /* Alias toUTCString with toGMTString. (ECMA B.2.6) */
2184     if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
2185     return NULL;
2186    
2187     /* Set the value of the Date.prototype date to NaN */
2188     proto_date = date_constructor(cx, proto);
2189     if (!proto_date)
2190     return NULL;
2191     *proto_date = *cx->runtime->jsNaN;
2192    
2193     return proto;
2194     }
2195    
2196     JS_FRIEND_API(JSObject *)
2197     js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
2198     {
2199     JSObject *obj;
2200     jsdouble *date;
2201    
2202     obj = js_NewObject(cx, &js_DateClass, NULL, NULL, 0);
2203     if (!obj)
2204     return NULL;
2205    
2206     date = date_constructor(cx, obj);
2207     if (!date)
2208     return NULL;
2209    
2210     *date = msec_time;
2211     return obj;
2212     }
2213    
2214     JS_FRIEND_API(JSObject *)
2215     js_NewDateObject(JSContext* cx, int year, int mon, int mday,
2216     int hour, int min, int sec)
2217     {
2218     JSObject *obj;
2219     jsdouble msec_time;
2220    
2221     JS_ASSERT(mon < 12);
2222     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
2223     obj = js_NewDateObjectMsec(cx, UTC(msec_time));
2224     return obj;
2225     }
2226    
2227     JS_FRIEND_API(JSBool)
2228     js_DateIsValid(JSContext *cx, JSObject* obj)
2229     {
2230     jsdouble utctime;
2231     return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime);
2232     }
2233    
2234     JS_FRIEND_API(int)
2235     js_DateGetYear(JSContext *cx, JSObject* obj)
2236     {
2237     jsdouble localtime;
2238    
2239     /* Preserve legacy API behavior of returning 0 for invalid dates. */
2240     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
2241     JSDOUBLE_IS_NaN(localtime)) {
2242     return 0;
2243     }
2244    
2245     return (int) YearFromTime(localtime);
2246     }
2247    
2248     JS_FRIEND_API(int)
2249     js_DateGetMonth(JSContext *cx, JSObject* obj)
2250     {
2251     jsdouble localtime;
2252    
2253     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
2254     JSDOUBLE_IS_NaN(localtime)) {
2255     return 0;
2256     }
2257    
2258     return (int) MonthFromTime(localtime);
2259     }
2260    
2261     JS_FRIEND_API(int)
2262     js_DateGetDate(JSContext *cx, JSObject* obj)
2263     {
2264     jsdouble localtime;
2265    
2266     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
2267     JSDOUBLE_IS_NaN(localtime)) {
2268     return 0;
2269     }
2270    
2271     return (int) DateFromTime(localtime);
2272     }
2273    
2274     JS_FRIEND_API(int)
2275     js_DateGetHours(JSContext *cx, JSObject* obj)
2276     {
2277     jsdouble localtime;
2278    
2279     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
2280     JSDOUBLE_IS_NaN(localtime)) {
2281     return 0;
2282     }
2283    
2284     return (int) HourFromTime(localtime);
2285     }
2286    
2287     JS_FRIEND_API(int)
2288     js_DateGetMinutes(JSContext *cx, JSObject* obj)
2289     {
2290     jsdouble localtime;
2291    
2292     if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
2293     JSDOUBLE_IS_NaN(localtime)) {
2294     return 0;
2295     }
2296    
2297     return (int) MinFromTime(localtime);
2298     }
2299    
2300     JS_FRIEND_API(int)
2301     js_DateGetSeconds(JSContext *cx, JSObject* obj)
2302     {
2303     jsdouble utctime;
2304    
2305     if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime))
2306     return 0;
2307    
2308     return (int) SecFromTime(utctime);
2309     }
2310    
2311     JS_FRIEND_API(void)
2312     js_DateSetYear(JSContext *cx, JSObject *obj, int year)
2313     {
2314     jsdouble local;
2315    
2316     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2317     return;
2318    
2319     /* reset date if it was NaN */
2320     if (JSDOUBLE_IS_NaN(local))
2321     local = 0;
2322    
2323     local = date_msecFromDate(year,
2324     MonthFromTime(local),
2325     DateFromTime(local),
2326     HourFromTime(local),
2327     MinFromTime(local),
2328     SecFromTime(local),
2329     msFromTime(local));
2330    
2331     /* SetUTCTime also invalidates local time cache. */
2332     SetUTCTime(cx, obj, NULL, UTC(local));
2333     }
2334    
2335     JS_FRIEND_API(void)
2336     js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
2337     {
2338     jsdouble local;
2339    
2340     JS_ASSERT(month < 12);
2341    
2342     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2343     return;
2344    
2345     /* bail if date was NaN */
2346     if (JSDOUBLE_IS_NaN(local))
2347     return;
2348    
2349     local = date_msecFromDate(YearFromTime(local),
2350     month,
2351     DateFromTime(local),
2352     HourFromTime(local),
2353     MinFromTime(local),
2354     SecFromTime(local),
2355     msFromTime(local));
2356     SetUTCTime(cx, obj, NULL, UTC(local));
2357     }
2358    
2359     JS_FRIEND_API(void)
2360     js_DateSetDate(JSContext *cx, JSObject *obj, int date)
2361     {
2362     jsdouble local;
2363    
2364     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2365     return;
2366    
2367     if (JSDOUBLE_IS_NaN(local))
2368     return;
2369    
2370     local = date_msecFromDate(YearFromTime(local),
2371     MonthFromTime(local),
2372     date,
2373     HourFromTime(local),
2374     MinFromTime(local),
2375     SecFromTime(local),
2376     msFromTime(local));
2377     SetUTCTime(cx, obj, NULL, UTC(local));
2378     }
2379    
2380     JS_FRIEND_API(void)
2381     js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
2382     {
2383     jsdouble local;
2384    
2385     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2386     return;
2387    
2388     if (JSDOUBLE_IS_NaN(local))
2389     return;
2390     local = date_msecFromDate(YearFromTime(local),
2391     MonthFromTime(local),
2392     DateFromTime(local),
2393     hours,
2394     MinFromTime(local),
2395     SecFromTime(local),
2396     msFromTime(local));
2397     SetUTCTime(cx, obj, NULL, UTC(local));
2398     }
2399    
2400     JS_FRIEND_API(void)
2401     js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
2402     {
2403     jsdouble local;
2404    
2405     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2406     return;
2407    
2408     if (JSDOUBLE_IS_NaN(local))
2409     return;
2410     local = date_msecFromDate(YearFromTime(local),
2411     MonthFromTime(local),
2412     DateFromTime(local),
2413     HourFromTime(local),
2414     minutes,
2415     SecFromTime(local),
2416     msFromTime(local));
2417     SetUTCTime(cx, obj, NULL, UTC(local));
2418     }
2419    
2420     JS_FRIEND_API(void)
2421     js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
2422     {
2423     jsdouble local;
2424    
2425     if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
2426     return;
2427    
2428     if (JSDOUBLE_IS_NaN(local))
2429     return;
2430     local = date_msecFromDate(YearFromTime(local),
2431     MonthFromTime(local),
2432     DateFromTime(local),
2433     HourFromTime(local),
2434     MinFromTime(local),
2435     seconds,
2436     msFromTime(local));
2437     SetUTCTime(cx, obj, NULL, UTC(local));
2438     }
2439    
2440     JS_FRIEND_API(jsdouble)
2441     js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
2442     {
2443     jsdouble utctime;
2444     if (!GetUTCTime(cx, obj, NULL, &utctime))
2445     return 0;
2446     return utctime;
2447     }
2448 siliconforks 460
2449     #ifdef JS_THREADSAFE
2450     #include "prinrval.h"
2451    
2452     uint32
2453     js_IntervalNow()
2454     {
2455     return uint32(PR_IntervalToMilliseconds(PR_IntervalNow()));
2456     }
2457    
2458     #else /* !JS_THREADSAFE */
2459    
2460     uint32
2461     js_IntervalNow()
2462     {
2463     return uint32(PRMJ_Now() / PRMJ_USEC_PER_MSEC);
2464     }
2465     #endif

  ViewVC Help
Powered by ViewVC 1.1.24