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

Annotation of /trunk/js/jsdate.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 399 - (hide annotations)
Tue Dec 9 03:37:47 2008 UTC (11 years, 1 month ago) by siliconforks
File size: 70272 byte(s)
Use SpiderMonkey from Firefox 3.1b2.

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

  ViewVC Help
Powered by ViewVC 1.1.24