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 d
= js_ValueToNumber(cx
, &argv
[loop
]);
577 if (JSVAL_IS_NULL(argv
[loop
]))
579 /* return NaN if any arg is not finite */
580 if (!JSDOUBLE_IS_FINITE(d
)) {
581 *rval
= *cx
->runtime
->jsNaN
;
584 array
[loop
] = js_DoubleToInteger(d
);
587 array
[loop
] = 1; /* Default the date argument to 1. */
594 /* adjust 2-digit years into the 20th century */
595 if (array
[0] >= 0 && array
[0] <= 99)
598 msec_time
= date_msecFromDate(array
[0], array
[1], array
[2],
599 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_NewNumberInRootedValue(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
= JS_ARRAY_LENGTH(wtb
); --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
)
896 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
899 str
= js_ValueToString(cx
, vp
[2]);
902 vp
[2] = STRING_TO_JSVAL(str
);
903 if (!date_parseString(str
, &result
)) {
904 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
908 result
= TIMECLIP(result
);
909 return js_NewNumberInRootedValue(cx
, result
, vp
);
913 date_now(JSContext
*cx
, uintN argc
, jsval
*vp
)
919 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
920 JSLL_DIV(ms
, us
, us2ms
);
921 JSLL_L2D(msec_time
, ms
);
923 return js_NewDoubleInRootedValue(cx
, msec_time
, vp
);
927 * Get UTC time from the date object. Returns false if the object is not
931 GetUTCTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
935 if (!JS_InstanceOf(cx
, obj
, &js_DateClass
, vp
? vp
+ 2 : NULL
))
937 if (!JS_GetReservedSlot(cx
, obj
, UTC_TIME_SLOT
, &v
))
940 *dp
= *JSVAL_TO_DOUBLE(v
);
945 * Set UTC time slot with a pointer pointing to a jsdouble. This function is
946 * used only for setting UTC time to some predefined values, such as NaN.
948 * It also invalidates cached local time.
951 SetUTCTimePtr(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
953 if (vp
&& !JS_InstanceOf(cx
, obj
, &js_DateClass
, vp
+ 2))
956 /* Invalidate local time cache. */
957 if (!JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
958 DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
))) {
962 return JS_SetReservedSlot(cx
, obj
, UTC_TIME_SLOT
, DOUBLE_TO_JSVAL(dp
));
966 * Set UTC time to a given time.
969 SetUTCTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble t
)
971 jsdouble
*dp
= js_NewWeaklyRootedDouble(cx
, t
);
974 return SetUTCTimePtr(cx
, obj
, vp
, dp
);
978 * Get the local time, cache it if necessary. If UTC time is not finite
979 * (e.g., NaN), the local time slot is set to the UTC time without conversion.
982 GetAndCacheLocalTime(JSContext
*cx
, JSObject
*obj
, jsval
*vp
, jsdouble
*dp
)
988 if (!obj
|| !JS_GetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
, &v
))
991 result
= *JSVAL_TO_DOUBLE(v
);
993 if (JSDOUBLE_IS_NaN(result
)) {
994 if (!GetUTCTime(cx
, obj
, vp
, &result
))
997 /* if result is NaN, it couldn't be finite. */
998 if (JSDOUBLE_IS_FINITE(result
))
999 result
= LocalTime(result
);
1001 cached
= js_NewWeaklyRootedDouble(cx
, result
);
1005 if (!JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
1006 DOUBLE_TO_JSVAL(cached
))) {
1016 * See ECMA 15.9.5.4 thru 15.9.5.23
1019 date_getTime(JSContext
*cx
, uintN argc
, jsval
*vp
)
1023 return GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
) &&
1024 js_NewNumberInRootedValue(cx
, result
, vp
);
1028 GetYear(JSContext
*cx
, JSBool fullyear
, jsval
*vp
)
1032 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1035 if (JSDOUBLE_IS_FINITE(result
)) {
1036 result
= YearFromTime(result
);
1038 /* Follow ECMA-262 to the letter, contrary to IE JScript. */
1043 return js_NewNumberInRootedValue(cx
, result
, vp
);
1047 date_getYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1049 return GetYear(cx
, JS_FALSE
, vp
);
1053 date_getFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1055 return GetYear(cx
, JS_TRUE
, vp
);
1059 date_getUTCFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1063 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1066 if (JSDOUBLE_IS_FINITE(result
))
1067 result
= YearFromTime(result
);
1069 return js_NewNumberInRootedValue(cx
, result
, vp
);
1073 date_getMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1077 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1080 if (JSDOUBLE_IS_FINITE(result
))
1081 result
= MonthFromTime(result
);
1083 return js_NewNumberInRootedValue(cx
, result
, vp
);
1087 date_getUTCMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1091 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1094 if (JSDOUBLE_IS_FINITE(result
))
1095 result
= MonthFromTime(result
);
1097 return js_NewNumberInRootedValue(cx
, result
, vp
);
1101 date_getDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1105 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1108 if (JSDOUBLE_IS_FINITE(result
))
1109 result
= DateFromTime(result
);
1111 return js_NewNumberInRootedValue(cx
, result
, vp
);
1115 date_getUTCDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1119 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1122 if (JSDOUBLE_IS_FINITE(result
))
1123 result
= DateFromTime(result
);
1125 return js_NewNumberInRootedValue(cx
, result
, vp
);
1129 date_getDay(JSContext
*cx
, uintN argc
, jsval
*vp
)
1133 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1136 if (JSDOUBLE_IS_FINITE(result
))
1137 result
= WeekDay(result
);
1139 return js_NewNumberInRootedValue(cx
, result
, vp
);
1143 date_getUTCDay(JSContext
*cx
, uintN argc
, jsval
*vp
)
1147 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1150 if (JSDOUBLE_IS_FINITE(result
))
1151 result
= WeekDay(result
);
1153 return js_NewNumberInRootedValue(cx
, result
, vp
);
1157 date_getHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1161 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1164 if (JSDOUBLE_IS_FINITE(result
))
1165 result
= HourFromTime(result
);
1167 return js_NewNumberInRootedValue(cx
, result
, vp
);
1171 date_getUTCHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1175 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1178 if (JSDOUBLE_IS_FINITE(result
))
1179 result
= HourFromTime(result
);
1181 return js_NewNumberInRootedValue(cx
, result
, vp
);
1185 date_getMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1189 if (!GetAndCacheLocalTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1192 if (JSDOUBLE_IS_FINITE(result
))
1193 result
= MinFromTime(result
);
1195 return js_NewNumberInRootedValue(cx
, result
, vp
);
1199 date_getUTCMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1203 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1206 if (JSDOUBLE_IS_FINITE(result
))
1207 result
= MinFromTime(result
);
1209 return js_NewNumberInRootedValue(cx
, result
, vp
);
1212 /* Date.getSeconds is mapped to getUTCSeconds */
1215 date_getUTCSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1219 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1222 if (JSDOUBLE_IS_FINITE(result
))
1223 result
= SecFromTime(result
);
1225 return js_NewNumberInRootedValue(cx
, result
, vp
);
1228 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
1231 date_getUTCMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1235 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &result
))
1238 if (JSDOUBLE_IS_FINITE(result
))
1239 result
= msFromTime(result
);
1241 return js_NewNumberInRootedValue(cx
, result
, vp
);
1245 date_getTimezoneOffset(JSContext
*cx
, uintN argc
, jsval
*vp
)
1248 jsdouble utctime
, localtime
, result
;
1250 obj
= JS_THIS_OBJECT(cx
, vp
);
1251 if (!GetUTCTime(cx
, obj
, vp
, &utctime
))
1253 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
))
1257 * Return the time zone offset in minutes for the current locale that is
1258 * appropriate for this time. This value would be a constant except for
1259 * daylight savings time.
1261 result
= (utctime
- localtime
) / msPerMinute
;
1262 return js_NewNumberInRootedValue(cx
, result
, vp
);
1266 SetDateToNaN(JSContext
*cx
, jsval
*vp
)
1270 obj
= JS_THIS_OBJECT(cx
, vp
);
1271 if (!SetUTCTimePtr(cx
, obj
, NULL
, cx
->runtime
->jsNaN
))
1273 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
1278 date_setTime(JSContext
*cx
, uintN argc
, jsval
*vp
)
1283 return SetDateToNaN(cx
, vp
);
1284 result
= js_ValueToNumber(cx
, &vp
[2]);
1285 if (JSVAL_IS_NULL(vp
[2]))
1288 result
= TIMECLIP(result
);
1290 if (!SetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, result
))
1293 return js_NewNumberInRootedValue(cx
, result
, vp
);
1297 date_makeTime(JSContext
*cx
, uintN maxargs
, JSBool local
, uintN argc
, jsval
*vp
)
1302 jsdouble args
[4], *argp
, *stop
;
1303 jsdouble hour
, min
, sec
, msec
;
1304 jsdouble lorutime
; /* Local or UTC version of *date */
1309 obj
= JS_THIS_OBJECT(cx
, vp
);
1310 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1313 /* just return NaN if the date is already NaN */
1314 if (!JSDOUBLE_IS_FINITE(result
))
1315 return js_NewNumberInRootedValue(cx
, result
, vp
);
1318 * Satisfy the ECMA rule that if a function is called with
1319 * fewer arguments than the specified formal arguments, the
1320 * remaining arguments are set to undefined. Seems like all
1321 * the Date.setWhatever functions in ECMA are only varargs
1322 * beyond the first argument; this should be set to undefined
1323 * if it's not given. This means that "d = new Date();
1324 * d.setMilliseconds()" returns NaN. Blech.
1327 return SetDateToNaN(cx
, vp
);
1329 argc
= maxargs
; /* clamp argc */
1330 JS_ASSERT(argc
<= 4);
1333 for (i
= 0; i
< argc
; i
++) {
1334 args
[i
] = js_ValueToNumber(cx
, &argv
[i
]);
1335 if (JSVAL_IS_NULL(argv
[i
]))
1337 if (!JSDOUBLE_IS_FINITE(args
[i
]))
1338 return SetDateToNaN(cx
, vp
);
1339 args
[i
] = js_DoubleToInteger(args
[i
]);
1343 lorutime
= LocalTime(result
);
1349 if (maxargs
>= 4 && argp
< stop
)
1352 hour
= HourFromTime(lorutime
);
1354 if (maxargs
>= 3 && argp
< stop
)
1357 min
= MinFromTime(lorutime
);
1359 if (maxargs
>= 2 && argp
< stop
)
1362 sec
= SecFromTime(lorutime
);
1364 if (maxargs
>= 1 && argp
< stop
)
1367 msec
= msFromTime(lorutime
);
1369 msec_time
= MakeTime(hour
, min
, sec
, msec
);
1370 result
= MakeDate(Day(lorutime
), msec_time
);
1372 /* fprintf(stderr, "%f\n", result); */
1375 result
= UTC(result
);
1377 /* fprintf(stderr, "%f\n", result); */
1379 result
= TIMECLIP(result
);
1380 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1383 return js_NewNumberInRootedValue(cx
, result
, vp
);
1387 date_setMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1389 return date_makeTime(cx
, 1, JS_TRUE
, argc
, vp
);
1393 date_setUTCMilliseconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1395 return date_makeTime(cx
, 1, JS_FALSE
, argc
, vp
);
1399 date_setSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1401 return date_makeTime(cx
, 2, JS_TRUE
, argc
, vp
);
1405 date_setUTCSeconds(JSContext
*cx
, uintN argc
, jsval
*vp
)
1407 return date_makeTime(cx
, 2, JS_FALSE
, argc
, vp
);
1411 date_setMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1413 return date_makeTime(cx
, 3, JS_TRUE
, argc
, vp
);
1417 date_setUTCMinutes(JSContext
*cx
, uintN argc
, jsval
*vp
)
1419 return date_makeTime(cx
, 3, JS_FALSE
, argc
, vp
);
1423 date_setHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1425 return date_makeTime(cx
, 4, JS_TRUE
, argc
, vp
);
1429 date_setUTCHours(JSContext
*cx
, uintN argc
, jsval
*vp
)
1431 return date_makeTime(cx
, 4, JS_FALSE
, argc
, vp
);
1435 date_makeDate(JSContext
*cx
, uintN maxargs
, JSBool local
, uintN argc
, jsval
*vp
)
1440 jsdouble lorutime
; /* local or UTC version of *date */
1441 jsdouble args
[3], *argp
, *stop
;
1442 jsdouble year
, month
, day
;
1445 obj
= JS_THIS_OBJECT(cx
, vp
);
1446 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1449 /* see complaint about ECMA in date_MakeTime */
1451 return SetDateToNaN(cx
, vp
);
1453 argc
= maxargs
; /* clamp argc */
1454 JS_ASSERT(1 <= argc
&& argc
<= 3);
1457 for (i
= 0; i
< argc
; i
++) {
1458 args
[i
] = js_ValueToNumber(cx
, &argv
[i
]);
1459 if (JSVAL_IS_NULL(argv
[i
]))
1461 if (!JSDOUBLE_IS_FINITE(args
[i
]))
1462 return SetDateToNaN(cx
, vp
);
1463 args
[i
] = js_DoubleToInteger(args
[i
]);
1466 /* return NaN if date is NaN and we're not setting the year,
1467 * If we are, use 0 as the time. */
1468 if (!(JSDOUBLE_IS_FINITE(result
))) {
1470 return js_NewNumberInRootedValue(cx
, result
, vp
);
1473 lorutime
= local
? LocalTime(result
) : result
;
1478 if (maxargs
>= 3 && argp
< stop
)
1481 year
= YearFromTime(lorutime
);
1483 if (maxargs
>= 2 && argp
< stop
)
1486 month
= MonthFromTime(lorutime
);
1488 if (maxargs
>= 1 && argp
< stop
)
1491 day
= DateFromTime(lorutime
);
1493 day
= MakeDay(year
, month
, day
); /* day within year */
1494 result
= MakeDate(day
, TimeWithinDay(lorutime
));
1497 result
= UTC(result
);
1499 result
= TIMECLIP(result
);
1500 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1503 return js_NewNumberInRootedValue(cx
, result
, vp
);
1507 date_setDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1509 return date_makeDate(cx
, 1, JS_TRUE
, argc
, vp
);
1513 date_setUTCDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1515 return date_makeDate(cx
, 1, JS_FALSE
, argc
, vp
);
1519 date_setMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1521 return date_makeDate(cx
, 2, JS_TRUE
, argc
, vp
);
1525 date_setUTCMonth(JSContext
*cx
, uintN argc
, jsval
*vp
)
1527 return date_makeDate(cx
, 2, JS_FALSE
, argc
, vp
);
1531 date_setFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1533 return date_makeDate(cx
, 3, JS_TRUE
, argc
, vp
);
1537 date_setUTCFullYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1539 return date_makeDate(cx
, 3, JS_FALSE
, argc
, vp
);
1543 date_setYear(JSContext
*cx
, uintN argc
, jsval
*vp
)
1551 obj
= JS_THIS_OBJECT(cx
, vp
);
1552 if (!GetUTCTime(cx
, obj
, vp
, &result
))
1556 return SetDateToNaN(cx
, vp
);
1557 year
= js_ValueToNumber(cx
, &vp
[2]);
1558 if (JSVAL_IS_NULL(vp
[2]))
1560 if (!JSDOUBLE_IS_FINITE(year
))
1561 return SetDateToNaN(cx
, vp
);
1563 year
= js_DoubleToInteger(year
);
1565 if (!JSDOUBLE_IS_FINITE(result
)) {
1568 t
= LocalTime(result
);
1571 if (year
>= 0 && year
<= 99)
1574 day
= MakeDay(year
, MonthFromTime(t
), DateFromTime(t
));
1575 result
= MakeDate(day
, TimeWithinDay(t
));
1576 result
= UTC(result
);
1578 result
= TIMECLIP(result
);
1579 if (!SetUTCTime(cx
, obj
, NULL
, result
))
1582 return js_NewNumberInRootedValue(cx
, result
, vp
);
1585 /* constants for toString, toUTCString */
1586 static char js_NaN_date_str
[] = "Invalid Date";
1587 static const char* days
[] =
1589 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1591 static const char* months
[] =
1593 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1597 date_toGMTString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1603 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &utctime
))
1606 if (!JSDOUBLE_IS_FINITE(utctime
)) {
1607 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1609 /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1610 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1612 JS_snprintf(buf
, sizeof buf
, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
1613 days
[WeekDay(utctime
)],
1614 DateFromTime(utctime
),
1615 months
[MonthFromTime(utctime
)],
1616 YearFromTime(utctime
),
1617 HourFromTime(utctime
),
1618 MinFromTime(utctime
),
1619 SecFromTime(utctime
));
1621 str
= JS_NewStringCopyZ(cx
, buf
);
1624 *vp
= STRING_TO_JSVAL(str
);
1628 /* for Date.toLocaleString; interface to PRMJTime date struct.
1631 new_explode(jsdouble timeval
, PRMJTime
*split
)
1633 jsint year
= YearFromTime(timeval
);
1635 split
->tm_usec
= (int32
) msFromTime(timeval
) * 1000;
1636 split
->tm_sec
= (int8
) SecFromTime(timeval
);
1637 split
->tm_min
= (int8
) MinFromTime(timeval
);
1638 split
->tm_hour
= (int8
) HourFromTime(timeval
);
1639 split
->tm_mday
= (int8
) DateFromTime(timeval
);
1640 split
->tm_mon
= (int8
) MonthFromTime(timeval
);
1641 split
->tm_wday
= (int8
) WeekDay(timeval
);
1642 split
->tm_year
= year
;
1643 split
->tm_yday
= (int16
) DayWithinYear(timeval
, year
);
1645 /* not sure how this affects things, but it doesn't seem
1647 split
->tm_isdst
= (DaylightSavingTA(timeval
) != 0);
1650 typedef enum formatspec
{
1651 FORMATSPEC_FULL
, FORMATSPEC_DATE
, FORMATSPEC_TIME
1654 /* helper function */
1656 date_format(JSContext
*cx
, jsdouble date
, formatspec format
, jsval
*rval
)
1665 if (!JSDOUBLE_IS_FINITE(date
)) {
1666 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1668 jsdouble local
= LocalTime(date
);
1670 /* offset from GMT in minutes. The offset includes daylight savings,
1672 jsint minutes
= (jsint
) floor(AdjustTime(date
) / msPerMinute
);
1674 /* map 510 minutes to 0830 hours */
1675 intN offset
= (minutes
/ 60) * 100 + minutes
% 60;
1677 /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
1678 * printed as 'GMT-0800' rather than as 'PST' to avoid
1679 * operating-system dependence on strftime (which
1680 * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
1681 * PST as 'Pacific Standard Time.' This way we always know
1682 * what we're getting, and can parse it if we produce it.
1683 * The OS TZA string is included as a comment.
1686 /* get a timezone string from the OS to include as a
1688 new_explode(date
, &split
);
1689 if (PRMJ_FormatTime(tzbuf
, sizeof tzbuf
, "(%Z)", &split
) != 0) {
1691 /* Decide whether to use the resulting timezone string.
1693 * Reject it if it contains any non-ASCII, non-alphanumeric
1694 * characters. It's then likely in some other character
1695 * encoding, and we probably won't display it correctly.
1698 tzlen
= strlen(tzbuf
);
1702 for (i
= 0; i
< tzlen
; i
++) {
1703 jschar c
= tzbuf
[i
];
1705 !(isalpha(c
) || isdigit(c
) ||
1706 c
== ' ' || c
== '(' || c
== ')')) {
1712 /* Also reject it if it's not parenthesized or if it's '()'. */
1713 if (tzbuf
[0] != '(' || tzbuf
[1] == ')')
1719 case FORMATSPEC_FULL
:
1721 * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1722 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1724 /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
1725 JS_snprintf(buf
, sizeof buf
,
1726 "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
1727 days
[WeekDay(local
)],
1728 months
[MonthFromTime(local
)],
1729 DateFromTime(local
),
1730 YearFromTime(local
),
1731 HourFromTime(local
),
1736 usetz
? tzbuf
: "");
1738 case FORMATSPEC_DATE
:
1739 /* Tue Oct 31 2000 */
1740 JS_snprintf(buf
, sizeof buf
,
1742 days
[WeekDay(local
)],
1743 months
[MonthFromTime(local
)],
1744 DateFromTime(local
),
1745 YearFromTime(local
));
1747 case FORMATSPEC_TIME
:
1748 /* 09:41:40 GMT-0800 (PST) */
1749 JS_snprintf(buf
, sizeof buf
,
1750 "%.2d:%.2d:%.2d GMT%+.4d%s%s",
1751 HourFromTime(local
),
1756 usetz
? tzbuf
: "");
1761 str
= JS_NewStringCopyZ(cx
, buf
);
1764 *rval
= STRING_TO_JSVAL(str
);
1769 date_toLocaleHelper(JSContext
*cx
, const char *format
, jsval
*vp
)
1777 obj
= JS_THIS_OBJECT(cx
, vp
);
1778 if (!GetUTCTime(cx
, obj
, vp
, &utctime
))
1781 if (!JSDOUBLE_IS_FINITE(utctime
)) {
1782 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
1785 jsdouble local
= LocalTime(utctime
);
1786 new_explode(local
, &split
);
1788 /* let PRMJTime format it. */
1789 result_len
= PRMJ_FormatTime(buf
, sizeof buf
, format
, &split
);
1791 /* If it failed, default to toString. */
1792 if (result_len
== 0)
1793 return date_format(cx
, utctime
, FORMATSPEC_FULL
, vp
);
1795 /* Hacked check against undesired 2-digit year 00/00/00 form. */
1796 if (strcmp(format
, "%x") == 0 && result_len
>= 6 &&
1797 /* Format %x means use OS settings, which may have 2-digit yr, so
1798 hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
1799 !isdigit(buf
[result_len
- 3]) &&
1800 isdigit(buf
[result_len
- 2]) && isdigit(buf
[result_len
- 1]) &&
1801 /* ...but not if starts with 4-digit year, like 2022/3/11. */
1802 !(isdigit(buf
[0]) && isdigit(buf
[1]) &&
1803 isdigit(buf
[2]) && isdigit(buf
[3]))) {
1804 JS_snprintf(buf
+ (result_len
- 2), (sizeof buf
) - (result_len
- 2),
1805 "%d", js_DateGetYear(cx
, obj
));
1810 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUnicode
)
1811 return cx
->localeCallbacks
->localeToUnicode(cx
, buf
, vp
);
1813 str
= JS_NewStringCopyZ(cx
, buf
);
1816 *vp
= STRING_TO_JSVAL(str
);
1821 date_toLocaleString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1823 /* Use '%#c' for windows, because '%c' is
1824 * backward-compatible and non-y2k with msvc; '%#c' requests that a
1825 * full year be used in the result string.
1827 return date_toLocaleHelper(cx
,
1828 #if defined(_WIN32) && !defined(__MWERKS__)
1837 date_toLocaleDateString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1839 /* Use '%#x' for windows, because '%x' is
1840 * backward-compatible and non-y2k with msvc; '%#x' requests that a
1841 * full year be used in the result string.
1843 return date_toLocaleHelper(cx
,
1844 #if defined(_WIN32) && !defined(__MWERKS__)
1853 date_toLocaleTimeString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1855 return date_toLocaleHelper(cx
, "%X", vp
);
1859 date_toLocaleFormat(JSContext
*cx
, uintN argc
, jsval
*vp
)
1862 const char *fmtbytes
;
1865 return date_toLocaleString(cx
, argc
, vp
);
1867 fmt
= js_ValueToString(cx
, vp
[2]);
1870 vp
[2] = STRING_TO_JSVAL(fmt
);
1871 fmtbytes
= js_GetStringBytes(cx
, fmt
);
1875 return date_toLocaleHelper(cx
, fmtbytes
, vp
);
1879 date_toTimeString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1883 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &utctime
))
1885 return date_format(cx
, utctime
, FORMATSPEC_TIME
, vp
);
1889 date_toDateString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1893 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &utctime
))
1895 return date_format(cx
, utctime
, FORMATSPEC_DATE
, vp
);
1903 date_toSource(JSContext
*cx
, uintN argc
, jsval
*vp
)
1906 char buf
[DTOSTR_STANDARD_BUFFER_SIZE
], *numStr
, *bytes
;
1909 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &utctime
))
1912 numStr
= JS_dtostr(buf
, sizeof buf
, DTOSTR_STANDARD
, 0, utctime
);
1914 JS_ReportOutOfMemory(cx
);
1918 bytes
= JS_smprintf("(new %s(%s))", js_Date_str
, numStr
);
1920 JS_ReportOutOfMemory(cx
);
1924 str
= JS_NewString(cx
, bytes
, strlen(bytes
));
1929 *vp
= STRING_TO_JSVAL(str
);
1935 date_toString(JSContext
*cx
, uintN argc
, jsval
*vp
)
1939 if (!GetUTCTime(cx
, JS_THIS_OBJECT(cx
, vp
), vp
, &utctime
))
1941 return date_format(cx
, utctime
, FORMATSPEC_FULL
, vp
);
1945 date_valueOf(JSContext
*cx
, uintN argc
, jsval
*vp
)
1947 JSString
*str
, *str2
;
1949 /* It is an error to call date_valueOf on a non-date object, but we don't
1950 * need to check for that explicitly here because every path calls
1951 * GetUTCTime, which does the check.
1954 /* If called directly with no arguments, convert to a time number. */
1956 return date_getTime(cx
, argc
, vp
);
1958 /* Convert to number only if the hint was given, otherwise favor string. */
1959 str
= js_ValueToString(cx
, vp
[2]);
1962 str2
= ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[JSTYPE_NUMBER
]);
1963 if (js_EqualStrings(str
, str2
))
1964 return date_getTime(cx
, argc
, vp
);
1965 return date_toString(cx
, argc
, vp
);
1969 * creation and destruction
1972 static JSFunctionSpec date_static_methods
[] = {
1973 JS_FN("UTC", date_UTC
, MAXARGS
,0),
1974 JS_FN("parse", date_parse
, 1,0),
1975 JS_FN("now", date_now
, 0,0),
1979 static JSFunctionSpec date_methods
[] = {
1980 JS_FN("getTime", date_getTime
, 0,0),
1981 JS_FN("getTimezoneOffset", date_getTimezoneOffset
, 0,0),
1982 JS_FN("getYear", date_getYear
, 0,0),
1983 JS_FN("getFullYear", date_getFullYear
, 0,0),
1984 JS_FN("getUTCFullYear", date_getUTCFullYear
, 0,0),
1985 JS_FN("getMonth", date_getMonth
, 0,0),
1986 JS_FN("getUTCMonth", date_getUTCMonth
, 0,0),
1987 JS_FN("getDate", date_getDate
, 0,0),
1988 JS_FN("getUTCDate", date_getUTCDate
, 0,0),
1989 JS_FN("getDay", date_getDay
, 0,0),
1990 JS_FN("getUTCDay", date_getUTCDay
, 0,0),
1991 JS_FN("getHours", date_getHours
, 0,0),
1992 JS_FN("getUTCHours", date_getUTCHours
, 0,0),
1993 JS_FN("getMinutes", date_getMinutes
, 0,0),
1994 JS_FN("getUTCMinutes", date_getUTCMinutes
, 0,0),
1995 JS_FN("getSeconds", date_getUTCSeconds
, 0,0),
1996 JS_FN("getUTCSeconds", date_getUTCSeconds
, 0,0),
1997 JS_FN("getMilliseconds", date_getUTCMilliseconds
, 0,0),
1998 JS_FN("getUTCMilliseconds", date_getUTCMilliseconds
, 0,0),
1999 JS_FN("setTime", date_setTime
, 1,0),
2000 JS_FN("setYear", date_setYear
, 1,0),
2001 JS_FN("setFullYear", date_setFullYear
, 3,0),
2002 JS_FN("setUTCFullYear", date_setUTCFullYear
, 3,0),
2003 JS_FN("setMonth", date_setMonth
, 2,0),
2004 JS_FN("setUTCMonth", date_setUTCMonth
, 2,0),
2005 JS_FN("setDate", date_setDate
, 1,0),
2006 JS_FN("setUTCDate", date_setUTCDate
, 1,0),
2007 JS_FN("setHours", date_setHours
, 4,0),
2008 JS_FN("setUTCHours", date_setUTCHours
, 4,0),
2009 JS_FN("setMinutes", date_setMinutes
, 3,0),
2010 JS_FN("setUTCMinutes", date_setUTCMinutes
, 3,0),
2011 JS_FN("setSeconds", date_setSeconds
, 2,0),
2012 JS_FN("setUTCSeconds", date_setUTCSeconds
, 2,0),
2013 JS_FN("setMilliseconds", date_setMilliseconds
, 1,0),
2014 JS_FN("setUTCMilliseconds", date_setUTCMilliseconds
, 1,0),
2015 JS_FN("toUTCString", date_toGMTString
, 0,0),
2016 JS_FN(js_toLocaleString_str
, date_toLocaleString
, 0,0),
2017 JS_FN("toLocaleDateString", date_toLocaleDateString
, 0,0),
2018 JS_FN("toLocaleTimeString", date_toLocaleTimeString
, 0,0),
2019 JS_FN("toLocaleFormat", date_toLocaleFormat
, 0,0),
2020 JS_FN("toDateString", date_toDateString
, 0,0),
2021 JS_FN("toTimeString", date_toTimeString
, 0,0),
2023 JS_FN(js_toSource_str
, date_toSource
, 0,0),
2025 JS_FN(js_toString_str
, date_toString
, 0,0),
2026 JS_FN(js_valueOf_str
, date_valueOf
, 0,0),
2031 date_constructor(JSContext
*cx
, JSObject
* obj
)
2035 date
= js_NewWeaklyRootedDouble(cx
, 0.0);
2039 JS_SetReservedSlot(cx
, obj
, UTC_TIME_SLOT
,
2040 DOUBLE_TO_JSVAL(date
));
2041 JS_SetReservedSlot(cx
, obj
, LOCAL_TIME_SLOT
,
2042 DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
));
2047 Date(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2053 /* Date called as function. */
2054 if (!(cx
->fp
->flags
& JSFRAME_CONSTRUCTING
)) {
2055 int64 us
, ms
, us2ms
;
2058 /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
2059 * so compute ms from PRMJ_Now.
2062 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
2063 JSLL_DIV(ms
, us
, us2ms
);
2064 JSLL_L2D(msec_time
, ms
);
2066 return date_format(cx
, msec_time
, FORMATSPEC_FULL
, rval
);
2069 /* Date called as constructor. */
2071 int64 us
, ms
, us2ms
;
2074 date
= date_constructor(cx
, obj
);
2079 JSLL_UI2L(us2ms
, PRMJ_USEC_PER_MSEC
);
2080 JSLL_DIV(ms
, us
, us2ms
);
2081 JSLL_L2D(msec_time
, ms
);
2084 } else if (argc
== 1) {
2085 if (!JSVAL_IS_STRING(argv
[0])) {
2086 /* the argument is a millisecond number */
2087 d
= js_ValueToNumber(cx
, &argv
[0]);
2088 if (JSVAL_IS_NULL(argv
[0]))
2090 date
= date_constructor(cx
, obj
);
2093 *date
= TIMECLIP(d
);
2095 /* the argument is a string; parse it. */
2096 date
= date_constructor(cx
, obj
);
2100 str
= js_ValueToString(cx
, argv
[0]);
2104 if (!date_parseString(str
, date
))
2105 *date
= *cx
->runtime
->jsNaN
;
2106 *date
= TIMECLIP(*date
);
2112 if (!date_msecFromArgs(cx
, argc
, argv
, &msec_time
))
2115 date
= date_constructor(cx
, obj
);
2119 if (JSDOUBLE_IS_FINITE(msec_time
)) {
2120 msec_time
= UTC(msec_time
);
2121 msec_time
= TIMECLIP(msec_time
);
2130 js_InitDateClass(JSContext
*cx
, JSObject
*obj
)
2133 jsdouble
*proto_date
;
2135 /* set static LocalTZA */
2136 LocalTZA
= -(PRMJ_LocalGMTDifference() * msPerSecond
);
2137 proto
= JS_InitClass(cx
, obj
, NULL
, &js_DateClass
, Date
, MAXARGS
,
2138 NULL
, date_methods
, NULL
, date_static_methods
);
2142 /* Alias toUTCString with toGMTString. (ECMA B.2.6) */
2143 if (!JS_AliasProperty(cx
, proto
, "toUTCString", "toGMTString"))
2146 /* Set the value of the Date.prototype date to NaN */
2147 proto_date
= date_constructor(cx
, proto
);
2150 *proto_date
= *cx
->runtime
->jsNaN
;
2155 JS_FRIEND_API(JSObject
*)
2156 js_NewDateObjectMsec(JSContext
*cx
, jsdouble msec_time
)
2161 obj
= js_NewObject(cx
, &js_DateClass
, NULL
, NULL
, 0);
2165 date
= date_constructor(cx
, obj
);
2173 JS_FRIEND_API(JSObject
*)
2174 js_NewDateObject(JSContext
* cx
, int year
, int mon
, int mday
,
2175 int hour
, int min
, int sec
)
2180 JS_ASSERT(mon
< 12);
2181 msec_time
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
2182 obj
= js_NewDateObjectMsec(cx
, UTC(msec_time
));
2186 JS_FRIEND_API(JSBool
)
2187 js_DateIsValid(JSContext
*cx
, JSObject
* obj
)
2190 return GetUTCTime(cx
, obj
, NULL
, &utctime
) && !JSDOUBLE_IS_NaN(utctime
);
2194 js_DateGetYear(JSContext
*cx
, JSObject
* obj
)
2198 /* Preserve legacy API behavior of returning 0 for invalid dates. */
2199 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
) ||
2200 JSDOUBLE_IS_NaN(localtime
)) {
2204 return (int) YearFromTime(localtime
);
2208 js_DateGetMonth(JSContext
*cx
, JSObject
* obj
)
2212 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
) ||
2213 JSDOUBLE_IS_NaN(localtime
)) {
2217 return (int) MonthFromTime(localtime
);
2221 js_DateGetDate(JSContext
*cx
, JSObject
* obj
)
2225 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
) ||
2226 JSDOUBLE_IS_NaN(localtime
)) {
2230 return (int) DateFromTime(localtime
);
2234 js_DateGetHours(JSContext
*cx
, JSObject
* obj
)
2238 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
) ||
2239 JSDOUBLE_IS_NaN(localtime
)) {
2243 return (int) HourFromTime(localtime
);
2247 js_DateGetMinutes(JSContext
*cx
, JSObject
* obj
)
2251 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &localtime
) ||
2252 JSDOUBLE_IS_NaN(localtime
)) {
2256 return (int) MinFromTime(localtime
);
2260 js_DateGetSeconds(JSContext
*cx
, JSObject
* obj
)
2264 if (!GetUTCTime(cx
, obj
, NULL
, &utctime
) || JSDOUBLE_IS_NaN(utctime
))
2267 return (int) SecFromTime(utctime
);
2271 js_DateSetYear(JSContext
*cx
, JSObject
*obj
, int year
)
2275 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2278 /* reset date if it was NaN */
2279 if (JSDOUBLE_IS_NaN(local
))
2282 local
= date_msecFromDate(year
,
2283 MonthFromTime(local
),
2284 DateFromTime(local
),
2285 HourFromTime(local
),
2290 /* SetUTCTime also invalidates local time cache. */
2291 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2295 js_DateSetMonth(JSContext
*cx
, JSObject
*obj
, int month
)
2299 JS_ASSERT(month
< 12);
2301 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2304 /* bail if date was NaN */
2305 if (JSDOUBLE_IS_NaN(local
))
2308 local
= date_msecFromDate(YearFromTime(local
),
2310 DateFromTime(local
),
2311 HourFromTime(local
),
2315 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2319 js_DateSetDate(JSContext
*cx
, JSObject
*obj
, int date
)
2323 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2326 if (JSDOUBLE_IS_NaN(local
))
2329 local
= date_msecFromDate(YearFromTime(local
),
2330 MonthFromTime(local
),
2332 HourFromTime(local
),
2336 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2340 js_DateSetHours(JSContext
*cx
, JSObject
*obj
, int hours
)
2344 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2347 if (JSDOUBLE_IS_NaN(local
))
2349 local
= date_msecFromDate(YearFromTime(local
),
2350 MonthFromTime(local
),
2351 DateFromTime(local
),
2356 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2360 js_DateSetMinutes(JSContext
*cx
, JSObject
*obj
, int minutes
)
2364 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2367 if (JSDOUBLE_IS_NaN(local
))
2369 local
= date_msecFromDate(YearFromTime(local
),
2370 MonthFromTime(local
),
2371 DateFromTime(local
),
2372 HourFromTime(local
),
2376 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2380 js_DateSetSeconds(JSContext
*cx
, JSObject
*obj
, int seconds
)
2384 if (!GetAndCacheLocalTime(cx
, obj
, NULL
, &local
))
2387 if (JSDOUBLE_IS_NaN(local
))
2389 local
= date_msecFromDate(YearFromTime(local
),
2390 MonthFromTime(local
),
2391 DateFromTime(local
),
2392 HourFromTime(local
),
2396 SetUTCTime(cx
, obj
, NULL
, UTC(local
));
2399 JS_FRIEND_API(jsdouble
)
2400 js_DateGetMsecSinceEpoch(JSContext
*cx
, JSObject
*obj
)
2403 if (!GetUTCTime(cx
, obj
, NULL
, &utctime
))