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"
38 #include "js/Conversions.h"
40 #include "vm/DateTime.h"
41 #include "vm/GlobalObject.h"
42 #include "vm/Interpreter.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
;
60 * The JS 'Date' object is patterned after the Java 'Date' object.
65 * print(today.toLocaleString());
67 * weekDay = today.getDay();
70 * These Java (and ECMA-262) methods are supported:
73 * getDate (getUTCDate)
75 * getHours (getUTCHours)
76 * getMinutes (getUTCMinutes)
77 * getMonth (getUTCMonth)
78 * getSeconds (getUTCSeconds)
79 * getMilliseconds (getUTCMilliseconds)
83 * getFullYear (getUTCFullYear)
85 * setDate (setUTCDate)
86 * setHours (setUTCHours)
87 * setMinutes (setUTCMinutes)
88 * setMonth (setUTCMonth)
89 * setSeconds (setUTCSeconds)
90 * setMilliseconds (setUTCMilliseconds)
92 * setYear (setFullYear, setUTCFullYear)
93 * toGMTString (toUTCString)
98 * These Java methods are not supported
110 return floor(t
/ msPerDay
);
114 TimeWithinDay(double t
)
116 double result
= fmod(t
, msPerDay
);
124 IsLeapYear(double year
)
126 MOZ_ASSERT(ToInteger(year
) == year
);
127 return fmod(year
, 4) == 0 && (fmod(year
, 100) != 0 || fmod(year
, 400) == 0);
131 DaysInYear(double year
)
135 return IsLeapYear(year
) ? 366 : 365;
139 DayFromYear(double y
)
141 return 365 * (y
- 1970) +
142 floor((y
- 1969) / 4.0) -
143 floor((y
- 1901) / 100.0) +
144 floor((y
- 1601) / 400.0);
148 TimeFromYear(double y
)
150 return DayFromYear(y
) * msPerDay
;
154 YearFromTime(double t
)
159 MOZ_ASSERT(ToInteger(t
) == t
);
161 double y
= floor(t
/ (msPerDay
* 365.2425)) + 1970;
162 double t2
= TimeFromYear(y
);
165 * Adjust the year if the approximation was wrong. Since the year was
166 * computed using the average number of ms per year, it will usually
167 * be wrong for dates within several hours of a year transition.
172 if (t2
+ msPerDay
* DaysInYear(y
) <= t
)
179 DaysInFebruary(double year
)
181 return IsLeapYear(year
) ? 29 : 28;
186 DayWithinYear(double t
, double year
)
188 MOZ_ASSERT_IF(IsFinite(t
), YearFromTime(t
) == year
);
189 return Day(t
) - DayFromYear(year
);
193 MonthFromTime(double t
)
198 double year
= YearFromTime(t
);
199 double d
= DayWithinYear(t
, year
);
204 if (d
< (step
+= DaysInFebruary(year
)))
206 if (d
< (step
+= 31))
208 if (d
< (step
+= 30))
210 if (d
< (step
+= 31))
212 if (d
< (step
+= 30))
214 if (d
< (step
+= 31))
216 if (d
< (step
+= 31))
218 if (d
< (step
+= 30))
220 if (d
< (step
+= 31))
222 if (d
< (step
+= 30))
229 DateFromTime(double t
)
234 double year
= YearFromTime(t
);
235 double d
= DayWithinYear(t
, year
);
238 if (d
<= (next
= 30))
241 if (d
<= (next
+= DaysInFebruary(year
)))
244 if (d
<= (next
+= 31))
247 if (d
<= (next
+= 30))
250 if (d
<= (next
+= 31))
253 if (d
<= (next
+= 30))
256 if (d
<= (next
+= 31))
259 if (d
<= (next
+= 31))
262 if (d
<= (next
+= 30))
265 if (d
<= (next
+= 31))
268 if (d
<= (next
+= 30))
279 * We can't assert TimeClip(t) == t because we call this function with
280 * local times, which can be offset outside TimeClip's permitted range.
282 MOZ_ASSERT(ToInteger(t
) == t
);
283 int result
= (int(Day(t
)) + 4) % 7;
290 DayFromMonth(int month
, bool isLeapYear
)
293 * The following array contains the day of year for the first day of
294 * each month, where index 0 is January, and day 0 is January 1.
296 static const int firstDayOfMonth
[2][13] = {
297 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
298 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
301 MOZ_ASSERT(0 <= month
&& month
<= 12);
302 return firstDayOfMonth
[isLeapYear
][month
];
307 DayFromMonth(T month
, bool isLeapYear
) = delete;
309 /* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
311 MakeDay(double year
, double month
, double date
)
314 if (!IsFinite(year
) || !IsFinite(month
) || !IsFinite(date
))
318 double y
= ToInteger(year
);
319 double m
= ToInteger(month
);
320 double dt
= ToInteger(date
);
323 double ym
= y
+ floor(m
/ 12);
326 int mn
= int(fmod(m
, 12.0));
331 bool leap
= IsLeapYear(ym
);
333 double yearday
= floor(TimeFromYear(ym
) / msPerDay
);
334 double monthday
= DayFromMonth(mn
, leap
);
336 return yearday
+ monthday
+ dt
- 1;
339 /* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
341 MakeDate(double day
, double time
)
344 if (!IsFinite(day
) || !IsFinite(time
))
348 return day
* msPerDay
+ time
;
351 JS_PUBLIC_API(double)
352 JS::MakeDate(double year
, unsigned month
, unsigned day
)
354 return TimeClip(::MakeDate(MakeDay(year
, month
, day
), 0));
357 JS_PUBLIC_API(double)
358 JS::YearFromTime(double time
)
360 return ::YearFromTime(time
);
363 JS_PUBLIC_API(double)
364 JS::MonthFromTime(double time
)
366 return ::MonthFromTime(time
);
369 JS_PUBLIC_API(double)
370 JS::DayFromTime(double time
)
372 return DateFromTime(time
);
376 * Find a year for which any given date will fall on the same weekday.
378 * This function should be used with caution when used other than
379 * for determining DST; it hasn't been proven not to produce an
380 * incorrect year for times near year boundaries.
383 EquivalentYearForDST(int year
)
386 * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
388 * yearStartingWith[0][i] is an example non-leap year where
389 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
391 * yearStartingWith[1][i] is an example leap year where
392 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
394 static const int yearStartingWith
[2][7] = {
395 {1978, 1973, 1974, 1975, 1981, 1971, 1977},
396 {1984, 1996, 1980, 1992, 1976, 1988, 1972}
399 int day
= int(DayFromYear(year
) + 4) % 7;
403 return yearStartingWith
[IsLeapYear(year
)][day
];
408 DaylightSavingTA(double t
, DateTimeInfo
* dtInfo
)
414 * If earlier than 1970 or after 2038, potentially beyond the ken of
415 * many OSes, map it to an equivalent year before asking.
417 if (t
< 0.0 || t
> 2145916800000.0) {
418 int year
= EquivalentYearForDST(int(YearFromTime(t
)));
419 double day
= MakeDay(year
, MonthFromTime(t
), DateFromTime(t
));
420 t
= MakeDate(day
, TimeWithinDay(t
));
423 int64_t utcMilliseconds
= static_cast<int64_t>(t
);
424 int64_t offsetMilliseconds
= dtInfo
->getDSTOffsetMilliseconds(utcMilliseconds
);
425 return static_cast<double>(offsetMilliseconds
);
429 AdjustTime(double date
, DateTimeInfo
* dtInfo
)
431 double t
= DaylightSavingTA(date
, dtInfo
) + dtInfo
->localTZA();
432 t
= (dtInfo
->localTZA() >= 0) ? fmod(t
, msPerDay
) : -fmod(msPerDay
- t
, msPerDay
);
438 LocalTime(double t
, DateTimeInfo
* dtInfo
)
440 return t
+ AdjustTime(t
, dtInfo
);
444 UTC(double t
, DateTimeInfo
* dtInfo
)
446 return t
- AdjustTime(t
- dtInfo
->localTZA(), dtInfo
);
451 HourFromTime(double t
)
453 double result
= fmod(floor(t
/msPerHour
), HoursPerDay
);
455 result
+= HoursPerDay
;
460 MinFromTime(double t
)
462 double result
= fmod(floor(t
/ msPerMinute
), MinutesPerHour
);
464 result
+= MinutesPerHour
;
469 SecFromTime(double t
)
471 double result
= fmod(floor(t
/ msPerSecond
), SecondsPerMinute
);
473 result
+= SecondsPerMinute
;
480 double result
= fmod(t
, msPerSecond
);
482 result
+= msPerSecond
;
488 MakeTime(double hour
, double min
, double sec
, double ms
)
491 if (!IsFinite(hour
) ||
500 double h
= ToInteger(hour
);
503 double m
= ToInteger(min
);
506 double s
= ToInteger(sec
);
509 double milli
= ToInteger(ms
);
512 return h
* msPerHour
+ m
* msPerMinute
+ s
* msPerSecond
+ milli
;
516 * end of ECMA 'support' functions
520 date_convert(JSContext
* cx
, HandleObject obj
, JSType hint
, MutableHandleValue vp
)
522 MOZ_ASSERT(hint
== JSTYPE_NUMBER
|| hint
== JSTYPE_STRING
|| hint
== JSTYPE_VOID
);
523 MOZ_ASSERT(obj
->is
<DateObject
>());
525 return DefaultValue(cx
, obj
, (hint
== JSTYPE_VOID
) ? JSTYPE_STRING
: hint
, vp
);
528 /* for use by date_parse */
530 static const char* const wtb
[] = {
532 "monday", "tuesday", "wednesday", "thursday", "friday",
533 "saturday", "sunday",
534 "january", "february", "march", "april", "may", "june",
535 "july", "august", "september", "october", "november", "december",
541 /* time zone table needs to be expanded */
544 static const int ttb
[] = {
545 -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
546 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
547 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
548 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
549 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
550 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
551 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
554 template <typename CharT
>
556 RegionMatches(const char* s1
, int s1off
, const CharT
* s2
, int s2off
, int count
)
558 while (count
> 0 && s1
[s1off
] && s2
[s2off
]) {
559 if (unicode::ToLowerCase(s1
[s1off
]) != unicode::ToLowerCase(s2
[s2off
]))
570 /* find UTC time from given date... no 1900 correction! */
572 date_msecFromDate(double year
, double mon
, double mday
, double hour
,
573 double min
, double sec
, double msec
)
575 return MakeDate(MakeDay(year
, mon
, mday
), MakeTime(hour
, min
, sec
, msec
));
578 /* compute the time in msec (unclipped) from the given args */
582 date_msecFromArgs(JSContext
* cx
, CallArgs args
, double* rval
)
585 double array
[MAXARGS
];
588 for (loop
= 0; loop
< MAXARGS
; loop
++) {
589 if (loop
< args
.length()) {
591 if (!ToNumber(cx
, args
[loop
], &d
))
593 /* return NaN if any arg is not finite */
595 *rval
= GenericNaN();
598 array
[loop
] = ToInteger(d
);
601 array
[loop
] = 1; /* Default the date argument to 1. */
608 /* adjust 2-digit years into the 20th century */
609 if (array
[0] >= 0 && array
[0] <= 99)
612 msec_time
= date_msecFromDate(array
[0], array
[1], array
[2],
613 array
[3], array
[4], array
[5], array
[6]);
619 * See ECMA 15.9.4.[3-10];
622 date_UTC(JSContext
* cx
, unsigned argc
, Value
* vp
)
624 CallArgs args
= CallArgsFromVp(argc
, vp
);
627 if (!date_msecFromArgs(cx
, args
, &msec_time
))
630 msec_time
= TimeClip(msec_time
);
632 args
.rval().setNumber(msec_time
);
637 * Read and convert decimal digits from s[*i] into *result
640 * Succeed if any digits are converted. Advance *i only
641 * as digits are consumed.
643 template <typename CharT
>
645 ParseDigits(size_t* result
, const CharT
* s
, size_t* i
, size_t limit
)
649 while (*i
< limit
&& ('0' <= s
[*i
] && s
[*i
] <= '9')) {
651 *result
+= (s
[*i
] - '0');
658 * Read and convert decimal digits to the right of a decimal point,
659 * representing a fractional integer, from s[*i] into *result
662 * Succeed if any digits are converted. Advance *i only
663 * as digits are consumed.
665 template <typename CharT
>
667 ParseFractional(double* result
, const CharT
* s
, size_t* i
, size_t limit
)
672 while (*i
< limit
&& ('0' <= s
[*i
] && s
[*i
] <= '9')) {
673 *result
+= (s
[*i
] - '0') * factor
;
681 * Read and convert exactly n decimal digits from s[*i]
682 * to s[min(*i+n,limit)] into *result.
684 * Succeed if exactly n digits are converted. Advance *i only
687 template <typename CharT
>
689 ParseDigitsN(size_t n
, size_t* result
, const CharT
* s
, size_t* i
, size_t limit
)
693 if (ParseDigits(result
, s
, i
, Min(limit
, init
+ n
)))
694 return (*i
- init
) == n
;
701 DaysInMonth(int year
, int month
)
703 bool leap
= IsLeapYear(year
);
704 int result
= int(DayFromMonth(month
, leap
) - DayFromMonth(month
- 1, leap
));
709 * Parse a string in one of the date-time formats given by the W3C
710 * "NOTE-datetime" specification. These formats make up a restricted
711 * profile of the ISO 8601 format. Quoted here:
713 * The formats are as follows. Exactly the components shown here
714 * must be present, with exactly this punctuation. Note that the "T"
715 * appears literally in the string, to indicate the beginning of the
716 * time element, as specified in ISO 8601.
718 * Any combination of the date formats with the time formats is
719 * allowed, and also either the date or the time can be missing.
721 * The specification is silent on the meaning when fields are
722 * ommitted so the interpretations are a guess, but hopefully a
723 * reasonable one. We default the month to January, the day to the
724 * 1st, and hours minutes and seconds all to 0. If the date is
725 * missing entirely then we assume 1970-01-01 so that the time can
726 * be aded to a date later. If the time is missing then we assume
727 * 00:00 UTC. If the time is present but the time zone field is
728 * missing then we use local time.
736 * YYYY-MM (eg 1997-07)
739 * YYYY-MM-DD (eg 1997-07-16)
744 * Thh:mmTZD (eg T19:20+01:00)
746 * Hours, minutes and seconds:
747 * Thh:mm:ssTZD (eg T19:20:30+01:00)
749 * Hours, minutes, seconds and a decimal fraction of a second:
750 * Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
754 * YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
755 * MM = two-digit month (01=January, etc.)
756 * DD = two-digit day of month (01 through 31)
757 * hh = two digits of hour (00 through 23) (am/pm NOT allowed)
758 * mm = two digits of minute (00 through 59)
759 * ss = two digits of second (00 through 59)
760 * s = one or more digits representing a decimal fraction of a second
761 * TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
763 template <typename CharT
>
765 ParseISODate(const CharT
* s
, size_t length
, double* result
, DateTimeInfo
* dtInfo
)
777 bool isLocalTime
= false;
781 #define PEEK(ch) (i < length && s[i] == ch)
784 if (i >= length || s[i] != ch) { return false; } else { ++i; }
786 #define DONE_DATE_UNLESS(ch) \
787 if (i >= length || s[i] != ch) { goto done_date; } else { ++i; }
789 #define DONE_UNLESS(ch) \
790 if (i >= length || s[i] != ch) { goto done; } else { ++i; }
792 #define NEED_NDIGITS(n, field) \
793 if (!ParseDigitsN(n, &field, s, &i, length)) { return false; }
795 if (PEEK('+') || PEEK('-')) {
799 NEED_NDIGITS(6, year
);
800 } else if (!PEEK('T')) {
801 NEED_NDIGITS(4, year
);
803 DONE_DATE_UNLESS('-');
804 NEED_NDIGITS(2, month
);
805 DONE_DATE_UNLESS('-');
806 NEED_NDIGITS(2, day
);
810 NEED_NDIGITS(2, hour
);
812 NEED_NDIGITS(2, min
);
816 NEED_NDIGITS(2, sec
);
819 if (!ParseFractional(&frac
, s
, &i
, length
))
826 } else if (PEEK('+') || PEEK('-')) {
830 NEED_NDIGITS(2, tzHour
);
832 * Non-standard extension to the ISO date format (permitted by ES5):
833 * allow "-0700" as a time zone offset, not just "-07:00".
837 NEED_NDIGITS(2, tzMin
);
843 if (year
> 275943 // ceil(1e8/365) + 1970
844 || (month
== 0 || month
> 12)
845 || (day
== 0 || day
> size_t(DaysInMonth(year
,month
)))
847 || ((hour
== 24) && (min
> 0 || sec
> 0))
859 month
-= 1; /* convert month to 0-based */
861 double msec
= date_msecFromDate(dateMul
* double(year
), month
, day
,
862 hour
, min
, sec
, frac
* 1000.0);
865 msec
= UTC(msec
, dtInfo
);
867 msec
-= tzMul
* (tzHour
* msPerHour
+ tzMin
* msPerMinute
);
869 if (msec
< -8.64e15
|| msec
> 8.64e15
)
881 template <typename CharT
>
883 ParseDate(const CharT
* s
, size_t length
, double* result
, DateTimeInfo
* dtInfo
)
885 if (ParseISODate(s
, length
, result
, dtInfo
))
901 bool seenPlusMinus
= false;
902 bool seenMonthName
= false;
908 if (c
<= ' ' || c
== ',' || c
== '-') {
909 if (c
== '-' && '0' <= s
[i
] && s
[i
] <= '9')
913 if (c
== '(') { /* comments) */
920 } else if (c
== ')') {
927 if ('0' <= c
&& c
<= '9') {
929 while (i
< length
&& '0' <= (c
= s
[i
]) && c
<= '9') {
930 n
= n
* 10 + c
- '0';
935 * Allow TZA before the year, so 'Wed Nov 05 21:49:11 GMT-0800 1997'
938 * Uses of seenPlusMinus allow ':' in TZA, so Java no-timezone style
942 if ((prevc
== '+' || prevc
== '-')/* && year>=0 */) {
943 /* Make ':' case below change tzOffset. */
944 seenPlusMinus
= true;
948 n
= n
* 60; /* EG. "GMT-3" */
950 n
= n
% 100 + n
/ 100 * 60; /* eg "GMT-0430" */
952 if (prevc
== '+') /* plus means east of GMT */
955 if (tzOffset
!= 0 && tzOffset
!= -1)
959 } else if (prevc
== '/' && mon
>= 0 && mday
>= 0 && year
< 0) {
960 if (c
<= ' ' || c
== ',' || c
== '/' || i
>= length
)
964 } else if (c
== ':') {
971 } else if (c
== '/') {
973 * Until it is determined that mon is the actual month, keep
974 * it as 1-based rather than 0-based.
982 } else if (i
< length
&& c
!= ',' && c
> ' ' && c
!= '-' && c
!= '(') {
984 } else if (seenPlusMinus
&& n
< 60) { /* handle GMT-3:30 */
989 } else if (hour
>= 0 && min
< 0) {
991 } else if (prevc
== ':' && min
>= 0 && sec
< 0) {
993 } else if (mon
< 0) {
995 } else if (mon
>= 0 && mday
< 0) {
997 } else if (mon
>= 0 && mday
>= 0 && year
< 0) {
1003 } else if (c
== '/' || c
== ':' || c
== '+' || c
== '-') {
1008 while (i
< length
) {
1010 if (!(('A' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')))
1018 for (k
= ArrayLength(wtb
); --k
>= 0;) {
1019 if (RegionMatches(wtb
[k
], 0, s
, st
, i
- st
)) {
1020 int action
= ttb
[k
];
1024 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
1025 * 12:30, instead of blindly adding 12 if PM.
1027 MOZ_ASSERT(action
== -1 || action
== -2);
1028 if (hour
> 12 || hour
< 0)
1031 if (action
== -1 && hour
== 12) /* am */
1033 else if (action
== -2 && hour
!= 12) /* pm */
1035 } else if (action
<= 13) { /* month! */
1037 * Adjust mon to be 1-based until the final values
1038 * for mon, mday and year are adjusted below.
1043 seenMonthName
= true;
1044 int temp
= /*byte*/ (action
- 2) + 1;
1048 } else if (mday
< 0) {
1051 } else if (year
< 0) {
1058 tzOffset
= action
- 10000;
1072 if (year
< 0 || mon
< 0 || mday
< 0)
1076 * Case 1. The input string contains an English month name.
1077 * The form of the string can be month f l, or f month l, or
1078 * f l month which each evaluate to the same date.
1079 * If f and l are both greater than or equal to 70, or
1080 * both less than 70, the date is invalid.
1081 * The year is taken to be the greater of the values f, l.
1082 * If the year is greater than or equal to 70 and less than 100,
1083 * it is considered to be the number of years after 1900.
1084 * Case 2. The input string is of the form "f/m/l" where f, m and l are
1085 * integers, e.g. 7/16/45.
1086 * Adjust the mon, mday and year values to achieve 100% MSIE
1088 * a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
1089 * i. If year < 100, it is the number of years after 1900
1090 * ii. If year >= 100, it is the number of years after 0.
1091 * b. If 70 <= f < 100
1092 * i. If m < 70, f/m/l is interpreted as
1093 * year/month/day where year is the number of years after
1095 * ii. If m >= 70, the date is invalid.
1097 * i. If m < 70, f/m/l is interpreted as
1098 * year/month/day where year is the number of years after 0.
1099 * ii. If m >= 70, the date is invalid.
1101 if (seenMonthName
) {
1102 if ((mday
>= 70 && year
>= 70) || (mday
< 70 && year
< 70))
1110 if (year
>= 70 && year
< 100) {
1113 } else if (mon
< 70) { /* (a) month/day/year */
1117 } else if (mon
< 100) { /* (b) year/month/day */
1126 } else { /* (c) year/month/day */
1137 mon
-= 1; /* convert month to 0-based */
1145 double msec
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
1147 if (tzOffset
== -1) /* no time zone specified, have to use local */
1148 msec
= UTC(msec
, dtInfo
);
1150 msec
+= tzOffset
* msPerMinute
;
1157 ParseDate(JSLinearString
* s
, double* result
, DateTimeInfo
* dtInfo
)
1159 AutoCheckCannotGC nogc
;
1160 return s
->hasLatin1Chars()
1161 ? ParseDate(s
->latin1Chars(nogc
), s
->length(), result
, dtInfo
)
1162 : ParseDate(s
->twoByteChars(nogc
), s
->length(), result
, dtInfo
);
1166 date_parse(JSContext
* cx
, unsigned argc
, Value
* vp
)
1168 CallArgs args
= CallArgsFromVp(argc
, vp
);
1169 if (args
.length() == 0) {
1170 args
.rval().setNaN();
1174 JSString
* str
= ToString
<CanGC
>(cx
, args
[0]);
1178 JSLinearString
* linearStr
= str
->ensureLinear(cx
);
1183 if (!ParseDate(linearStr
, &result
, &cx
->runtime()->dateTimeInfo
)) {
1184 args
.rval().setNaN();
1188 result
= TimeClip(result
);
1189 args
.rval().setNumber(result
);
1193 static inline double
1196 return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC
);
1200 js::date_now(JSContext
* cx
, unsigned argc
, Value
* vp
)
1202 CallArgs args
= CallArgsFromVp(argc
, vp
);
1203 args
.rval().setDouble(NowAsMillis());
1208 DateObject::setUTCTime(double t
)
1210 for (size_t ind
= COMPONENTS_START_SLOT
; ind
< RESERVED_SLOTS
; ind
++)
1211 setReservedSlot(ind
, UndefinedValue());
1213 setFixedSlot(UTC_TIME_SLOT
, DoubleValue(t
));
1217 DateObject::setUTCTime(double t
, MutableHandleValue vp
)
1224 DateObject::fillLocalTimeSlots(DateTimeInfo
* dtInfo
)
1226 /* Check if the cache is already populated. */
1227 if (!getReservedSlot(LOCAL_TIME_SLOT
).isUndefined() &&
1228 getReservedSlot(TZA_SLOT
).toDouble() == dtInfo
->localTZA())
1233 /* Remember timezone used to generate the local cache. */
1234 setReservedSlot(TZA_SLOT
, DoubleValue(dtInfo
->localTZA()));
1236 double utcTime
= UTCTime().toNumber();
1238 if (!IsFinite(utcTime
)) {
1239 for (size_t ind
= COMPONENTS_START_SLOT
; ind
< RESERVED_SLOTS
; ind
++)
1240 setReservedSlot(ind
, DoubleValue(utcTime
));
1244 double localTime
= LocalTime(utcTime
, dtInfo
);
1246 setReservedSlot(LOCAL_TIME_SLOT
, DoubleValue(localTime
));
1248 int year
= (int) floor(localTime
/(msPerDay
* 365.2425)) + 1970;
1249 double yearStartTime
= TimeFromYear(year
);
1251 /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
1253 if (yearStartTime
> localTime
) {
1255 yearStartTime
-= (msPerDay
* DaysInYear(year
));
1256 yearDays
= DaysInYear(year
);
1258 yearDays
= DaysInYear(year
);
1259 double nextStart
= yearStartTime
+ (msPerDay
* yearDays
);
1260 if (nextStart
<= localTime
) {
1262 yearStartTime
= nextStart
;
1263 yearDays
= DaysInYear(year
);
1267 setReservedSlot(LOCAL_YEAR_SLOT
, Int32Value(year
));
1269 uint64_t yearTime
= uint64_t(localTime
- yearStartTime
);
1270 int yearSeconds
= uint32_t(yearTime
/ 1000);
1272 int day
= yearSeconds
/ int(SecondsPerDay
);
1274 int step
= -1, next
= 30;
1283 next
+= ((yearDays
== 366) ? 29 : 28);
1289 if (day
<= (next
+= 31)) {
1294 if (day
<= (next
+= 30)) {
1299 if (day
<= (next
+= 31)) {
1304 if (day
<= (next
+= 30)) {
1309 if (day
<= (next
+= 31)) {
1314 if (day
<= (next
+= 31)) {
1319 if (day
<= (next
+= 30)) {
1324 if (day
<= (next
+= 31)) {
1329 if (day
<= (next
+= 30)) {
1337 setReservedSlot(LOCAL_MONTH_SLOT
, Int32Value(month
));
1338 setReservedSlot(LOCAL_DATE_SLOT
, Int32Value(day
- step
));
1340 int weekday
= WeekDay(localTime
);
1341 setReservedSlot(LOCAL_DAY_SLOT
, Int32Value(weekday
));
1343 int seconds
= yearSeconds
% 60;
1344 setReservedSlot(LOCAL_SECONDS_SLOT
, Int32Value(seconds
));
1346 int minutes
= (yearSeconds
/ 60) % 60;
1347 setReservedSlot(LOCAL_MINUTES_SLOT
, Int32Value(minutes
));
1349 int hours
= (yearSeconds
/ (60 * 60)) % 24;
1350 setReservedSlot(LOCAL_HOURS_SLOT
, Int32Value(hours
));
1354 DateObject::cachedLocalTime(DateTimeInfo
* dtInfo
)
1356 fillLocalTimeSlots(dtInfo
);
1357 return getReservedSlot(LOCAL_TIME_SLOT
).toDouble();
1360 MOZ_ALWAYS_INLINE
bool
1361 IsDate(HandleValue v
)
1363 return v
.isObject() && v
.toObject().is
<DateObject
>();
1367 * See ECMA 15.9.5.4 thru 15.9.5.23
1369 /* static */ MOZ_ALWAYS_INLINE
bool
1370 DateObject::getTime_impl(JSContext
* cx
, CallArgs args
)
1372 args
.rval().set(args
.thisv().toObject().as
<DateObject
>().UTCTime());
1377 date_getTime(JSContext
* cx
, unsigned argc
, Value
* vp
)
1379 CallArgs args
= CallArgsFromVp(argc
, vp
);
1380 return CallNonGenericMethod
<IsDate
, DateObject::getTime_impl
>(cx
, args
);
1383 /* static */ MOZ_ALWAYS_INLINE
bool
1384 DateObject::getYear_impl(JSContext
* cx
, CallArgs args
)
1386 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1387 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1389 Value yearVal
= dateObj
->getReservedSlot(LOCAL_YEAR_SLOT
);
1390 if (yearVal
.isInt32()) {
1391 /* Follow ECMA-262 to the letter, contrary to IE JScript. */
1392 int year
= yearVal
.toInt32() - 1900;
1393 args
.rval().setInt32(year
);
1395 args
.rval().set(yearVal
);
1402 date_getYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
1404 CallArgs args
= CallArgsFromVp(argc
, vp
);
1405 return CallNonGenericMethod
<IsDate
, DateObject::getYear_impl
>(cx
, args
);
1408 /* static */ MOZ_ALWAYS_INLINE
bool
1409 DateObject::getFullYear_impl(JSContext
* cx
, CallArgs args
)
1411 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1412 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1414 args
.rval().set(dateObj
->getReservedSlot(LOCAL_YEAR_SLOT
));
1419 date_getFullYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
1421 CallArgs args
= CallArgsFromVp(argc
, vp
);
1422 return CallNonGenericMethod
<IsDate
, DateObject::getFullYear_impl
>(cx
, args
);
1425 /* static */ MOZ_ALWAYS_INLINE
bool
1426 DateObject::getUTCFullYear_impl(JSContext
* cx
, CallArgs args
)
1428 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1429 if (IsFinite(result
))
1430 result
= YearFromTime(result
);
1432 args
.rval().setNumber(result
);
1437 date_getUTCFullYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
1439 CallArgs args
= CallArgsFromVp(argc
, vp
);
1440 return CallNonGenericMethod
<IsDate
, DateObject::getUTCFullYear_impl
>(cx
, args
);
1443 /* static */ MOZ_ALWAYS_INLINE
bool
1444 DateObject::getMonth_impl(JSContext
* cx
, CallArgs args
)
1446 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1447 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1449 args
.rval().set(dateObj
->getReservedSlot(LOCAL_MONTH_SLOT
));
1454 date_getMonth(JSContext
* cx
, unsigned argc
, Value
* vp
)
1456 CallArgs args
= CallArgsFromVp(argc
, vp
);
1457 return CallNonGenericMethod
<IsDate
, DateObject::getMonth_impl
>(cx
, args
);
1460 /* static */ MOZ_ALWAYS_INLINE
bool
1461 DateObject::getUTCMonth_impl(JSContext
* cx
, CallArgs args
)
1463 double d
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1464 args
.rval().setNumber(MonthFromTime(d
));
1469 date_getUTCMonth(JSContext
* cx
, unsigned argc
, Value
* vp
)
1471 CallArgs args
= CallArgsFromVp(argc
, vp
);
1472 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMonth_impl
>(cx
, args
);
1475 /* static */ MOZ_ALWAYS_INLINE
bool
1476 DateObject::getDate_impl(JSContext
* cx
, CallArgs args
)
1478 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1479 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1481 args
.rval().set(dateObj
->getReservedSlot(LOCAL_DATE_SLOT
));
1486 date_getDate(JSContext
* cx
, unsigned argc
, Value
* vp
)
1488 CallArgs args
= CallArgsFromVp(argc
, vp
);
1489 return CallNonGenericMethod
<IsDate
, DateObject::getDate_impl
>(cx
, args
);
1492 /* static */ MOZ_ALWAYS_INLINE
bool
1493 DateObject::getUTCDate_impl(JSContext
* cx
, CallArgs args
)
1495 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1496 if (IsFinite(result
))
1497 result
= DateFromTime(result
);
1499 args
.rval().setNumber(result
);
1504 date_getUTCDate(JSContext
* cx
, unsigned argc
, Value
* vp
)
1506 CallArgs args
= CallArgsFromVp(argc
, vp
);
1507 return CallNonGenericMethod
<IsDate
, DateObject::getUTCDate_impl
>(cx
, args
);
1510 /* static */ MOZ_ALWAYS_INLINE
bool
1511 DateObject::getDay_impl(JSContext
* cx
, CallArgs args
)
1513 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1514 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1516 args
.rval().set(dateObj
->getReservedSlot(LOCAL_DAY_SLOT
));
1521 date_getDay(JSContext
* cx
, unsigned argc
, Value
* vp
)
1523 CallArgs args
= CallArgsFromVp(argc
, vp
);
1524 return CallNonGenericMethod
<IsDate
, DateObject::getDay_impl
>(cx
, args
);
1527 /* static */ MOZ_ALWAYS_INLINE
bool
1528 DateObject::getUTCDay_impl(JSContext
* cx
, CallArgs args
)
1530 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1531 if (IsFinite(result
))
1532 result
= WeekDay(result
);
1534 args
.rval().setNumber(result
);
1539 date_getUTCDay(JSContext
* cx
, unsigned argc
, Value
* vp
)
1541 CallArgs args
= CallArgsFromVp(argc
, vp
);
1542 return CallNonGenericMethod
<IsDate
, DateObject::getUTCDay_impl
>(cx
, args
);
1545 /* static */ MOZ_ALWAYS_INLINE
bool
1546 DateObject::getHours_impl(JSContext
* cx
, CallArgs args
)
1548 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1549 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1551 args
.rval().set(dateObj
->getReservedSlot(LOCAL_HOURS_SLOT
));
1556 date_getHours(JSContext
* cx
, unsigned argc
, Value
* vp
)
1558 CallArgs args
= CallArgsFromVp(argc
, vp
);
1559 return CallNonGenericMethod
<IsDate
, DateObject::getHours_impl
>(cx
, args
);
1562 /* static */ MOZ_ALWAYS_INLINE
bool
1563 DateObject::getUTCHours_impl(JSContext
* cx
, CallArgs args
)
1565 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1566 if (IsFinite(result
))
1567 result
= HourFromTime(result
);
1569 args
.rval().setNumber(result
);
1574 date_getUTCHours(JSContext
* cx
, unsigned argc
, Value
* vp
)
1576 CallArgs args
= CallArgsFromVp(argc
, vp
);
1577 return CallNonGenericMethod
<IsDate
, DateObject::getUTCHours_impl
>(cx
, args
);
1580 /* static */ MOZ_ALWAYS_INLINE
bool
1581 DateObject::getMinutes_impl(JSContext
* cx
, CallArgs args
)
1583 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1584 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1586 args
.rval().set(dateObj
->getReservedSlot(LOCAL_MINUTES_SLOT
));
1591 date_getMinutes(JSContext
* cx
, unsigned argc
, Value
* vp
)
1593 CallArgs args
= CallArgsFromVp(argc
, vp
);
1594 return CallNonGenericMethod
<IsDate
, DateObject::getMinutes_impl
>(cx
, args
);
1597 /* static */ MOZ_ALWAYS_INLINE
bool
1598 DateObject::getUTCMinutes_impl(JSContext
* cx
, CallArgs args
)
1600 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1601 if (IsFinite(result
))
1602 result
= MinFromTime(result
);
1604 args
.rval().setNumber(result
);
1609 date_getUTCMinutes(JSContext
* cx
, unsigned argc
, Value
* vp
)
1611 CallArgs args
= CallArgsFromVp(argc
, vp
);
1612 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMinutes_impl
>(cx
, args
);
1615 /* Date.getSeconds is mapped to getUTCSeconds */
1617 /* static */ MOZ_ALWAYS_INLINE
bool
1618 DateObject::getUTCSeconds_impl(JSContext
* cx
, CallArgs args
)
1620 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1621 dateObj
->fillLocalTimeSlots(&cx
->runtime()->dateTimeInfo
);
1623 args
.rval().set(dateObj
->getReservedSlot(LOCAL_SECONDS_SLOT
));
1628 date_getUTCSeconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1630 CallArgs args
= CallArgsFromVp(argc
, vp
);
1631 return CallNonGenericMethod
<IsDate
, DateObject::getUTCSeconds_impl
>(cx
, args
);
1634 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
1636 /* static */ MOZ_ALWAYS_INLINE
bool
1637 DateObject::getUTCMilliseconds_impl(JSContext
* cx
, CallArgs args
)
1639 double result
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
1640 if (IsFinite(result
))
1641 result
= msFromTime(result
);
1643 args
.rval().setNumber(result
);
1648 date_getUTCMilliseconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1650 CallArgs args
= CallArgsFromVp(argc
, vp
);
1651 return CallNonGenericMethod
<IsDate
, DateObject::getUTCMilliseconds_impl
>(cx
, args
);
1654 /* static */ MOZ_ALWAYS_INLINE
bool
1655 DateObject::getTimezoneOffset_impl(JSContext
* cx
, CallArgs args
)
1657 DateObject
* dateObj
= &args
.thisv().toObject().as
<DateObject
>();
1658 double utctime
= dateObj
->UTCTime().toNumber();
1659 double localtime
= dateObj
->cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
1662 * Return the time zone offset in minutes for the current locale that is
1663 * appropriate for this time. This value would be a constant except for
1664 * daylight savings time.
1666 double result
= (utctime
- localtime
) / msPerMinute
;
1667 args
.rval().setNumber(result
);
1672 date_getTimezoneOffset(JSContext
* cx
, unsigned argc
, Value
* vp
)
1674 CallArgs args
= CallArgsFromVp(argc
, vp
);
1675 return CallNonGenericMethod
<IsDate
, DateObject::getTimezoneOffset_impl
>(cx
, args
);
1678 MOZ_ALWAYS_INLINE
bool
1679 date_setTime_impl(JSContext
* cx
, CallArgs args
)
1681 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1682 if (args
.length() == 0) {
1683 dateObj
->setUTCTime(GenericNaN(), args
.rval());
1688 if (!ToNumber(cx
, args
[0], &result
))
1691 dateObj
->setUTCTime(TimeClip(result
), args
.rval());
1696 date_setTime(JSContext
* cx
, unsigned argc
, Value
* vp
)
1698 CallArgs args
= CallArgsFromVp(argc
, vp
);
1699 return CallNonGenericMethod
<IsDate
, date_setTime_impl
>(cx
, args
);
1703 GetMsecsOrDefault(JSContext
* cx
, const CallArgs
& args
, unsigned i
, double t
, double* millis
)
1705 if (args
.length() <= i
) {
1706 *millis
= msFromTime(t
);
1709 return ToNumber(cx
, args
[i
], millis
);
1713 GetSecsOrDefault(JSContext
* cx
, const CallArgs
& args
, unsigned i
, double t
, double* sec
)
1715 if (args
.length() <= i
) {
1716 *sec
= SecFromTime(t
);
1719 return ToNumber(cx
, args
[i
], sec
);
1723 GetMinsOrDefault(JSContext
* cx
, const CallArgs
& args
, unsigned i
, double t
, double* mins
)
1725 if (args
.length() <= i
) {
1726 *mins
= MinFromTime(t
);
1729 return ToNumber(cx
, args
[i
], mins
);
1732 /* ES5 15.9.5.28. */
1733 MOZ_ALWAYS_INLINE
bool
1734 date_setMilliseconds_impl(JSContext
* cx
, CallArgs args
)
1736 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1739 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1743 if (!ToNumber(cx
, args
.get(0), &milli
))
1745 double time
= MakeTime(HourFromTime(t
), MinFromTime(t
), SecFromTime(t
), milli
);
1748 double u
= TimeClip(UTC(MakeDate(Day(t
), time
), &cx
->runtime()->dateTimeInfo
));
1751 dateObj
->setUTCTime(u
, args
.rval());
1756 date_setMilliseconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1758 CallArgs args
= CallArgsFromVp(argc
, vp
);
1759 return CallNonGenericMethod
<IsDate
, date_setMilliseconds_impl
>(cx
, args
);
1762 /* ES5 15.9.5.29. */
1763 MOZ_ALWAYS_INLINE
bool
1764 date_setUTCMilliseconds_impl(JSContext
* cx
, CallArgs args
)
1766 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1769 double t
= dateObj
->UTCTime().toNumber();
1773 if (!ToNumber(cx
, args
.get(0), &milli
))
1775 double time
= MakeTime(HourFromTime(t
), MinFromTime(t
), SecFromTime(t
), milli
);
1778 double v
= TimeClip(MakeDate(Day(t
), time
));
1781 dateObj
->setUTCTime(v
, args
.rval());
1786 date_setUTCMilliseconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1788 CallArgs args
= CallArgsFromVp(argc
, vp
);
1789 return CallNonGenericMethod
<IsDate
, date_setUTCMilliseconds_impl
>(cx
, args
);
1792 /* ES5 15.9.5.30. */
1793 MOZ_ALWAYS_INLINE
bool
1794 date_setSeconds_impl(JSContext
* cx
, CallArgs args
)
1796 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1799 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1803 if (!ToNumber(cx
, args
.get(0), &s
))
1808 if (!GetMsecsOrDefault(cx
, args
, 1, t
, &milli
))
1812 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), MinFromTime(t
), s
, milli
));
1815 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1818 dateObj
->setUTCTime(u
, args
.rval());
1822 /* ES5 15.9.5.31. */
1824 date_setSeconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1826 CallArgs args
= CallArgsFromVp(argc
, vp
);
1827 return CallNonGenericMethod
<IsDate
, date_setSeconds_impl
>(cx
, args
);
1830 MOZ_ALWAYS_INLINE
bool
1831 date_setUTCSeconds_impl(JSContext
* cx
, CallArgs args
)
1833 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1836 double t
= dateObj
->UTCTime().toNumber();
1840 if (!ToNumber(cx
, args
.get(0), &s
))
1845 if (!GetMsecsOrDefault(cx
, args
, 1, t
, &milli
))
1849 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), MinFromTime(t
), s
, milli
));
1852 double v
= TimeClip(date
);
1855 dateObj
->setUTCTime(v
, args
.rval());
1859 /* ES5 15.9.5.32. */
1861 date_setUTCSeconds(JSContext
* cx
, unsigned argc
, Value
* vp
)
1863 CallArgs args
= CallArgsFromVp(argc
, vp
);
1864 return CallNonGenericMethod
<IsDate
, date_setUTCSeconds_impl
>(cx
, args
);
1867 MOZ_ALWAYS_INLINE
bool
1868 date_setMinutes_impl(JSContext
* cx
, CallArgs args
)
1870 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1873 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1877 if (!ToNumber(cx
, args
.get(0), &m
))
1882 if (!GetSecsOrDefault(cx
, args
, 1, t
, &s
))
1887 if (!GetMsecsOrDefault(cx
, args
, 2, t
, &milli
))
1891 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), m
, s
, milli
));
1894 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1897 dateObj
->setUTCTime(u
, args
.rval());
1901 /* ES5 15.9.5.33. */
1903 date_setMinutes(JSContext
* cx
, unsigned argc
, Value
* vp
)
1905 CallArgs args
= CallArgsFromVp(argc
, vp
);
1906 return CallNonGenericMethod
<IsDate
, date_setMinutes_impl
>(cx
, args
);
1909 MOZ_ALWAYS_INLINE
bool
1910 date_setUTCMinutes_impl(JSContext
* cx
, CallArgs args
)
1912 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1915 double t
= dateObj
->UTCTime().toNumber();
1919 if (!ToNumber(cx
, args
.get(0), &m
))
1924 if (!GetSecsOrDefault(cx
, args
, 1, t
, &s
))
1929 if (!GetMsecsOrDefault(cx
, args
, 2, t
, &milli
))
1933 double date
= MakeDate(Day(t
), MakeTime(HourFromTime(t
), m
, s
, milli
));
1936 double v
= TimeClip(date
);
1939 dateObj
->setUTCTime(v
, args
.rval());
1943 /* ES5 15.9.5.34. */
1945 date_setUTCMinutes(JSContext
* cx
, unsigned argc
, Value
* vp
)
1947 CallArgs args
= CallArgsFromVp(argc
, vp
);
1948 return CallNonGenericMethod
<IsDate
, date_setUTCMinutes_impl
>(cx
, args
);
1951 MOZ_ALWAYS_INLINE
bool
1952 date_setHours_impl(JSContext
* cx
, CallArgs args
)
1954 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
1957 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
1961 if (!ToNumber(cx
, args
.get(0), &h
))
1966 if (!GetMinsOrDefault(cx
, args
, 1, t
, &m
))
1971 if (!GetSecsOrDefault(cx
, args
, 2, t
, &s
))
1976 if (!GetMsecsOrDefault(cx
, args
, 3, t
, &milli
))
1980 double date
= MakeDate(Day(t
), MakeTime(h
, m
, s
, milli
));
1983 double u
= TimeClip(UTC(date
, &cx
->runtime()->dateTimeInfo
));
1986 dateObj
->setUTCTime(u
, args
.rval());
1990 /* ES5 15.9.5.35. */
1992 date_setHours(JSContext
* cx
, unsigned argc
, Value
* vp
)
1994 CallArgs args
= CallArgsFromVp(argc
, vp
);
1995 return CallNonGenericMethod
<IsDate
, date_setHours_impl
>(cx
, args
);
1998 MOZ_ALWAYS_INLINE
bool
1999 date_setUTCHours_impl(JSContext
* cx
, CallArgs args
)
2001 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2004 double t
= dateObj
->UTCTime().toNumber();
2008 if (!ToNumber(cx
, args
.get(0), &h
))
2013 if (!GetMinsOrDefault(cx
, args
, 1, t
, &m
))
2018 if (!GetSecsOrDefault(cx
, args
, 2, t
, &s
))
2023 if (!GetMsecsOrDefault(cx
, args
, 3, t
, &milli
))
2027 double newDate
= MakeDate(Day(t
), MakeTime(h
, m
, s
, milli
));
2030 double v
= TimeClip(newDate
);
2033 dateObj
->setUTCTime(v
, args
.rval());
2037 /* ES5 15.9.5.36. */
2039 date_setUTCHours(JSContext
* cx
, unsigned argc
, Value
* vp
)
2041 CallArgs args
= CallArgsFromVp(argc
, vp
);
2042 return CallNonGenericMethod
<IsDate
, date_setUTCHours_impl
>(cx
, args
);
2045 MOZ_ALWAYS_INLINE
bool
2046 date_setDate_impl(JSContext
* cx
, CallArgs args
)
2048 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2051 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
2055 if (!ToNumber(cx
, args
.get(0), &date
))
2059 double newDate
= MakeDate(MakeDay(YearFromTime(t
), MonthFromTime(t
), date
), TimeWithinDay(t
));
2062 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2065 dateObj
->setUTCTime(u
, args
.rval());
2069 /* ES5 15.9.5.37. */
2071 date_setDate(JSContext
* cx
, unsigned argc
, Value
* vp
)
2073 CallArgs args
= CallArgsFromVp(argc
, vp
);
2074 return CallNonGenericMethod
<IsDate
, date_setDate_impl
>(cx
, args
);
2077 MOZ_ALWAYS_INLINE
bool
2078 date_setUTCDate_impl(JSContext
* cx
, CallArgs args
)
2080 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2083 double t
= dateObj
->UTCTime().toNumber();
2087 if (!ToNumber(cx
, args
.get(0), &date
))
2091 double newDate
= MakeDate(MakeDay(YearFromTime(t
), MonthFromTime(t
), date
), TimeWithinDay(t
));
2094 double v
= TimeClip(newDate
);
2097 dateObj
->setUTCTime(v
, args
.rval());
2102 date_setUTCDate(JSContext
* cx
, unsigned argc
, Value
* vp
)
2104 CallArgs args
= CallArgsFromVp(argc
, vp
);
2105 return CallNonGenericMethod
<IsDate
, date_setUTCDate_impl
>(cx
, args
);
2109 GetDateOrDefault(JSContext
* cx
, const CallArgs
& args
, unsigned i
, double t
, double* date
)
2111 if (args
.length() <= i
) {
2112 *date
= DateFromTime(t
);
2115 return ToNumber(cx
, args
[i
], date
);
2119 GetMonthOrDefault(JSContext
* cx
, const CallArgs
& args
, unsigned i
, double t
, double* month
)
2121 if (args
.length() <= i
) {
2122 *month
= MonthFromTime(t
);
2125 return ToNumber(cx
, args
[i
], month
);
2128 /* ES5 15.9.5.38. */
2129 MOZ_ALWAYS_INLINE
bool
2130 date_setMonth_impl(JSContext
* cx
, CallArgs args
)
2132 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2135 double t
= LocalTime(dateObj
->UTCTime().toNumber(), &cx
->runtime()->dateTimeInfo
);
2139 if (!ToNumber(cx
, args
.get(0), &m
))
2144 if (!GetDateOrDefault(cx
, args
, 1, t
, &date
))
2148 double newDate
= MakeDate(MakeDay(YearFromTime(t
), m
, date
), TimeWithinDay(t
));
2151 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2154 dateObj
->setUTCTime(u
, args
.rval());
2159 date_setMonth(JSContext
* cx
, unsigned argc
, Value
* vp
)
2161 CallArgs args
= CallArgsFromVp(argc
, vp
);
2162 return CallNonGenericMethod
<IsDate
, date_setMonth_impl
>(cx
, args
);
2165 /* ES5 15.9.5.39. */
2166 MOZ_ALWAYS_INLINE
bool
2167 date_setUTCMonth_impl(JSContext
* cx
, CallArgs args
)
2169 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2172 double t
= dateObj
->UTCTime().toNumber();
2176 if (!ToNumber(cx
, args
.get(0), &m
))
2181 if (!GetDateOrDefault(cx
, args
, 1, t
, &date
))
2185 double newDate
= MakeDate(MakeDay(YearFromTime(t
), m
, date
), TimeWithinDay(t
));
2188 double v
= TimeClip(newDate
);
2191 dateObj
->setUTCTime(v
, args
.rval());
2196 date_setUTCMonth(JSContext
* cx
, unsigned argc
, Value
* vp
)
2198 CallArgs args
= CallArgsFromVp(argc
, vp
);
2199 return CallNonGenericMethod
<IsDate
, date_setUTCMonth_impl
>(cx
, args
);
2203 ThisLocalTimeOrZero(Handle
<DateObject
*> dateObj
, DateTimeInfo
* dtInfo
)
2205 double t
= dateObj
->UTCTime().toNumber();
2208 return LocalTime(t
, dtInfo
);
2212 ThisUTCTimeOrZero(Handle
<DateObject
*> dateObj
)
2214 double t
= dateObj
->as
<DateObject
>().UTCTime().toNumber();
2215 return IsNaN(t
) ? +0 : t
;
2218 /* ES5 15.9.5.40. */
2219 MOZ_ALWAYS_INLINE
bool
2220 date_setFullYear_impl(JSContext
* cx
, CallArgs args
)
2222 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2225 double t
= ThisLocalTimeOrZero(dateObj
, &cx
->runtime()->dateTimeInfo
);
2229 if (!ToNumber(cx
, args
.get(0), &y
))
2234 if (!GetMonthOrDefault(cx
, args
, 1, t
, &m
))
2239 if (!GetDateOrDefault(cx
, args
, 2, t
, &date
))
2243 double newDate
= MakeDate(MakeDay(y
, m
, date
), TimeWithinDay(t
));
2246 double u
= TimeClip(UTC(newDate
, &cx
->runtime()->dateTimeInfo
));
2249 dateObj
->setUTCTime(u
, args
.rval());
2254 date_setFullYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
2256 CallArgs args
= CallArgsFromVp(argc
, vp
);
2257 return CallNonGenericMethod
<IsDate
, date_setFullYear_impl
>(cx
, args
);
2260 /* ES5 15.9.5.41. */
2261 MOZ_ALWAYS_INLINE
bool
2262 date_setUTCFullYear_impl(JSContext
* cx
, CallArgs args
)
2264 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2267 double t
= ThisUTCTimeOrZero(dateObj
);
2271 if (!ToNumber(cx
, args
.get(0), &y
))
2276 if (!GetMonthOrDefault(cx
, args
, 1, t
, &m
))
2281 if (!GetDateOrDefault(cx
, args
, 2, t
, &date
))
2285 double newDate
= MakeDate(MakeDay(y
, m
, date
), TimeWithinDay(t
));
2288 double v
= TimeClip(newDate
);
2291 dateObj
->setUTCTime(v
, args
.rval());
2296 date_setUTCFullYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
2298 CallArgs args
= CallArgsFromVp(argc
, vp
);
2299 return CallNonGenericMethod
<IsDate
, date_setUTCFullYear_impl
>(cx
, args
);
2302 /* ES5 Annex B.2.5. */
2303 MOZ_ALWAYS_INLINE
bool
2304 date_setYear_impl(JSContext
* cx
, CallArgs args
)
2306 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2309 double t
= ThisLocalTimeOrZero(dateObj
, &cx
->runtime()->dateTimeInfo
);
2313 if (!ToNumber(cx
, args
.get(0), &y
))
2318 dateObj
->setUTCTime(GenericNaN(), args
.rval());
2323 double yint
= ToInteger(y
);
2324 if (0 <= yint
&& yint
<= 99)
2328 double day
= MakeDay(yint
, MonthFromTime(t
), DateFromTime(t
));
2331 double u
= UTC(MakeDate(day
, TimeWithinDay(t
)), &cx
->runtime()->dateTimeInfo
);
2334 dateObj
->setUTCTime(TimeClip(u
), args
.rval());
2339 date_setYear(JSContext
* cx
, unsigned argc
, Value
* vp
)
2341 CallArgs args
= CallArgsFromVp(argc
, vp
);
2342 return CallNonGenericMethod
<IsDate
, date_setYear_impl
>(cx
, args
);
2345 /* constants for toString, toUTCString */
2346 static const char js_NaN_date_str
[] = "Invalid Date";
2347 static const char * const days
[] =
2349 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
2351 static const char * const months
[] =
2353 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2357 // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
2358 // requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
2360 print_gmt_string(char* buf
, size_t size
, double utctime
)
2362 MOZ_ASSERT(TimeClip(utctime
) == utctime
);
2363 JS_snprintf(buf
, size
, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
2364 days
[int(WeekDay(utctime
))],
2365 int(DateFromTime(utctime
)),
2366 months
[int(MonthFromTime(utctime
))],
2367 int(YearFromTime(utctime
)),
2368 int(HourFromTime(utctime
)),
2369 int(MinFromTime(utctime
)),
2370 int(SecFromTime(utctime
)));
2374 print_iso_string(char* buf
, size_t size
, double utctime
)
2376 MOZ_ASSERT(TimeClip(utctime
) == utctime
);
2377 JS_snprintf(buf
, size
, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
2378 int(YearFromTime(utctime
)),
2379 int(MonthFromTime(utctime
)) + 1,
2380 int(DateFromTime(utctime
)),
2381 int(HourFromTime(utctime
)),
2382 int(MinFromTime(utctime
)),
2383 int(SecFromTime(utctime
)),
2384 int(msFromTime(utctime
)));
2388 MOZ_ALWAYS_INLINE
bool
2389 date_toGMTString_impl(JSContext
* cx
, CallArgs args
)
2391 double utctime
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
2394 if (!IsFinite(utctime
))
2395 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2397 print_gmt_string(buf
, sizeof buf
, utctime
);
2399 JSString
* str
= JS_NewStringCopyZ(cx
, buf
);
2402 args
.rval().setString(str
);
2406 /* ES5 15.9.5.43. */
2408 date_toGMTString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2410 CallArgs args
= CallArgsFromVp(argc
, vp
);
2411 return CallNonGenericMethod
<IsDate
, date_toGMTString_impl
>(cx
, args
);
2414 MOZ_ALWAYS_INLINE
bool
2415 date_toISOString_impl(JSContext
* cx
, CallArgs args
)
2417 double utctime
= args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber();
2418 if (!IsFinite(utctime
)) {
2419 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_INVALID_DATE
);
2424 print_iso_string(buf
, sizeof buf
, utctime
);
2426 JSString
* str
= JS_NewStringCopyZ(cx
, buf
);
2429 args
.rval().setString(str
);
2435 date_toISOString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2437 CallArgs args
= CallArgsFromVp(argc
, vp
);
2438 return CallNonGenericMethod
<IsDate
, date_toISOString_impl
>(cx
, args
);
2441 /* ES5 15.9.5.44. */
2443 date_toJSON(JSContext
* cx
, unsigned argc
, Value
* vp
)
2445 CallArgs args
= CallArgsFromVp(argc
, vp
);
2448 RootedObject
obj(cx
, ToObject(cx
, args
.thisv()));
2453 RootedValue
tv(cx
, ObjectValue(*obj
));
2454 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, &tv
))
2458 if (tv
.isDouble() && !IsFinite(tv
.toDouble())) {
2459 args
.rval().setNull();
2464 RootedValue
toISO(cx
);
2465 if (!JSObject::getProperty(cx
, obj
, obj
, cx
->names().toISOString
, &toISO
))
2469 if (!IsCallable(toISO
)) {
2470 JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
, js_GetErrorMessage
, nullptr,
2471 JSMSG_BAD_TOISOSTRING_PROP
);
2476 InvokeArgs
args2(cx
);
2480 args2
.setCallee(toISO
);
2481 args2
.setThis(ObjectValue(*obj
));
2483 if (!Invoke(cx
, args2
))
2485 args
.rval().set(args2
.rval());
2489 /* for Date.toLocaleFormat; interface to PRMJTime date struct.
2492 new_explode(double timeval
, PRMJTime
* split
, DateTimeInfo
* dtInfo
)
2494 double year
= YearFromTime(timeval
);
2496 split
->tm_usec
= int32_t(msFromTime(timeval
)) * 1000;
2497 split
->tm_sec
= int8_t(SecFromTime(timeval
));
2498 split
->tm_min
= int8_t(MinFromTime(timeval
));
2499 split
->tm_hour
= int8_t(HourFromTime(timeval
));
2500 split
->tm_mday
= int8_t(DateFromTime(timeval
));
2501 split
->tm_mon
= int8_t(MonthFromTime(timeval
));
2502 split
->tm_wday
= int8_t(WeekDay(timeval
));
2503 split
->tm_year
= year
;
2504 split
->tm_yday
= int16_t(DayWithinYear(timeval
, year
));
2506 /* not sure how this affects things, but it doesn't seem
2508 split
->tm_isdst
= (DaylightSavingTA(timeval
, dtInfo
) != 0);
2511 typedef enum formatspec
{
2512 FORMATSPEC_FULL
, FORMATSPEC_DATE
, FORMATSPEC_TIME
2515 /* helper function */
2517 date_format(JSContext
* cx
, double date
, formatspec format
, MutableHandleValue rval
)
2525 if (!IsFinite(date
)) {
2526 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2528 MOZ_ASSERT(TimeClip(date
) == date
);
2530 double local
= LocalTime(date
, &cx
->runtime()->dateTimeInfo
);
2532 /* offset from GMT in minutes. The offset includes daylight savings,
2534 int minutes
= (int) floor(AdjustTime(date
, &cx
->runtime()->dateTimeInfo
) / msPerMinute
);
2536 /* map 510 minutes to 0830 hours */
2537 int offset
= (minutes
/ 60) * 100 + minutes
% 60;
2539 /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
2540 * printed as 'GMT-0800' rather than as 'PST' to avoid
2541 * operating-system dependence on strftime (which
2542 * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
2543 * PST as 'Pacific Standard Time.' This way we always know
2544 * what we're getting, and can parse it if we produce it.
2545 * The OS TZA string is included as a comment.
2548 /* get a timezone string from the OS to include as a
2550 new_explode(date
, &split
, &cx
->runtime()->dateTimeInfo
);
2551 if (PRMJ_FormatTime(tzbuf
, sizeof tzbuf
, "(%Z)", &split
) != 0) {
2553 /* Decide whether to use the resulting timezone string.
2555 * Reject it if it contains any non-ASCII, non-alphanumeric
2556 * characters. It's then likely in some other character
2557 * encoding, and we probably won't display it correctly.
2560 tzlen
= strlen(tzbuf
);
2564 for (i
= 0; i
< tzlen
; i
++) {
2565 char16_t c
= tzbuf
[i
];
2567 !(isalpha(c
) || isdigit(c
) ||
2568 c
== ' ' || c
== '(' || c
== ')')) {
2574 /* Also reject it if it's not parenthesized or if it's '()'. */
2575 if (tzbuf
[0] != '(' || tzbuf
[1] == ')')
2581 case FORMATSPEC_FULL
:
2583 * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
2584 * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
2586 /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
2587 JS_snprintf(buf
, sizeof buf
,
2588 "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
2589 days
[int(WeekDay(local
))],
2590 months
[int(MonthFromTime(local
))],
2591 int(DateFromTime(local
)),
2592 int(YearFromTime(local
)),
2593 int(HourFromTime(local
)),
2594 int(MinFromTime(local
)),
2595 int(SecFromTime(local
)),
2598 usetz
? tzbuf
: "");
2600 case FORMATSPEC_DATE
:
2601 /* Tue Oct 31 2000 */
2602 JS_snprintf(buf
, sizeof buf
,
2604 days
[int(WeekDay(local
))],
2605 months
[int(MonthFromTime(local
))],
2606 int(DateFromTime(local
)),
2607 int(YearFromTime(local
)));
2609 case FORMATSPEC_TIME
:
2610 /* 09:41:40 GMT-0800 (PST) */
2611 JS_snprintf(buf
, sizeof buf
,
2612 "%.2d:%.2d:%.2d GMT%+.4d%s%s",
2613 int(HourFromTime(local
)),
2614 int(MinFromTime(local
)),
2615 int(SecFromTime(local
)),
2618 usetz
? tzbuf
: "");
2623 JSString
* str
= JS_NewStringCopyZ(cx
, buf
);
2626 rval
.setString(str
);
2631 ToLocaleFormatHelper(JSContext
* cx
, HandleObject obj
, const char* format
, MutableHandleValue rval
)
2633 double utctime
= obj
->as
<DateObject
>().UTCTime().toNumber();
2636 if (!IsFinite(utctime
)) {
2637 JS_snprintf(buf
, sizeof buf
, js_NaN_date_str
);
2640 double local
= LocalTime(utctime
, &cx
->runtime()->dateTimeInfo
);
2642 new_explode(local
, &split
, &cx
->runtime()->dateTimeInfo
);
2644 /* Let PRMJTime format it. */
2645 result_len
= PRMJ_FormatTime(buf
, sizeof buf
, format
, &split
);
2647 /* If it failed, default to toString. */
2648 if (result_len
== 0)
2649 return date_format(cx
, utctime
, FORMATSPEC_FULL
, rval
);
2651 /* Hacked check against undesired 2-digit year 00/00/00 form. */
2652 if (strcmp(format
, "%x") == 0 && result_len
>= 6 &&
2653 /* Format %x means use OS settings, which may have 2-digit yr, so
2654 hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
2655 !isdigit(buf
[result_len
- 3]) &&
2656 isdigit(buf
[result_len
- 2]) && isdigit(buf
[result_len
- 1]) &&
2657 /* ...but not if starts with 4-digit year, like 2022/3/11. */
2658 !(isdigit(buf
[0]) && isdigit(buf
[1]) &&
2659 isdigit(buf
[2]) && isdigit(buf
[3]))) {
2660 double localtime
= obj
->as
<DateObject
>().cachedLocalTime(&cx
->runtime()->dateTimeInfo
);
2661 int year
= IsNaN(localtime
) ? 0 : (int) YearFromTime(localtime
);
2662 JS_snprintf(buf
+ (result_len
- 2), (sizeof buf
) - (result_len
- 2),
2668 if (cx
->runtime()->localeCallbacks
&& cx
->runtime()->localeCallbacks
->localeToUnicode
)
2669 return cx
->runtime()->localeCallbacks
->localeToUnicode(cx
, buf
, rval
);
2671 JSString
* str
= JS_NewStringCopyZ(cx
, buf
);
2674 rval
.setString(str
);
2678 #if !EXPOSE_INTL_API
2680 ToLocaleStringHelper(JSContext
* cx
, Handle
<DateObject
*> dateObj
, MutableHandleValue rval
)
2683 * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
2684 * with msvc; '%#c' requests that a full year be used in the result string.
2686 return ToLocaleFormatHelper(cx
, dateObj
,
2687 #if defined(_WIN32) && !defined(__MWERKS__)
2696 MOZ_ALWAYS_INLINE
bool
2697 date_toLocaleString_impl(JSContext
* cx
, CallArgs args
)
2699 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2700 return ToLocaleStringHelper(cx
, dateObj
, args
.rval());
2704 date_toLocaleString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2706 CallArgs args
= CallArgsFromVp(argc
, vp
);
2707 return CallNonGenericMethod
<IsDate
, date_toLocaleString_impl
>(cx
, args
);
2711 MOZ_ALWAYS_INLINE
bool
2712 date_toLocaleDateString_impl(JSContext
* cx
, CallArgs args
)
2715 * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
2716 * with msvc; '%#x' requests that a full year be used in the result string.
2718 static const char format
[] =
2719 #if defined(_WIN32) && !defined(__MWERKS__)
2726 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2727 return ToLocaleFormatHelper(cx
, dateObj
, format
, args
.rval());
2731 date_toLocaleDateString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2733 CallArgs args
= CallArgsFromVp(argc
, vp
);
2734 return CallNonGenericMethod
<IsDate
, date_toLocaleDateString_impl
>(cx
, args
);
2738 MOZ_ALWAYS_INLINE
bool
2739 date_toLocaleTimeString_impl(JSContext
* cx
, CallArgs args
)
2741 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2742 return ToLocaleFormatHelper(cx
, dateObj
, "%X", args
.rval());
2746 date_toLocaleTimeString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2748 CallArgs args
= CallArgsFromVp(argc
, vp
);
2749 return CallNonGenericMethod
<IsDate
, date_toLocaleTimeString_impl
>(cx
, args
);
2751 #endif /* !EXPOSE_INTL_API */
2753 MOZ_ALWAYS_INLINE
bool
2754 date_toLocaleFormat_impl(JSContext
* cx
, CallArgs args
)
2756 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2758 if (args
.length() == 0) {
2760 * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
2761 * with msvc; '%#c' requests that a full year be used in the result string.
2763 return ToLocaleFormatHelper(cx
, dateObj
,
2764 #if defined(_WIN32) && !defined(__MWERKS__)
2772 RootedString
fmt(cx
, ToString
<CanGC
>(cx
, args
[0]));
2776 JSAutoByteString
fmtbytes(cx
, fmt
);
2780 return ToLocaleFormatHelper(cx
, dateObj
, fmtbytes
.ptr(), args
.rval());
2784 date_toLocaleFormat(JSContext
* cx
, unsigned argc
, Value
* vp
)
2786 CallArgs args
= CallArgsFromVp(argc
, vp
);
2787 return CallNonGenericMethod
<IsDate
, date_toLocaleFormat_impl
>(cx
, args
);
2791 MOZ_ALWAYS_INLINE
bool
2792 date_toTimeString_impl(JSContext
* cx
, CallArgs args
)
2794 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2795 FORMATSPEC_TIME
, args
.rval());
2799 date_toTimeString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2801 CallArgs args
= CallArgsFromVp(argc
, vp
);
2802 return CallNonGenericMethod
<IsDate
, date_toTimeString_impl
>(cx
, args
);
2806 MOZ_ALWAYS_INLINE
bool
2807 date_toDateString_impl(JSContext
* cx
, CallArgs args
)
2809 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2810 FORMATSPEC_DATE
, args
.rval());
2814 date_toDateString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2816 CallArgs args
= CallArgsFromVp(argc
, vp
);
2817 return CallNonGenericMethod
<IsDate
, date_toDateString_impl
>(cx
, args
);
2821 MOZ_ALWAYS_INLINE
bool
2822 date_toSource_impl(JSContext
* cx
, CallArgs args
)
2824 StringBuffer
sb(cx
);
2825 if (!sb
.append("(new Date(") ||
2826 !NumberValueToStringBuffer(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime(), sb
) ||
2832 JSString
* str
= sb
.finishString();
2835 args
.rval().setString(str
);
2840 date_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
)
2842 CallArgs args
= CallArgsFromVp(argc
, vp
);
2843 return CallNonGenericMethod
<IsDate
, date_toSource_impl
>(cx
, args
);
2847 MOZ_ALWAYS_INLINE
bool
2848 date_toString_impl(JSContext
* cx
, CallArgs args
)
2850 return date_format(cx
, args
.thisv().toObject().as
<DateObject
>().UTCTime().toNumber(),
2851 FORMATSPEC_FULL
, args
.rval());
2855 date_toString(JSContext
* cx
, unsigned argc
, Value
* vp
)
2857 CallArgs args
= CallArgsFromVp(argc
, vp
);
2858 return CallNonGenericMethod
<IsDate
, date_toString_impl
>(cx
, args
);
2861 MOZ_ALWAYS_INLINE
bool
2862 date_valueOf_impl(JSContext
* cx
, CallArgs args
)
2864 Rooted
<DateObject
*> dateObj(cx
, &args
.thisv().toObject().as
<DateObject
>());
2865 args
.rval().set(dateObj
->UTCTime());
2870 js::date_valueOf(JSContext
* cx
, unsigned argc
, Value
* vp
)
2872 CallArgs args
= CallArgsFromVp(argc
, vp
);
2873 return CallNonGenericMethod
<IsDate
, date_valueOf_impl
>(cx
, args
);
2876 static const JSFunctionSpec date_static_methods
[] = {
2877 JS_FN("UTC", date_UTC
, MAXARGS
,0),
2878 JS_FN("parse", date_parse
, 1,0),
2879 JS_FN("now", date_now
, 0,0),
2883 static const JSFunctionSpec date_methods
[] = {
2884 JS_FN("getTime", date_getTime
, 0,0),
2885 JS_FN("getTimezoneOffset", date_getTimezoneOffset
, 0,0),
2886 JS_FN("getYear", date_getYear
, 0,0),
2887 JS_FN("getFullYear", date_getFullYear
, 0,0),
2888 JS_FN("getUTCFullYear", date_getUTCFullYear
, 0,0),
2889 JS_FN("getMonth", date_getMonth
, 0,0),
2890 JS_FN("getUTCMonth", date_getUTCMonth
, 0,0),
2891 JS_FN("getDate", date_getDate
, 0,0),
2892 JS_FN("getUTCDate", date_getUTCDate
, 0,0),
2893 JS_FN("getDay", date_getDay
, 0,0),
2894 JS_FN("getUTCDay", date_getUTCDay
, 0,0),
2895 JS_FN("getHours", date_getHours
, 0,0),
2896 JS_FN("getUTCHours", date_getUTCHours
, 0,0),
2897 JS_FN("getMinutes", date_getMinutes
, 0,0),
2898 JS_FN("getUTCMinutes", date_getUTCMinutes
, 0,0),
2899 JS_FN("getSeconds", date_getUTCSeconds
, 0,0),
2900 JS_FN("getUTCSeconds", date_getUTCSeconds
, 0,0),
2901 JS_FN("getMilliseconds", date_getUTCMilliseconds
, 0,0),
2902 JS_FN("getUTCMilliseconds", date_getUTCMilliseconds
, 0,0),
2903 JS_FN("setTime", date_setTime
, 1,0),
2904 JS_FN("setYear", date_setYear
, 1,0),
2905 JS_FN("setFullYear", date_setFullYear
, 3,0),
2906 JS_FN("setUTCFullYear", date_setUTCFullYear
, 3,0),
2907 JS_FN("setMonth", date_setMonth
, 2,0),
2908 JS_FN("setUTCMonth", date_setUTCMonth
, 2,0),
2909 JS_FN("setDate", date_setDate
, 1,0),
2910 JS_FN("setUTCDate", date_setUTCDate
, 1,0),
2911 JS_FN("setHours", date_setHours
, 4,0),
2912 JS_FN("setUTCHours", date_setUTCHours
, 4,0),
2913 JS_FN("setMinutes", date_setMinutes
, 3,0),
2914 JS_FN("setUTCMinutes", date_setUTCMinutes
, 3,0),
2915 JS_FN("setSeconds", date_setSeconds
, 2,0),
2916 JS_FN("setUTCSeconds", date_setUTCSeconds
, 2,0),
2917 JS_FN("setMilliseconds", date_setMilliseconds
, 1,0),
2918 JS_FN("setUTCMilliseconds", date_setUTCMilliseconds
, 1,0),
2919 JS_FN("toUTCString", date_toGMTString
, 0,0),
2920 JS_FN("toLocaleFormat", date_toLocaleFormat
, 0,0),
2922 JS_SELF_HOSTED_FN(js_toLocaleString_str
, "Date_toLocaleString", 0,0),
2923 JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0),
2924 JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0),
2926 JS_FN(js_toLocaleString_str
, date_toLocaleString
, 0,0),
2927 JS_FN("toLocaleDateString", date_toLocaleDateString
, 0,0),
2928 JS_FN("toLocaleTimeString", date_toLocaleTimeString
, 0,0),
2930 JS_FN("toDateString", date_toDateString
, 0,0),
2931 JS_FN("toTimeString", date_toTimeString
, 0,0),
2932 JS_FN("toISOString", date_toISOString
, 0,0),
2933 JS_FN(js_toJSON_str
, date_toJSON
, 1,0),
2935 JS_FN(js_toSource_str
, date_toSource
, 0,0),
2937 JS_FN(js_toString_str
, date_toString
, 0,0),
2938 JS_FN(js_valueOf_str
, date_valueOf
, 0,0),
2943 js_Date(JSContext
* cx
, unsigned argc
, Value
* vp
)
2945 CallArgs args
= CallArgsFromVp(argc
, vp
);
2947 /* Date called as function. */
2948 if (!args
.isConstructing())
2949 return date_format(cx
, NowAsMillis(), FORMATSPEC_FULL
, args
.rval());
2951 /* Date called as constructor. */
2953 if (args
.length() == 0) {
2956 } else if (args
.length() == 1) {
2960 if (!ToPrimitive(cx
, args
[0]))
2963 if (args
[0].isString()) {
2965 JSString
* str
= args
[0].toString();
2969 JSLinearString
* linearStr
= str
->ensureLinear(cx
);
2973 if (!ParseDate(linearStr
, &d
, &cx
->runtime()->dateTimeInfo
))
2979 if (!ToNumber(cx
, args
[0], &d
))
2985 if (!date_msecFromArgs(cx
, args
, &msec_time
))
2988 if (IsFinite(msec_time
)) {
2989 msec_time
= UTC(msec_time
, &cx
->runtime()->dateTimeInfo
);
2990 msec_time
= TimeClip(msec_time
);
2995 JSObject
* obj
= js_NewDateObjectMsec(cx
, d
);
2999 args
.rval().setObject(*obj
);
3004 FinishDateClassInit(JSContext
* cx
, HandleObject ctor
, HandleObject proto
)
3006 proto
->as
<DateObject
>().setUTCTime(GenericNaN());
3009 * Date.prototype.toGMTString has the same initial value as
3010 * Date.prototype.toUTCString.
3012 RootedValue
toUTCStringFun(cx
);
3013 RootedId
toUTCStringId(cx
, NameToId(cx
->names().toUTCString
));
3014 RootedId
toGMTStringId(cx
, NameToId(cx
->names().toGMTString
));
3015 return baseops::GetProperty(cx
, proto
.as
<DateObject
>(), toUTCStringId
, &toUTCStringFun
) &&
3016 baseops::DefineGeneric(cx
, proto
.as
<DateObject
>(), toGMTStringId
, toUTCStringFun
,
3017 nullptr, nullptr, 0);
3020 const Class
DateObject::class_
= {
3022 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS
) |
3023 JSCLASS_HAS_CACHED_PROTO(JSProto_Date
),
3024 nullptr, /* addProperty */
3025 nullptr, /* delProperty */
3026 nullptr, /* getProperty */
3027 nullptr, /* setProperty */
3028 nullptr, /* enumerate */
3029 nullptr, /* resolve */
3031 nullptr, /* finalize */
3033 nullptr, /* hasInstance */
3034 nullptr, /* construct */
3035 nullptr, /* trace */
3037 GenericCreateConstructor
<js_Date
, MAXARGS
, JSFunction::FinalizeKind
>,
3038 GenericCreatePrototype
,
3039 date_static_methods
,
3046 JS_FRIEND_API(JSObject
*)
3047 js_NewDateObjectMsec(JSContext
* cx
, double msec_time
)
3049 JSObject
* obj
= NewBuiltinClassInstance(cx
, &DateObject::class_
);
3052 obj
->as
<DateObject
>().setUTCTime(msec_time
);
3056 JS_FRIEND_API(JSObject
*)
3057 js_NewDateObject(JSContext
* cx
, int year
, int mon
, int mday
,
3058 int hour
, int min
, int sec
)
3060 MOZ_ASSERT(mon
< 12);
3061 double msec_time
= date_msecFromDate(year
, mon
, mday
, hour
, min
, sec
, 0);
3062 return js_NewDateObjectMsec(cx
, UTC(msec_time
, &cx
->runtime()->dateTimeInfo
));
3066 js::DateIsValid(JSContext
* cx
, JSObject
* objArg
)
3068 RootedObject
obj(cx
, objArg
);
3069 if (!ObjectClassIs(obj
, ESClass_Date
, cx
))
3072 RootedValue
unboxed(cx
);
3073 if (!Unbox(cx
, obj
, &unboxed
)) {
3074 // This can't actually happen, so we don't force consumers to deal with
3075 // a clunky out-param API. Do something sane-ish if it does happen.
3076 cx
->clearPendingException();
3080 return !IsNaN(unboxed
.toNumber());
3083 JS_FRIEND_API(double)
3084 js::DateGetMsecSinceEpoch(JSContext
* cx
, JSObject
* objArg
)
3086 RootedObject
obj(cx
, objArg
);
3087 if (!ObjectClassIs(obj
, ESClass_Date
, cx
))
3090 RootedValue
unboxed(cx
);
3091 if (!Unbox(cx
, obj
, &unboxed
)) {
3092 // This can't actually happen, so we don't force consumers to deal with
3093 // a clunky out-param API. Do something sane-ish if it does happen.
3094 cx
->clearPendingException();
3098 return unboxed
.toNumber();