1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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.
39 * ***** END LICENSE BLOCK ***** */
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."
51 * Frederick Brooks, 'The Second-System Effect'.
63 #include "jsutil.h" /* Added by JSIFY */
74 * The JS 'Date' object is patterned after the Java 'Date' object.
79 * print(today.toLocaleString());
81 * weekDay = today.getDay();
84 * These Java (and ECMA-262) methods are supported:
87 * getDate (getUTCDate)
89 * getHours (getUTCHours)
90 * getMinutes (getUTCMinutes)
91 * getMonth (getUTCMonth)
92 * getSeconds (getUTCSeconds)
93 * getMilliseconds (getUTCMilliseconds)
97 * getFullYear (getUTCFullYear)
99 * setDate (setUTCDate)
100 * setHours (setUTCHours)
101 * setMinutes (setUTCMinutes)
102 * setMonth (setUTCMonth)
103 * setSeconds (setUTCSeconds)
104 * setMilliseconds (setUTCMilliseconds)
106 * setYear (setFullYear, setUTCFullYear)
107 * toGMTString (toUTCString)
112 * These Java methods are not supported
122 * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
123 * definition and reduce dependence on NSPR. NSPR is used to get the current
124 * time in milliseconds, the time zone offset, and the daylight savings time
125 * offset for a given time. NSPR is also used for Date.toLocaleString(), for
126 * locale-specific formatting, and to get a string representing the timezone.
127 * (Which turns out to be platform-dependent.)
130 * (I did some performance tests by timing how long it took to run what
131 * I had of the js ECMA conformance tests.)
133 * - look at saving results across multiple calls to supporting
134 * functions; the toString functions compute some of the same values
135 * multiple times. Although - I took a quick stab at this, and I lost
136 * rather than gained. (Fractionally.) Hard to tell what compilers/processors
137 * are doing these days.
139 * - look at tweaking function return types to return double instead
140 * of int; this seems to make things run slightly faster sometimes.
141 * (though it could be architecture-dependent.) It'd be good to see
142 * how this does on win32. (Tried it on irix.) Types could use a
143 * general going-over.
147 * Supporting functions - ECMA 15.9.1.*
150 #define HalfTimeDomain 8.64e15
151 #define HoursPerDay 24.0
152 #define MinutesPerDay (HoursPerDay * MinutesPerHour)
153 #define MinutesPerHour 60.0
154 #define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
155 #define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
156 #define SecondsPerMinute 60.0
158 #if defined(XP_WIN) || defined(XP_OS2)
159 /* Work around msvc double optimization bug by making these runtime values; if
160 * they're available at compile time, msvc optimizes division by them by
161 * computing the reciprocal and multiplying instead of dividing - this loses
162 * when the reciprocal isn't representable in a double.
164 static jsdouble msPerSecond
= 1000.0;
165 static jsdouble msPerDay
= SecondsPerDay
* 1000.0;
166 static jsdouble msPerHour
= SecondsPerHour
* 1000.0;
167 static jsdouble msPerMinute
= SecondsPerMinute
* 1000.0;
169 #define msPerDay (SecondsPerDay * msPerSecond)
170 #define msPerHour (SecondsPerHour * msPerSecond)
171 #define msPerMinute (SecondsPerMinute * msPerSecond)
172 #define msPerSecond 1000.0
175 #define Day(t) floor((t) / msPerDay)
178 TimeWithinDay(jsdouble t
)
181 result
= fmod(t
, msPerDay
);
187 #define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
190 /* math here has to be f.p, because we need
191 * floor((1968 - 1969) / 4) == -1
193 #define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
194 - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
195 #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
198 YearFromTime(jsdouble t
)
200 jsint y
= (jsint
) floor(t
/(msPerDay
*365.2425)) + 1970;
201 jsdouble t2
= (jsdouble
) TimeFromYear(y
);
206 if (t2
+ msPerDay
* DaysInYear(y
) <= t
)
212 #define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
214 #define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
217 * The following array contains the day of year for the first day of
218 * each month, where index 0 is January, and day 0 is January 1.
220 static jsdouble firstDayOfMonth
[2][12] = {
221 {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
222 {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
225 #define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
228 MonthFromTime(jsdouble t
)
231 jsint year
= YearFromTime(t
);
232 d
= DayWithinYear(t
, year
);
236 step
+= (InLeapYear(t
) ? 29 : 28);
239 if (d
< (step
+= 31))
241 if (d
< (step
+= 30))
243 if (d
< (step
+= 31))
245 if (d
< (step
+= 30))
247 if (d
< (step
+= 31))
249 if (d
< (step
+= 31))
251 if (d
< (step
+= 30))
253 if (d
< (step
+= 31))
255 if (d
< (step
+= 30))
261 DateFromTime(jsdouble t
)
264 jsint year
= YearFromTime(t
);
265 d
= DayWithinYear(t
, year
);
267 if (d
<= (next
= 30))
270 next
+= (InLeapYear(t
) ? 29 : 28);
274 if (d
<= (next
+= 31))
277 if (d
<= (next
+= 30))
280 if (d
<= (next
+= 31))
283 if (d
<= (next
+= 30))
286 if (d
<= (next
+= 31))
289 if (d
<= (next
+= 31))
292 if (d
<= (next
+= 30))
295 if (d
<= (next
+= 31))
298 if (d
<= (next
+= 30))
308 result
= (jsint
) Day(t
) + 4;
312 return (intN
) result
;
315 #define MakeTime(hour, min, sec, ms) \
316 ((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
319 MakeDay(jsdouble year
, jsdouble month
, jsdouble date
)
325 year
+= floor(month
/ 12);
327 month
= fmod(month
, 12.0);
331 leap
= (DaysInYear((jsint
) year
) == 366);
333 yearday
= floor(TimeFromYear(year
) / msPerDay
);
334 monthday
= DayFromMonth(month
, leap
);
336 return yearday
+ monthday
+ date
- 1;
339 #define MakeDate(day, time) ((day) * msPerDay + (time))
342 * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
344 * yearStartingWith[0][i] is an example non-leap year where
345 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
347 * yearStartingWith[1][i] is an example leap year where
348 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
350 static jsint yearStartingWith
[2][7] = {
351 {1978, 1973, 1974, 1975, 1981, 1971, 1977},
352 {1984, 1996, 1980, 1992, 1976, 1988, 1972}
356 * Find a year for which any given date will fall on the same weekday.
358 * This function should be used with caution when used other than
359 * for determining DST; it hasn't been proven not to produce an
360 * incorrect year for times near year boundaries.
363 EquivalentYearForDST(jsint year
)
368 day
= (jsint
) DayFromYear(year
) + 4;
373 isLeapYear
= (DaysInYear(year
) == 366);
375 return yearStartingWith
[isLeapYear
][day
];
378 /* LocalTZA gets set by js_InitDateClass() */
379 static jsdouble LocalTZA
;
382 DaylightSavingTA(jsdouble t
)
390 if (JSDOUBLE_IS_NaN(t
))
394 * If earlier than 1970 or after 2038, potentially beyond the ken of
395 * many OSes, map it to an equivalent year before asking.
397 if (t
< 0.0 || t
> 2145916800000.0) {
401 year
= EquivalentYearForDST(YearFromTime(t
));
402 day
= MakeDay(year
, MonthFromTime(t
), DateFromTime(t
));
403 t
= MakeDate(day
, TimeWithinDay(t
));
406 /* put our t in an LL, and map it to usec for prtime */
408 JSLL_I2L(ms2us
, PRMJ_USEC_PER_MSEC
);
409 JSLL_MUL(PR_t
, PR_t
, ms2us
);
411 offset
= PRMJ_DSTOffset(PR_t
);
413 JSLL_DIV(offset
, offset
, ms2us
);
414 JSLL_L2D(result
, offset
);
419 #define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay)
421 #define LocalTime(t) ((t) + AdjustTime(t))
426 return t
- AdjustTime(t
- LocalTZA
);
430 HourFromTime(jsdouble t
)
432 intN result
= (intN
) fmod(floor(t
/msPerHour
), HoursPerDay
);
434 result
+= (intN
)HoursPerDay
;
439 MinFromTime(jsdouble t
)
441 intN result
= (intN
) fmod(floor(t
/ msPerMinute
), MinutesPerHour
);
443 result
+= (intN
)MinutesPerHour
;
448 SecFromTime(jsdouble t
)
450 intN result
= (intN
) fmod(floor(t
/ msPerSecond
), SecondsPerMinute
);
452 result
+= (intN
)SecondsPerMinute
;
457 msFromTime(jsdouble t
)
459 intN result
= (intN
) fmod(t
, msPerSecond
);
461 result
+= (intN
)msPerSecond
;
465 #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
466 && !((d < 0 ? -d : d) > HalfTimeDomain)) \
467 ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
470 * end of ECMA 'support' functions
474 * Other Support routines and definitions
478 * We use the first reseved slot to store UTC time, and the second for caching
479 * the local time. The initial value of the cache entry is NaN.
481 #define UTC_TIME_SLOT 0
482 #define LOCAL_TIME_SLOT 1
484 JSClass js_DateClass
= {
486 JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date
),
487 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
488 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
,
489 JSCLASS_NO_OPTIONAL_MEMBERS
492 /* for use by date_parse */
494 static const char* wtb
[] = {
496 "monday", "tuesday", "wednesday", "thursday", "friday",
497 "saturday", "sunday",
498 "january", "february", "march", "april", "may", "june",
499 "july", "august", "september", "october", "november", "december",
505 /* time zone table needs to be expanded */
509 -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
510 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
511 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
512 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
513 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
514 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
515 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
518 /* helper for date_parse */
520 date_regionMatches(const char* s1
, int s1off
, const jschar
* s2
, int s2off
,
521 int count
, int ignoreCase
)
523 JSBool result
= JS_FALSE
;
524 /* return true if matches, otherwise, false */
526 while (count
> 0 && s1
[s1off
] && s2
[s2off
]) {
528 if (JS_TOLOWER((jschar
)s1
[s1off
]) != JS_TOLOWER(s2
[s2off
])) {
532 if ((jschar
)s1
[s1off
] != s2
[s2off
]) {
548 /* find UTC time from given date... no 1900 correction! */
550 date_msecFromDate(jsdouble year
, jsdouble mon
, jsdouble mday
, jsdouble hour
,
551 jsdouble min
, jsdouble sec
, jsdouble msec
)
557 day
= MakeDay(year
, mon
, mday
);
558 msec_time
= MakeTime(hour
, min
, sec
, msec
);
559 result
= MakeDate(day
, msec_time
);
563 /* compute the time in msec (unclipped) from the given args */
567 date_msecFromArgs(JSContext
*cx
, uintN argc
, jsval
*argv
, jsdouble
*rval
)
570 jsdouble array
[MAXARGS
];
574 for (loop
= 0; loop
< MAXARGS
; loop
++) {
576 if (!js_ValueToNumber(cx
, argv
[loop
], &d
))
578 /* return NaN if any arg is not finite */
579 if (!JSDOUBLE_IS_FINITE(d
)) {
580 *rval
= *cx
->runtime
->jsNaN
;
583 array
[loop
] = js_DoubleToInteger(d
);
586 array
[loop
] = 1; /* Default the date argument to 1. */
593 /* adjust 2-digit years into the 20th century */
594 if (array
[0] >= 0 && array
[0] <= 99)
597 msec_time
= date_msecFromDate(array
[0], array
[1], array
[2],
598 array
[3], array
[4], array
[5], array
[6]);
605 * See ECMA 15.9.4.[3-10];
608 date_UTC(JSContext
*cx
, uintN argc
, jsval
*vp
)
612 if (!date_msecFromArgs(cx
, argc
, vp
+ 2, &msec_time
))
615 msec_time
= TIMECLIP(msec_time
);
617 return js_NewNumberValue(cx
, msec_time
, vp
);
621 date_parseString(JSString
*str
, jsdouble
*result
)
638 JSBool seenplusminus
= JS_FALSE
;
640 JSBool seenmonthname
= JS_FALSE
;
642 JSSTRING_CHARS_AND_LENGTH(str
, s
, limit
);
648 if (c
<= ' ' || c
== ',' || c
== '-') {
649 if (c
== '-' && '0' <= s
[i
] && s
[i
] <= '9') {
654 if (c
== '(') { /* comments) */
659 if (c
== '(') depth
++;
666 if ('0' <= c
&& c
<= '9') {
668 while (i
< limit
&& '0' <= (c
= s
[i
]) && c
<= '9') {
669 n
= n
* 10 + c
- '0';
673 /* allow TZA before the year, so
674 * 'Wed Nov 05 21:49:11 GMT-0800 1997'
677 /* uses of seenplusminus allow : in TZA, so Java
678 * no-timezone style of GMT+4:30 works
681 if ((prevc
== '+' || prevc
== '-')/* && year>=0 */) {
682 /* make ':' case below change tzoffset */
683 seenplusminus
= JS_TRUE
;
687 n
= n
* 60; /* EG. "GMT-3" */
689 n
= n
% 100 + n
/ 100 * 60; /* eg "GMT-0430" */
690 if (prevc
== '+') /* plus means east of GMT */
692 if (tzoffset
!= 0 && tzoffset
!= -1)
695 } else if (prevc
== '/' && mon
>= 0 && mday
>= 0 && year
< 0) {
696 if (c
<= ' ' || c
== ',' || c
== '/' || i
>= limit
)
700 } else if (c
== ':') {
707 } else if (c
== '/') {
708 /* until it is determined that mon is the actual
709 month, keep it as 1-based rather than 0-based */
716 } else if (i
< limit
&& c
!= ',' && c
> ' ' && c
!= '-' && c
!= '(') {
718 } else if (seenplusminus
&& n
< 60) { /* handle GMT-3:30 */
723 } else if (hour
>= 0 && min
< 0) {
725 } else if (prevc
== ':' && min
>= 0 && sec
< 0) {
727 } else if (mon
< 0) {
729 } else if (mon
>= 0 && mday
< 0) {
731 } else if (mon
>= 0 && mday
>= 0 && year
< 0) {
737 } else if (c
== '/' || c
== ':' || c
== '+' || c
== '-') {
744 if (!(('A' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')))
750 for (k
= (sizeof(wtb
)/sizeof(char*)); --k
>= 0;)
751 if (date_regionMatches(wtb
[k
], 0, s
, st
, i
-st
, 1)) {
756 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
757 * 12:30, instead of blindly adding 12 if PM.
759 JS_ASSERT(action
== -1 || action
== -2);
760 if (hour
> 12 || hour
< 0) {
763 if (action
== -1 && hour
== 12) { /* am */
765 } else if (action
== -2 && hour
!= 12) { /* pm */
769 } else if (action
<= 13) { /* month! */
770 /* Adjust mon to be 1-based until the final values
771 for mon, mday and year are adjusted below */
775 seenmonthname
= JS_TRUE
;
776 temp
= /*byte*/ (action
- 2) + 1;
780 } else if (mday
< 0) {
783 } else if (year
< 0) {
790 tzoffset
= action
- 10000;
800 if (year
< 0 || mon
< 0 || mday
< 0)
803 Case 1. The input string contains an English month name.
804 The form of the string can be month f l, or f month l, or
805 f l month which each evaluate to the same date.
806 If f and l are both greater than or equal to 70, or
807 both less than 70, the date is invalid.
808 The year is taken to be the greater of the values f, l.
809 If the year is greater than or equal to 70 and less than 100,
810 it is considered to be the number of years after 1900.
811 Case 2. The input string is of the form "f/m/l" where f, m and l are
812 integers, e.g. 7/16/45.
813 Adjust the mon, mday and year values to achieve 100% MSIE
815 a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
816 i. If year < 100, it is the number of years after 1900
817 ii. If year >= 100, it is the number of years after 0.
819 i. If m < 70, f/m/l is interpreted as
820 year/month/day where year is the number of years after
822 ii. If m >= 70, the date is invalid.
824 i. If m < 70, f/m/l is interpreted as
825 year/month/day where year is the number of years after 0.
826 ii. If m >= 70, the date is invalid.
829 if ((mday
>= 70 && year
>= 70) || (mday
< 70 && year
< 70)) {
837 if (year
>= 70 && year
< 100) {
840 } else if (mon
< 70) { /* (a) month/day/year */
844 } else if (mon
< 100) { /* (b) year/month/day */
853 } else { /* (c) year/month/day */
863 mon
-= 1; /* convert month to 0-based */
870 if (tzoffset
== -1) { /* no time zone specified, have to use local */
872 msec_time
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
874 *result
= UTC(msec_time
);
878 msec
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
879 msec
+= tzoffset
* msPerMinute
;
890 date_parse(JSContext
*cx
, uintN argc
, jsval
*vp
)
895 str
= js_ValueToString(cx
, vp
[2]);
898 if (!date_parseString(str
, &result
)) {
899 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
903 result
= TIMECLIP(result
);
904 return js_NewNumberValue(cx
, result
, vp
);
908 date_now(JSContext
*cx
, uintN argc
, jsval
*vp
)
914 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
915 JSLL_DIV(ms
, us
, us2ms
);
916 JSLL_L2D(msec_time
, ms
);
918 return js_NewDoubleValue(cx
, msec_time
, vp
);
922 * Get UTC time from the date object. Returns false if the object is not
926 GetUTCTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
930 if (vp
&& !JS_InstanceOf(cx
, obj
, &js_DateClass
, vp
+ 2))
932 if (!JS_GetReservedSlot(cx
, obj
, UTC_TIME_SLOT
, &v
))
935 *dp
= *JSVAL_TO_DOUBLE(v
);
940 * Set UTC time slot with a pointer pointing to a jsdouble. This function is
941 * used only for setting UTC time to some predefined values, such as NaN.
943 * It also invalidates cached local time.
946 SetUTCTimePtr(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
948 if (vp
&& !JS_InstanceOf(cx
, obj
, &js_DateClass
, vp
+ 2))
951 /* Invalidate local time cache. */
952 if (!JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
953 DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
))) {
957 return JS_SetReservedSlot(cx
, obj
, UTC_TIME_SLOT
, DOUBLE_TO_JSVAL(dp
));
961 * Set UTC time to a given time.
964 SetUTCTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble t
)
966 jsdouble
*dp
= js_NewDouble(cx
, t
, 0);
969 return SetUTCTimePtr(cx
, obj
, vp
, dp
);
973 * Get the local time, cache it if necessary. If UTC time is not finite
974 * (e.g., NaN), the local time slot is set to the UTC time without conversion.
977 GetLocalTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
983 if (!JS_GetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
, &v
))
986 result
= *JSVAL_TO_DOUBLE(v
);
988 if (JSDOUBLE_IS_NaN(result
)) {
989 if (!GetUTCTime(cx
, obj
, vp
, &result
))
992 /* if result is NaN, it couldn't be finite. */
993 if (JSDOUBLE_IS_FINITE(result
))
994 result
= LocalTime(result
);
996 cached
= js_NewDouble(cx
, result
, 0);
1000 if (!JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
1001 DOUBLE_TO_JSVAL(cached
))) {
1011 * See ECMA 15.9.5.4 thru 15.9.5.23
1014 date_getTime(JSContext
*cx
, uintN argc
, jsval
*vp
)
1018 return GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
) &&
1019 js_NewNumberValue(cx
, result
, vp
);
1023 GetYear(JSContext
*cx
, JSBool fullyear
, jsval
*vp
)
1027 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1030 if (JSDOUBLE_IS_FINITE(result
)) {
1031 result
= YearFromTime(result
);
1033 /* Follow ECMA-262 to the letter, contrary to IE JScript. */
1038 return js_NewNumberValue(cx
, result
, vp
);
1042 date_getYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1044 return GetYear(cx
, JS_FALSE
, vp
);
1048 date_getFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1050 return GetYear(cx
, JS_TRUE
, vp
);
1054 date_getUTCFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1058 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1061 if (JSDOUBLE_IS_FINITE(result
))
1062 result
= YearFromTime(result
);
1064 return js_NewNumberValue(cx
, result
, vp
);
1068 date_getMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1072 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1075 if (JSDOUBLE_IS_FINITE(result
))
1076 result
= MonthFromTime(result
);
1078 return js_NewNumberValue(cx
, result
, vp
);
1082 date_getUTCMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1086 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1089 if (JSDOUBLE_IS_FINITE(result
))
1090 result
= MonthFromTime(result
);
1092 return js_NewNumberValue(cx
, result
, vp
);
1096 date_getDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1100 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1103 if (JSDOUBLE_IS_FINITE(result
))
1104 result
= DateFromTime(result
);
1106 return js_NewNumberValue(cx
, result
, vp
);
1110 date_getUTCDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1114 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1117 if (JSDOUBLE_IS_FINITE(result
))
1118 result
= DateFromTime(result
);
1120 return js_NewNumberValue(cx
, result
, vp
);
1124 date_getDay(JSContext
*cx
, uintN argc
, jsval
*vp
)
1128 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1131 if (JSDOUBLE_IS_FINITE(result
))
1132 result
= WeekDay(result
);
1134 return js_NewNumberValue(cx
, result
, vp
);
1138 date_getUTCDay(JSContext
*cx
, uintN argc
, jsval
*vp
)
1142 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1145 if (JSDOUBLE_IS_FINITE(result
))
1146 result
= WeekDay(result
);
1148 return js_NewNumberValue(cx
, result
, vp
);
1152 date_getHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1156 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1159 if (JSDOUBLE_IS_FINITE(result
))
1160 result
= HourFromTime(result
);
1162 return js_NewNumberValue(cx
, result
, vp
);
1166 date_getUTCHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1170 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1173 if (JSDOUBLE_IS_FINITE(result
))
1174 result
= HourFromTime(result
);
1176 return js_NewNumberValue(cx
, result
, vp
);
1180 date_getMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1184 if (!GetLocalTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1187 if (JSDOUBLE_IS_FINITE(result
))
1188 result
= MinFromTime(result
);
1190 return js_NewNumberValue(cx
, result
, vp
);
1194 date_getUTCMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1198 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1201 if (JSDOUBLE_IS_FINITE(result
))
1202 result
= MinFromTime(result
);
1204 return js_NewNumberValue(cx
, result
, vp
);
1207 /* Date.getSeconds is mapped to getUTCSeconds */
1210 date_getUTCSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1214 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1217 if (JSDOUBLE_IS_FINITE(result
))
1218 result
= SecFromTime(result
);
1220 return js_NewNumberValue(cx
, result
, vp
);
1223 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
1226 date_getUTCMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1230 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &result
))
1233 if (JSDOUBLE_IS_FINITE(result
))
1234 result
= msFromTime(result
);
1236 return js_NewNumberValue(cx
, result
, vp
);
1240 date_getTimezoneOffset(JSContext
*cx
, uintN argc
, jsval
*vp
)
1243 jsdouble utctime
, localtime
, result
;
1245 obj
= JSVAL_TO_OBJECT(vp
[1]);
1246 if (!GetUTCTime(cx
, obj
, vp
, &utctime
))
1248 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
))
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.
1256 result
= (utctime
- localtime
) / msPerMinute
;
1257 return js_NewNumberValue(cx
, result
, vp
);
1261 date_setTime(JSContext
*cx
, uintN argc
, jsval
*vp
)
1265 if (!js_ValueToNumber(cx
, vp
[2], &result
))
1268 result
= TIMECLIP(result
);
1270 if (!SetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, result
))
1273 return js_NewNumberValue(cx
, result
, vp
);
1277 date_makeTime(JSContext
*cx
, uintN maxargs
, JSBool local
, uintN argc
, jsval
*vp
)
1282 jsdouble args
[4], *argp
, *stop
;
1283 jsdouble hour
, min
, sec
, msec
;
1284 jsdouble lorutime
; /* Local or UTC version of *date */
1289 obj
= JSVAL_TO_OBJECT(vp
[1]);
1290 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1293 /* just return NaN if the date is already NaN */
1294 if (!JSDOUBLE_IS_FINITE(result
))
1295 return js_NewNumberValue(cx
, result
, vp
);
1298 * Satisfy the ECMA rule that if a function is called with
1299 * fewer arguments than the specified formal arguments, the
1300 * remaining arguments are set to undefined. Seems like all
1301 * the Date.setWhatever functions in ECMA are only varargs
1302 * beyond the first argument; this should be set to undefined
1303 * if it's not given. This means that "d = new Date();
1304 * d.setMilliseconds()" returns NaN. Blech.
1307 argc
= 1; /* should be safe, because length of all setters is 1 */
1308 else if (argc
> maxargs
)
1309 argc
= maxargs
; /* clamp argc */
1310 JS_ASSERT(1 <= argc
&& argc
<= 4);
1313 for (i
= 0; i
< argc
; i
++) {
1314 if (!js_ValueToNumber(cx
, argv
[i
], &args
[i
]))
1316 if (!JSDOUBLE_IS_FINITE(args
[i
])) {
1317 if (!SetUTCTimePtr(cx
, obj
, NULL
, cx
->runtime
->jsNaN
))
1319 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
1322 args
[i
] = js_DoubleToInteger(args
[i
]);
1326 lorutime
= LocalTime(result
);
1332 if (maxargs
>= 4 && argp
< stop
)
1335 hour
= HourFromTime(lorutime
);
1337 if (maxargs
>= 3 && argp
< stop
)
1340 min
= MinFromTime(lorutime
);
1342 if (maxargs
>= 2 && argp
< stop
)
1345 sec
= SecFromTime(lorutime
);
1347 if (maxargs
>= 1 && argp
< stop
)
1350 msec
= msFromTime(lorutime
);
1352 msec_time
= MakeTime(hour
, min
, sec
, msec
);
1353 result
= MakeDate(Day(lorutime
), msec_time
);
1355 /* fprintf(stderr, "%f\n", result); */
1358 result
= UTC(result
);
1360 /* fprintf(stderr, "%f\n", result); */
1362 result
= TIMECLIP(result
);
1363 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1366 return js_NewNumberValue(cx
, result
, vp
);
1370 date_setMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1372 return date_makeTime(cx
, 1, JS_TRUE
, argc
, vp
);
1376 date_setUTCMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1378 return date_makeTime(cx
, 1, JS_FALSE
, argc
, vp
);
1382 date_setSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1384 return date_makeTime(cx
, 2, JS_TRUE
, argc
, vp
);
1388 date_setUTCSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1390 return date_makeTime(cx
, 2, JS_FALSE
, argc
, vp
);
1394 date_setMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1396 return date_makeTime(cx
, 3, JS_TRUE
, argc
, vp
);
1400 date_setUTCMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1402 return date_makeTime(cx
, 3, JS_FALSE
, argc
, vp
);
1406 date_setHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1408 return date_makeTime(cx
, 4, JS_TRUE
, argc
, vp
);
1412 date_setUTCHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1414 return date_makeTime(cx
, 4, JS_FALSE
, argc
, vp
);
1418 date_makeDate(JSContext
*cx
, uintN maxargs
, JSBool local
, uintN argc
, jsval
*vp
)
1423 jsdouble lorutime
; /* local or UTC version of *date */
1424 jsdouble args
[3], *argp
, *stop
;
1425 jsdouble year
, month
, day
;
1428 obj
= JSVAL_TO_OBJECT(vp
[1]);
1429 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1432 /* see complaint about ECMA in date_MakeTime */
1434 argc
= 1; /* should be safe, because length of all setters is 1 */
1435 else if (argc
> maxargs
)
1436 argc
= maxargs
; /* clamp argc */
1437 JS_ASSERT(1 <= argc
&& argc
<= 3);
1440 for (i
= 0; i
< argc
; i
++) {
1441 if (!js_ValueToNumber(cx
, argv
[i
], &args
[i
]))
1443 if (!JSDOUBLE_IS_FINITE(args
[i
])) {
1444 if (!SetUTCTimePtr(cx
, obj
, NULL
, cx
->runtime
->jsNaN
))
1446 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
1449 args
[i
] = js_DoubleToInteger(args
[i
]);
1452 /* return NaN if date is NaN and we're not setting the year,
1453 * If we are, use 0 as the time. */
1454 if (!(JSDOUBLE_IS_FINITE(result
))) {
1456 return js_NewNumberValue(cx
, result
, vp
);
1459 lorutime
= local
? LocalTime(result
) : result
;
1464 if (maxargs
>= 3 && argp
< stop
)
1467 year
= YearFromTime(lorutime
);
1469 if (maxargs
>= 2 && argp
< stop
)
1472 month
= MonthFromTime(lorutime
);
1474 if (maxargs
>= 1 && argp
< stop
)
1477 day
= DateFromTime(lorutime
);
1479 day
= MakeDay(year
, month
, day
); /* day within year */
1480 result
= MakeDate(day
, TimeWithinDay(lorutime
));
1483 result
= UTC(result
);
1485 result
= TIMECLIP(result
);
1486 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1489 return js_NewNumberValue(cx
, result
, vp
);
1493 date_setDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1495 return date_makeDate(cx
, 1, JS_TRUE
, argc
, vp
);
1499 date_setUTCDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1501 return date_makeDate(cx
, 1, JS_FALSE
, argc
, vp
);
1505 date_setMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1507 return date_makeDate(cx
, 2, JS_TRUE
, argc
, vp
);
1511 date_setUTCMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1513 return date_makeDate(cx
, 2, JS_FALSE
, argc
, vp
);
1517 date_setFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1519 return date_makeDate(cx
, 3, JS_TRUE
, argc
, vp
);
1523 date_setUTCFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1525 return date_makeDate(cx
, 3, JS_FALSE
, argc
, vp
);
1529 date_setYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1537 obj
= JSVAL_TO_OBJECT(vp
[1]);
1538 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1541 if (!js_ValueToNumber(cx
, vp
[2], &year
))
1543 if (!JSDOUBLE_IS_FINITE(year
)) {
1544 if (!SetUTCTimePtr(cx
, obj
, NULL
, cx
->runtime
->jsNaN
))
1546 return js_NewNumberValue(cx
, *cx
->runtime
->jsNaN
, vp
);
1549 year
= js_DoubleToInteger(year
);
1551 if (!JSDOUBLE_IS_FINITE(result
)) {
1554 t
= LocalTime(result
);
1557 if (year
>= 0 && year
<= 99)
1560 day
= MakeDay(year
, MonthFromTime(t
), DateFromTime(t
));
1561 result
= MakeDate(day
, TimeWithinDay(t
));
1562 result
= UTC(result
);
1564 result
= TIMECLIP(result
);
1565 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1568 return js_NewNumberValue(cx
, result
, vp
);
1571 /* constants for toString, toUTCString */
1572 static char js_NaN_date_str
[] = "Invalid Date";
1573 static const char* days
[] =
1575 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1577 static const char* months
[] =
1579 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1583 date_toGMTString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1589 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &utctime
))
1592 if (!JSDOUBLE_IS_FINITE(utctime
)) {
1593 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1595 /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1596 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1598 JS_snprintf(buf
, sizeof buf
, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
1599 days
[WeekDay(utctime
)],
1600 DateFromTime(utctime
),
1601 months
[MonthFromTime(utctime
)],
1602 YearFromTime(utctime
),
1603 HourFromTime(utctime
),
1604 MinFromTime(utctime
),
1605 SecFromTime(utctime
));
1607 str
= JS_NewStringCopyZ(cx
, buf
);
1610 *vp
= STRING_TO_JSVAL(str
);
1614 /* for Date.toLocaleString; interface to PRMJTime date struct.
1615 * If findEquivalent is true, then try to map the year to an equivalent year
1619 new_explode(jsdouble timeval
, PRMJTime
*split
, JSBool findEquivalent
)
1621 jsint year
= YearFromTime(timeval
);
1624 /* If the year doesn't fit in a PRMJTime, find something to do about it. */
1625 if (year
> 32767 || year
< -32768) {
1626 if (findEquivalent
) {
1627 /* We're really just trying to get a timezone string; map the year
1628 * to some equivalent year in the range 0 to 2800. Borrowed from
1632 #define CYCLE_YEARS 2800L
1633 cycles
= (year
>= 0) ? year
/ CYCLE_YEARS
1634 : -1 - (-1 - year
) / CYCLE_YEARS
;
1635 adjustedYear
= (int16
)(year
- cycles
* CYCLE_YEARS
);
1637 /* Clamp it to the nearest representable year. */
1638 adjustedYear
= (int16
)((year
> 0) ? 32767 : - 32768);
1641 adjustedYear
= (int16
)year
;
1644 split
->tm_usec
= (int32
) msFromTime(timeval
) * 1000;
1645 split
->tm_sec
= (int8
) SecFromTime(timeval
);
1646 split
->tm_min
= (int8
) MinFromTime(timeval
);
1647 split
->tm_hour
= (int8
) HourFromTime(timeval
);
1648 split
->tm_mday
= (int8
) DateFromTime(timeval
);
1649 split
->tm_mon
= (int8
) MonthFromTime(timeval
);
1650 split
->tm_wday
= (int8
) WeekDay(timeval
);
1651 split
->tm_year
= (int16
) adjustedYear
;
1652 split
->tm_yday
= (int16
) DayWithinYear(timeval
, year
);
1654 /* not sure how this affects things, but it doesn't seem
1656 split
->tm_isdst
= (DaylightSavingTA(timeval
) != 0);
1659 typedef enum formatspec
{
1660 FORMATSPEC_FULL
, FORMATSPEC_DATE
, FORMATSPEC_TIME
1663 /* helper function */
1665 date_format(JSContext
*cx
, jsdouble date
, formatspec format
, jsval
*rval
)
1674 if (!JSDOUBLE_IS_FINITE(date
)) {
1675 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1677 jsdouble local
= LocalTime(date
);
1679 /* offset from GMT in minutes. The offset includes daylight savings,
1681 jsint minutes
= (jsint
) floor(AdjustTime(date
) / msPerMinute
);
1683 /* map 510 minutes to 0830 hours */
1684 intN offset
= (minutes
/ 60) * 100 + minutes
% 60;
1686 /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
1687 * printed as 'GMT-0800' rather than as 'PST' to avoid
1688 * operating-system dependence on strftime (which
1689 * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
1690 * PST as 'Pacific Standard Time.' This way we always know
1691 * what we're getting, and can parse it if we produce it.
1692 * The OS TZA string is included as a comment.
1695 /* get a timezone string from the OS to include as a
1697 new_explode(date
, &split
, JS_TRUE
);
1698 if (PRMJ_FormatTime(tzbuf
, sizeof tzbuf
, "(%Z)", &split
) != 0) {
1700 /* Decide whether to use the resulting timezone string.
1702 * Reject it if it contains any non-ASCII, non-alphanumeric
1703 * characters. It's then likely in some other character
1704 * encoding, and we probably won't display it correctly.
1707 tzlen
= strlen(tzbuf
);
1711 for (i
= 0; i
< tzlen
; i
++) {
1712 jschar c
= tzbuf
[i
];
1714 !(isalpha(c
) || isdigit(c
) ||
1715 c
== ' ' || c
== '(' || c
== ')')) {
1721 /* Also reject it if it's not parenthesized or if it's '()'. */
1722 if (tzbuf
[0] != '(' || tzbuf
[1] == ')')
1728 case FORMATSPEC_FULL
:
1730 * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1731 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1733 /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
1734 JS_snprintf(buf
, sizeof buf
,
1735 "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
1736 days
[WeekDay(local
)],
1737 months
[MonthFromTime(local
)],
1738 DateFromTime(local
),
1739 YearFromTime(local
),
1740 HourFromTime(local
),
1745 usetz
? tzbuf
: "");
1747 case FORMATSPEC_DATE
:
1748 /* Tue Oct 31 2000 */
1749 JS_snprintf(buf
, sizeof buf
,
1751 days
[WeekDay(local
)],
1752 months
[MonthFromTime(local
)],
1753 DateFromTime(local
),
1754 YearFromTime(local
));
1756 case FORMATSPEC_TIME
:
1757 /* 09:41:40 GMT-0800 (PST) */
1758 JS_snprintf(buf
, sizeof buf
,
1759 "%.2d:%.2d:%.2d GMT%+.4d%s%s",
1760 HourFromTime(local
),
1765 usetz
? tzbuf
: "");
1770 str
= JS_NewStringCopyZ(cx
, buf
);
1773 *rval
= STRING_TO_JSVAL(str
);
1778 date_toLocaleHelper(JSContext
*cx
, const char *format
, jsval
*vp
)
1786 obj
= JSVAL_TO_OBJECT(vp
[1]);
1787 if (!GetUTCTime(cx
, obj
, vp
, &utctime
))
1790 if (!JSDOUBLE_IS_FINITE(utctime
)) {
1791 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1794 jsdouble local
= LocalTime(utctime
);
1795 new_explode(local
, &split
, JS_FALSE
);
1797 /* let PRMJTime format it. */
1798 result_len
= PRMJ_FormatTime(buf
, sizeof buf
, format
, &split
);
1800 /* If it failed, default to toString. */
1801 if (result_len
== 0)
1802 return date_format(cx
, utctime
, FORMATSPEC_FULL
, vp
);
1804 /* Hacked check against undesired 2-digit year 00/00/00 form. */
1805 if (strcmp(format
, "%x") == 0 && result_len
>= 6 &&
1806 /* Format %x means use OS settings, which may have 2-digit yr, so
1807 hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
1808 !isdigit(buf
[result_len
- 3]) &&
1809 isdigit(buf
[result_len
- 2]) && isdigit(buf
[result_len
- 1]) &&
1810 /* ...but not if starts with 4-digit year, like 2022/3/11. */
1811 !(isdigit(buf
[0]) && isdigit(buf
[1]) &&
1812 isdigit(buf
[2]) && isdigit(buf
[3]))) {
1813 JS_snprintf(buf
+ (result_len
- 2), (sizeof buf
) - (result_len
- 2),
1814 "%d", js_DateGetYear(cx
, obj
));
1819 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUnicode
)
1820 return cx
->localeCallbacks
->localeToUnicode(cx
, buf
, vp
);
1822 str
= JS_NewStringCopyZ(cx
, buf
);
1825 *vp
= STRING_TO_JSVAL(str
);
1830 date_toLocaleString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1832 /* Use '%#c' for windows, because '%c' is
1833 * backward-compatible and non-y2k with msvc; '%#c' requests that a
1834 * full year be used in the result string.
1836 return date_toLocaleHelper(cx
,
1837 #if defined(_WIN32) && !defined(__MWERKS__)
1846 date_toLocaleDateString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1848 /* Use '%#x' for windows, because '%x' is
1849 * backward-compatible and non-y2k with msvc; '%#x' requests that a
1850 * full year be used in the result string.
1852 return date_toLocaleHelper(cx
,
1853 #if defined(_WIN32) && !defined(__MWERKS__)
1862 date_toLocaleTimeString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1864 return date_toLocaleHelper(cx
, "%X", vp
);
1868 date_toLocaleFormat(JSContext
*cx
, uintN argc
, jsval
*vp
)
1871 const char *fmtbytes
;
1874 return date_toLocaleString(cx
, argc
, vp
);
1876 fmt
= js_ValueToString(cx
, vp
[2]);
1879 vp
[2] = STRING_TO_JSVAL(fmt
);
1880 fmtbytes
= js_GetStringBytes(cx
, fmt
);
1884 return date_toLocaleHelper(cx
, fmtbytes
, vp
);
1888 date_toTimeString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1892 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &utctime
))
1894 return date_format(cx
, utctime
, FORMATSPEC_TIME
, vp
);
1898 date_toDateString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1902 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &utctime
))
1904 return date_format(cx
, utctime
, FORMATSPEC_DATE
, vp
);
1912 date_toSource(JSContext
*cx
, uintN argc
, jsval
*vp
)
1915 char buf
[DTOSTR_STANDARD_BUFFER_SIZE
], *numStr
, *bytes
;
1918 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &utctime
))
1921 numStr
= JS_dtostr(buf
, sizeof buf
, DTOSTR_STANDARD
, 0, utctime
);
1923 JS_ReportOutOfMemory(cx
);
1927 bytes
= JS_smprintf("(new %s(%s))", js_Date_str
, numStr
);
1929 JS_ReportOutOfMemory(cx
);
1933 str
= JS_NewString(cx
, bytes
, strlen(bytes
));
1938 *vp
= STRING_TO_JSVAL(str
);
1944 date_toString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1948 if (!GetUTCTime(cx
, JSVAL_TO_OBJECT(vp
[1]), vp
, &utctime
))
1950 return date_format(cx
, utctime
, FORMATSPEC_FULL
, vp
);
1954 date_valueOf(JSContext
*cx
, uintN argc
, jsval
*vp
)
1956 JSString
*str
, *str2
;
1958 /* It is an error to call date_valueOf on a non-date object, but we don't
1959 * need to check for that explicitly here because every path calls
1960 * GetUTCTime, which does the check.
1963 /* If called directly with no arguments, convert to a time number. */
1965 return date_getTime(cx
, argc
, vp
);
1967 /* Convert to number only if the hint was given, otherwise favor string. */
1968 str
= js_ValueToString(cx
, vp
[2]);
1971 str2
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_NUMBER
]);
1972 if (js_EqualStrings(str
, str2
))
1973 return date_getTime(cx
, argc
, vp
);
1974 return date_toString(cx
, argc
, vp
);
1979 * creation and destruction
1982 static JSFunctionSpec date_static_methods
[] = {
1983 JS_FN("UTC", date_UTC
, 2,MAXARGS
,0,0),
1984 JS_FN("parse", date_parse
, 1,1,0,0),
1985 JS_FN("now", date_now
, 0,0,0,0),
1989 static JSFunctionSpec date_methods
[] = {
1990 JS_FN("getTime", date_getTime
, 0,0,0,0),
1991 JS_FN("getTimezoneOffset", date_getTimezoneOffset
, 0,0,0,0),
1992 JS_FN("getYear", date_getYear
, 0,0,0,0),
1993 JS_FN("getFullYear", date_getFullYear
, 0,0,0,0),
1994 JS_FN("getUTCFullYear", date_getUTCFullYear
, 0,0,0,0),
1995 JS_FN("getMonth", date_getMonth
, 0,0,0,0),
1996 JS_FN("getUTCMonth", date_getUTCMonth
, 0,0,0,0),
1997 JS_FN("getDate", date_getDate
, 0,0,0,0),
1998 JS_FN("getUTCDate", date_getUTCDate
, 0,0,0,0),
1999 JS_FN("getDay", date_getDay
, 0,0,0,0),
2000 JS_FN("getUTCDay", date_getUTCDay
, 0,0,0,0),
2001 JS_FN("getHours", date_getHours
, 0,0,0,0),
2002 JS_FN("getUTCHours", date_getUTCHours
, 0,0,0,0),
2003 JS_FN("getMinutes", date_getMinutes
, 0,0,0,0),
2004 JS_FN("getUTCMinutes", date_getUTCMinutes
, 0,0,0,0),
2005 JS_FN("getSeconds", date_getUTCSeconds
, 0,0,0,0),
2006 JS_FN("getUTCSeconds", date_getUTCSeconds
, 0,0,0,0),
2007 JS_FN("getMilliseconds", date_getUTCMilliseconds
, 0,0,0,0),
2008 JS_FN("getUTCMilliseconds", date_getUTCMilliseconds
, 0,0,0,0),
2009 JS_FN("setTime", date_setTime
, 1,1,0,0),
2010 JS_FN("setYear", date_setYear
, 1,1,0,0),
2011 JS_FN("setFullYear", date_setFullYear
, 1,3,0,0),
2012 JS_FN("setUTCFullYear", date_setUTCFullYear
, 1,3,0,0),
2013 JS_FN("setMonth", date_setMonth
, 1,2,0,0),
2014 JS_FN("setUTCMonth", date_setUTCMonth
, 1,2,0,0),
2015 JS_FN("setDate", date_setDate
, 1,1,0,0),
2016 JS_FN("setUTCDate", date_setUTCDate
, 1,1,0,0),
2017 JS_FN("setHours", date_setHours
, 1,4,0,0),
2018 JS_FN("setUTCHours", date_setUTCHours
, 1,4,0,0),
2019 JS_FN("setMinutes", date_setMinutes
, 1,3,0,0),
2020 JS_FN("setUTCMinutes", date_setUTCMinutes
, 1,3,0,0),
2021 JS_FN("setSeconds", date_setSeconds
, 1,2,0,0),
2022 JS_FN("setUTCSeconds", date_setUTCSeconds
, 1,2,0,0),
2023 JS_FN("setMilliseconds", date_setMilliseconds
, 1,1,0,0),
2024 JS_FN("setUTCMilliseconds", date_setUTCMilliseconds
, 1,1,0,0),
2025 JS_FN("toUTCString", date_toGMTString
, 0,0,0,0),
2026 JS_FN(js_toLocaleString_str
, date_toLocaleString
, 0,0,0,0),
2027 JS_FN("toLocaleDateString", date_toLocaleDateString
, 0,0,0,0),
2028 JS_FN("toLocaleTimeString", date_toLocaleTimeString
, 0,0,0,0),
2029 JS_FN("toLocaleFormat", date_toLocaleFormat
, 0,0,0,0),
2030 JS_FN("toDateString", date_toDateString
, 0,0,0,0),
2031 JS_FN("toTimeString", date_toTimeString
, 0,0,0,0),
2033 JS_FN(js_toSource_str
, date_toSource
, 0,0,0,0),
2035 JS_FN(js_toString_str
, date_toString
, 0,0,0,0),
2036 JS_FN(js_valueOf_str
, date_valueOf
, 0,0,0,0),
2041 date_constructor(JSContext
*cx
, JSObject
* obj
)
2045 date
= js_NewDouble(cx
, 0.0, 0);
2049 JS_SetReservedSlot(cx
, obj
, UTC_TIME_SLOT
,
2050 DOUBLE_TO_JSVAL(date
));
2051 JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
2052 DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
));
2057 Date(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2063 /* Date called as function. */
2064 if (!(cx
->fp
->flags
& JSFRAME_CONSTRUCTING
)) {
2065 int64 us
, ms
, us2ms
;
2068 /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
2069 * so compute ms from PRMJ_Now.
2072 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
2073 JSLL_DIV(ms
, us
, us2ms
);
2074 JSLL_L2D(msec_time
, ms
);
2076 return date_format(cx
, msec_time
, FORMATSPEC_FULL
, rval
);
2079 /* Date called as constructor. */
2081 int64 us
, ms
, us2ms
;
2084 date
= date_constructor(cx
, obj
);
2089 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
2090 JSLL_DIV(ms
, us
, us2ms
);
2091 JSLL_L2D(msec_time
, ms
);
2094 } else if (argc
== 1) {
2095 if (!JSVAL_IS_STRING(argv
[0])) {
2096 /* the argument is a millisecond number */
2097 if (!js_ValueToNumber(cx
, argv
[0], &d
))
2099 date
= date_constructor(cx
, obj
);
2102 *date
= TIMECLIP(d
);
2104 /* the argument is a string; parse it. */
2105 date
= date_constructor(cx
, obj
);
2109 str
= js_ValueToString(cx
, argv
[0]);
2113 if (!date_parseString(str
, date
))
2114 *date
= *cx
->runtime
->jsNaN
;
2115 *date
= TIMECLIP(*date
);
2121 if (!date_msecFromArgs(cx
, argc
, argv
, &msec_time
))
2124 date
= date_constructor(cx
, obj
);
2128 if (JSDOUBLE_IS_FINITE(msec_time
)) {
2129 msec_time
= UTC(msec_time
);
2130 msec_time
= TIMECLIP(msec_time
);
2139 js_InitDateClass(JSContext
*cx
, JSObject
*obj
)
2142 jsdouble
*proto_date
;
2144 /* set static LocalTZA */
2145 LocalTZA
= -(PRMJ_LocalGMTDifference() * msPerSecond
);
2146 proto
= JS_InitClass(cx
, obj
, NULL
, &js_DateClass
, Date
, MAXARGS
,
2147 NULL
, date_methods
, NULL
, date_static_methods
);
2151 /* Alias toUTCString with toGMTString. (ECMA B.2.6) */
2152 if (!JS_AliasProperty(cx
, proto
, "toUTCString", "toGMTString"))
2155 /* Set the value of the Date.prototype date to NaN */
2156 proto_date
= date_constructor(cx
, proto
);
2159 *proto_date
= *cx
->runtime
->jsNaN
;
2164 JS_FRIEND_API(JSObject
*)
2165 js_NewDateObjectMsec(JSContext
*cx
, jsdouble msec_time
)
2170 obj
= js_NewObject(cx
, &js_DateClass
, NULL
, NULL
);
2174 date
= date_constructor(cx
, obj
);
2182 JS_FRIEND_API(JSObject
*)
2183 js_NewDateObject(JSContext
* cx
, int year
, int mon
, int mday
,
2184 int hour
, int min
, int sec
)
2189 msec_time
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
2190 obj
= js_NewDateObjectMsec(cx
, UTC(msec_time
));
2194 JS_FRIEND_API(JSBool
)
2195 js_DateIsValid(JSContext
*cx
, JSObject
* obj
)
2198 return GetUTCTime(cx
, obj
, NULL
, &utctime
) && !JSDOUBLE_IS_NaN(utctime
);
2202 js_DateGetYear(JSContext
*cx
, JSObject
* obj
)
2206 /* Preserve legacy API behavior of returning 0 for invalid dates. */
2207 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
) || JSDOUBLE_IS_NaN(localtime
))
2210 return (int) YearFromTime(localtime
);
2214 js_DateGetMonth(JSContext
*cx
, JSObject
* obj
)
2218 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
) || JSDOUBLE_IS_NaN(localtime
))
2221 return (int) MonthFromTime(localtime
);
2225 js_DateGetDate(JSContext
*cx
, JSObject
* obj
)
2229 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
) || JSDOUBLE_IS_NaN(localtime
))
2232 return (int) DateFromTime(localtime
);
2236 js_DateGetHours(JSContext
*cx
, JSObject
* obj
)
2240 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
) || JSDOUBLE_IS_NaN(localtime
))
2243 return (int) HourFromTime(localtime
);
2247 js_DateGetMinutes(JSContext
*cx
, JSObject
* obj
)
2251 if (!GetLocalTime(cx
, obj
, NULL
, &localtime
) || JSDOUBLE_IS_NaN(localtime
))
2254 return (int) MinFromTime(localtime
);
2258 js_DateGetSeconds(JSContext
*cx
, JSObject
* obj
)
2262 if (!GetUTCTime(cx
, obj
, NULL
, &utctime
) || JSDOUBLE_IS_NaN(utctime
))
2265 return (int) SecFromTime(utctime
);
2269 js_DateSetYear(JSContext
*cx
, JSObject
*obj
, int year
)
2273 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2276 /* reset date if it was NaN */
2277 if (JSDOUBLE_IS_NaN(local
))
2280 local
= date_msecFromDate(year
,
2281 MonthFromTime(local
),
2282 DateFromTime(local
),
2283 HourFromTime(local
),
2288 /* SetUTCTime also invalidates local time cache. */
2289 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2293 js_DateSetMonth(JSContext
*cx
, JSObject
*obj
, int month
)
2297 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2300 /* bail if date was NaN */
2301 if (JSDOUBLE_IS_NaN(local
))
2304 local
= date_msecFromDate(YearFromTime(local
),
2306 DateFromTime(local
),
2307 HourFromTime(local
),
2311 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2315 js_DateSetDate(JSContext
*cx
, JSObject
*obj
, int date
)
2319 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2322 if (JSDOUBLE_IS_NaN(local
))
2325 local
= date_msecFromDate(YearFromTime(local
),
2326 MonthFromTime(local
),
2328 HourFromTime(local
),
2332 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2336 js_DateSetHours(JSContext
*cx
, JSObject
*obj
, int hours
)
2340 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2343 if (JSDOUBLE_IS_NaN(local
))
2345 local
= date_msecFromDate(YearFromTime(local
),
2346 MonthFromTime(local
),
2347 DateFromTime(local
),
2352 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2356 js_DateSetMinutes(JSContext
*cx
, JSObject
*obj
, int minutes
)
2360 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2363 if (JSDOUBLE_IS_NaN(local
))
2365 local
= date_msecFromDate(YearFromTime(local
),
2366 MonthFromTime(local
),
2367 DateFromTime(local
),
2368 HourFromTime(local
),
2372 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2376 js_DateSetSeconds(JSContext
*cx
, JSObject
*obj
, int seconds
)
2380 if (!GetLocalTime(cx
, obj
, NULL
, &local
))
2383 if (JSDOUBLE_IS_NaN(local
))
2385 local
= date_msecFromDate(YearFromTime(local
),
2386 MonthFromTime(local
),
2387 DateFromTime(local
),
2388 HourFromTime(local
),
2392 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2395 JS_FRIEND_API(jsdouble
)
2396 js_DateGetMsecSinceEpoch(JSContext
*cx
, JSObject
*obj
)
2399 if (!GetUTCTime(cx
, obj
, NULL
, &utctime
))