1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 * "For example, OS/360 devotes 26 bytes of the permanently
11 * resident date-turnover routine to the proper handling of
12 * December 31 on leap years (when it is Day 366). That
13 * might have been left to the operator."
15 * Frederick Brooks, 'The Second-System Effect'.
20 #include "mozilla/ArrayUtils.h"
21 #include "mozilla/FloatingPoint.h"
35 #include "jswrapper.h"
39 #include "vm/DateTime.h"
40 #include "vm/GlobalObject.h"
41 #include "vm/Interpreter.h"
42 #include "vm/NumericConversions.h"
43 #include "vm/String.h"
44 #include "vm/StringBuffer.h"
46 #include "jsobjinlines.h"
49 using namespace js::types
;
51 using mozilla::ArrayLength
;
52 using mozilla::IsFinite
;
55 using JS::AutoCheckCannotGC
;
59 * The JS 'Date' object is patterned after the Java 'Date' object.
64 * print(today.toLocaleString());
66 * weekDay = today.getDay();
69 * These Java (and ECMA-262) methods are supported:
72 * getDate (getUTCDate)
74 * getHours (getUTCHours)
75 * getMinutes (getUTCMinutes)
76 * getMonth (getUTCMonth)
77 * getSeconds (getUTCSeconds)
78 * getMilliseconds (getUTCMilliseconds)
82 * getFullYear (getUTCFullYear)
84 * setDate (setUTCDate)
85 * setHours (setUTCHours)
86 * setMinutes (setUTCMinutes)
87 * setMonth (setUTCMonth)
88 * setSeconds (setUTCSeconds)
89 * setMilliseconds (setUTCMilliseconds)
91 * setYear (setFullYear, setUTCFullYear)
92 * toGMTString (toUTCString)
97 * These Java methods are not supported
109 return floor(t
/ msPerDay
);
113 TimeWithinDay(double t
)
115 double result
= fmod(t
, msPerDay
);
123 IsLeapYear(double year
)
125 JS_ASSERT(ToInteger(year
) == year
);
126 return fmod(year
, 4) == 0 && (fmod(year
, 100) != 0 || fmod(year
, 400) == 0);
130 DaysInYear(double year
)
134 return IsLeapYear(year
) ? 366 : 365;
138 DayFromYear(double y
)
140 return 365 * (y
- 1970) +
141 floor((y
- 1969) / 4.0) -
142 floor((y
- 1901) / 100.0) +
143 floor((y
- 1601) / 400.0);
147 TimeFromYear(double y
)
149 return DayFromYear(y
) * msPerDay
;
153 YearFromTime(double t
)
158 JS_ASSERT(ToInteger(t
) == t
);
160 double y
= floor(t
/ (msPerDay
* 365.2425)) + 1970;
161 double t2
= TimeFromYear(y
);
164 * Adjust the year if the approximation was wrong. Since the year was
165 * computed using the average number of ms per year, it will usually
166 * be wrong for dates within several hours of a year transition.
171 if (t2
+ msPerDay
* DaysInYear(y
) <= t
)
178 DaysInFebruary(double year
)
180 return IsLeapYear(year
) ? 29 : 28;
185 DayWithinYear(double t
, double year
)
187 JS_ASSERT_IF(IsFinite(t
), YearFromTime(t
) == year
);
188 return Day(t
) - DayFromYear(year
);
192 MonthFromTime(double t
)
197 double year
= YearFromTime(t
);
198 double d
= DayWithinYear(t
, year
);
203 if (d
< (step
+= DaysInFebruary(year
)))
205 if (d
< (step
+= 31))
207 if (d
< (step
+= 30))
209 if (d
< (step
+= 31))
211 if (d
< (step
+= 30))
213 if (d
< (step
+= 31))
215 if (d
< (step
+= 31))
217 if (d
< (step
+= 30))
219 if (d
< (step
+= 31))
221 if (d
< (step
+= 30))
228 DateFromTime(double t
)
233 double year
= YearFromTime(t
);
234 double d
= DayWithinYear(t
, year
);
237 if (d
<= (next
= 30))
240 if (d
<= (next
+= DaysInFebruary(year
)))
243 if (d
<= (next
+= 31))
246 if (d
<= (next
+= 30))
249 if (d
<= (next
+= 31))
252 if (d
<= (next
+= 30))
255 if (d
<= (next
+= 31))
258 if (d
<= (next
+= 31))
261 if (d
<= (next
+= 30))
264 if (d
<= (next
+= 31))
267 if (d
<= (next
+= 30))
278 * We can't assert TimeClip(t) == t because we call this function with
279 * local times, which can be offset outside TimeClip's permitted range.
281 JS_ASSERT(ToInteger(t
) == t
);
282 int result
= (int(Day(t
)) + 4) % 7;
289 DayFromMonth(int month
, bool isLeapYear
)
292 * The following array contains the day of year for the first day of
293 * each month, where index 0 is January, and day 0 is January 1.
295 static const int firstDayOfMonth
[2][13] = {
296 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
297 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
300 JS_ASSERT(0 <= month
&& month
<= 12);
301 return firstDayOfMonth
[isLeapYear
][month
];
306 DayFromMonth(T month
, bool isLeapYear
) MOZ_DELETE
;
308 /* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
310 MakeDay(double year
, double month
, double date
)
313 if (!IsFinite(year
) || !IsFinite(month
) || !IsFinite(date
))
317 double y
= ToInteger(year
);
318 double m
= ToInteger(month
);
319 double dt
= ToInteger(date
);
322 double ym
= y
+ floor(m
/ 12);
325 int mn
= int(fmod(m
, 12.0));
330 bool leap
= IsLeapYear(ym
);
332 double yearday
= floor(TimeFromYear(ym
) / msPerDay
);
333 double monthday
= DayFromMonth(mn
, leap
);
335 return yearday
+ monthday
+ dt
- 1;
338 /* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
340 MakeDate(double day
, double time
)
343 if (!IsFinite(day
) || !IsFinite(time
))
347 return day
* msPerDay
+ time
;
350 JS_PUBLIC_API(double)
351 JS::MakeDate(double year
, unsigned month
, unsigned day
)
353 return TimeClip(::MakeDate(MakeDay(year
, month
, day
), 0));
356 JS_PUBLIC_API(double)
357 JS::YearFromTime(double time
)
359 return ::YearFromTime(time
);
362 JS_PUBLIC_API(double)
363 JS::MonthFromTime(double time
)
365 return ::MonthFromTime(time
);
368 JS_PUBLIC_API(double)
369 JS::DayFromTime(double time
)
371 return DateFromTime(time
);
375 * Find a year for which any given date will fall on the same weekday.
377 * This function should be used with caution when used other than
378 * for determining DST; it hasn't been proven not to produce an
379 * incorrect year for times near year boundaries.
382 EquivalentYearForDST(int year
)
385 * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
387 * yearStartingWith[0][i] is an example non-leap year where
388 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
390 * yearStartingWith[1][i] is an example leap year where
391 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
393 static const int yearStartingWith
[2][7] = {
394 {1978, 1973, 1974, 1975, 1981, 1971, 1977},
395 {1984, 1996, 1980, 1992, 1976, 1988, 1972}
398 int day
= int(DayFromYear(year
) + 4) % 7;
402 return yearStartingWith
[IsLeapYear(year
)][day
];
407 DaylightSavingTA(double t
, DateTimeInfo
*dtInfo
)
413 * If earlier than 1970 or after 2038, potentially beyond the ken of
414 * many OSes, map it to an equivalent year before asking.
416 if (t
< 0.0 || t
> 2145916800000.0) {
417 int year
= EquivalentYearForDST(int(YearFromTime(t
)));
418 double day
= MakeDay(year
, MonthFromTime(t
), DateFromTime(t
));
419 t
= MakeDate(day
, TimeWithinDay(t
));
422 int64_t utcMilliseconds
= static_cast<int64_t>(t
);
423 int64_t offsetMilliseconds
= dtInfo
->getDSTOffsetMilliseconds(utcMilliseconds
);
424 return static_cast<double>(offsetMilliseconds
);
428 AdjustTime(double date
, DateTimeInfo
*dtInfo
)
430 double t
= DaylightSavingTA(date
, dtInfo
) + dtInfo
->localTZA();
431 t
= (dtInfo
->localTZA() >= 0) ? fmod(t
, msPerDay
) : -fmod(msPerDay
- t
, msPerDay
);
437 LocalTime(double t
, DateTimeInfo
*dtInfo
)
439 return t
+ AdjustTime(t
, dtInfo
);
443 UTC(double t
, DateTimeInfo
*dtInfo
)
445 return t
- AdjustTime(t
- dtInfo
->localTZA(), dtInfo
);
450 HourFromTime(double t
)
452 double result
= fmod(floor(t
/msPerHour
), HoursPerDay
);
454 result
+= HoursPerDay
;
459 MinFromTime(double t
)
461 double result
= fmod(floor(t
/ msPerMinute
), MinutesPerHour
);
463 result
+= MinutesPerHour
;
468 SecFromTime(double t
)
470 double result
= fmod(floor(t
/ msPerSecond
), SecondsPerMinute
);
472 result
+= SecondsPerMinute
;
479 double result
= fmod(t
, msPerSecond
);
481 result
+= msPerSecond
;
487 MakeTime(double hour
, double min
, double sec
, double ms
)
490 if (!IsFinite(hour
) ||
499 double h
= ToInteger(hour
);
502 double m
= ToInteger(min
);
505 double s
= ToInteger(sec
);
508 double milli
= ToInteger(ms
);
511 return h
* msPerHour
+ m
* msPerMinute
+ s
* msPerSecond
+ milli
;
515 * end of ECMA 'support' functions
519 date_convert(JSContext
*cx
, HandleObject obj
, JSType hint
, MutableHandleValue vp
)
521 JS_ASSERT(hint
== JSTYPE_NUMBER
|| hint
== JSTYPE_STRING
|| hint
== JSTYPE_VOID
);
522 JS_ASSERT(obj
->is
<DateObject
>());
524 return DefaultValue(cx
, obj
, (hint
== JSTYPE_VOID
) ? JSTYPE_STRING
: hint
, vp
);
527 /* for use by date_parse */
529 static const char* const wtb
[] = {
531 "monday", "tuesday", "wednesday", "thursday", "friday",
532 "saturday", "sunday",
533 "january", "february", "march", "april", "may", "june",
534 "july", "august", "september", "october", "november", "december",
540 /* time zone table needs to be expanded */
543 static const int ttb
[] = {
544 -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
545 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
546 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
547 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
548 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
549 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
550 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
553 template <typename CharT
>
555 RegionMatches(const char *s1
, int s1off
, const CharT
*s2
, int s2off
, int count
)
557 while (count
> 0 && s1
[s1off
] && s2
[s2off
]) {
558 if (unicode::ToLowerCase(s1
[s1off
]) != unicode::ToLowerCase(s2
[s2off
]))
569 /* find UTC time from given date... no 1900 correction! */
571 date_msecFromDate(double year
, double mon
, double mday
, double hour
,
572 double min
, double sec
, double msec
)
574 return MakeDate(MakeDay(year
, mon
, mday
), MakeTime(hour
, min
, sec
, msec
));
577 /* compute the time in msec (unclipped) from the given args */
581 date_msecFromArgs(JSContext
*cx
, CallArgs args
, double *rval
)
584 double array
[MAXARGS
];
587 for (loop
= 0; loop
< MAXARGS
; loop
++) {
588 if (loop
< args
.length()) {
590 if (!ToNumber(cx
, args
[loop
], &d
))
592 /* return NaN if any arg is not finite */
594 *rval
= GenericNaN();
597 array
[loop
] = ToInteger(d
);
600 array
[loop
] = 1; /* Default the date argument to 1. */
607 /* adjust 2-digit years into the 20th century */
608 if (array
[0] >= 0 && array
[0] <= 99)
611 msec_time
= date_msecFromDate(array
[0], array
[1], array
[2],
612 array
[3], array
[4], array
[5], array
[6]);
618 * See ECMA 15.9.4.[3-10];
621 date_UTC(JSContext
*cx
, unsigned argc
, Value
*vp
)
623 CallArgs args
= CallArgsFromVp(argc
, vp
);
626 if (!date_msecFromArgs(cx
, args
, &msec_time
))
629 msec_time
= TimeClip(msec_time
);
631 args
.rval().setNumber(msec_time
);
636 * Read and convert decimal digits from s[*i] into *result
639 * Succeed if any digits are converted. Advance *i only
640 * as digits are consumed.
642 template <typename CharT
>
644 ParseDigits(size_t *result
, const CharT
*s
, size_t *i
, size_t limit
)
648 while (*i
< limit
&& ('0' <= s
[*i
] && s
[*i
] <= '9')) {
650 *result
+= (s
[*i
] - '0');
657 * Read and convert decimal digits to the right of a decimal point,
658 * representing a fractional integer, from s[*i] into *result
661 * Succeed if any digits are converted. Advance *i only
662 * as digits are consumed.
664 template <typename CharT
>
666 ParseFractional(double *result
, const CharT
*s
, size_t *i
, size_t limit
)
671 while (*i
< limit
&& ('0' <= s
[*i
] && s
[*i
] <= '9')) {
672 *result
+= (s
[*i
] - '0') * factor
;
680 * Read and convert exactly n decimal digits from s[*i]
681 * to s[min(*i+n,limit)] into *result.
683 * Succeed if exactly n digits are converted. Advance *i only
686 template <typename CharT
>
688 ParseDigitsN(size_t n
, size_t *result
, const CharT
*s
, size_t *i
, size_t limit
)
692 if (ParseDigits(result
, s
, i
, Min(limit
, init
+ n
)))
693 return (*i
- init
) == n
;
700 DaysInMonth(int year
, int month
)
702 bool leap
= IsLeapYear(year
);
703 int result
= int(DayFromMonth(month
, leap
) - DayFromMonth(month
- 1, leap
));
708 * Parse a string in one of the date-time formats given by the W3C
709 * "NOTE-datetime" specification. These formats make up a restricted
710 * profile of the ISO 8601 format. Quoted here:
712 * The formats are as follows. Exactly the components shown here
713 * must be present, with exactly this punctuation. Note that the "T"
714 * appears literally in the string, to indicate the beginning of the
715 * time element, as specified in ISO 8601.
717 * Any combination of the date formats with the time formats is
718 * allowed, and also either the date or the time can be missing.
720 * The specification is silent on the meaning when fields are
721 * ommitted so the interpretations are a guess, but hopefully a
722 * reasonable one. We default the month to January, the day to the
723 * 1st, and hours minutes and seconds all to 0. If the date is
724 * missing entirely then we assume 1970-01-01 so that the time can
725 * be aded to a date later. If the time is missing then we assume
726 * 00:00 UTC. If the time is present but the time zone field is
727 * missing then we use local time.
735 * YYYY-MM (eg 1997-07)
738 * YYYY-MM-DD (eg 1997-07-16)
743 * Thh:mmTZD (eg T19:20+01:00)
745 * Hours, minutes and seconds:
746 * Thh:mm:ssTZD (eg T19:20:30+01:00)
748 * Hours, minutes, seconds and a decimal fraction of a second:
749 * Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
753 * YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
754 * MM = two-digit month (01=January, etc.)
755 * DD = two-digit day of month (01 through 31)
756 * hh = two digits of hour (00 through 23) (am/pm NOT allowed)
757 * mm = two digits of minute (00 through 59)
758 * ss = two digits of second (00 through 59)
759 * s = one or more digits representing a decimal fraction of a second
760 * TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
762 template <typename CharT
>
764 ParseISODate(const CharT
*s
, size_t length
, double *result
, DateTimeInfo
*dtInfo
)
776 bool isLocalTime
= false;
780 #define PEEK(ch) (i < length && s[i] == ch)
783 if (i >= length || s[i] != ch) { return false; } else { ++i; }
785 #define DONE_DATE_UNLESS(ch) \
786 if (i >= length || s[i] != ch) { goto done_date; } else { ++i; }
788 #define DONE_UNLESS(ch) \
789 if (i >= length || s[i] != ch) { goto done; } else { ++i; }
791 #define NEED_NDIGITS(n, field) \
792 if (!ParseDigitsN(n, &field, s, &i, length)) { return false; }
794 if (PEEK('+') || PEEK('-')) {
798 NEED_NDIGITS(6, year
);
799 } else if (!PEEK('T')) {
800 NEED_NDIGITS(4, year
);
802 DONE_DATE_UNLESS('-');
803 NEED_NDIGITS(2, month
);
804 DONE_DATE_UNLESS('-');
805 NEED_NDIGITS(2, day
);
809 NEED_NDIGITS(2, hour
);
811 NEED_NDIGITS(2, min
);
815 NEED_NDIGITS(2, sec
);
818 if (!ParseFractional(&frac
, s
, &i
, length
))
825 } else if (PEEK('+') || PEEK('-')) {
829 NEED_NDIGITS(2, tzHour
);
831 * Non-standard extension to the ISO date format (permitted by ES5):
832 * allow "-0700" as a time zone offset, not just "-07:00".
836 NEED_NDIGITS(2, tzMin
);
842 if (year
> 275943 // ceil(1e8/365) + 1970
843 || (month
== 0 || month
> 12)
844 || (day
== 0 || day
> size_t(DaysInMonth(year
,month
)))
846 || ((hour
== 24) && (min
> 0 || sec
> 0))
858 month
-= 1; /* convert month to 0-based */
860 double msec
= date_msecFromDate(dateMul
* double(year
), month
, day
,
861 hour
, min
, sec
, frac
* 1000.0);
864 msec
= UTC(msec
, dtInfo
);
866 msec
-= tzMul
* (tzHour
* msPerHour
+ tzMin
* msPerMinute
);
868 if (msec
< -8.64e15
|| msec
> 8.64e15
)
880 template <typename CharT
>
882 ParseDate(const CharT
*s
, size_t length
, double *result
, DateTimeInfo
*dtInfo
)
884 if (ParseISODate(s
, length
, result
, dtInfo
))
900 bool seenPlusMinus
= false;
901 bool seenMonthName
= false;
907 if (c
<= ' ' || c
== ',' || c
== '-') {
908 if (c
== '-' && '0' <= s
[i
] && s
[i
] <= '9')
912 if (c
== '(') { /* comments) */
919 } else if (c
== ')') {
926 if ('0' <= c
&& c
<= '9') {
928 while (i
< length
&& '0' <= (c
= s
[i
]) && c
<= '9') {
929 n
= n
* 10 + c
- '0';
934 * Allow TZA before the year, so 'Wed Nov 05 21:49:11 GMT-0800 1997'
937 * Uses of seenPlusMinus allow ':' in TZA, so Java no-timezone style
941 if ((prevc
== '+' || prevc
== '-')/* && year>=0 */) {
942 /* Make ':' case below change tzOffset. */
943 seenPlusMinus
= true;
947 n
= n
* 60; /* EG. "GMT-3" */
949 n
= n
% 100 + n
/ 100 * 60; /* eg "GMT-0430" */
951 if (prevc
== '+') /* plus means east of GMT */
954 if (tzOffset
!= 0 && tzOffset
!= -1)
958 } else if (prevc
== '/' && mon
>= 0 && mday
>= 0 && year
< 0) {
959 if (c
<= ' ' || c
== ',' || c
== '/' || i
>= length
)
963 } else if (c
== ':') {
970 } else if (c
== '/') {
972 * Until it is determined that mon is the actual month, keep
973 * it as 1-based rather than 0-based.
981 } else if (i
< length
&& c
!= ',' && c
> ' ' && c
!= '-' && c
!= '(') {
983 } else if (seenPlusMinus
&& n
< 60) { /* handle GMT-3:30 */
988 } else if (hour
>= 0 && min
< 0) {
990 } else if (prevc
== ':' && min
>= 0 && sec
< 0) {
992 } else if (mon
< 0) {
994 } else if (mon
>= 0 && mday
< 0) {
996 } else if (mon
>= 0 && mday
>= 0 && year
< 0) {
1002 } else if (c
== '/' || c
== ':' || c
== '+' || c
== '-') {
1007 while (i
< length
) {
1009 if (!(('A' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')))
1017 for (k
= ArrayLength(wtb
); --k
>= 0;) {
1018 if (RegionMatches(wtb
[k
], 0, s
, st
, i
- st
)) {
1019 int action
= ttb
[k
];
1023 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
1024 * 12:30, instead of blindly adding 12 if PM.
1026 JS_ASSERT(action
== -1 || action
== -2);
1027 if (hour
> 12 || hour
< 0)
1030 if (action
== -1 && hour
== 12) /* am */
1032 else if (action
== -2 && hour
!= 12) /* pm */
1034 } else if (action
<= 13) { /* month! */
1036 * Adjust mon to be 1-based until the final values
1037 * for mon, mday and year are adjusted below.
1042 seenMonthName
= true;
1043 int temp
= /*byte*/ (action
- 2) + 1;
1047 } else if (mday
< 0) {
1050 } else if (year
< 0) {
1057 tzOffset
= action
- 10000;
1071 if (year
< 0 || mon
< 0 || mday
< 0)
1075 * Case 1. The input string contains an English month name.
1076 * The form of the string can be month f l, or f month l, or
1077 * f l month which each evaluate to the same date.
1078 * If f and l are both greater than or equal to 70, or
1079 * both less than 70, the date is invalid.
1080 * The year is taken to be the greater of the values f, l.
1081 * If the year is greater than or equal to 70 and less than 100,
1082 * it is considered to be the number of years after 1900.
1083 * Case 2. The input string is of the form "f/m/l" where f, m and l are
1084 * integers, e.g. 7/16/45.
1085 * Adjust the mon, mday and year values to achieve 100% MSIE
1087 * a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
1088 * i. If year < 100, it is the number of years after 1900
1089 * ii. If year >= 100, it is the number of years after 0.
1090 * b. If 70 <= f < 100
1091 * i. If m < 70, f/m/l is interpreted as
1092 * year/month/day where year is the number of years after
1094 * ii. If m >= 70, the date is invalid.
1096 * i. If m < 70, f/m/l is interpreted as
1097 * year/month/day where year is the number of years after 0.
1098 * ii. If m >= 70, the date is invalid.
1100 if (seenMonthName
) {
1101 if ((mday
>= 70 && year
>= 70) || (mday
< 70 && year
< 70))
1109 if (year
>= 70 && year
< 100) {
1112 } else if (mon
< 70) { /* (a) month/day/year */
1116 } else if (mon
< 100) { /* (b) year/month/day */
1125 } else { /* (c) year/month/day */
1136 mon
-= 1; /* convert month to 0-based */
1144 double msec
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
1146 if (tzOffset
== -1) /* no time zone specified, have to use local */
1147 msec
= UTC(msec
, dtInfo
);
1149 msec
+= tzOffset
* msPerMinute
;
1156 ParseDate(JSLinearString
*s
, double *result
, DateTimeInfo
*dtInfo
)
1158 AutoCheckCannotGC nogc
;
1159 return s
->hasLatin1Chars()
1160 ? ParseDate(s
->latin1Chars(nogc
), s
->length(), result
, dtInfo
)
1161 : ParseDate(s
->twoByteChars(nogc
), s
->length(), result
, dtInfo
);
1165 date_parse(JSContext
*cx
, unsigned argc
, Value
*vp
)
1167 CallArgs args
= CallArgsFromVp(argc
, vp
);
1168 if (args
.length() == 0) {
1169 args
.rval().setNaN();
1173 JSString
*str
= ToString
<CanGC
>(cx
, args
[0]);
1177 JSLinearString
*linearStr
= str
->ensureLinear(cx
);
1182 if (!ParseDate(linearStr
, &result
, &cx
->runtime()->dateTimeInfo
)) {
1183 args
.rval().setNaN();
1187 result
= TimeClip(result
);
1188 args
.rval().setNumber(result
);
1192 static inline double
1195 return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC
);
1199 date_now(JSContext
*cx
, unsigned argc
, Value
*vp
)
1201 CallArgs args
= CallArgsFromVp(argc
, vp
);
1202 args
.rval().setDouble(NowAsMillis());
1207 DateObject::setUTCTime(double t
, Value
*vp
)
1209 for (size_t ind
= COMPONENTS_START_SLOT
; ind
< RESERVED_SLOTS
; ind
++)
1210 setReservedSlot(ind
, UndefinedValue());
1212 setFixedSlot(UTC_TIME_SLOT
, DoubleValue(t
));
1218 DateObject::fillLocalTimeSlots(DateTimeInfo
*dtInfo
)
1220 /* Check if the cache is already populated. */
1221 if (!getReservedSlot(LOCAL_TIME_SLOT
).isUndefined() &&
1222 getReservedSlot(TZA_SLOT
).toDouble() == dtInfo
->localTZA())
1227 /* Remember timezone used to generate the local cache. */
1228 setReservedSlot(TZA_SLOT
, DoubleValue(dtInfo
->localTZA()));
1230 double utcTime
= UTCTime().toNumber();
1232 if (!IsFinite(utcTime
)) {
1233 for (size_t ind
= COMPONENTS_START_SLOT
; ind
< RESERVED_SLOTS
; ind
++)
1234 setReservedSlot(ind
, DoubleValue(utcTime
));
1238 double localTime
= LocalTime(utcTime
, dtInfo
);
1240 setReservedSlot(LOCAL_TIME_SLOT
, DoubleValue(localTime
));
1242 int year
= (int) floor(localTime
/(msPerDay
* 365.2425)) + 1970;
1243 double yearStartTime
= TimeFromYear(year
);
1245 /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
1247 if (yearStartTime
> localTime
) {
1249 yearStartTime
-= (msPerDay
* DaysInYear(year
));
1250 yearDays
= DaysInYear(year
);
1252 yearDays
= DaysInYear(year
);
1253 double nextStart
= yearStartTime
+ (msPerDay
* yearDays
);
1254 if (nextStart
<= localTime
) {
1256 yearStartTime
= nextStart
;
1257 yearDays
= DaysInYear(year
);
1261 setReservedSlot(LOCAL_YEAR_SLOT
, Int32Value(year
));
1263 uint64_t yearTime
= uint64_t(localTime
- yearStartTime
);
1264 int yearSeconds
= uint32_t(yearTime
/ 1000);
1266 int day
= yearSeconds
/ int(SecondsPerDay
);
1268 int step
= -1, next
= 30;
1277 next
+= ((yearDays
== 366) ? 29 : 28);
1283 if (day
<= (next
+= 31)) {
1288 if (day
<= (next
+= 30)) {
1293 if (day
<= (next
+= 31)) {
1298 if (day
<= (next
+= 30)) {
1303 if (day
<= (next
+= 31)) {
1308 if (day
<= (next
+= 31)) {
1313 if (day
<= (next
+= 30)) {
1318 if (day
<= (next
+= 31)) {
1323 if (day
<= (next
+= 30)) {
1331 setReservedSlot(LOCAL_MONTH_SLOT
, Int32Value(month
));
1332 setReservedSlot(LOCAL_DATE_SLOT
, Int32Value(day
- step
));
1334 int weekday
= WeekDay(localTime
);
1335 setReservedSlot(LOCAL_DAY_SLOT
, Int32Value(weekday
));
1337 int seconds
= yearSeconds
% 60;
1338 setReservedSlot(LOCAL_SECONDS_SLOT
, Int32Value(seconds
));
1340 int minutes
= (yearSeconds
/ 60) % 60;
1341 setReservedSlot(LOCAL_MINUTES_SLOT
, Int32Value(minutes
));
1343 int hours
= (yearSeconds
/ (60 * 60)) % 24;
1344 setReservedSlot(LOCAL_HOURS_SLOT
, Int32Value(hours
));
1348 DateObject::cachedLocalTime(DateTimeInfo
*dtInfo
)
1350 fillLocalTimeSlots(dtInfo
);
1351 return getReservedSlot(LOCAL_TIME_SLOT
).toDouble();
1354 MOZ_ALWAYS_INLINE
bool
1355 IsDate(HandleValue v
)
1357 return v
.isObject() && v
.toObject().is
<DateObject
>();
1361 * See ECMA 15.9.5.4 thru 15.9.5.23
1363 /* static */ MOZ_ALWAYS_INLINE
bool
1364 DateObject::getTime_impl(JSContext
*cx
, CallArgs args
)
1366 args
.rval().set(args
.thisv().toObject().as
<DateObject
>().UTCTime());
1371 date_getTime(JSContext
*cx
, unsigned argc
, Value
*vp
)
1373 CallArgs args
= CallArgsFromVp(argc
, vp
);
1374 return CallNonGenericMethod
<IsDate
, DateObject::getTime_impl
>(cx
, args
);
1377 /* static */ MOZ_ALWAYS_INLINE
bool
1378 DateObject::getYear_impl(JSContext
*cx
, CallArgs args
)
1380 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1381 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1383 Value yearVal
= dateObj
->getReservedSlot(LOCAL_YEAR_SLOT
);
1384 if (yearVal
.isInt32()) {
1385 /* Follow ECMA-262 to the letter, contrary to IE JScript. */
1386 int year
= yearVal
.toInt32() - 1900;
1387 args
.rval().setInt32(year
);
1389 args
.rval().set(yearVal
);
1396 date_getYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
1398 CallArgs args
= CallArgsFromVp(argc
, vp
);
1399 return CallNonGenericMethod
<IsDate
, DateObject::getYear_impl
>(cx
, args
);
1402 /* static */ MOZ_ALWAYS_INLINE
bool
1403 DateObject::getFullYear_impl(JSContext
*cx
, CallArgs args
)
1405 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1406 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1408 args
.rval().set(dateObj
->getReservedSlot(LOCAL_YEAR_SLOT
));
1413 date_getFullYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
1415 CallArgs args
= CallArgsFromVp(argc
, vp
);
1416 return CallNonGenericMethod
<IsDate
, DateObject::getFullYear_impl
>(cx
, args
);
1419 /* static */ MOZ_ALWAYS_INLINE
bool
1420 DateObject::getUTCFullYear_impl(JSContext
*cx
, CallArgs args
)
1422 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1423 if (IsFinite(result
))
1424 result
= YearFromTime(result
);
1426 args
.rval().setNumber(result
);
1431 date_getUTCFullYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
1433 CallArgs args
= CallArgsFromVp(argc
, vp
);
1434 return CallNonGenericMethod
<IsDate
, DateObject::getUTCFullYear_impl
>(cx
, args
);
1437 /* static */ MOZ_ALWAYS_INLINE
bool
1438 DateObject::getMonth_impl(JSContext
*cx
, CallArgs args
)
1440 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1441 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1443 args
.rval().set(dateObj
->getReservedSlot(LOCAL_MONTH_SLOT
));
1448 date_getMonth(JSContext
*cx
, unsigned argc
, Value
*vp
)
1450 CallArgs args
= CallArgsFromVp(argc
, vp
);
1451 return CallNonGenericMethod
<IsDate
, DateObject::getMonth_impl
>(cx
, args
);
1454 /* static */ MOZ_ALWAYS_INLINE
bool
1455 DateObject::getUTCMonth_impl(JSContext
*cx
, CallArgs args
)
1457 double d
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1458 args
.rval().setNumber(MonthFromTime(d
));
1463 date_getUTCMonth(JSContext
*cx
, unsigned argc
, Value
*vp
)
1465 CallArgs args
= CallArgsFromVp(argc
, vp
);
1466 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMonth_impl
>(cx
, args
);
1469 /* static */ MOZ_ALWAYS_INLINE
bool
1470 DateObject::getDate_impl(JSContext
*cx
, CallArgs args
)
1472 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1473 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1475 args
.rval().set(dateObj
->getReservedSlot(LOCAL_DATE_SLOT
));
1480 date_getDate(JSContext
*cx
, unsigned argc
, Value
*vp
)
1482 CallArgs args
= CallArgsFromVp(argc
, vp
);
1483 return CallNonGenericMethod
<IsDate
, DateObject::getDate_impl
>(cx
, args
);
1486 /* static */ MOZ_ALWAYS_INLINE
bool
1487 DateObject::getUTCDate_impl(JSContext
*cx
, CallArgs args
)
1489 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1490 if (IsFinite(result
))
1491 result
= DateFromTime(result
);
1493 args
.rval().setNumber(result
);
1498 date_getUTCDate(JSContext
*cx
, unsigned argc
, Value
*vp
)
1500 CallArgs args
= CallArgsFromVp(argc
, vp
);
1501 return CallNonGenericMethod
<IsDate
, DateObject::getUTCDate_impl
>(cx
, args
);
1504 /* static */ MOZ_ALWAYS_INLINE
bool
1505 DateObject::getDay_impl(JSContext
*cx
, CallArgs args
)
1507 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1508 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1510 args
.rval().set(dateObj
->getReservedSlot(LOCAL_DAY_SLOT
));
1515 date_getDay(JSContext
*cx
, unsigned argc
, Value
*vp
)
1517 CallArgs args
= CallArgsFromVp(argc
, vp
);
1518 return CallNonGenericMethod
<IsDate
, DateObject::getDay_impl
>(cx
, args
);
1521 /* static */ MOZ_ALWAYS_INLINE
bool
1522 DateObject::getUTCDay_impl(JSContext
*cx
, CallArgs args
)
1524 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1525 if (IsFinite(result
))
1526 result
= WeekDay(result
);
1528 args
.rval().setNumber(result
);
1533 date_getUTCDay(JSContext
*cx
, unsigned argc
, Value
*vp
)
1535 CallArgs args
= CallArgsFromVp(argc
, vp
);
1536 return CallNonGenericMethod
<IsDate
, DateObject::getUTCDay_impl
>(cx
, args
);
1539 /* static */ MOZ_ALWAYS_INLINE
bool
1540 DateObject::getHours_impl(JSContext
*cx
, CallArgs args
)
1542 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1543 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1545 args
.rval().set(dateObj
->getReservedSlot(LOCAL_HOURS_SLOT
));
1550 date_getHours(JSContext
*cx
, unsigned argc
, Value
*vp
)
1552 CallArgs args
= CallArgsFromVp(argc
, vp
);
1553 return CallNonGenericMethod
<IsDate
, DateObject::getHours_impl
>(cx
, args
);
1556 /* static */ MOZ_ALWAYS_INLINE
bool
1557 DateObject::getUTCHours_impl(JSContext
*cx
, CallArgs args
)
1559 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1560 if (IsFinite(result
))
1561 result
= HourFromTime(result
);
1563 args
.rval().setNumber(result
);
1568 date_getUTCHours(JSContext
*cx
, unsigned argc
, Value
*vp
)
1570 CallArgs args
= CallArgsFromVp(argc
, vp
);
1571 return CallNonGenericMethod
<IsDate
, DateObject::getUTCHours_impl
>(cx
, args
);
1574 /* static */ MOZ_ALWAYS_INLINE
bool
1575 DateObject::getMinutes_impl(JSContext
*cx
, CallArgs args
)
1577 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1578 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1580 args
.rval().set(dateObj
->getReservedSlot(LOCAL_MINUTES_SLOT
));
1585 date_getMinutes(JSContext
*cx
, unsigned argc
, Value
*vp
)
1587 CallArgs args
= CallArgsFromVp(argc
, vp
);
1588 return CallNonGenericMethod
<IsDate
, DateObject::getMinutes_impl
>(cx
, args
);
1591 /* static */ MOZ_ALWAYS_INLINE
bool
1592 DateObject::getUTCMinutes_impl(JSContext
*cx
, CallArgs args
)
1594 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1595 if (IsFinite(result
))
1596 result
= MinFromTime(result
);
1598 args
.rval().setNumber(result
);
1603 date_getUTCMinutes(JSContext
*cx
, unsigned argc
, Value
*vp
)
1605 CallArgs args
= CallArgsFromVp(argc
, vp
);
1606 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMinutes_impl
>(cx
, args
);
1609 /* Date.getSeconds is mapped to getUTCSeconds */
1611 /* static */ MOZ_ALWAYS_INLINE
bool
1612 DateObject::getUTCSeconds_impl(JSContext
*cx
, CallArgs args
)
1614 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1615 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1617 args
.rval().set(dateObj
->getReservedSlot(LOCAL_SECONDS_SLOT
));
1622 date_getUTCSeconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1624 CallArgs args
= CallArgsFromVp(argc
, vp
);
1625 return CallNonGenericMethod
<IsDate
, DateObject::getUTCSeconds_impl
>(cx
, args
);
1628 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
1630 /* static */ MOZ_ALWAYS_INLINE
bool
1631 DateObject::getUTCMilliseconds_impl(JSContext
*cx
, CallArgs args
)
1633 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1634 if (IsFinite(result
))
1635 result
= msFromTime(result
);
1637 args
.rval().setNumber(result
);
1642 date_getUTCMilliseconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1644 CallArgs args
= CallArgsFromVp(argc
, vp
);
1645 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMilliseconds_impl
>(cx
, args
);
1648 /* static */ MOZ_ALWAYS_INLINE
bool
1649 DateObject::getTimezoneOffset_impl(JSContext
*cx
, CallArgs args
)
1651 DateObject
*dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1652 double utctime
= dateObj
->UTCTime().toNumber();
1653 double localtime
= dateObj
->cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
1656 * Return the time zone offset in minutes for the current locale that is
1657 * appropriate for this time. This value would be a constant except for
1658 * daylight savings time.
1660 double result
= (utctime
- localtime
) / msPerMinute
;
1661 args
.rval().setNumber(result
);
1666 date_getTimezoneOffset(JSContext
*cx
, unsigned argc
, Value
*vp
)
1668 CallArgs args
= CallArgsFromVp(argc
, vp
);
1669 return CallNonGenericMethod
<IsDate
, DateObject::getTimezoneOffset_impl
>(cx
, args
);
1672 MOZ_ALWAYS_INLINE
bool
1673 date_setTime_impl(JSContext
*cx
, CallArgs args
)
1675 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1676 if (args
.length() == 0) {
1677 dateObj
->setUTCTime(GenericNaN(), args
.rval().address());
1682 if (!ToNumber(cx
, args
[0], &result
))
1685 dateObj
->setUTCTime(TimeClip(result
), args
.rval().address());
1690 date_setTime(JSContext
*cx
, unsigned argc
, Value
*vp
)
1692 CallArgs args
= CallArgsFromVp(argc
, vp
);
1693 return CallNonGenericMethod
<IsDate
, date_setTime_impl
>(cx
, args
);
1697 GetMsecsOrDefault(JSContext
*cx
, const CallArgs
&args
, unsigned i
, double t
, double *millis
)
1699 if (args
.length() <= i
) {
1700 *millis
= msFromTime(t
);
1703 return ToNumber(cx
, args
[i
], millis
);
1707 GetSecsOrDefault(JSContext
*cx
, const CallArgs
&args
, unsigned i
, double t
, double *sec
)
1709 if (args
.length() <= i
) {
1710 *sec
= SecFromTime(t
);
1713 return ToNumber(cx
, args
[i
], sec
);
1717 GetMinsOrDefault(JSContext
*cx
, const CallArgs
&args
, unsigned i
, double t
, double *mins
)
1719 if (args
.length() <= i
) {
1720 *mins
= MinFromTime(t
);
1723 return ToNumber(cx
, args
[i
], mins
);
1726 /* ES5 15.9.5.28. */
1727 MOZ_ALWAYS_INLINE
bool
1728 date_setMilliseconds_impl(JSContext
*cx
, CallArgs args
)
1730 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1733 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1737 if (!ToNumber(cx
, args
.get(0), &milli
))
1739 double time
= MakeTime(HourFromTime(t
), MinFromTime(t
), SecFromTime(t
), milli
);
1742 double u
= TimeClip(UTC(MakeDate(Day(t
), time
), &cx
->runtime()->dateTimeInfo
));
1745 dateObj
->setUTCTime(u
, args
.rval().address());
1750 date_setMilliseconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1752 CallArgs args
= CallArgsFromVp(argc
, vp
);
1753 return CallNonGenericMethod
<IsDate
, date_setMilliseconds_impl
>(cx
, args
);
1756 /* ES5 15.9.5.29. */
1757 MOZ_ALWAYS_INLINE
bool
1758 date_setUTCMilliseconds_impl(JSContext
*cx
, CallArgs args
)
1760 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1763 double t
= dateObj
->UTCTime().toNumber();
1767 if (!ToNumber(cx
, args
.get(0), &milli
))
1769 double time
= MakeTime(HourFromTime(t
), MinFromTime(t
), SecFromTime(t
), milli
);
1772 double v
= TimeClip(MakeDate(Day(t
), time
));
1775 dateObj
->setUTCTime(v
, args
.rval().address());
1780 date_setUTCMilliseconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1782 CallArgs args
= CallArgsFromVp(argc
, vp
);
1783 return CallNonGenericMethod
<IsDate
, date_setUTCMilliseconds_impl
>(cx
, args
);
1786 /* ES5 15.9.5.30. */
1787 MOZ_ALWAYS_INLINE
bool
1788 date_setSeconds_impl(JSContext
*cx
, CallArgs args
)
1790 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1793 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1797 if (!ToNumber(cx
, args
.get(0), &s
))
1802 if (!GetMsecsOrDefault(cx
, args
, 1, t
, &milli
))
1806 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), MinFromTime(t
), s
, milli
));
1809 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1812 dateObj
->setUTCTime(u
, args
.rval().address());
1816 /* ES5 15.9.5.31. */
1818 date_setSeconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1820 CallArgs args
= CallArgsFromVp(argc
, vp
);
1821 return CallNonGenericMethod
<IsDate
, date_setSeconds_impl
>(cx
, args
);
1824 MOZ_ALWAYS_INLINE
bool
1825 date_setUTCSeconds_impl(JSContext
*cx
, CallArgs args
)
1827 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1830 double t
= dateObj
->UTCTime().toNumber();
1834 if (!ToNumber(cx
, args
.get(0), &s
))
1839 if (!GetMsecsOrDefault(cx
, args
, 1, t
, &milli
))
1843 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), MinFromTime(t
), s
, milli
));
1846 double v
= TimeClip(date
);
1849 dateObj
->setUTCTime(v
, args
.rval().address());
1853 /* ES5 15.9.5.32. */
1855 date_setUTCSeconds(JSContext
*cx
, unsigned argc
, Value
*vp
)
1857 CallArgs args
= CallArgsFromVp(argc
, vp
);
1858 return CallNonGenericMethod
<IsDate
, date_setUTCSeconds_impl
>(cx
, args
);
1861 MOZ_ALWAYS_INLINE
bool
1862 date_setMinutes_impl(JSContext
*cx
, CallArgs args
)
1864 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1867 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1871 if (!ToNumber(cx
, args
.get(0), &m
))
1876 if (!GetSecsOrDefault(cx
, args
, 1, t
, &s
))
1881 if (!GetMsecsOrDefault(cx
, args
, 2, t
, &milli
))
1885 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), m
, s
, milli
));
1888 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1891 dateObj
->setUTCTime(u
, args
.rval().address());
1895 /* ES5 15.9.5.33. */
1897 date_setMinutes(JSContext
*cx
, unsigned argc
, Value
*vp
)
1899 CallArgs args
= CallArgsFromVp(argc
, vp
);
1900 return CallNonGenericMethod
<IsDate
, date_setMinutes_impl
>(cx
, args
);
1903 MOZ_ALWAYS_INLINE
bool
1904 date_setUTCMinutes_impl(JSContext
*cx
, CallArgs args
)
1906 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1909 double t
= dateObj
->UTCTime().toNumber();
1913 if (!ToNumber(cx
, args
.get(0), &m
))
1918 if (!GetSecsOrDefault(cx
, args
, 1, t
, &s
))
1923 if (!GetMsecsOrDefault(cx
, args
, 2, t
, &milli
))
1927 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), m
, s
, milli
));
1930 double v
= TimeClip(date
);
1933 dateObj
->setUTCTime(v
, args
.rval().address());
1937 /* ES5 15.9.5.34. */
1939 date_setUTCMinutes(JSContext
*cx
, unsigned argc
, Value
*vp
)
1941 CallArgs args
= CallArgsFromVp(argc
, vp
);
1942 return CallNonGenericMethod
<IsDate
, date_setUTCMinutes_impl
>(cx
, args
);
1945 MOZ_ALWAYS_INLINE
bool
1946 date_setHours_impl(JSContext
*cx
, CallArgs args
)
1948 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1951 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1955 if (!ToNumber(cx
, args
.get(0), &h
))
1960 if (!GetMinsOrDefault(cx
, args
, 1, t
, &m
))
1965 if (!GetSecsOrDefault(cx
, args
, 2, t
, &s
))
1970 if (!GetMsecsOrDefault(cx
, args
, 3, t
, &milli
))
1974 double date
= MakeDate(Day(t
), MakeTime(h
, m
, s
, milli
));
1977 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1980 dateObj
->setUTCTime(u
, args
.rval().address());
1984 /* ES5 15.9.5.35. */
1986 date_setHours(JSContext
*cx
, unsigned argc
, Value
*vp
)
1988 CallArgs args
= CallArgsFromVp(argc
, vp
);
1989 return CallNonGenericMethod
<IsDate
, date_setHours_impl
>(cx
, args
);
1992 MOZ_ALWAYS_INLINE
bool
1993 date_setUTCHours_impl(JSContext
*cx
, CallArgs args
)
1995 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1998 double t
= dateObj
->UTCTime().toNumber();
2002 if (!ToNumber(cx
, args
.get(0), &h
))
2007 if (!GetMinsOrDefault(cx
, args
, 1, t
, &m
))
2012 if (!GetSecsOrDefault(cx
, args
, 2, t
, &s
))
2017 if (!GetMsecsOrDefault(cx
, args
, 3, t
, &milli
))
2021 double newDate
= MakeDate(Day(t
), MakeTime(h
, m
, s
, milli
));
2024 double v
= TimeClip(newDate
);
2027 dateObj
->setUTCTime(v
, args
.rval().address());
2031 /* ES5 15.9.5.36. */
2033 date_setUTCHours(JSContext
*cx
, unsigned argc
, Value
*vp
)
2035 CallArgs args
= CallArgsFromVp(argc
, vp
);
2036 return CallNonGenericMethod
<IsDate
, date_setUTCHours_impl
>(cx
, args
);
2039 MOZ_ALWAYS_INLINE
bool
2040 date_setDate_impl(JSContext
*cx
, CallArgs args
)
2042 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2045 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
2049 if (!ToNumber(cx
, args
.get(0), &date
))
2053 double newDate
= MakeDate(MakeDay(YearFromTime(t
), MonthFromTime(t
), date
), TimeWithinDay(t
));
2056 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2059 dateObj
->setUTCTime(u
, args
.rval().address());
2063 /* ES5 15.9.5.37. */
2065 date_setDate(JSContext
*cx
, unsigned argc
, Value
*vp
)
2067 CallArgs args
= CallArgsFromVp(argc
, vp
);
2068 return CallNonGenericMethod
<IsDate
, date_setDate_impl
>(cx
, args
);
2071 MOZ_ALWAYS_INLINE
bool
2072 date_setUTCDate_impl(JSContext
*cx
, CallArgs args
)
2074 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2077 double t
= dateObj
->UTCTime().toNumber();
2081 if (!ToNumber(cx
, args
.get(0), &date
))
2085 double newDate
= MakeDate(MakeDay(YearFromTime(t
), MonthFromTime(t
), date
), TimeWithinDay(t
));
2088 double v
= TimeClip(newDate
);
2091 dateObj
->setUTCTime(v
, args
.rval().address());
2096 date_setUTCDate(JSContext
*cx
, unsigned argc
, Value
*vp
)
2098 CallArgs args
= CallArgsFromVp(argc
, vp
);
2099 return CallNonGenericMethod
<IsDate
, date_setUTCDate_impl
>(cx
, args
);
2103 GetDateOrDefault(JSContext
*cx
, const CallArgs
&args
, unsigned i
, double t
, double *date
)
2105 if (args
.length() <= i
) {
2106 *date
= DateFromTime(t
);
2109 return ToNumber(cx
, args
[i
], date
);
2113 GetMonthOrDefault(JSContext
*cx
, const CallArgs
&args
, unsigned i
, double t
, double *month
)
2115 if (args
.length() <= i
) {
2116 *month
= MonthFromTime(t
);
2119 return ToNumber(cx
, args
[i
], month
);
2122 /* ES5 15.9.5.38. */
2123 MOZ_ALWAYS_INLINE
bool
2124 date_setMonth_impl(JSContext
*cx
, CallArgs args
)
2126 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2129 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
2133 if (!ToNumber(cx
, args
.get(0), &m
))
2138 if (!GetDateOrDefault(cx
, args
, 1, t
, &date
))
2142 double newDate
= MakeDate(MakeDay(YearFromTime(t
), m
, date
), TimeWithinDay(t
));
2145 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2148 dateObj
->setUTCTime(u
, args
.rval().address());
2153 date_setMonth(JSContext
*cx
, unsigned argc
, Value
*vp
)
2155 CallArgs args
= CallArgsFromVp(argc
, vp
);
2156 return CallNonGenericMethod
<IsDate
, date_setMonth_impl
>(cx
, args
);
2159 /* ES5 15.9.5.39. */
2160 MOZ_ALWAYS_INLINE
bool
2161 date_setUTCMonth_impl(JSContext
*cx
, CallArgs args
)
2163 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2166 double t
= dateObj
->UTCTime().toNumber();
2170 if (!ToNumber(cx
, args
.get(0), &m
))
2175 if (!GetDateOrDefault(cx
, args
, 1, t
, &date
))
2179 double newDate
= MakeDate(MakeDay(YearFromTime(t
), m
, date
), TimeWithinDay(t
));
2182 double v
= TimeClip(newDate
);
2185 dateObj
->setUTCTime(v
, args
.rval().address());
2190 date_setUTCMonth(JSContext
*cx
, unsigned argc
, Value
*vp
)
2192 CallArgs args
= CallArgsFromVp(argc
, vp
);
2193 return CallNonGenericMethod
<IsDate
, date_setUTCMonth_impl
>(cx
, args
);
2197 ThisLocalTimeOrZero(Handle
<DateObject
*> dateObj
, DateTimeInfo
*dtInfo
)
2199 double t
= dateObj
->UTCTime().toNumber();
2202 return LocalTime(t
, dtInfo
);
2206 ThisUTCTimeOrZero(Handle
<DateObject
*> dateObj
)
2208 double t
= dateObj
->as
<DateObject
>().UTCTime().toNumber();
2209 return IsNaN(t
) ? +0 : t
;
2212 /* ES5 15.9.5.40. */
2213 MOZ_ALWAYS_INLINE
bool
2214 date_setFullYear_impl(JSContext
*cx
, CallArgs args
)
2216 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2219 double t
= ThisLocalTimeOrZero(dateObj
, &cx
->runtime()->dateTimeInfo
);
2223 if (!ToNumber(cx
, args
.get(0), &y
))
2228 if (!GetMonthOrDefault(cx
, args
, 1, t
, &m
))
2233 if (!GetDateOrDefault(cx
, args
, 2, t
, &date
))
2237 double newDate
= MakeDate(MakeDay(y
, m
, date
), TimeWithinDay(t
));
2240 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2243 dateObj
->setUTCTime(u
, args
.rval().address());
2248 date_setFullYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
2250 CallArgs args
= CallArgsFromVp(argc
, vp
);
2251 return CallNonGenericMethod
<IsDate
, date_setFullYear_impl
>(cx
, args
);
2254 /* ES5 15.9.5.41. */
2255 MOZ_ALWAYS_INLINE
bool
2256 date_setUTCFullYear_impl(JSContext
*cx
, CallArgs args
)
2258 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2261 double t
= ThisUTCTimeOrZero(dateObj
);
2265 if (!ToNumber(cx
, args
.get(0), &y
))
2270 if (!GetMonthOrDefault(cx
, args
, 1, t
, &m
))
2275 if (!GetDateOrDefault(cx
, args
, 2, t
, &date
))
2279 double newDate
= MakeDate(MakeDay(y
, m
, date
), TimeWithinDay(t
));
2282 double v
= TimeClip(newDate
);
2285 dateObj
->setUTCTime(v
, args
.rval().address());
2290 date_setUTCFullYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
2292 CallArgs args
= CallArgsFromVp(argc
, vp
);
2293 return CallNonGenericMethod
<IsDate
, date_setUTCFullYear_impl
>(cx
, args
);
2296 /* ES5 Annex B.2.5. */
2297 MOZ_ALWAYS_INLINE
bool
2298 date_setYear_impl(JSContext
*cx
, CallArgs args
)
2300 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2303 double t
= ThisLocalTimeOrZero(dateObj
, &cx
->runtime()->dateTimeInfo
);
2307 if (!ToNumber(cx
, args
.get(0), &y
))
2312 dateObj
->setUTCTime(GenericNaN(), args
.rval().address());
2317 double yint
= ToInteger(y
);
2318 if (0 <= yint
&& yint
<= 99)
2322 double day
= MakeDay(yint
, MonthFromTime(t
), DateFromTime(t
));
2325 double u
= UTC(MakeDate(day
, TimeWithinDay(t
)), &cx
->runtime()->dateTimeInfo
);
2328 dateObj
->setUTCTime(TimeClip(u
), args
.rval().address());
2333 date_setYear(JSContext
*cx
, unsigned argc
, Value
*vp
)
2335 CallArgs args
= CallArgsFromVp(argc
, vp
);
2336 return CallNonGenericMethod
<IsDate
, date_setYear_impl
>(cx
, args
);
2339 /* constants for toString, toUTCString */
2340 static const char js_NaN_date_str
[] = "Invalid Date";
2341 static const char * const days
[] =
2343 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
2345 static const char * const months
[] =
2347 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2351 // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
2352 // requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
2354 print_gmt_string(char* buf
, size_t size
, double utctime
)
2356 JS_ASSERT(TimeClip(utctime
) == utctime
);
2357 JS_snprintf(buf
, size
, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
2358 days
[int(WeekDay(utctime
))],
2359 int(DateFromTime(utctime
)),
2360 months
[int(MonthFromTime(utctime
))],
2361 int(YearFromTime(utctime
)),
2362 int(HourFromTime(utctime
)),
2363 int(MinFromTime(utctime
)),
2364 int(SecFromTime(utctime
)));
2368 print_iso_string(char* buf
, size_t size
, double utctime
)
2370 JS_ASSERT(TimeClip(utctime
) == utctime
);
2371 JS_snprintf(buf
, size
, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
2372 int(YearFromTime(utctime
)),
2373 int(MonthFromTime(utctime
)) + 1,
2374 int(DateFromTime(utctime
)),
2375 int(HourFromTime(utctime
)),
2376 int(MinFromTime(utctime
)),
2377 int(SecFromTime(utctime
)),
2378 int(msFromTime(utctime
)));
2382 MOZ_ALWAYS_INLINE
bool
2383 date_toGMTString_impl(JSContext
*cx
, CallArgs args
)
2385 double utctime
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
2388 if (!IsFinite(utctime
))
2389 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2391 print_gmt_string(buf
, sizeof buf
, utctime
);
2393 JSString
*str
= JS_NewStringCopyZ(cx
, buf
);
2396 args
.rval().setString(str
);
2400 /* ES5 15.9.5.43. */
2402 date_toGMTString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2404 CallArgs args
= CallArgsFromVp(argc
, vp
);
2405 return CallNonGenericMethod
<IsDate
, date_toGMTString_impl
>(cx
, args
);
2408 MOZ_ALWAYS_INLINE
bool
2409 date_toISOString_impl(JSContext
*cx
, CallArgs args
)
2411 double utctime
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
2412 if (!IsFinite(utctime
)) {
2413 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_INVALID_DATE
);
2418 print_iso_string(buf
, sizeof buf
, utctime
);
2420 JSString
*str
= JS_NewStringCopyZ(cx
, buf
);
2423 args
.rval().setString(str
);
2429 date_toISOString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2431 CallArgs args
= CallArgsFromVp(argc
, vp
);
2432 return CallNonGenericMethod
<IsDate
, date_toISOString_impl
>(cx
, args
);
2435 /* ES5 15.9.5.44. */
2437 date_toJSON(JSContext
*cx
, unsigned argc
, Value
*vp
)
2439 CallArgs args
= CallArgsFromVp(argc
, vp
);
2442 RootedObject
obj(cx
, ToObject(cx
, args
.thisv()));
2447 RootedValue
tv(cx
, ObjectValue(*obj
));
2448 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, &tv
))
2452 if (tv
.isDouble() && !IsFinite(tv
.toDouble())) {
2453 args
.rval().setNull();
2458 RootedValue
toISO(cx
);
2459 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().toISOString
, &toISO
))
2463 if (!IsCallable(toISO
)) {
2464 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, nullptr,
2465 JSMSG_BAD_TOISOSTRING_PROP
);
2470 InvokeArgs
args2(cx
);
2474 args2
.setCallee(toISO
);
2475 args2
.setThis(ObjectValue(*obj
));
2477 if (!Invoke(cx
, args2
))
2479 args
.rval().set(args2
.rval());
2483 /* for Date.toLocaleFormat; interface to PRMJTime date struct.
2486 new_explode(double timeval
, PRMJTime
*split
, DateTimeInfo
*dtInfo
)
2488 double year
= YearFromTime(timeval
);
2490 split
->tm_usec
= int32_t(msFromTime(timeval
)) * 1000;
2491 split
->tm_sec
= int8_t(SecFromTime(timeval
));
2492 split
->tm_min
= int8_t(MinFromTime(timeval
));
2493 split
->tm_hour
= int8_t(HourFromTime(timeval
));
2494 split
->tm_mday
= int8_t(DateFromTime(timeval
));
2495 split
->tm_mon
= int8_t(MonthFromTime(timeval
));
2496 split
->tm_wday
= int8_t(WeekDay(timeval
));
2497 split
->tm_year
= year
;
2498 split
->tm_yday
= int16_t(DayWithinYear(timeval
, year
));
2500 /* not sure how this affects things, but it doesn't seem
2502 split
->tm_isdst
= (DaylightSavingTA(timeval
, dtInfo
) != 0);
2505 typedef enum formatspec
{
2506 FORMATSPEC_FULL
, FORMATSPEC_DATE
, FORMATSPEC_TIME
2509 /* helper function */
2511 date_format(JSContext
*cx
, double date
, formatspec format
, MutableHandleValue rval
)
2519 if (!IsFinite(date
)) {
2520 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2522 JS_ASSERT(TimeClip(date
) == date
);
2524 double local
= LocalTime(date
, &cx
->runtime()->dateTimeInfo
);
2526 /* offset from GMT in minutes. The offset includes daylight savings,
2528 int minutes
= (int) floor(AdjustTime(date
, &cx
->runtime()->dateTimeInfo
) / msPerMinute
);
2530 /* map 510 minutes to 0830 hours */
2531 int offset
= (minutes
/ 60) * 100 + minutes
% 60;
2533 /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
2534 * printed as 'GMT-0800' rather than as 'PST' to avoid
2535 * operating-system dependence on strftime (which
2536 * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
2537 * PST as 'Pacific Standard Time.' This way we always know
2538 * what we're getting, and can parse it if we produce it.
2539 * The OS TZA string is included as a comment.
2542 /* get a timezone string from the OS to include as a
2544 new_explode(date
, &split
, &cx
->runtime()->dateTimeInfo
);
2545 if (PRMJ_FormatTime(tzbuf
, sizeof tzbuf
, "(%Z)", &split
) != 0) {
2547 /* Decide whether to use the resulting timezone string.
2549 * Reject it if it contains any non-ASCII, non-alphanumeric
2550 * characters. It's then likely in some other character
2551 * encoding, and we probably won't display it correctly.
2554 tzlen
= strlen(tzbuf
);
2558 for (i
= 0; i
< tzlen
; i
++) {
2559 jschar c
= tzbuf
[i
];
2561 !(isalpha(c
) || isdigit(c
) ||
2562 c
== ' ' || c
== '(' || c
== ')')) {
2568 /* Also reject it if it's not parenthesized or if it's '()'. */
2569 if (tzbuf
[0] != '(' || tzbuf
[1] == ')')
2575 case FORMATSPEC_FULL
:
2577 * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
2578 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
2580 /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
2581 JS_snprintf(buf
, sizeof buf
,
2582 "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
2583 days
[int(WeekDay(local
))],
2584 months
[int(MonthFromTime(local
))],
2585 int(DateFromTime(local
)),
2586 int(YearFromTime(local
)),
2587 int(HourFromTime(local
)),
2588 int(MinFromTime(local
)),
2589 int(SecFromTime(local
)),
2592 usetz
? tzbuf
: "");
2594 case FORMATSPEC_DATE
:
2595 /* Tue Oct 31 2000 */
2596 JS_snprintf(buf
, sizeof buf
,
2598 days
[int(WeekDay(local
))],
2599 months
[int(MonthFromTime(local
))],
2600 int(DateFromTime(local
)),
2601 int(YearFromTime(local
)));
2603 case FORMATSPEC_TIME
:
2604 /* 09:41:40 GMT-0800 (PST) */
2605 JS_snprintf(buf
, sizeof buf
,
2606 "%.2d:%.2d:%.2d GMT%+.4d%s%s",
2607 int(HourFromTime(local
)),
2608 int(MinFromTime(local
)),
2609 int(SecFromTime(local
)),
2612 usetz
? tzbuf
: "");
2617 JSString
*str
= JS_NewStringCopyZ(cx
, buf
);
2620 rval
.setString(str
);
2625 ToLocaleFormatHelper(JSContext
*cx
, HandleObject obj
, const char *format
, MutableHandleValue rval
)
2627 double utctime
= obj
->as
<DateObject
>().UTCTime().toNumber();
2630 if (!IsFinite(utctime
)) {
2631 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2634 double local
= LocalTime(utctime
, &cx
->runtime()->dateTimeInfo
);
2636 new_explode(local
, &split
, &cx
->runtime()->dateTimeInfo
);
2638 /* Let PRMJTime format it. */
2639 result_len
= PRMJ_FormatTime(buf
, sizeof buf
, format
, &split
);
2641 /* If it failed, default to toString. */
2642 if (result_len
== 0)
2643 return date_format(cx
, utctime
, FORMATSPEC_FULL
, rval
);
2645 /* Hacked check against undesired 2-digit year 00/00/00 form. */
2646 if (strcmp(format
, "%x") == 0 && result_len
>= 6 &&
2647 /* Format %x means use OS settings, which may have 2-digit yr, so
2648 hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
2649 !isdigit(buf
[result_len
- 3]) &&
2650 isdigit(buf
[result_len
- 2]) && isdigit(buf
[result_len
- 1]) &&
2651 /* ...but not if starts with 4-digit year, like 2022/3/11. */
2652 !(isdigit(buf
[0]) && isdigit(buf
[1]) &&
2653 isdigit(buf
[2]) && isdigit(buf
[3]))) {
2654 JS_snprintf(buf
+ (result_len
- 2), (sizeof buf
) - (result_len
- 2),
2655 "%d", js_DateGetYear(cx
, obj
));
2660 if (cx
->runtime()->localeCallbacks
&& cx
->runtime()->localeCallbacks
->localeToUnicode
)
2661 return cx
->runtime()->localeCallbacks
->localeToUnicode(cx
, buf
, rval
);
2663 JSString
*str
= JS_NewStringCopyZ(cx
, buf
);
2666 rval
.setString(str
);
2670 #if !EXPOSE_INTL_API
2672 ToLocaleStringHelper(JSContext
*cx
, Handle
<DateObject
*> dateObj
, MutableHandleValue rval
)
2675 * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
2676 * with msvc; '%#c' requests that a full year be used in the result string.
2678 return ToLocaleFormatHelper(cx
, dateObj
,
2679 #if defined(_WIN32) && !defined(__MWERKS__)
2688 MOZ_ALWAYS_INLINE
bool
2689 date_toLocaleString_impl(JSContext
*cx
, CallArgs args
)
2691 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2692 return ToLocaleStringHelper(cx
, dateObj
, args
.rval());
2696 date_toLocaleString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2698 CallArgs args
= CallArgsFromVp(argc
, vp
);
2699 return CallNonGenericMethod
<IsDate
, date_toLocaleString_impl
>(cx
, args
);
2703 MOZ_ALWAYS_INLINE
bool
2704 date_toLocaleDateString_impl(JSContext
*cx
, CallArgs args
)
2707 * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
2708 * with msvc; '%#x' requests that a full year be used in the result string.
2710 static const char format
[] =
2711 #if defined(_WIN32) && !defined(__MWERKS__)
2718 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2719 return ToLocaleFormatHelper(cx
, dateObj
, format
, args
.rval());
2723 date_toLocaleDateString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2725 CallArgs args
= CallArgsFromVp(argc
, vp
);
2726 return CallNonGenericMethod
<IsDate
, date_toLocaleDateString_impl
>(cx
, args
);
2730 MOZ_ALWAYS_INLINE
bool
2731 date_toLocaleTimeString_impl(JSContext
*cx
, CallArgs args
)
2733 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2734 return ToLocaleFormatHelper(cx
, dateObj
, "%X", args
.rval());
2738 date_toLocaleTimeString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2740 CallArgs args
= CallArgsFromVp(argc
, vp
);
2741 return CallNonGenericMethod
<IsDate
, date_toLocaleTimeString_impl
>(cx
, args
);
2743 #endif /* !EXPOSE_INTL_API */
2745 MOZ_ALWAYS_INLINE
bool
2746 date_toLocaleFormat_impl(JSContext
*cx
, CallArgs args
)
2748 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2750 if (args
.length() == 0) {
2752 * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
2753 * with msvc; '%#c' requests that a full year be used in the result string.
2755 return ToLocaleFormatHelper(cx
, dateObj
,
2756 #if defined(_WIN32) && !defined(__MWERKS__)
2764 RootedString
fmt(cx
, ToString
<CanGC
>(cx
, args
[0]));
2768 JSAutoByteString
fmtbytes(cx
, fmt
);
2772 return ToLocaleFormatHelper(cx
, dateObj
, fmtbytes
.ptr(), args
.rval());
2776 date_toLocaleFormat(JSContext
*cx
, unsigned argc
, Value
*vp
)
2778 CallArgs args
= CallArgsFromVp(argc
, vp
);
2779 return CallNonGenericMethod
<IsDate
, date_toLocaleFormat_impl
>(cx
, args
);
2783 MOZ_ALWAYS_INLINE
bool
2784 date_toTimeString_impl(JSContext
*cx
, CallArgs args
)
2786 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2787 FORMATSPEC_TIME
, args
.rval());
2791 date_toTimeString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2793 CallArgs args
= CallArgsFromVp(argc
, vp
);
2794 return CallNonGenericMethod
<IsDate
, date_toTimeString_impl
>(cx
, args
);
2798 MOZ_ALWAYS_INLINE
bool
2799 date_toDateString_impl(JSContext
*cx
, CallArgs args
)
2801 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2802 FORMATSPEC_DATE
, args
.rval());
2806 date_toDateString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2808 CallArgs args
= CallArgsFromVp(argc
, vp
);
2809 return CallNonGenericMethod
<IsDate
, date_toDateString_impl
>(cx
, args
);
2813 MOZ_ALWAYS_INLINE
bool
2814 date_toSource_impl(JSContext
*cx
, CallArgs args
)
2816 StringBuffer
sb(cx
);
2817 if (!sb
.append("(new Date(") ||
2818 !NumberValueToStringBuffer(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime(), sb
) ||
2824 JSString
*str
= sb
.finishString();
2827 args
.rval().setString(str
);
2832 date_toSource(JSContext
*cx
, unsigned argc
, Value
*vp
)
2834 CallArgs args
= CallArgsFromVp(argc
, vp
);
2835 return CallNonGenericMethod
<IsDate
, date_toSource_impl
>(cx
, args
);
2839 MOZ_ALWAYS_INLINE
bool
2840 date_toString_impl(JSContext
*cx
, CallArgs args
)
2842 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2843 FORMATSPEC_FULL
, args
.rval());
2847 date_toString(JSContext
*cx
, unsigned argc
, Value
*vp
)
2849 CallArgs args
= CallArgsFromVp(argc
, vp
);
2850 return CallNonGenericMethod
<IsDate
, date_toString_impl
>(cx
, args
);
2853 MOZ_ALWAYS_INLINE
bool
2854 date_valueOf_impl(JSContext
*cx
, CallArgs args
)
2856 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2857 args
.rval().set(dateObj
->UTCTime());
2862 date_valueOf(JSContext
*cx
, unsigned argc
, Value
*vp
)
2864 CallArgs args
= CallArgsFromVp(argc
, vp
);
2865 return CallNonGenericMethod
<IsDate
, date_valueOf_impl
>(cx
, args
);
2868 static const JSFunctionSpec date_static_methods
[] = {
2869 JS_FN("UTC", date_UTC
, MAXARGS
,0),
2870 JS_FN("parse", date_parse
, 1,0),
2871 JS_FN("now", date_now
, 0,0),
2875 static const JSFunctionSpec date_methods
[] = {
2876 JS_FN("getTime", date_getTime
, 0,0),
2877 JS_FN("getTimezoneOffset", date_getTimezoneOffset
, 0,0),
2878 JS_FN("getYear", date_getYear
, 0,0),
2879 JS_FN("getFullYear", date_getFullYear
, 0,0),
2880 JS_FN("getUTCFullYear", date_getUTCFullYear
, 0,0),
2881 JS_FN("getMonth", date_getMonth
, 0,0),
2882 JS_FN("getUTCMonth", date_getUTCMonth
, 0,0),
2883 JS_FN("getDate", date_getDate
, 0,0),
2884 JS_FN("getUTCDate", date_getUTCDate
, 0,0),
2885 JS_FN("getDay", date_getDay
, 0,0),
2886 JS_FN("getUTCDay", date_getUTCDay
, 0,0),
2887 JS_FN("getHours", date_getHours
, 0,0),
2888 JS_FN("getUTCHours", date_getUTCHours
, 0,0),
2889 JS_FN("getMinutes", date_getMinutes
, 0,0),
2890 JS_FN("getUTCMinutes", date_getUTCMinutes
, 0,0),
2891 JS_FN("getSeconds", date_getUTCSeconds
, 0,0),
2892 JS_FN("getUTCSeconds", date_getUTCSeconds
, 0,0),
2893 JS_FN("getMilliseconds", date_getUTCMilliseconds
, 0,0),
2894 JS_FN("getUTCMilliseconds", date_getUTCMilliseconds
, 0,0),
2895 JS_FN("setTime", date_setTime
, 1,0),
2896 JS_FN("setYear", date_setYear
, 1,0),
2897 JS_FN("setFullYear", date_setFullYear
, 3,0),
2898 JS_FN("setUTCFullYear", date_setUTCFullYear
, 3,0),
2899 JS_FN("setMonth", date_setMonth
, 2,0),
2900 JS_FN("setUTCMonth", date_setUTCMonth
, 2,0),
2901 JS_FN("setDate", date_setDate
, 1,0),
2902 JS_FN("setUTCDate", date_setUTCDate
, 1,0),
2903 JS_FN("setHours", date_setHours
, 4,0),
2904 JS_FN("setUTCHours", date_setUTCHours
, 4,0),
2905 JS_FN("setMinutes", date_setMinutes
, 3,0),
2906 JS_FN("setUTCMinutes", date_setUTCMinutes
, 3,0),
2907 JS_FN("setSeconds", date_setSeconds
, 2,0),
2908 JS_FN("setUTCSeconds", date_setUTCSeconds
, 2,0),
2909 JS_FN("setMilliseconds", date_setMilliseconds
, 1,0),
2910 JS_FN("setUTCMilliseconds", date_setUTCMilliseconds
, 1,0),
2911 JS_FN("toUTCString", date_toGMTString
, 0,0),
2912 JS_FN("toLocaleFormat", date_toLocaleFormat
, 0,0),
2914 JS_SELF_HOSTED_FN(js_toLocaleString_str
, "Date_toLocaleString", 0,0),
2915 JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0),
2916 JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0),
2918 JS_FN(js_toLocaleString_str
, date_toLocaleString
, 0,0),
2919 JS_FN("toLocaleDateString", date_toLocaleDateString
, 0,0),
2920 JS_FN("toLocaleTimeString", date_toLocaleTimeString
, 0,0),
2922 JS_FN("toDateString", date_toDateString
, 0,0),
2923 JS_FN("toTimeString", date_toTimeString
, 0,0),
2924 JS_FN("toISOString", date_toISOString
, 0,0),
2925 JS_FN(js_toJSON_str
, date_toJSON
, 1,0),
2927 JS_FN(js_toSource_str
, date_toSource
, 0,0),
2929 JS_FN(js_toString_str
, date_toString
, 0,0),
2930 JS_FN(js_valueOf_str
, date_valueOf
, 0,0),
2935 js_Date(JSContext
*cx
, unsigned argc
, Value
*vp
)
2937 CallArgs args
= CallArgsFromVp(argc
, vp
);
2939 /* Date called as function. */
2940 if (!args
.isConstructing())
2941 return date_format(cx
, NowAsMillis(), FORMATSPEC_FULL
, args
.rval());
2943 /* Date called as constructor. */
2945 if (args
.length() == 0) {
2948 } else if (args
.length() == 1) {
2952 if (!ToPrimitive(cx
, args
[0]))
2955 if (args
[0].isString()) {
2957 JSString
*str
= args
[0].toString();
2961 JSLinearString
*linearStr
= str
->ensureLinear(cx
);
2965 if (!ParseDate(linearStr
, &d
, &cx
->runtime()->dateTimeInfo
))
2971 if (!ToNumber(cx
, args
[0], &d
))
2977 if (!date_msecFromArgs(cx
, args
, &msec_time
))
2980 if (IsFinite(msec_time
)) {
2981 msec_time
= UTC(msec_time
, &cx
->runtime()->dateTimeInfo
);
2982 msec_time
= TimeClip(msec_time
);
2987 JSObject
*obj
= js_NewDateObjectMsec(cx
, d
);
2991 args
.rval().setObject(*obj
);
2996 FinishDateClassInit(JSContext
*cx
, HandleObject ctor
, HandleObject proto
)
2998 proto
->as
<DateObject
>().setUTCTime(GenericNaN());
3001 * Date.prototype.toGMTString has the same initial value as
3002 * Date.prototype.toUTCString.
3004 RootedValue
toUTCStringFun(cx
);
3005 RootedId
toUTCStringId(cx
, NameToId(cx
->names().toUTCString
));
3006 RootedId
toGMTStringId(cx
, NameToId(cx
->names().toGMTString
));
3007 return baseops::GetProperty(cx
, proto
, toUTCStringId
, &toUTCStringFun
) &&
3008 baseops::DefineGeneric(cx
, proto
, toGMTStringId
, toUTCStringFun
,
3009 JS_PropertyStub
, JS_StrictPropertyStub
, 0);
3012 const Class
DateObject::class_
= {
3014 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS
) |
3015 JSCLASS_HAS_CACHED_PROTO(JSProto_Date
),
3016 JS_PropertyStub
, /* addProperty */
3017 JS_DeletePropertyStub
, /* delProperty */
3018 JS_PropertyStub
, /* getProperty */
3019 JS_StrictPropertyStub
, /* setProperty */
3023 nullptr, /* finalize */
3025 nullptr, /* hasInstance */
3026 nullptr, /* construct */
3027 nullptr, /* trace */
3029 GenericCreateConstructor
<js_Date
, MAXARGS
, JSFunction::FinalizeKind
>,
3030 GenericCreatePrototype
<&DateObject::class_
>,
3031 date_static_methods
,
3038 JS_FRIEND_API(JSObject
*)
3039 js_NewDateObjectMsec(JSContext
*cx
, double msec_time
)
3041 JSObject
*obj
= NewBuiltinClassInstance(cx
, &DateObject::class_
);
3044 obj
->as
<DateObject
>().setUTCTime(msec_time
);
3048 JS_FRIEND_API(JSObject
*)
3049 js_NewDateObject(JSContext
*cx
, int year
, int mon
, int mday
,
3050 int hour
, int min
, int sec
)
3052 JS_ASSERT(mon
< 12);
3053 double msec_time
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
3054 return js_NewDateObjectMsec(cx
, UTC(msec_time
, &cx
->runtime()->dateTimeInfo
));
3058 js_DateIsValid(JSObject
*obj
)
3060 return obj
->is
<DateObject
>() && !IsNaN(obj
->as
<DateObject
>().UTCTime().toNumber());
3064 js_DateGetYear(JSContext
*cx
, JSObject
*obj
)
3066 /* Preserve legacy API behavior of returning 0 for invalid dates. */
3068 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
3069 if (IsNaN(localtime
))
3072 return (int) YearFromTime(localtime
);
3076 js_DateGetMonth(JSContext
*cx
, JSObject
*obj
)
3079 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
3080 if (IsNaN(localtime
))
3083 return (int) MonthFromTime(localtime
);
3087 js_DateGetDate(JSContext
*cx
, JSObject
*obj
)
3090 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
3091 if (IsNaN(localtime
))
3094 return (int) DateFromTime(localtime
);
3098 js_DateGetHours(JSContext
*cx
, JSObject
*obj
)
3101 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
3102 if (IsNaN(localtime
))
3105 return (int) HourFromTime(localtime
);
3109 js_DateGetMinutes(JSContext
*cx
, JSObject
*obj
)
3112 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
3113 if (IsNaN(localtime
))
3116 return (int) MinFromTime(localtime
);
3120 js_DateGetSeconds(JSObject
*obj
)
3122 if (!obj
->is
<DateObject
>())
3125 double utctime
= obj
->as
<DateObject
>().UTCTime().toNumber();
3128 return (int) SecFromTime(utctime
);
3131 JS_FRIEND_API(double)
3132 js_DateGetMsecSinceEpoch(JSObject
*obj
)
3134 obj
= CheckedUnwrap(obj
);
3135 if (!obj
|| !obj
->is
<DateObject
>())
3137 return obj
->as
<DateObject
>().UTCTime().toNumber();