1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* ***** BEGIN LICENSE BLOCK *****
4
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 1.1 (the "License"); you may not use this file except in compliance with
8
* the License. You may obtain a copy of the License at
9
* http://www.mozilla.org/MPL/
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
16
* The Original Code is Mozilla Communicator client code, released
19
* The Initial Developer of the Original Code is
20
* Netscape Communications Corporation.
21
* Portions created by the Initial Developer are Copyright (C) 1998
22
* the Initial Developer. All Rights Reserved.
26
* Alternatively, the contents of this file may be used under the terms of
27
* either of the GNU General Public License Version 2 or later (the "GPL"),
28
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
* in which case the provisions of the GPL or the LGPL are applicable instead
30
* of those above. If you wish to allow use of your version of this file only
31
* under the terms of either the GPL or the LGPL, and not to allow others to
32
* use your version of this file under the terms of the MPL, indicate your
33
* decision by deleting the provisions above and replace them with the notice
34
* and other provisions required by the GPL or the LGPL. If you do not delete
35
* the provisions above, a recipient may use your version of this file under
36
* the terms of any one of the MPL, the GPL or the LGPL.
38
* ***** END LICENSE BLOCK ***** */
45
* "For example, OS/360 devotes 26 bytes of the permanently
46
* resident date-turnover routine to the proper handling of
47
* December 31 on leap years (when it is Day 366). That
48
* might have been left to the operator."
50
* Frederick Brooks, 'The Second-System Effect'.
62
#include "jsutil.h" /* Added by JSIFY */
73
* The JS 'Date' object is patterned after the Java 'Date' object.
78
* print(today.toLocaleString());
80
* weekDay = today.getDay();
83
* These Java (and ECMA-262) methods are supported:
86
* getDate (getUTCDate)
88
* getHours (getUTCHours)
89
* getMinutes (getUTCMinutes)
90
* getMonth (getUTCMonth)
91
* getSeconds (getUTCSeconds)
92
* getMilliseconds (getUTCMilliseconds)
96
* getFullYear (getUTCFullYear)
98
* setDate (setUTCDate)
99
* setHours (setUTCHours)
100
* setMinutes (setUTCMinutes)
101
* setMonth (setUTCMonth)
102
* setSeconds (setUTCSeconds)
103
* setMilliseconds (setUTCMilliseconds)
105
* setYear (setFullYear, setUTCFullYear)
106
* toGMTString (toUTCString)
111
* These Java methods are not supported
121
* 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
122
* definition and reduce dependence on NSPR. NSPR is used to get the current
123
* time in milliseconds, the time zone offset, and the daylight savings time
124
* offset for a given time. NSPR is also used for Date.toLocaleString(), for
125
* locale-specific formatting, and to get a string representing the timezone.
126
* (Which turns out to be platform-dependent.)
129
* (I did some performance tests by timing how long it took to run what
130
* I had of the js ECMA conformance tests.)
132
* - look at saving results across multiple calls to supporting
133
* functions; the toString functions compute some of the same values
134
* multiple times. Although - I took a quick stab at this, and I lost
135
* rather than gained. (Fractionally.) Hard to tell what compilers/processors
136
* are doing these days.
138
* - look at tweaking function return types to return double instead
139
* of int; this seems to make things run slightly faster sometimes.
140
* (though it could be architecture-dependent.) It'd be good to see
141
* how this does on win32. (Tried it on irix.) Types could use a
142
* general going-over.
146
* Supporting functions - ECMA 15.9.1.*
149
#define HalfTimeDomain 8.64e15
150
#define HoursPerDay 24.0
151
#define MinutesPerDay (HoursPerDay * MinutesPerHour)
152
#define MinutesPerHour 60.0
153
#define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
154
#define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
155
#define SecondsPerMinute 60.0
157
#if defined(XP_WIN) || defined(XP_OS2)
158
/* Work around msvc double optimization bug by making these runtime values; if
159
* they're available at compile time, msvc optimizes division by them by
160
* computing the reciprocal and multiplying instead of dividing - this loses
161
* when the reciprocal isn't representable in a double.
163
static jsdouble msPerSecond = 1000.0;
164
static jsdouble msPerDay = SecondsPerDay * 1000.0;
165
static jsdouble msPerHour = SecondsPerHour * 1000.0;
166
static jsdouble msPerMinute = SecondsPerMinute * 1000.0;
168
#define msPerDay (SecondsPerDay * msPerSecond)
169
#define msPerHour (SecondsPerHour * msPerSecond)
170
#define msPerMinute (SecondsPerMinute * msPerSecond)
171
#define msPerSecond 1000.0
174
#define Day(t) floor((t) / msPerDay)
177
TimeWithinDay(jsdouble t)
180
result = fmod(t, msPerDay);
186
#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
189
/* math here has to be f.p, because we need
190
* floor((1968 - 1969) / 4) == -1
192
#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
193
- floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
194
#define TimeFromYear(y) (DayFromYear(y) * msPerDay)
197
YearFromTime(jsdouble t)
199
jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
200
jsdouble t2 = (jsdouble) TimeFromYear(y);
205
if (t2 + msPerDay * DaysInYear(y) <= t)
211
#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
213
#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
216
* The following array contains the day of year for the first day of
217
* each month, where index 0 is January, and day 0 is January 1.
219
static jsdouble firstDayOfMonth[2][12] = {
220
{0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
221
{0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
224
#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
227
MonthFromTime(jsdouble t)
230
jsint year = YearFromTime(t);
231
d = DayWithinYear(t, year);
235
step += (InLeapYear(t) ? 29 : 28);
238
if (d < (step += 31))
240
if (d < (step += 30))
242
if (d < (step += 31))
244
if (d < (step += 30))
246
if (d < (step += 31))
248
if (d < (step += 31))
250
if (d < (step += 30))
252
if (d < (step += 31))
254
if (d < (step += 30))
260
DateFromTime(jsdouble t)
263
jsint year = YearFromTime(t);
264
d = DayWithinYear(t, year);
266
if (d <= (next = 30))
269
next += (InLeapYear(t) ? 29 : 28);
273
if (d <= (next += 31))
276
if (d <= (next += 30))
279
if (d <= (next += 31))
282
if (d <= (next += 30))
285
if (d <= (next += 31))
288
if (d <= (next += 31))
291
if (d <= (next += 30))
294
if (d <= (next += 31))
297
if (d <= (next += 30))
307
result = (jsint) Day(t) + 4;
311
return (intN) result;
314
#define MakeTime(hour, min, sec, ms) \
315
((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
318
MakeDay(jsdouble year, jsdouble month, jsdouble date)
324
year += floor(month / 12);
326
month = fmod(month, 12.0);
330
leap = (DaysInYear((jsint) year) == 366);
332
yearday = floor(TimeFromYear(year) / msPerDay);
333
monthday = DayFromMonth(month, leap);
335
return yearday + monthday + date - 1;
338
#define MakeDate(day, time) ((day) * msPerDay + (time))
341
* Years and leap years on which Jan 1 is a Sunday, Monday, etc.
343
* yearStartingWith[0][i] is an example non-leap year where
344
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
346
* yearStartingWith[1][i] is an example leap year where
347
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
349
static jsint yearStartingWith[2][7] = {
350
{1978, 1973, 1974, 1975, 1981, 1971, 1977},
351
{1984, 1996, 1980, 1992, 1976, 1988, 1972}
355
* Find a year for which any given date will fall on the same weekday.
357
* This function should be used with caution when used other than
358
* for determining DST; it hasn't been proven not to produce an
359
* incorrect year for times near year boundaries.
362
EquivalentYearForDST(jsint year)
367
day = (jsint) DayFromYear(year) + 4;
372
isLeapYear = (DaysInYear(year) == 366);
374
return yearStartingWith[isLeapYear][day];
377
/* LocalTZA gets set by js_InitDateClass() */
378
static jsdouble LocalTZA;
381
DaylightSavingTA(jsdouble t)
389
if (JSDOUBLE_IS_NaN(t))
393
* If earlier than 1970 or after 2038, potentially beyond the ken of
394
* many OSes, map it to an equivalent year before asking.
396
if (t < 0.0 || t > 2145916800000.0) {
400
year = EquivalentYearForDST(YearFromTime(t));
401
day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
402
t = MakeDate(day, TimeWithinDay(t));
405
/* put our t in an LL, and map it to usec for prtime */
407
JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
408
JSLL_MUL(PR_t, PR_t, ms2us);
410
offset = PRMJ_DSTOffset(PR_t);
412
JSLL_DIV(offset, offset, ms2us);
413
JSLL_L2D(result, offset);
418
#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay)
420
#define LocalTime(t) ((t) + AdjustTime(t))
425
return t - AdjustTime(t - LocalTZA);
429
HourFromTime(jsdouble t)
431
intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
433
result += (intN)HoursPerDay;
438
MinFromTime(jsdouble t)
440
intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
442
result += (intN)MinutesPerHour;
447
SecFromTime(jsdouble t)
449
intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
451
result += (intN)SecondsPerMinute;
456
msFromTime(jsdouble t)
458
intN result = (intN) fmod(t, msPerSecond);
460
result += (intN)msPerSecond;
464
#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
465
&& !((d < 0 ? -d : d) > HalfTimeDomain)) \
466
? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
469
* end of ECMA 'support' functions
473
* Other Support routines and definitions
476
JSClass js_DateClass = {
478
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
479
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
480
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
481
JSCLASS_NO_OPTIONAL_MEMBERS
484
/* for use by date_parse */
486
static const char* wtb[] = {
488
"monday", "tuesday", "wednesday", "thursday", "friday",
489
"saturday", "sunday",
490
"january", "february", "march", "april", "may", "june",
491
"july", "august", "september", "october", "november", "december",
497
/* time zone table needs to be expanded */
501
-1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
502
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
503
10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
504
10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
505
10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
506
10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
507
10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
510
/* helper for date_parse */
512
date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
513
int count, int ignoreCase)
515
JSBool result = JS_FALSE;
516
/* return true if matches, otherwise, false */
518
while (count > 0 && s1[s1off] && s2[s2off]) {
520
if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
524
if ((jschar)s1[s1off] != s2[s2off]) {
540
/* find UTC time from given date... no 1900 correction! */
542
date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
543
jsdouble min, jsdouble sec, jsdouble msec)
549
day = MakeDay(year, mon, mday);
550
msec_time = MakeTime(hour, min, sec, msec);
551
result = MakeDate(day, msec_time);
556
* See ECMA 15.9.4.[3-10];
558
/* XXX this function must be above date_parseString to avoid a
559
horrid bug in the Win16 1.52 compiler */
562
date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
564
jsdouble array[MAXARGS];
568
for (loop = 0; loop < MAXARGS; loop++) {
570
if (!js_ValueToNumber(cx, argv[loop], &d))
572
/* return NaN if any arg is NaN */
573
if (!JSDOUBLE_IS_FINITE(d)) {
574
return js_NewNumberValue(cx, d, rval);
576
array[loop] = floor(d);
582
/* adjust 2-digit years into the 20th century */
583
if (array[0] >= 0 && array[0] <= 99)
586
/* if we got a 0 for 'date' (which is out of range)
587
* pretend it's a 1. (So Date.UTC(1972, 5) works) */
591
d = date_msecFromDate(array[0], array[1], array[2],
592
array[3], array[4], array[5], array[6]);
595
return js_NewNumberValue(cx, d, rval);
599
date_parseString(JSString *str, jsdouble *result)
603
const jschar *s = JSSTRING_CHARS(str);
604
size_t limit = JSSTRING_LENGTH(str);
614
jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */
616
JSBool seenplusminus = JS_FALSE;
618
JSBool seenmonthname = JS_FALSE;
625
if (c <= ' ' || c == ',' || c == '-') {
626
if (c == '-' && '0' <= s[i] && s[i] <= '9') {
631
if (c == '(') { /* comments) */
636
if (c == '(') depth++;
643
if ('0' <= c && c <= '9') {
645
while (i < limit && '0' <= (c = s[i]) && c <= '9') {
646
n = n * 10 + c - '0';
650
/* allow TZA before the year, so
651
* 'Wed Nov 05 21:49:11 GMT-0800 1997'
654
/* uses of seenplusminus allow : in TZA, so Java
655
* no-timezone style of GMT+4:30 works
658
if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
659
/* make ':' case below change tzoffset */
660
seenplusminus = JS_TRUE;
664
n = n * 60; /* EG. "GMT-3" */
666
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
667
if (prevc == '+') /* plus means east of GMT */
669
if (tzoffset != 0 && tzoffset != -1)
672
} else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
673
if (c <= ' ' || c == ',' || c == '/' || i >= limit)
677
} else if (c == ':') {
684
} else if (c == '/') {
685
/* until it is determined that mon is the actual
686
month, keep it as 1-based rather than 0-based */
693
} else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
695
} else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
700
} else if (hour >= 0 && min < 0) {
702
} else if (prevc == ':' && min >= 0 && sec < 0) {
704
} else if (mon < 0) {
706
} else if (mon >= 0 && mday < 0) {
708
} else if (mon >= 0 && mday >= 0 && year < 0) {
714
} else if (c == '/' || c == ':' || c == '+' || c == '-') {
721
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
727
for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;)
728
if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
733
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
734
* 12:30, instead of blindly adding 12 if PM.
736
JS_ASSERT(action == -1 || action == -2);
737
if (hour > 12 || hour < 0) {
740
if (action == -1 && hour == 12) { /* am */
742
} else if (action == -2 && hour != 12) { /* pm */
746
} else if (action <= 13) { /* month! */
747
/* Adjust mon to be 1-based until the final values
748
for mon, mday and year are adjusted below */
752
seenmonthname = JS_TRUE;
753
temp = /*byte*/ (action - 2) + 1;
757
} else if (mday < 0) {
760
} else if (year < 0) {
767
tzoffset = action - 10000;
777
if (year < 0 || mon < 0 || mday < 0)
780
Case 1. The input string contains an English month name.
781
The form of the string can be month f l, or f month l, or
782
f l month which each evaluate to the same date.
783
If f and l are both greater than or equal to 70, or
784
both less than 70, the date is invalid.
785
The year is taken to be the greater of the values f, l.
786
If the year is greater than or equal to 70 and less than 100,
787
it is considered to be the number of years after 1900.
788
Case 2. The input string is of the form "f/m/l" where f, m and l are
789
integers, e.g. 7/16/45.
790
Adjust the mon, mday and year values to achieve 100% MSIE
792
a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
793
i. If year < 100, it is the number of years after 1900
794
ii. If year >= 100, it is the number of years after 0.
796
i. If m < 70, f/m/l is interpreted as
797
year/month/day where year is the number of years after
799
ii. If m >= 70, the date is invalid.
801
i. If m < 70, f/m/l is interpreted as
802
year/month/day where year is the number of years after 0.
803
ii. If m >= 70, the date is invalid.
806
if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
814
if (year >= 70 && year < 100) {
817
} else if (mon < 70) { /* (a) month/day/year */
821
} else if (mon < 100) { /* (b) year/month/day */
830
} else { /* (c) year/month/day */
840
mon -= 1; /* convert month to 0-based */
847
if (tzoffset == -1) { /* no time zone specified, have to use local */
849
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
851
*result = UTC(msec_time);
855
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
856
msec += tzoffset * msPerMinute;
867
date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
872
str = js_ValueToString(cx, argv[0]);
875
if (!date_parseString(str, &result)) {
876
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
880
result = TIMECLIP(result);
881
return js_NewNumberValue(cx, result, rval);
885
date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
891
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
892
JSLL_DIV(ms, us, us2ms);
893
JSLL_L2D(msec_time, ms);
895
return js_NewDoubleValue(cx, msec_time, rval);
899
* Check that obj is an object of class Date, and get the date value.
900
* Return NULL on failure.
903
date_getProlog(JSContext *cx, JSObject *obj, jsval *argv)
905
if (!JS_InstanceOf(cx, obj, &js_DateClass, argv))
907
return JSVAL_TO_DOUBLE(OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE));
911
* See ECMA 15.9.5.4 thru 15.9.5.23
914
date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
916
jsdouble *date = date_getProlog(cx, obj, argv);
920
return js_NewNumberValue(cx, *date, rval);
924
date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
929
date = date_getProlog(cx, obj, argv);
934
if (!JSDOUBLE_IS_FINITE(result))
935
return js_NewNumberValue(cx, result, rval);
937
result = YearFromTime(LocalTime(result));
939
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
941
return js_NewNumberValue(cx, result, rval);
945
date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
949
jsdouble *date = date_getProlog(cx, obj, argv);
954
if (!JSDOUBLE_IS_FINITE(result))
955
return js_NewNumberValue(cx, result, rval);
957
result = YearFromTime(LocalTime(result));
958
return js_NewNumberValue(cx, result, rval);
962
date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
966
jsdouble *date = date_getProlog(cx, obj, argv);
971
if (!JSDOUBLE_IS_FINITE(result))
972
return js_NewNumberValue(cx, result, rval);
974
result = YearFromTime(result);
975
return js_NewNumberValue(cx, result, rval);
979
date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
983
jsdouble *date = date_getProlog(cx, obj, argv);
988
if (!JSDOUBLE_IS_FINITE(result))
989
return js_NewNumberValue(cx, result, rval);
991
result = MonthFromTime(LocalTime(result));
992
return js_NewNumberValue(cx, result, rval);
996
date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1000
jsdouble *date = date_getProlog(cx, obj, argv);
1005
if (!JSDOUBLE_IS_FINITE(result))
1006
return js_NewNumberValue(cx, result, rval);
1008
result = MonthFromTime(result);
1009
return js_NewNumberValue(cx, result, rval);
1013
date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1016
jsdouble *date = date_getProlog(cx, obj, argv);
1021
if (!JSDOUBLE_IS_FINITE(result))
1022
return js_NewNumberValue(cx, result, rval);
1024
result = LocalTime(result);
1025
result = DateFromTime(result);
1026
return js_NewNumberValue(cx, result, rval);
1030
date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1034
jsdouble *date = date_getProlog(cx, obj, argv);
1039
if (!JSDOUBLE_IS_FINITE(result))
1040
return js_NewNumberValue(cx, result, rval);
1042
result = DateFromTime(result);
1043
return js_NewNumberValue(cx, result, rval);
1047
date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1050
jsdouble *date = date_getProlog(cx, obj, argv);
1055
if (!JSDOUBLE_IS_FINITE(result))
1056
return js_NewNumberValue(cx, result, rval);
1058
result = LocalTime(result);
1059
result = WeekDay(result);
1060
return js_NewNumberValue(cx, result, rval);
1064
date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1068
jsdouble *date = date_getProlog(cx, obj, argv);
1073
if (!JSDOUBLE_IS_FINITE(result))
1074
return js_NewNumberValue(cx, result, rval);
1076
result = WeekDay(result);
1077
return js_NewNumberValue(cx, result, rval);
1081
date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1085
jsdouble *date = date_getProlog(cx, obj, argv);
1090
if (!JSDOUBLE_IS_FINITE(result))
1091
return js_NewNumberValue(cx, result, rval);
1093
result = HourFromTime(LocalTime(result));
1094
return js_NewNumberValue(cx, result, rval);
1098
date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1102
jsdouble *date = date_getProlog(cx, obj, argv);
1107
if (!JSDOUBLE_IS_FINITE(result))
1108
return js_NewNumberValue(cx, result, rval);
1110
result = HourFromTime(result);
1111
return js_NewNumberValue(cx, result, rval);
1115
date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1119
jsdouble *date = date_getProlog(cx, obj, argv);
1124
if (!JSDOUBLE_IS_FINITE(result))
1125
return js_NewNumberValue(cx, result, rval);
1127
result = MinFromTime(LocalTime(result));
1128
return js_NewNumberValue(cx, result, rval);
1132
date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1136
jsdouble *date = date_getProlog(cx, obj, argv);
1141
if (!JSDOUBLE_IS_FINITE(result))
1142
return js_NewNumberValue(cx, result, rval);
1144
result = MinFromTime(result);
1145
return js_NewNumberValue(cx, result, rval);
1148
/* Date.getSeconds is mapped to getUTCSeconds */
1151
date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1155
jsdouble *date = date_getProlog(cx, obj, argv);
1160
if (!JSDOUBLE_IS_FINITE(result))
1161
return js_NewNumberValue(cx, result, rval);
1163
result = SecFromTime(result);
1164
return js_NewNumberValue(cx, result, rval);
1167
/* Date.getMilliseconds is mapped to getUTCMilliseconds */
1170
date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1174
jsdouble *date = date_getProlog(cx, obj, argv);
1179
if (!JSDOUBLE_IS_FINITE(result))
1180
return js_NewNumberValue(cx, result, rval);
1182
result = msFromTime(result);
1183
return js_NewNumberValue(cx, result, rval);
1187
date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1191
jsdouble *date = date_getProlog(cx, obj, argv);
1197
* Return the time zone offset in minutes for the current locale
1198
* that is appropriate for this time. This value would be a
1199
* constant except for daylight savings time.
1201
result = (result - LocalTime(result)) / msPerMinute;
1202
return js_NewNumberValue(cx, result, rval);
1206
date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1209
jsdouble *date = date_getProlog(cx, obj, argv);
1213
if (!js_ValueToNumber(cx, argv[0], &result))
1216
result = TIMECLIP(result);
1219
return js_NewNumberValue(cx, result, rval);
1223
date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1224
uintN maxargs, JSBool local, jsval *rval)
1227
jsdouble args[4], *argp, *stop;
1228
jsdouble hour, min, sec, msec;
1229
jsdouble lorutime; /* Local or UTC version of *date */
1234
jsdouble *date = date_getProlog(cx, obj, argv);
1240
/* just return NaN if the date is already NaN */
1241
if (!JSDOUBLE_IS_FINITE(result))
1242
return js_NewNumberValue(cx, result, rval);
1244
/* Satisfy the ECMA rule that if a function is called with
1245
* fewer arguments than the specified formal arguments, the
1246
* remaining arguments are set to undefined. Seems like all
1247
* the Date.setWhatever functions in ECMA are only varargs
1248
* beyond the first argument; this should be set to undefined
1249
* if it's not given. This means that "d = new Date();
1250
* d.setMilliseconds()" returns NaN. Blech.
1253
argc = 1; /* should be safe, because length of all setters is 1 */
1254
else if (argc > maxargs)
1255
argc = maxargs; /* clamp argc */
1257
for (i = 0; i < argc; i++) {
1258
if (!js_ValueToNumber(cx, argv[i], &args[i]))
1260
if (!JSDOUBLE_IS_FINITE(args[i])) {
1261
*date = *cx->runtime->jsNaN;
1262
return js_NewNumberValue(cx, *date, rval);
1264
args[i] = js_DoubleToInteger(args[i]);
1268
lorutime = LocalTime(result);
1274
if (maxargs >= 4 && argp < stop)
1277
hour = HourFromTime(lorutime);
1279
if (maxargs >= 3 && argp < stop)
1282
min = MinFromTime(lorutime);
1284
if (maxargs >= 2 && argp < stop)
1287
sec = SecFromTime(lorutime);
1289
if (maxargs >= 1 && argp < stop)
1292
msec = msFromTime(lorutime);
1294
msec_time = MakeTime(hour, min, sec, msec);
1295
result = MakeDate(Day(lorutime), msec_time);
1297
/* fprintf(stderr, "%f\n", result); */
1300
result = UTC(result);
1302
/* fprintf(stderr, "%f\n", result); */
1304
*date = TIMECLIP(result);
1305
return js_NewNumberValue(cx, *date, rval);
1309
date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
1310
jsval *argv, jsval *rval)
1312
return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval);
1316
date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
1317
jsval *argv, jsval *rval)
1319
return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval);
1323
date_setSeconds(JSContext *cx, JSObject *obj, uintN argc,
1324
jsval *argv, jsval *rval)
1326
return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval);
1330
date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc,
1331
jsval *argv, jsval *rval)
1333
return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval);
1337
date_setMinutes(JSContext *cx, JSObject *obj, uintN argc,
1338
jsval *argv, jsval *rval)
1340
return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval);
1344
date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc,
1345
jsval *argv, jsval *rval)
1347
return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval);
1351
date_setHours(JSContext *cx, JSObject *obj, uintN argc,
1352
jsval *argv, jsval *rval)
1354
return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval);
1358
date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc,
1359
jsval *argv, jsval *rval)
1361
return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval);
1365
date_makeDate(JSContext *cx, JSObject *obj, uintN argc,
1366
jsval *argv, uintN maxargs, JSBool local, jsval *rval)
1369
jsdouble lorutime; /* local or UTC version of *date */
1370
jsdouble args[3], *argp, *stop;
1371
jsdouble year, month, day;
1374
jsdouble *date = date_getProlog(cx, obj, argv);
1380
/* see complaint about ECMA in date_MakeTime */
1382
argc = 1; /* should be safe, because length of all setters is 1 */
1383
else if (argc > maxargs)
1384
argc = maxargs; /* clamp argc */
1386
for (i = 0; i < argc; i++) {
1387
if (!js_ValueToNumber(cx, argv[i], &args[i]))
1389
if (!JSDOUBLE_IS_FINITE(args[i])) {
1390
*date = *cx->runtime->jsNaN;
1391
return js_NewNumberValue(cx, *date, rval);
1393
args[i] = js_DoubleToInteger(args[i]);
1396
/* return NaN if date is NaN and we're not setting the year,
1397
* If we are, use 0 as the time. */
1398
if (!(JSDOUBLE_IS_FINITE(result))) {
1400
return js_NewNumberValue(cx, result, rval);
1405
lorutime = LocalTime(result);
1412
if (maxargs >= 3 && argp < stop)
1415
year = YearFromTime(lorutime);
1417
if (maxargs >= 2 && argp < stop)
1420
month = MonthFromTime(lorutime);
1422
if (maxargs >= 1 && argp < stop)
1425
day = DateFromTime(lorutime);
1427
day = MakeDay(year, month, day); /* day within year */
1428
result = MakeDate(day, TimeWithinDay(lorutime));
1431
result = UTC(result);
1433
*date = TIMECLIP(result);
1434
return js_NewNumberValue(cx, *date, rval);
1438
date_setDate(JSContext *cx, JSObject *obj, uintN argc,
1439
jsval *argv, jsval *rval)
1441
return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval);
1445
date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc,
1446
jsval *argv, jsval *rval)
1448
return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval);
1452
date_setMonth(JSContext *cx, JSObject *obj, uintN argc,
1453
jsval *argv, jsval *rval)
1455
return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval);
1459
date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc,
1460
jsval *argv, jsval *rval)
1462
return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval);
1466
date_setFullYear(JSContext *cx, JSObject *obj, uintN argc,
1467
jsval *argv, jsval *rval)
1469
return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval);
1473
date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc,
1474
jsval *argv, jsval *rval)
1476
return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval);
1480
date_setYear(JSContext *cx, JSObject *obj, uintN argc,
1481
jsval *argv, jsval *rval)
1488
jsdouble *date = date_getProlog(cx, obj, argv);
1494
if (!js_ValueToNumber(cx, argv[0], &year))
1496
if (!JSDOUBLE_IS_FINITE(year)) {
1497
*date = *cx->runtime->jsNaN;
1498
return js_NewNumberValue(cx, *date, rval);
1501
year = js_DoubleToInteger(year);
1503
if (!JSDOUBLE_IS_FINITE(result)) {
1506
t = LocalTime(result);
1509
if (year >= 0 && year <= 99)
1512
day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
1513
result = MakeDate(day, TimeWithinDay(t));
1514
result = UTC(result);
1516
*date = TIMECLIP(result);
1517
return js_NewNumberValue(cx, *date, rval);
1520
/* constants for toString, toUTCString */
1521
static char js_NaN_date_str[] = "Invalid Date";
1522
static const char* days[] =
1524
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1526
static const char* months[] =
1528
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1532
date_toGMTString(JSContext *cx, JSObject *obj, uintN argc,
1533
jsval *argv, jsval *rval)
1537
jsdouble *date = date_getProlog(cx, obj, argv);
1541
if (!JSDOUBLE_IS_FINITE(*date)) {
1542
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1544
jsdouble temp = *date;
1546
/* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1547
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1549
JS_snprintf(buf, sizeof buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
1550
days[WeekDay(temp)],
1552
months[MonthFromTime(temp)],
1558
str = JS_NewStringCopyZ(cx, buf);
1561
*rval = STRING_TO_JSVAL(str);
1565
/* for Date.toLocaleString; interface to PRMJTime date struct.
1566
* If findEquivalent is true, then try to map the year to an equivalent year
1570
new_explode(jsdouble timeval, PRMJTime *split, JSBool findEquivalent)
1572
jsint year = YearFromTime(timeval);
1575
/* If the year doesn't fit in a PRMJTime, find something to do about it. */
1576
if (year > 32767 || year < -32768) {
1577
if (findEquivalent) {
1578
/* We're really just trying to get a timezone string; map the year
1579
* to some equivalent year in the range 0 to 2800. Borrowed from
1583
#define CYCLE_YEARS 2800L
1584
cycles = (year >= 0) ? year / CYCLE_YEARS
1585
: -1 - (-1 - year) / CYCLE_YEARS;
1586
adjustedYear = (int16)(year - cycles * CYCLE_YEARS);
1588
/* Clamp it to the nearest representable year. */
1589
adjustedYear = (int16)((year > 0) ? 32767 : - 32768);
1592
adjustedYear = (int16)year;
1595
split->tm_usec = (int32) msFromTime(timeval) * 1000;
1596
split->tm_sec = (int8) SecFromTime(timeval);
1597
split->tm_min = (int8) MinFromTime(timeval);
1598
split->tm_hour = (int8) HourFromTime(timeval);
1599
split->tm_mday = (int8) DateFromTime(timeval);
1600
split->tm_mon = (int8) MonthFromTime(timeval);
1601
split->tm_wday = (int8) WeekDay(timeval);
1602
split->tm_year = (int16) adjustedYear;
1603
split->tm_yday = (int16) DayWithinYear(timeval, year);
1605
/* not sure how this affects things, but it doesn't seem
1607
split->tm_isdst = (DaylightSavingTA(timeval) != 0);
1610
typedef enum formatspec {
1611
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
1614
/* helper function */
1616
date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
1625
if (!JSDOUBLE_IS_FINITE(date)) {
1626
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1628
jsdouble local = LocalTime(date);
1630
/* offset from GMT in minutes. The offset includes daylight savings,
1632
jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute);
1634
/* map 510 minutes to 0830 hours */
1635
intN offset = (minutes / 60) * 100 + minutes % 60;
1637
/* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
1638
* printed as 'GMT-0800' rather than as 'PST' to avoid
1639
* operating-system dependence on strftime (which
1640
* PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
1641
* PST as 'Pacific Standard Time.' This way we always know
1642
* what we're getting, and can parse it if we produce it.
1643
* The OS TZA string is included as a comment.
1646
/* get a timezone string from the OS to include as a
1648
new_explode(date, &split, JS_TRUE);
1649
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
1651
/* Decide whether to use the resulting timezone string.
1653
* Reject it if it contains any non-ASCII, non-alphanumeric
1654
* characters. It's then likely in some other character
1655
* encoding, and we probably won't display it correctly.
1658
tzlen = strlen(tzbuf);
1662
for (i = 0; i < tzlen; i++) {
1663
jschar c = tzbuf[i];
1665
!(isalpha(c) || isdigit(c) ||
1666
c == ' ' || c == '(' || c == ')')) {
1672
/* Also reject it if it's not parenthesized or if it's '()'. */
1673
if (tzbuf[0] != '(' || tzbuf[1] == ')')
1679
case FORMATSPEC_FULL:
1681
* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
1682
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
1684
/* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
1685
JS_snprintf(buf, sizeof buf,
1686
"%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
1687
days[WeekDay(local)],
1688
months[MonthFromTime(local)],
1689
DateFromTime(local),
1690
YearFromTime(local),
1691
HourFromTime(local),
1696
usetz ? tzbuf : "");
1698
case FORMATSPEC_DATE:
1699
/* Tue Oct 31 2000 */
1700
JS_snprintf(buf, sizeof buf,
1702
days[WeekDay(local)],
1703
months[MonthFromTime(local)],
1704
DateFromTime(local),
1705
YearFromTime(local));
1707
case FORMATSPEC_TIME:
1708
/* 09:41:40 GMT-0800 (PST) */
1709
JS_snprintf(buf, sizeof buf,
1710
"%.2d:%.2d:%.2d GMT%+.4d%s%s",
1711
HourFromTime(local),
1716
usetz ? tzbuf : "");
1721
str = JS_NewStringCopyZ(cx, buf);
1724
*rval = STRING_TO_JSVAL(str);
1729
date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc,
1730
jsval *argv, jsval *rval, char *format)
1735
jsdouble *date = date_getProlog(cx, obj, argv);
1739
if (!JSDOUBLE_IS_FINITE(*date)) {
1740
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
1743
jsdouble local = LocalTime(*date);
1744
new_explode(local, &split, JS_FALSE);
1746
/* let PRMJTime format it. */
1747
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
1749
/* If it failed, default to toString. */
1750
if (result_len == 0)
1751
return date_format(cx, *date, FORMATSPEC_FULL, rval);
1753
/* Hacked check against undesired 2-digit year 00/00/00 form. */
1754
if (strcmp(format, "%x") == 0 && result_len >= 6 &&
1755
/* Format %x means use OS settings, which may have 2-digit yr, so
1756
hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
1757
!isdigit(buf[result_len - 3]) &&
1758
isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
1759
/* ...but not if starts with 4-digit year, like 2022/3/11. */
1760
!(isdigit(buf[0]) && isdigit(buf[1]) &&
1761
isdigit(buf[2]) && isdigit(buf[3]))) {
1762
JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
1763
"%d", js_DateGetYear(cx, obj));
1768
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
1769
return cx->localeCallbacks->localeToUnicode(cx, buf, rval);
1771
str = JS_NewStringCopyZ(cx, buf);
1774
*rval = STRING_TO_JSVAL(str);
1779
date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
1780
jsval *argv, jsval *rval)
1782
/* Use '%#c' for windows, because '%c' is
1783
* backward-compatible and non-y2k with msvc; '%#c' requests that a
1784
* full year be used in the result string.
1786
return date_toLocaleHelper(cx, obj, argc, argv, rval,
1787
#if defined(_WIN32) && !defined(__MWERKS__)
1796
date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc,
1797
jsval *argv, jsval *rval)
1799
/* Use '%#x' for windows, because '%x' is
1800
* backward-compatible and non-y2k with msvc; '%#x' requests that a
1801
* full year be used in the result string.
1803
return date_toLocaleHelper(cx, obj, argc, argv, rval,
1804
#if defined(_WIN32) && !defined(__MWERKS__)
1813
date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc,
1814
jsval *argv, jsval *rval)
1816
return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X");
1820
date_toLocaleFormat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1826
return date_toLocaleString(cx, obj, argc, argv, rval);
1828
fmt = JS_ValueToString(cx, argv[0]);
1832
return date_toLocaleHelper(cx, obj, argc, argv, rval,
1833
JS_GetStringBytes(fmt));
1837
date_toTimeString(JSContext *cx, JSObject *obj, uintN argc,
1838
jsval *argv, jsval *rval)
1840
jsdouble *date = date_getProlog(cx, obj, argv);
1843
return date_format(cx, *date, FORMATSPEC_TIME, rval);
1847
date_toDateString(JSContext *cx, JSObject *obj, uintN argc,
1848
jsval *argv, jsval *rval)
1850
jsdouble *date = date_getProlog(cx, obj, argv);
1853
return date_format(cx, *date, FORMATSPEC_DATE, rval);
1861
date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1865
char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes;
1868
date = date_getProlog(cx, obj, argv);
1872
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *date);
1874
JS_ReportOutOfMemory(cx);
1878
bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
1880
JS_ReportOutOfMemory(cx);
1884
str = JS_NewString(cx, bytes, strlen(bytes));
1889
*rval = STRING_TO_JSVAL(str);
1895
date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1898
jsdouble *date = date_getProlog(cx, obj, argv);
1901
return date_format(cx, *date, FORMATSPEC_FULL, rval);
1905
date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1908
/* It is an error to call date_valueOf on a non-date object, but we don't
1909
* need to check for that explicitly here because every path calls
1910
* date_getProlog, which does the check.
1913
/* If called directly with no arguments, convert to a time number. */
1915
return date_getTime(cx, obj, argc, argv, rval);
1917
/* Convert to number only if the hint was given, otherwise favor string. */
1919
JSString *str, *str2;
1921
str = js_ValueToString(cx, argv[0]);
1924
str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
1925
if (js_EqualStrings(str, str2))
1926
return date_getTime(cx, obj, argc, argv, rval);
1928
return date_toString(cx, obj, argc, argv, rval);
1933
* creation and destruction
1936
static JSFunctionSpec date_static_methods[] = {
1937
{"UTC", date_UTC, MAXARGS,0,0 },
1938
{"parse", date_parse, 1,0,0 },
1939
{"now", date_now, 0,0,0 },
1943
static JSFunctionSpec date_methods[] = {
1944
{"getTime", date_getTime, 0,0,0 },
1945
{"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 },
1946
{"getYear", date_getYear, 0,0,0 },
1947
{"getFullYear", date_getFullYear, 0,0,0 },
1948
{"getUTCFullYear", date_getUTCFullYear, 0,0,0 },
1949
{"getMonth", date_getMonth, 0,0,0 },
1950
{"getUTCMonth", date_getUTCMonth, 0,0,0 },
1951
{"getDate", date_getDate, 0,0,0 },
1952
{"getUTCDate", date_getUTCDate, 0,0,0 },
1953
{"getDay", date_getDay, 0,0,0 },
1954
{"getUTCDay", date_getUTCDay, 0,0,0 },
1955
{"getHours", date_getHours, 0,0,0 },
1956
{"getUTCHours", date_getUTCHours, 0,0,0 },
1957
{"getMinutes", date_getMinutes, 0,0,0 },
1958
{"getUTCMinutes", date_getUTCMinutes, 0,0,0 },
1959
{"getSeconds", date_getUTCSeconds, 0,0,0 },
1960
{"getUTCSeconds", date_getUTCSeconds, 0,0,0 },
1961
{"getMilliseconds", date_getUTCMilliseconds,0,0,0 },
1962
{"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 },
1963
{"setTime", date_setTime, 1,0,0 },
1964
{"setYear", date_setYear, 1,0,0 },
1965
{"setFullYear", date_setFullYear, 3,0,0 },
1966
{"setUTCFullYear", date_setUTCFullYear, 3,0,0 },
1967
{"setMonth", date_setMonth, 2,0,0 },
1968
{"setUTCMonth", date_setUTCMonth, 2,0,0 },
1969
{"setDate", date_setDate, 1,0,0 },
1970
{"setUTCDate", date_setUTCDate, 1,0,0 },
1971
{"setHours", date_setHours, 4,0,0 },
1972
{"setUTCHours", date_setUTCHours, 4,0,0 },
1973
{"setMinutes", date_setMinutes, 3,0,0 },
1974
{"setUTCMinutes", date_setUTCMinutes, 3,0,0 },
1975
{"setSeconds", date_setSeconds, 2,0,0 },
1976
{"setUTCSeconds", date_setUTCSeconds, 2,0,0 },
1977
{"setMilliseconds", date_setMilliseconds, 1,0,0 },
1978
{"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 },
1979
{"toUTCString", date_toGMTString, 0,0,0 },
1980
{js_toLocaleString_str, date_toLocaleString, 0,0,0 },
1981
{"toLocaleDateString", date_toLocaleDateString,0,0,0 },
1982
{"toLocaleTimeString", date_toLocaleTimeString,0,0,0 },
1983
{"toLocaleFormat", date_toLocaleFormat, 1,0,0 },
1984
{"toDateString", date_toDateString, 0,0,0 },
1985
{"toTimeString", date_toTimeString, 0,0,0 },
1987
{js_toSource_str, date_toSource, 0,0,0 },
1989
{js_toString_str, date_toString, 0,0,0 },
1990
{js_valueOf_str, date_valueOf, 0,0,0 },
1995
date_constructor(JSContext *cx, JSObject* obj)
1999
date = js_NewDouble(cx, 0.0, 0);
2002
OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date));
2007
Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2013
/* Date called as function. */
2014
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
2015
int64 us, ms, us2ms;
2018
/* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
2019
* so compute ms from PRMJ_Now.
2022
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
2023
JSLL_DIV(ms, us, us2ms);
2024
JSLL_L2D(msec_time, ms);
2026
return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
2029
/* Date called as constructor. */
2031
int64 us, ms, us2ms;
2034
date = date_constructor(cx, obj);
2039
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
2040
JSLL_DIV(ms, us, us2ms);
2041
JSLL_L2D(msec_time, ms);
2044
} else if (argc == 1) {
2045
if (!JSVAL_IS_STRING(argv[0])) {
2046
/* the argument is a millisecond number */
2047
if (!js_ValueToNumber(cx, argv[0], &d))
2049
date = date_constructor(cx, obj);
2052
*date = TIMECLIP(d);
2054
/* the argument is a string; parse it. */
2055
date = date_constructor(cx, obj);
2059
str = js_ValueToString(cx, argv[0]);
2063
if (!date_parseString(str, date))
2064
*date = *cx->runtime->jsNaN;
2065
*date = TIMECLIP(*date);
2068
jsdouble array[MAXARGS];
2070
jsdouble double_arg;
2074
for (loop = 0; loop < MAXARGS; loop++) {
2076
if (!js_ValueToNumber(cx, argv[loop], &double_arg))
2078
/* if any arg is NaN, make a NaN date object
2080
if (!JSDOUBLE_IS_FINITE(double_arg)) {
2081
date = date_constructor(cx, obj);
2084
*date = *cx->runtime->jsNaN;
2087
array[loop] = js_DoubleToInteger(double_arg);
2090
array[loop] = 1; /* Default the date argument to 1. */
2097
date = date_constructor(cx, obj);
2101
/* adjust 2-digit years into the 20th century */
2102
if (array[0] >= 0 && array[0] <= 99)
2105
day = MakeDay(array[0], array[1], array[2]);
2106
msec_time = MakeTime(array[3], array[4], array[5], array[6]);
2107
msec_time = MakeDate(day, msec_time);
2108
msec_time = UTC(msec_time);
2109
*date = TIMECLIP(msec_time);
2115
js_InitDateClass(JSContext *cx, JSObject *obj)
2118
jsdouble *proto_date;
2120
/* set static LocalTZA */
2121
LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
2122
proto = JS_InitClass(cx, obj, NULL, &js_DateClass, Date, MAXARGS,
2123
NULL, date_methods, NULL, date_static_methods);
2127
/* Alias toUTCString with toGMTString. (ECMA B.2.6) */
2128
if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
2131
/* Set the value of the Date.prototype date to NaN */
2132
proto_date = date_constructor(cx, proto);
2135
*proto_date = *cx->runtime->jsNaN;
2140
JS_FRIEND_API(JSObject *)
2141
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
2146
obj = js_NewObject(cx, &js_DateClass, NULL, NULL);
2150
date = date_constructor(cx, obj);
2158
JS_FRIEND_API(JSObject *)
2159
js_NewDateObject(JSContext* cx, int year, int mon, int mday,
2160
int hour, int min, int sec)
2165
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
2166
obj = js_NewDateObjectMsec(cx, UTC(msec_time));
2170
JS_FRIEND_API(JSBool)
2171
js_DateIsValid(JSContext *cx, JSObject* obj)
2173
jsdouble *date = date_getProlog(cx, obj, NULL);
2175
if (!date || JSDOUBLE_IS_NaN(*date))
2182
js_DateGetYear(JSContext *cx, JSObject* obj)
2184
jsdouble *date = date_getProlog(cx, obj, NULL);
2186
/* Preserve legacy API behavior of returning 0 for invalid dates. */
2187
if (!date || JSDOUBLE_IS_NaN(*date))
2189
return (int) YearFromTime(LocalTime(*date));
2193
js_DateGetMonth(JSContext *cx, JSObject* obj)
2195
jsdouble *date = date_getProlog(cx, obj, NULL);
2197
if (!date || JSDOUBLE_IS_NaN(*date))
2199
return (int) MonthFromTime(LocalTime(*date));
2203
js_DateGetDate(JSContext *cx, JSObject* obj)
2205
jsdouble *date = date_getProlog(cx, obj, NULL);
2207
if (!date || JSDOUBLE_IS_NaN(*date))
2209
return (int) DateFromTime(LocalTime(*date));
2213
js_DateGetHours(JSContext *cx, JSObject* obj)
2215
jsdouble *date = date_getProlog(cx, obj, NULL);
2217
if (!date || JSDOUBLE_IS_NaN(*date))
2219
return (int) HourFromTime(LocalTime(*date));
2223
js_DateGetMinutes(JSContext *cx, JSObject* obj)
2225
jsdouble *date = date_getProlog(cx, obj, NULL);
2227
if (!date || JSDOUBLE_IS_NaN(*date))
2229
return (int) MinFromTime(LocalTime(*date));
2233
js_DateGetSeconds(JSContext *cx, JSObject* obj)
2235
jsdouble *date = date_getProlog(cx, obj, NULL);
2237
if (!date || JSDOUBLE_IS_NaN(*date))
2239
return (int) SecFromTime(*date);
2243
js_DateSetYear(JSContext *cx, JSObject *obj, int year)
2246
jsdouble *date = date_getProlog(cx, obj, NULL);
2249
local = LocalTime(*date);
2250
/* reset date if it was NaN */
2251
if (JSDOUBLE_IS_NaN(local))
2253
local = date_msecFromDate(year,
2254
MonthFromTime(local),
2255
DateFromTime(local),
2256
HourFromTime(local),
2264
js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
2267
jsdouble *date = date_getProlog(cx, obj, NULL);
2270
local = LocalTime(*date);
2271
/* bail if date was NaN */
2272
if (JSDOUBLE_IS_NaN(local))
2274
local = date_msecFromDate(YearFromTime(local),
2276
DateFromTime(local),
2277
HourFromTime(local),
2285
js_DateSetDate(JSContext *cx, JSObject *obj, int date)
2288
jsdouble *datep = date_getProlog(cx, obj, NULL);
2291
local = LocalTime(*datep);
2292
if (JSDOUBLE_IS_NaN(local))
2294
local = date_msecFromDate(YearFromTime(local),
2295
MonthFromTime(local),
2297
HourFromTime(local),
2301
*datep = UTC(local);
2305
js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
2308
jsdouble *date = date_getProlog(cx, obj, NULL);
2311
local = LocalTime(*date);
2312
if (JSDOUBLE_IS_NaN(local))
2314
local = date_msecFromDate(YearFromTime(local),
2315
MonthFromTime(local),
2316
DateFromTime(local),
2325
js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
2328
jsdouble *date = date_getProlog(cx, obj, NULL);
2331
local = LocalTime(*date);
2332
if (JSDOUBLE_IS_NaN(local))
2334
local = date_msecFromDate(YearFromTime(local),
2335
MonthFromTime(local),
2336
DateFromTime(local),
2337
HourFromTime(local),
2345
js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
2348
jsdouble *date = date_getProlog(cx, obj, NULL);
2351
local = LocalTime(*date);
2352
if (JSDOUBLE_IS_NaN(local))
2354
local = date_msecFromDate(YearFromTime(local),
2355
MonthFromTime(local),
2356
DateFromTime(local),
2357
HourFromTime(local),
2364
JS_FRIEND_API(jsdouble)
2365
js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
2367
jsdouble *date = date_getProlog(cx, obj, NULL);
2368
if (!date || JSDOUBLE_IS_NaN(*date))