2009-06-10 18:29:44 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2007-03-22 10:30:00 -07:00
|
|
|
* vim: set ts=8 sw=4 et tw=78:
|
|
|
|
*
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JS date methods.
|
|
|
|
*/
|
|
|
|
|
2012-01-23 03:43:16 -08:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
#include "mozilla/Util.h"
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* "For example, OS/360 devotes 26 bytes of the permanently
|
|
|
|
* resident date-turnover routine to the proper handling of
|
|
|
|
* December 31 on leap years (when it is Day 366). That
|
|
|
|
* might have been left to the operator."
|
|
|
|
*
|
|
|
|
* Frederick Brooks, 'The Second-System Effect'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-10-10 23:00:28 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "jstypes.h"
|
|
|
|
#include "jsprf.h"
|
|
|
|
#include "prmjtime.h"
|
2010-10-01 16:46:54 -07:00
|
|
|
#include "jsutil.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "jsapi.h"
|
2008-09-05 10:19:17 -07:00
|
|
|
#include "jsversion.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "jscntxt.h"
|
|
|
|
#include "jsdate.h"
|
|
|
|
#include "jsinterp.h"
|
|
|
|
#include "jsnum.h"
|
|
|
|
#include "jsobj.h"
|
|
|
|
#include "jsstr.h"
|
2011-06-07 18:41:37 -07:00
|
|
|
#include "jslibmath.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-03 12:18:36 -07:00
|
|
|
#include "vm/GlobalObject.h"
|
2012-04-19 16:18:24 -07:00
|
|
|
#include "vm/NumericConversions.h"
|
2012-03-14 15:29:29 -07:00
|
|
|
#include "vm/StringBuffer.h"
|
2011-05-03 12:18:36 -07:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jsinferinlines.h"
|
2010-04-10 16:16:35 -07:00
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
2011-04-13 09:27:37 -07:00
|
|
|
#include "vm/Stack-inl.h"
|
|
|
|
|
2011-10-10 23:00:28 -07:00
|
|
|
using namespace mozilla;
|
2010-04-07 13:18:50 -07:00
|
|
|
using namespace js;
|
2010-10-29 08:05:55 -07:00
|
|
|
using namespace js::types;
|
2010-04-07 13:18:50 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* The JS 'Date' object is patterned after the Java 'Date' object.
|
|
|
|
* Here is an script:
|
|
|
|
*
|
|
|
|
* today = new Date();
|
|
|
|
*
|
|
|
|
* print(today.toLocaleString());
|
|
|
|
*
|
|
|
|
* weekDay = today.getDay();
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* These Java (and ECMA-262) methods are supported:
|
|
|
|
*
|
|
|
|
* UTC
|
|
|
|
* getDate (getUTCDate)
|
|
|
|
* getDay (getUTCDay)
|
|
|
|
* getHours (getUTCHours)
|
|
|
|
* getMinutes (getUTCMinutes)
|
|
|
|
* getMonth (getUTCMonth)
|
|
|
|
* getSeconds (getUTCSeconds)
|
|
|
|
* getMilliseconds (getUTCMilliseconds)
|
|
|
|
* getTime
|
|
|
|
* getTimezoneOffset
|
|
|
|
* getYear
|
|
|
|
* getFullYear (getUTCFullYear)
|
|
|
|
* parse
|
|
|
|
* setDate (setUTCDate)
|
|
|
|
* setHours (setUTCHours)
|
|
|
|
* setMinutes (setUTCMinutes)
|
|
|
|
* setMonth (setUTCMonth)
|
|
|
|
* setSeconds (setUTCSeconds)
|
|
|
|
* setMilliseconds (setUTCMilliseconds)
|
|
|
|
* setTime
|
|
|
|
* setYear (setFullYear, setUTCFullYear)
|
|
|
|
* toGMTString (toUTCString)
|
|
|
|
* toLocaleString
|
|
|
|
* toString
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* These Java methods are not supported
|
|
|
|
*
|
|
|
|
* setDay
|
|
|
|
* before
|
|
|
|
* after
|
|
|
|
* equals
|
|
|
|
* hashCode
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
|
|
|
|
* definition and reduce dependence on NSPR. NSPR is used to get the current
|
|
|
|
* time in milliseconds, the time zone offset, and the daylight savings time
|
|
|
|
* offset for a given time. NSPR is also used for Date.toLocaleString(), for
|
|
|
|
* locale-specific formatting, and to get a string representing the timezone.
|
|
|
|
* (Which turns out to be platform-dependent.)
|
|
|
|
*
|
|
|
|
* To do:
|
|
|
|
* (I did some performance tests by timing how long it took to run what
|
|
|
|
* I had of the js ECMA conformance tests.)
|
|
|
|
*
|
|
|
|
* - look at saving results across multiple calls to supporting
|
|
|
|
* functions; the toString functions compute some of the same values
|
|
|
|
* multiple times. Although - I took a quick stab at this, and I lost
|
|
|
|
* rather than gained. (Fractionally.) Hard to tell what compilers/processors
|
|
|
|
* are doing these days.
|
|
|
|
*
|
|
|
|
* - look at tweaking function return types to return double instead
|
|
|
|
* of int; this seems to make things run slightly faster sometimes.
|
|
|
|
* (though it could be architecture-dependent.) It'd be good to see
|
|
|
|
* how this does on win32. (Tried it on irix.) Types could use a
|
|
|
|
* general going-over.
|
|
|
|
*/
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
/* Constants defined by ES5 15.9.1.10. */
|
|
|
|
const double HoursPerDay = 24.0;
|
|
|
|
const double MinutesPerHour = 60;
|
|
|
|
const double SecondsPerMinute = 60;
|
|
|
|
const double msPerSecond = 1000;
|
|
|
|
const double msPerMinute = msPerSecond * SecondsPerMinute;
|
|
|
|
const double msPerHour = msPerMinute * MinutesPerHour;
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.2. */
|
|
|
|
const double msPerDay = 86400000;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
inline double
|
|
|
|
Day(double t)
|
|
|
|
{
|
|
|
|
return floor(t / msPerDay);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
TimeWithinDay(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:52:53 -07:00
|
|
|
double result = fmod(t, msPerDay);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
|
|
|
result += msPerDay;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.3. */
|
|
|
|
inline bool
|
2012-07-09 14:28:20 -07:00
|
|
|
IsLeapYear(double year)
|
2010-08-18 19:44:28 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
JS_ASSERT(ToInteger(year) == year);
|
|
|
|
return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0);
|
2010-08-18 19:44:28 -07:00
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
inline double
|
|
|
|
DaysInYear(double year)
|
2010-08-18 19:44:28 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(year))
|
|
|
|
return js_NaN;
|
2010-08-18 19:44:28 -07:00
|
|
|
return IsLeapYear(year) ? 366 : 365;
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
inline double
|
|
|
|
DayFromYear(double y)
|
2010-08-18 19:44:28 -07:00
|
|
|
{
|
2012-07-06 13:52:53 -07:00
|
|
|
return 365 * (y - 1970) +
|
|
|
|
floor((y - 1969) / 4.0) -
|
|
|
|
floor((y - 1901) / 100.0) +
|
|
|
|
floor((y - 1601) / 400.0);
|
2010-08-18 19:44:28 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
inline double
|
2012-07-09 14:28:20 -07:00
|
|
|
TimeFromYear(double y)
|
2012-07-06 13:52:53 -07:00
|
|
|
{
|
|
|
|
return DayFromYear(y) * msPerDay;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
YearFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(t))
|
|
|
|
return js_NaN;
|
|
|
|
|
|
|
|
JS_ASSERT(ToInteger(t) == t);
|
|
|
|
|
|
|
|
double y = floor(t / (msPerDay * 365.2425)) + 1970;
|
2012-07-06 13:52:53 -07:00
|
|
|
double t2 = TimeFromYear(y);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-17 10:42:57 -07:00
|
|
|
/*
|
|
|
|
* Adjust the year if the approximation was wrong. Since the year was
|
|
|
|
* computed using the average number of ms per year, it will usually
|
|
|
|
* be wrong for dates within several hours of a year transition.
|
|
|
|
*/
|
2007-03-22 10:30:00 -07:00
|
|
|
if (t2 > t) {
|
|
|
|
y--;
|
|
|
|
} else {
|
|
|
|
if (t2 + msPerDay * DaysInYear(y) <= t)
|
|
|
|
y++;
|
|
|
|
}
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
inline int
|
|
|
|
DaysInFebruary(int year)
|
|
|
|
{
|
|
|
|
return IsLeapYear(year) ? 29 : 28;
|
|
|
|
}
|
2009-08-26 18:13:48 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.4. */
|
2012-07-09 14:28:20 -07:00
|
|
|
inline double
|
|
|
|
DayWithinYear(double t, double year)
|
2009-08-26 18:13:48 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
JS_ASSERT_IF(MOZ_DOUBLE_IS_FINITE(t), YearFromTime(t) == year);
|
|
|
|
return Day(t) - DayFromYear(year);
|
2009-08-26 18:13:48 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
MonthFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(t))
|
|
|
|
return js_NaN;
|
|
|
|
|
|
|
|
double year = YearFromTime(t);
|
|
|
|
double d = DayWithinYear(t, year);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
int step;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (d < (step = 31))
|
|
|
|
return 0;
|
2010-08-18 19:44:28 -07:00
|
|
|
if (d < (step += DaysInFebruary(year)))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 1;
|
|
|
|
if (d < (step += 31))
|
|
|
|
return 2;
|
|
|
|
if (d < (step += 30))
|
|
|
|
return 3;
|
|
|
|
if (d < (step += 31))
|
|
|
|
return 4;
|
|
|
|
if (d < (step += 30))
|
|
|
|
return 5;
|
|
|
|
if (d < (step += 31))
|
|
|
|
return 6;
|
|
|
|
if (d < (step += 31))
|
|
|
|
return 7;
|
|
|
|
if (d < (step += 30))
|
|
|
|
return 8;
|
|
|
|
if (d < (step += 31))
|
|
|
|
return 9;
|
|
|
|
if (d < (step += 30))
|
|
|
|
return 10;
|
|
|
|
return 11;
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.5. */
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
DateFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double year = YearFromTime(t);
|
|
|
|
double d = DayWithinYear(t, year);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
int next;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (d <= (next = 30))
|
|
|
|
return d + 1;
|
2012-07-06 13:52:53 -07:00
|
|
|
int step = next;
|
2010-08-18 19:44:28 -07:00
|
|
|
if (d <= (next += DaysInFebruary(year)))
|
2007-03-22 10:30:00 -07:00
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 31))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 30))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 31))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 30))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 31))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 31))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 30))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 31))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
if (d <= (next += 30))
|
|
|
|
return d - step;
|
|
|
|
step = next;
|
|
|
|
return d - step;
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.6. */
|
2012-02-28 15:11:11 -08:00
|
|
|
static int
|
2012-02-24 14:19:52 -08:00
|
|
|
WeekDay(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
/*
|
|
|
|
* We can't assert TimeClip(t) == t because we call this function with
|
|
|
|
* local times, which can be offset outside TimeClip's permitted range.
|
|
|
|
*/
|
|
|
|
JS_ASSERT(ToInteger(t) == t);
|
2012-07-06 13:52:53 -07:00
|
|
|
int result = (int(Day(t)) + 4) % 7;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
|
|
|
result += 7;
|
2012-07-06 13:52:53 -07:00
|
|
|
return result;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
/* ES5 15.9.1.7. Set by UpdateLocalTZA(). */
|
|
|
|
static double LocalTZA;
|
|
|
|
|
|
|
|
inline void
|
|
|
|
UpdateLocalTZA()
|
|
|
|
{
|
|
|
|
LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
|
|
|
|
}
|
2012-07-06 13:52:53 -07:00
|
|
|
|
|
|
|
inline int
|
|
|
|
DayFromMonth(int month, bool isLeapYear)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The following array contains the day of year for the first day of
|
|
|
|
* each month, where index 0 is January, and day 0 is January 1.
|
|
|
|
*/
|
|
|
|
static const int firstDayOfMonth[2][13] = {
|
|
|
|
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
|
|
|
|
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
|
|
|
|
};
|
|
|
|
|
|
|
|
JS_ASSERT(0 <= month && month <= 12);
|
|
|
|
return firstDayOfMonth[isLeapYear][month];
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
template<typename T>
|
|
|
|
inline int
|
|
|
|
DayFromMonth(T month, bool isLeapYear) MOZ_DELETE;
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
MakeDay(double year, double month, double date)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
/* Step 1. */
|
2012-07-06 13:52:53 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(year) || !MOZ_DOUBLE_IS_FINITE(month) || !MOZ_DOUBLE_IS_FINITE(date))
|
|
|
|
return js_NaN;
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
/* Steps 2-4. */
|
|
|
|
double y = ToInteger(year);
|
|
|
|
double m = ToInteger(month);
|
|
|
|
double dt = ToInteger(date);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
/* Step 5. */
|
|
|
|
double ym = y + floor(m / 12);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
/* Step 6. */
|
|
|
|
int mn = int(fmod(m, 12.0));
|
|
|
|
if (mn < 0)
|
|
|
|
mn += 12;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
/* Steps 7-8. */
|
|
|
|
bool leap = IsLeapYear(ym);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
double yearday = floor(TimeFromYear(ym) / msPerDay);
|
|
|
|
double monthday = DayFromMonth(mn, leap);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
return yearday + monthday + dt - 1;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
|
|
|
|
inline double
|
|
|
|
MakeDate(double day, double time)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:52:53 -07:00
|
|
|
/* Step 1. */
|
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(day) || !MOZ_DOUBLE_IS_FINITE(time))
|
|
|
|
return js_NaN;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* Step 2. */
|
|
|
|
return day * msPerDay + time;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
/*
|
|
|
|
* Find a year for which any given date will fall on the same weekday.
|
|
|
|
*
|
|
|
|
* This function should be used with caution when used other than
|
|
|
|
* for determining DST; it hasn't been proven not to produce an
|
|
|
|
* incorrect year for times near year boundaries.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
EquivalentYearForDST(int year)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Years and leap years on which Jan 1 is a Sunday, Monday, etc.
|
|
|
|
*
|
|
|
|
* yearStartingWith[0][i] is an example non-leap year where
|
|
|
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
|
|
|
|
*
|
|
|
|
* yearStartingWith[1][i] is an example leap year where
|
|
|
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
|
|
|
|
*/
|
|
|
|
static const int yearStartingWith[2][7] = {
|
|
|
|
{1978, 1973, 1974, 1975, 1981, 1971, 1977},
|
|
|
|
{1984, 1996, 1980, 1992, 1976, 1988, 1972}
|
|
|
|
};
|
|
|
|
|
|
|
|
int day = int(DayFromYear(year) + 4) % 7;
|
|
|
|
if (day < 0)
|
|
|
|
day += 7;
|
|
|
|
|
|
|
|
return yearStartingWith[IsLeapYear(year)][day];
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.8. */
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
DaylightSavingTA(double t, JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:52:53 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(t))
|
|
|
|
return js_NaN;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If earlier than 1970 or after 2038, potentially beyond the ken of
|
|
|
|
* many OSes, map it to an equivalent year before asking.
|
|
|
|
*/
|
|
|
|
if (t < 0.0 || t > 2145916800000.0) {
|
2012-07-09 14:28:20 -07:00
|
|
|
int year = EquivalentYearForDST(int(YearFromTime(t)));
|
2012-02-24 14:19:52 -08:00
|
|
|
double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
|
2007-03-22 10:30:00 -07:00
|
|
|
t = MakeDate(day, TimeWithinDay(t));
|
|
|
|
}
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
int64_t timeMilliseconds = static_cast<int64_t>(t);
|
|
|
|
int64_t offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx);
|
2012-02-24 14:19:52 -08:00
|
|
|
return static_cast<double>(offsetMilliseconds);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
AdjustTime(double date, JSContext *cx)
|
2009-01-06 09:18:35 -08:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double t = DaylightSavingTA(date, cx) + LocalTZA;
|
2009-03-26 17:51:50 -07:00
|
|
|
t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
|
2009-01-06 09:18:35 -08:00
|
|
|
return t;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.9. */
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
LocalTime(double t, JSContext *cx)
|
2010-05-26 17:00:28 -07:00
|
|
|
{
|
|
|
|
return t + AdjustTime(t, cx);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
UTC(double t, JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-05-26 17:00:28 -07:00
|
|
|
return t - AdjustTime(t - LocalTZA, cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:52:53 -07:00
|
|
|
/* ES5 15.9.1.10. */
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
HourFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double result = fmod(floor(t/msPerHour), HoursPerDay);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
2012-07-09 14:28:20 -07:00
|
|
|
result += HoursPerDay;
|
2007-03-22 10:30:00 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
MinFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double result = fmod(floor(t / msPerMinute), MinutesPerHour);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
2012-07-09 14:28:20 -07:00
|
|
|
result += MinutesPerHour;
|
2007-03-22 10:30:00 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
SecFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double result = fmod(floor(t / msPerSecond), SecondsPerMinute);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
2012-07-09 14:28:20 -07:00
|
|
|
result += SecondsPerMinute;
|
2007-03-22 10:30:00 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static double
|
2012-02-24 14:19:52 -08:00
|
|
|
msFromTime(double t)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double result = fmod(t, msPerSecond);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (result < 0)
|
2012-07-09 14:28:20 -07:00
|
|
|
result += msPerSecond;
|
2012-07-06 13:52:53 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ES5 15.9.1.11. */
|
|
|
|
static double
|
|
|
|
MakeTime(double hour, double min, double sec, double ms)
|
|
|
|
{
|
|
|
|
/* Step 1. */
|
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(hour) ||
|
|
|
|
!MOZ_DOUBLE_IS_FINITE(min) ||
|
|
|
|
!MOZ_DOUBLE_IS_FINITE(sec) ||
|
|
|
|
!MOZ_DOUBLE_IS_FINITE(ms))
|
|
|
|
{
|
|
|
|
return js_NaN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double h = ToInteger(hour);
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double m = ToInteger(min);
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double s = ToInteger(sec);
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double milli = ToInteger(ms);
|
|
|
|
|
|
|
|
/* Steps 6-7. */
|
|
|
|
return h * msPerHour + m * msPerMinute + s * msPerSecond + milli;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Additional quantities not mentioned in the spec. */
|
|
|
|
const double SecondsPerDay = SecondsPerMinute * MinutesPerHour * HoursPerDay;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/**
|
|
|
|
* end of ECMA 'support' functions
|
|
|
|
*/
|
2008-08-08 09:02:50 -07:00
|
|
|
|
2011-04-01 15:24:21 -07:00
|
|
|
static JSBool
|
2012-07-30 04:19:09 -07:00
|
|
|
date_convert(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp)
|
2011-04-01 15:24:21 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
|
|
|
|
JS_ASSERT(obj->isDate());
|
|
|
|
|
2012-05-19 15:03:45 -07:00
|
|
|
return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
|
2011-04-01 15:24:21 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* Other Support routines and definitions
|
|
|
|
*/
|
|
|
|
|
2011-09-02 17:23:26 -07:00
|
|
|
Class js::DateClass = {
|
2007-03-22 10:30:00 -07:00
|
|
|
js_Date_str,
|
2010-08-17 10:42:57 -07:00
|
|
|
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
|
2010-08-16 12:35:04 -07:00
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
|
2011-09-20 11:40:24 -07:00
|
|
|
JS_PropertyStub, /* addProperty */
|
|
|
|
JS_PropertyStub, /* delProperty */
|
|
|
|
JS_PropertyStub, /* getProperty */
|
|
|
|
JS_StrictPropertyStub, /* setProperty */
|
|
|
|
JS_EnumerateStub,
|
|
|
|
JS_ResolveStub,
|
2011-04-01 15:24:21 -07:00
|
|
|
date_convert
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* for use by date_parse */
|
|
|
|
|
|
|
|
static const char* wtb[] = {
|
|
|
|
"am", "pm",
|
|
|
|
"monday", "tuesday", "wednesday", "thursday", "friday",
|
|
|
|
"saturday", "sunday",
|
|
|
|
"january", "february", "march", "april", "may", "june",
|
|
|
|
"july", "august", "september", "october", "november", "december",
|
|
|
|
"gmt", "ut", "utc",
|
|
|
|
"est", "edt",
|
|
|
|
"cst", "cdt",
|
|
|
|
"mst", "mdt",
|
|
|
|
"pst", "pdt"
|
|
|
|
/* time zone table needs to be expanded */
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ttb[] = {
|
|
|
|
-1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
|
|
|
|
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
|
|
|
10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
|
|
|
|
10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
|
|
|
|
10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
|
|
|
|
10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
|
|
|
|
10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* helper for date_parse */
|
|
|
|
static JSBool
|
|
|
|
date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
|
|
|
|
int count, int ignoreCase)
|
|
|
|
{
|
|
|
|
JSBool result = JS_FALSE;
|
|
|
|
/* return true if matches, otherwise, false */
|
|
|
|
|
|
|
|
while (count > 0 && s1[s1off] && s2[s2off]) {
|
|
|
|
if (ignoreCase) {
|
2011-07-26 14:10:33 -07:00
|
|
|
if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off]))
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if ((jschar)s1[s1off] != s2[s2off]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s1off++;
|
|
|
|
s2off++;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
result = JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find UTC time from given date... no 1900 correction! */
|
2012-02-24 14:19:52 -08:00
|
|
|
static double
|
|
|
|
date_msecFromDate(double year, double mon, double mday, double hour,
|
|
|
|
double min, double sec, double msec)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
return MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, msec));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-13 13:45:32 -07:00
|
|
|
|
|
|
|
/* compute the time in msec (unclipped) from the given args */
|
2007-03-22 10:30:00 -07:00
|
|
|
#define MAXARGS 7
|
2007-08-01 21:33:52 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2011-09-08 21:02:26 -07:00
|
|
|
date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-28 15:11:11 -08:00
|
|
|
unsigned loop;
|
2012-02-24 14:19:52 -08:00
|
|
|
double array[MAXARGS];
|
|
|
|
double msec_time;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
for (loop = 0; loop < MAXARGS; loop++) {
|
2011-09-08 21:02:26 -07:00
|
|
|
if (loop < args.length()) {
|
2012-02-24 14:19:52 -08:00
|
|
|
double d;
|
2011-09-08 21:02:26 -07:00
|
|
|
if (!ToNumber(cx, args[loop], &d))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2007-08-13 13:45:32 -07:00
|
|
|
/* return NaN if any arg is not finite */
|
2012-01-23 03:43:16 -08:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(d)) {
|
2009-10-28 04:57:31 -07:00
|
|
|
*rval = js_NaN;
|
2007-08-13 13:45:32 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-04-19 16:18:24 -07:00
|
|
|
array[loop] = ToInteger(d);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-08-13 13:45:32 -07:00
|
|
|
if (loop == 2) {
|
|
|
|
array[loop] = 1; /* Default the date argument to 1. */
|
|
|
|
} else {
|
|
|
|
array[loop] = 0;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust 2-digit years into the 20th century */
|
|
|
|
if (array[0] >= 0 && array[0] <= 99)
|
|
|
|
array[0] += 1900;
|
|
|
|
|
2007-08-13 13:45:32 -07:00
|
|
|
msec_time = date_msecFromDate(array[0], array[1], array[2],
|
|
|
|
array[3], array[4], array[5], array[6]);
|
|
|
|
*rval = msec_time;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See ECMA 15.9.4.[3-10];
|
|
|
|
*/
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_UTC(JSContext *cx, unsigned argc, Value *vp)
|
2007-08-13 13:45:32 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-08-13 13:45:32 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double msec_time;
|
2011-09-08 21:02:26 -07:00
|
|
|
if (!date_msecFromArgs(cx, args, &msec_time))
|
2007-08-13 13:45:32 -07:00
|
|
|
return JS_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-04-19 16:22:08 -07:00
|
|
|
msec_time = TimeClip(msec_time);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(msec_time);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-10-18 11:23:27 -07:00
|
|
|
/*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Read and convert decimal digits from s[*i] into *result
|
2011-04-11 01:38:27 -07:00
|
|
|
* while *i < limit.
|
|
|
|
*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Succeed if any digits are converted. Advance *i only
|
|
|
|
* as digits are consumed.
|
|
|
|
*/
|
|
|
|
static JSBool
|
|
|
|
digits(size_t *result, const jschar *s, size_t *i, size_t limit)
|
|
|
|
{
|
|
|
|
size_t init = *i;
|
|
|
|
*result = 0;
|
2011-04-11 01:38:27 -07:00
|
|
|
while (*i < limit &&
|
2009-08-26 18:13:48 -07:00
|
|
|
('0' <= s[*i] && s[*i] <= '9')) {
|
|
|
|
*result *= 10;
|
|
|
|
*result += (s[*i] - '0');
|
|
|
|
++(*i);
|
|
|
|
}
|
|
|
|
return (*i != init);
|
|
|
|
}
|
|
|
|
|
2011-04-11 01:38:27 -07:00
|
|
|
/*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Read and convert decimal digits to the right of a decimal point,
|
|
|
|
* representing a fractional integer, from s[*i] into *result
|
2011-04-11 01:38:27 -07:00
|
|
|
* while *i < limit.
|
|
|
|
*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Succeed if any digits are converted. Advance *i only
|
|
|
|
* as digits are consumed.
|
|
|
|
*/
|
|
|
|
static JSBool
|
2012-02-24 14:19:52 -08:00
|
|
|
fractional(double *result, const jschar *s, size_t *i, size_t limit)
|
2009-08-26 18:13:48 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double factor = 0.1;
|
2009-08-26 18:13:48 -07:00
|
|
|
size_t init = *i;
|
|
|
|
*result = 0.0;
|
2011-04-11 01:38:27 -07:00
|
|
|
while (*i < limit &&
|
2009-08-26 18:13:48 -07:00
|
|
|
('0' <= s[*i] && s[*i] <= '9')) {
|
|
|
|
*result += (s[*i] - '0') * factor;
|
|
|
|
factor *= 0.1;
|
|
|
|
++(*i);
|
|
|
|
}
|
|
|
|
return (*i != init);
|
|
|
|
}
|
|
|
|
|
2011-04-11 01:38:27 -07:00
|
|
|
/*
|
|
|
|
* Read and convert exactly n decimal digits from s[*i]
|
|
|
|
* to s[min(*i+n,limit)] into *result.
|
2009-08-26 18:13:48 -07:00
|
|
|
*
|
|
|
|
* Succeed if exactly n digits are converted. Advance *i only
|
|
|
|
* on success.
|
|
|
|
*/
|
|
|
|
static JSBool
|
|
|
|
ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
|
|
|
|
{
|
|
|
|
size_t init = *i;
|
|
|
|
|
2012-08-02 20:50:51 -07:00
|
|
|
if (digits(result, s, i, Min(limit, init+n)))
|
2009-08-26 18:13:48 -07:00
|
|
|
return ((*i - init) == n);
|
2011-04-11 01:38:27 -07:00
|
|
|
|
2009-08-26 18:13:48 -07:00
|
|
|
*i = init;
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
static int
|
|
|
|
DaysInMonth(int year, int month)
|
|
|
|
{
|
|
|
|
bool leap = IsLeapYear(year);
|
|
|
|
int result = int(DayFromMonth(month, leap) - DayFromMonth(month - 1, leap));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-04-11 01:38:27 -07:00
|
|
|
/*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Parse a string in one of the date-time formats given by the W3C
|
|
|
|
* "NOTE-datetime" specification. These formats make up a restricted
|
|
|
|
* profile of the ISO 8601 format. Quoted here:
|
|
|
|
*
|
|
|
|
* The formats are as follows. Exactly the components shown here
|
|
|
|
* must be present, with exactly this punctuation. Note that the "T"
|
|
|
|
* appears literally in the string, to indicate the beginning of the
|
|
|
|
* time element, as specified in ISO 8601.
|
|
|
|
*
|
|
|
|
* Any combination of the date formats with the time formats is
|
|
|
|
* allowed, and also either the date or the time can be missing.
|
|
|
|
*
|
|
|
|
* The specification is silent on the meaning when fields are
|
|
|
|
* ommitted so the interpretations are a guess, but hopefully a
|
|
|
|
* reasonable one. We default the month to January, the day to the
|
|
|
|
* 1st, and hours minutes and seconds all to 0. If the date is
|
|
|
|
* missing entirely then we assume 1970-01-01 so that the time can
|
|
|
|
* be aded to a date later. If the time is missing then we assume
|
|
|
|
* 00:00 UTC. If the time is present but the time zone field is
|
|
|
|
* missing then we use local time.
|
2011-04-11 01:38:27 -07:00
|
|
|
*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Date part:
|
|
|
|
*
|
|
|
|
* Year:
|
|
|
|
* YYYY (eg 1997)
|
|
|
|
*
|
|
|
|
* Year and month:
|
|
|
|
* YYYY-MM (eg 1997-07)
|
|
|
|
*
|
|
|
|
* Complete date:
|
|
|
|
* YYYY-MM-DD (eg 1997-07-16)
|
|
|
|
*
|
|
|
|
* Time part:
|
|
|
|
*
|
|
|
|
* Hours and minutes:
|
|
|
|
* Thh:mmTZD (eg T19:20+01:00)
|
2011-04-11 01:38:27 -07:00
|
|
|
*
|
2009-08-26 18:13:48 -07:00
|
|
|
* Hours, minutes and seconds:
|
|
|
|
* Thh:mm:ssTZD (eg T19:20:30+01:00)
|
|
|
|
*
|
|
|
|
* Hours, minutes, seconds and a decimal fraction of a second:
|
|
|
|
* Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
|
|
|
|
*
|
|
|
|
* where:
|
|
|
|
*
|
|
|
|
* YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
|
|
|
|
* MM = two-digit month (01=January, etc.)
|
|
|
|
* DD = two-digit day of month (01 through 31)
|
|
|
|
* hh = two digits of hour (00 through 23) (am/pm NOT allowed)
|
|
|
|
* mm = two digits of minute (00 through 59)
|
|
|
|
* ss = two digits of second (00 through 59)
|
|
|
|
* s = one or more digits representing a decimal fraction of a second
|
|
|
|
* TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-24 14:19:52 -08:00
|
|
|
date_parseISOString(JSLinearString *str, double *result, JSContext *cx)
|
2009-08-26 18:13:48 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double msec;
|
2009-08-26 18:13:48 -07:00
|
|
|
|
|
|
|
const jschar *s;
|
|
|
|
size_t limit;
|
|
|
|
size_t i = 0;
|
|
|
|
int tzMul = 1;
|
|
|
|
int dateMul = 1;
|
|
|
|
size_t year = 1970;
|
|
|
|
size_t month = 1;
|
|
|
|
size_t day = 1;
|
|
|
|
size_t hour = 0;
|
|
|
|
size_t min = 0;
|
|
|
|
size_t sec = 0;
|
2012-02-24 14:19:52 -08:00
|
|
|
double frac = 0;
|
2009-08-26 18:13:48 -07:00
|
|
|
bool isLocalTime = JS_FALSE;
|
|
|
|
size_t tzHour = 0;
|
|
|
|
size_t tzMin = 0;
|
|
|
|
|
|
|
|
#define PEEK(ch) (i < limit && s[i] == ch)
|
|
|
|
|
|
|
|
#define NEED(ch) \
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
|
2011-04-11 01:38:27 -07:00
|
|
|
JS_END_MACRO
|
2009-08-26 18:13:48 -07:00
|
|
|
|
|
|
|
#define DONE_DATE_UNLESS(ch) \
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
|
2011-04-11 01:38:27 -07:00
|
|
|
JS_END_MACRO
|
2009-08-26 18:13:48 -07:00
|
|
|
|
|
|
|
#define DONE_UNLESS(ch) \
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
|
2011-04-11 01:38:27 -07:00
|
|
|
JS_END_MACRO
|
2009-08-26 18:13:48 -07:00
|
|
|
|
|
|
|
#define NEED_NDIGITS(n, field) \
|
|
|
|
JS_BEGIN_MACRO \
|
|
|
|
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
|
2011-04-11 01:38:27 -07:00
|
|
|
JS_END_MACRO
|
2009-08-26 18:13:48 -07:00
|
|
|
|
2010-12-06 10:26:58 -08:00
|
|
|
s = str->chars();
|
|
|
|
limit = str->length();
|
2009-08-26 18:13:48 -07:00
|
|
|
|
|
|
|
if (PEEK('+') || PEEK('-')) {
|
|
|
|
if (PEEK('-'))
|
|
|
|
dateMul = -1;
|
|
|
|
++i;
|
|
|
|
NEED_NDIGITS(6, year);
|
|
|
|
} else if (!PEEK('T')) {
|
|
|
|
NEED_NDIGITS(4, year);
|
|
|
|
}
|
|
|
|
DONE_DATE_UNLESS('-');
|
|
|
|
NEED_NDIGITS(2, month);
|
|
|
|
DONE_DATE_UNLESS('-');
|
|
|
|
NEED_NDIGITS(2, day);
|
|
|
|
|
|
|
|
done_date:
|
|
|
|
DONE_UNLESS('T');
|
|
|
|
NEED_NDIGITS(2, hour);
|
|
|
|
NEED(':');
|
|
|
|
NEED_NDIGITS(2, min);
|
|
|
|
|
|
|
|
if (PEEK(':')) {
|
|
|
|
++i;
|
|
|
|
NEED_NDIGITS(2, sec);
|
|
|
|
if (PEEK('.')) {
|
|
|
|
++i;
|
|
|
|
if (!fractional(&frac, s, &i, limit))
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PEEK('Z')) {
|
|
|
|
++i;
|
|
|
|
} else if (PEEK('+') || PEEK('-')) {
|
|
|
|
if (PEEK('-'))
|
|
|
|
tzMul = -1;
|
|
|
|
++i;
|
|
|
|
NEED_NDIGITS(2, tzHour);
|
2011-08-28 23:16:37 -07:00
|
|
|
/*
|
|
|
|
* Non-standard extension to the ISO date format (permitted by ES5):
|
|
|
|
* allow "-0700" as a time zone offset, not just "-07:00".
|
|
|
|
*/
|
|
|
|
if (PEEK(':'))
|
|
|
|
++i;
|
2009-08-26 18:13:48 -07:00
|
|
|
NEED_NDIGITS(2, tzMin);
|
|
|
|
} else {
|
|
|
|
isLocalTime = JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (year > 275943 // ceil(1e8/365) + 1970
|
|
|
|
|| (month == 0 || month > 12)
|
2009-09-05 08:59:11 -07:00
|
|
|
|| (day == 0 || day > size_t(DaysInMonth(year,month)))
|
2011-04-11 01:38:27 -07:00
|
|
|
|| hour > 24
|
2009-08-26 18:13:48 -07:00
|
|
|
|| ((hour == 24) && (min > 0 || sec > 0))
|
2011-04-11 01:38:27 -07:00
|
|
|
|| min > 59
|
2009-08-26 18:13:48 -07:00
|
|
|
|| sec > 59
|
|
|
|
|| tzHour > 23
|
2011-04-11 01:38:27 -07:00
|
|
|
|| tzMin > 59)
|
2009-08-26 18:13:48 -07:00
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
if (i != limit)
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
month -= 1; /* convert month to 0-based */
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
msec = date_msecFromDate(dateMul * (double)year, month, day,
|
2009-08-26 18:13:48 -07:00
|
|
|
hour, min, sec,
|
|
|
|
frac * 1000.0);;
|
|
|
|
|
|
|
|
if (isLocalTime) {
|
2010-05-26 17:00:28 -07:00
|
|
|
msec = UTC(msec, cx);
|
2009-08-26 18:13:48 -07:00
|
|
|
} else {
|
2011-04-11 01:38:27 -07:00
|
|
|
msec -= ((tzMul) * ((tzHour * msPerHour)
|
2009-08-26 18:13:48 -07:00
|
|
|
+ (tzMin * msPerMinute)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msec < -8.64e15 || msec > 8.64e15)
|
|
|
|
goto syntax;
|
|
|
|
|
|
|
|
*result = msec;
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
syntax:
|
|
|
|
/* syntax error */
|
|
|
|
*result = 0;
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
#undef PEEK
|
|
|
|
#undef NEED
|
|
|
|
#undef DONE_UNLESS
|
|
|
|
#undef NEED_NDIGITS
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-02-24 14:19:52 -08:00
|
|
|
date_parseString(JSLinearString *str, double *result, JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double msec;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-08-15 23:23:06 -07:00
|
|
|
const jschar *s;
|
|
|
|
size_t limit;
|
2007-03-22 10:30:00 -07:00
|
|
|
size_t i = 0;
|
|
|
|
int year = -1;
|
|
|
|
int mon = -1;
|
|
|
|
int mday = -1;
|
|
|
|
int hour = -1;
|
|
|
|
int min = -1;
|
|
|
|
int sec = -1;
|
|
|
|
int c = -1;
|
|
|
|
int n = -1;
|
2007-08-01 21:33:52 -07:00
|
|
|
int tzoffset = -1;
|
2007-03-22 10:30:00 -07:00
|
|
|
int prevc = 0;
|
|
|
|
JSBool seenplusminus = JS_FALSE;
|
|
|
|
int temp;
|
|
|
|
JSBool seenmonthname = JS_FALSE;
|
|
|
|
|
2010-05-26 17:00:28 -07:00
|
|
|
if (date_parseISOString(str, result, cx))
|
2009-08-26 18:13:48 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
|
2010-12-06 10:26:58 -08:00
|
|
|
s = str->chars();
|
|
|
|
limit = str->length();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (limit == 0)
|
|
|
|
goto syntax;
|
|
|
|
while (i < limit) {
|
|
|
|
c = s[i];
|
|
|
|
i++;
|
|
|
|
if (c <= ' ' || c == ',' || c == '-') {
|
|
|
|
if (c == '-' && '0' <= s[i] && s[i] <= '9') {
|
|
|
|
prevc = c;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '(') { /* comments) */
|
|
|
|
int depth = 1;
|
|
|
|
while (i < limit) {
|
|
|
|
c = s[i];
|
|
|
|
i++;
|
|
|
|
if (c == '(') depth++;
|
|
|
|
else if (c == ')')
|
|
|
|
if (--depth <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ('0' <= c && c <= '9') {
|
|
|
|
n = c - '0';
|
|
|
|
while (i < limit && '0' <= (c = s[i]) && c <= '9') {
|
|
|
|
n = n * 10 + c - '0';
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allow TZA before the year, so
|
|
|
|
* 'Wed Nov 05 21:49:11 GMT-0800 1997'
|
|
|
|
* works */
|
|
|
|
|
|
|
|
/* uses of seenplusminus allow : in TZA, so Java
|
|
|
|
* no-timezone style of GMT+4:30 works
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
|
|
|
|
/* make ':' case below change tzoffset */
|
|
|
|
seenplusminus = JS_TRUE;
|
|
|
|
|
|
|
|
/* offset */
|
|
|
|
if (n < 24)
|
|
|
|
n = n * 60; /* EG. "GMT-3" */
|
|
|
|
else
|
|
|
|
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
|
|
|
|
if (prevc == '+') /* plus means east of GMT */
|
|
|
|
n = -n;
|
|
|
|
if (tzoffset != 0 && tzoffset != -1)
|
|
|
|
goto syntax;
|
|
|
|
tzoffset = n;
|
|
|
|
} else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
|
|
|
|
if (c <= ' ' || c == ',' || c == '/' || i >= limit)
|
|
|
|
year = n;
|
|
|
|
else
|
|
|
|
goto syntax;
|
|
|
|
} else if (c == ':') {
|
|
|
|
if (hour < 0)
|
|
|
|
hour = /*byte*/ n;
|
|
|
|
else if (min < 0)
|
|
|
|
min = /*byte*/ n;
|
|
|
|
else
|
|
|
|
goto syntax;
|
|
|
|
} else if (c == '/') {
|
|
|
|
/* until it is determined that mon is the actual
|
|
|
|
month, keep it as 1-based rather than 0-based */
|
|
|
|
if (mon < 0)
|
|
|
|
mon = /*byte*/ n;
|
|
|
|
else if (mday < 0)
|
|
|
|
mday = /*byte*/ n;
|
|
|
|
else
|
|
|
|
goto syntax;
|
|
|
|
} else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
|
|
|
|
goto syntax;
|
|
|
|
} else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
|
|
|
|
if (tzoffset < 0)
|
|
|
|
tzoffset -= n;
|
|
|
|
else
|
|
|
|
tzoffset += n;
|
|
|
|
} else if (hour >= 0 && min < 0) {
|
|
|
|
min = /*byte*/ n;
|
|
|
|
} else if (prevc == ':' && min >= 0 && sec < 0) {
|
|
|
|
sec = /*byte*/ n;
|
|
|
|
} else if (mon < 0) {
|
|
|
|
mon = /*byte*/n;
|
|
|
|
} else if (mon >= 0 && mday < 0) {
|
|
|
|
mday = /*byte*/ n;
|
|
|
|
} else if (mon >= 0 && mday >= 0 && year < 0) {
|
|
|
|
year = n;
|
|
|
|
} else {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
prevc = 0;
|
|
|
|
} else if (c == '/' || c == ':' || c == '+' || c == '-') {
|
|
|
|
prevc = c;
|
|
|
|
} else {
|
|
|
|
size_t st = i - 1;
|
|
|
|
int k;
|
|
|
|
while (i < limit) {
|
|
|
|
c = s[i];
|
|
|
|
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i <= st + 1)
|
|
|
|
goto syntax;
|
2011-10-10 23:00:28 -07:00
|
|
|
for (k = ArrayLength(wtb); --k >= 0;)
|
2007-03-22 10:30:00 -07:00
|
|
|
if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
|
|
|
|
int action = ttb[k];
|
|
|
|
if (action != 0) {
|
|
|
|
if (action < 0) {
|
|
|
|
/*
|
|
|
|
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
|
|
|
|
* 12:30, instead of blindly adding 12 if PM.
|
|
|
|
*/
|
|
|
|
JS_ASSERT(action == -1 || action == -2);
|
|
|
|
if (hour > 12 || hour < 0) {
|
|
|
|
goto syntax;
|
|
|
|
} else {
|
|
|
|
if (action == -1 && hour == 12) { /* am */
|
|
|
|
hour = 0;
|
|
|
|
} else if (action == -2 && hour != 12) { /* pm */
|
|
|
|
hour += 12;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (action <= 13) { /* month! */
|
|
|
|
/* Adjust mon to be 1-based until the final values
|
|
|
|
for mon, mday and year are adjusted below */
|
|
|
|
if (seenmonthname) {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
seenmonthname = JS_TRUE;
|
|
|
|
temp = /*byte*/ (action - 2) + 1;
|
|
|
|
|
|
|
|
if (mon < 0) {
|
|
|
|
mon = temp;
|
|
|
|
} else if (mday < 0) {
|
|
|
|
mday = mon;
|
|
|
|
mon = temp;
|
|
|
|
} else if (year < 0) {
|
|
|
|
year = mon;
|
|
|
|
mon = temp;
|
|
|
|
} else {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tzoffset = action - 10000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (k < 0)
|
|
|
|
goto syntax;
|
|
|
|
prevc = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (year < 0 || mon < 0 || mday < 0)
|
|
|
|
goto syntax;
|
|
|
|
/*
|
|
|
|
Case 1. The input string contains an English month name.
|
|
|
|
The form of the string can be month f l, or f month l, or
|
|
|
|
f l month which each evaluate to the same date.
|
|
|
|
If f and l are both greater than or equal to 70, or
|
|
|
|
both less than 70, the date is invalid.
|
|
|
|
The year is taken to be the greater of the values f, l.
|
|
|
|
If the year is greater than or equal to 70 and less than 100,
|
|
|
|
it is considered to be the number of years after 1900.
|
|
|
|
Case 2. The input string is of the form "f/m/l" where f, m and l are
|
|
|
|
integers, e.g. 7/16/45.
|
|
|
|
Adjust the mon, mday and year values to achieve 100% MSIE
|
|
|
|
compatibility.
|
|
|
|
a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
|
|
|
|
i. If year < 100, it is the number of years after 1900
|
|
|
|
ii. If year >= 100, it is the number of years after 0.
|
|
|
|
b. If 70 <= f < 100
|
|
|
|
i. If m < 70, f/m/l is interpreted as
|
|
|
|
year/month/day where year is the number of years after
|
|
|
|
1900.
|
|
|
|
ii. If m >= 70, the date is invalid.
|
|
|
|
c. If f >= 100
|
|
|
|
i. If m < 70, f/m/l is interpreted as
|
|
|
|
year/month/day where year is the number of years after 0.
|
|
|
|
ii. If m >= 70, the date is invalid.
|
|
|
|
*/
|
|
|
|
if (seenmonthname) {
|
|
|
|
if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
if (mday > year) {
|
|
|
|
temp = year;
|
|
|
|
year = mday;
|
|
|
|
mday = temp;
|
|
|
|
}
|
|
|
|
if (year >= 70 && year < 100) {
|
|
|
|
year += 1900;
|
|
|
|
}
|
|
|
|
} else if (mon < 70) { /* (a) month/day/year */
|
|
|
|
if (year < 100) {
|
|
|
|
year += 1900;
|
|
|
|
}
|
|
|
|
} else if (mon < 100) { /* (b) year/month/day */
|
|
|
|
if (mday < 70) {
|
|
|
|
temp = year;
|
|
|
|
year = mon + 1900;
|
|
|
|
mon = mday;
|
|
|
|
mday = temp;
|
|
|
|
} else {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
} else { /* (c) year/month/day */
|
|
|
|
if (mday < 70) {
|
|
|
|
temp = year;
|
|
|
|
year = mon;
|
|
|
|
mon = mday;
|
|
|
|
mday = temp;
|
|
|
|
} else {
|
|
|
|
goto syntax;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mon -= 1; /* convert month to 0-based */
|
|
|
|
if (sec < 0)
|
|
|
|
sec = 0;
|
|
|
|
if (min < 0)
|
|
|
|
min = 0;
|
|
|
|
if (hour < 0)
|
|
|
|
hour = 0;
|
|
|
|
|
2009-08-26 18:13:48 -07:00
|
|
|
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
|
|
|
|
|
|
|
if (tzoffset == -1) { /* no time zone specified, have to use local */
|
2010-05-26 17:00:28 -07:00
|
|
|
msec = UTC(msec, cx);
|
2009-08-26 18:13:48 -07:00
|
|
|
} else {
|
|
|
|
msec += tzoffset * msPerMinute;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
*result = msec;
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
syntax:
|
|
|
|
/* syntax error */
|
|
|
|
*result = 0;
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_parse(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
JSString *str;
|
2012-02-24 14:19:52 -08:00
|
|
|
double result;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2009-10-28 04:57:31 -07:00
|
|
|
return true;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2011-12-01 19:35:44 -08:00
|
|
|
str = ToString(cx, vp[2]);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
2010-07-14 23:19:36 -07:00
|
|
|
vp[2].setString(str);
|
2010-12-06 10:26:58 -08:00
|
|
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
|
|
|
if (!linearStr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!date_parseString(linearStr, &result, cx)) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2009-10-28 04:57:31 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-04-19 16:22:08 -07:00
|
|
|
result = TimeClip(result);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setNumber(result);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static inline double
|
2009-02-26 00:49:39 -08:00
|
|
|
NowAsMillis()
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
|
2009-02-26 00:49:39 -08:00
|
|
|
}
|
|
|
|
|
2008-10-08 15:08:33 -07:00
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_now(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-04-13 06:35:06 -07:00
|
|
|
vp->setDouble(NowAsMillis());
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-10-24 11:42:29 -07:00
|
|
|
* Set UTC time to a given time and invalidate cached local time.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
|
|
|
static JSBool
|
2012-02-24 14:19:52 -08:00
|
|
|
SetUTCTime(JSContext *cx, JSObject *obj, double t, Value *vp = NULL)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-08-17 10:42:57 -07:00
|
|
|
JS_ASSERT(obj->isDate());
|
|
|
|
|
2011-10-10 11:41:03 -07:00
|
|
|
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
|
|
|
|
ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
|
|
|
|
ind++) {
|
2011-07-13 15:43:33 -07:00
|
|
|
obj->setSlot(ind, UndefinedValue());
|
2011-10-10 11:41:03 -07:00
|
|
|
}
|
2009-10-24 11:42:29 -07:00
|
|
|
|
2010-07-14 23:19:36 -07:00
|
|
|
obj->setDateUTCTime(DoubleValue(t));
|
2009-10-24 11:42:29 -07:00
|
|
|
if (vp)
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(t);
|
2009-10-24 11:42:29 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-17 10:42:57 -07:00
|
|
|
static void
|
|
|
|
SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double NaN = cx->runtime->NaNValue.getDoubleRef();
|
2010-08-17 10:42:57 -07:00
|
|
|
SetUTCTime(cx, obj, NaN, vp);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
2010-08-17 10:42:57 -07:00
|
|
|
* Cache the local time, year, month, and so forth of the object.
|
|
|
|
* If UTC time is not finite (e.g., NaN), the local time
|
|
|
|
* slots will be set to the UTC time without conversion.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2010-08-17 10:42:57 -07:00
|
|
|
static bool
|
2012-07-13 15:56:08 -07:00
|
|
|
CacheLocalTime(JSContext *cx, JSObject *obj)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-08-17 10:42:57 -07:00
|
|
|
JS_ASSERT(obj->isDate());
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
/* Check if the cache is already populated. */
|
|
|
|
if (!obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined() &&
|
|
|
|
obj->getSlot(JSObject::JSSLOT_DATE_TZA).toDouble() == LocalTZA)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remember timezone used to generate the local cache. */
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_TZA, DoubleValue(LocalTZA));
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double utcTime = obj->getDateUTCTime().toNumber();
|
2010-08-17 10:42:57 -07:00
|
|
|
|
2012-01-23 03:43:16 -08:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(utcTime)) {
|
2010-08-17 10:42:57 -07:00
|
|
|
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
|
|
|
|
ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
|
|
|
|
ind++) {
|
|
|
|
obj->setSlot(ind, DoubleValue(utcTime));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double localTime = LocalTime(utcTime, cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-09 14:28:20 -07:00
|
|
|
int year = (int) floor(localTime /(msPerDay * 365.2425)) + 1970;
|
|
|
|
double yearStartTime = TimeFromYear(year);
|
2010-08-17 10:42:57 -07:00
|
|
|
|
|
|
|
/* Adjust the year in case the approximation was wrong, as in YearFromTime. */
|
2012-03-01 18:54:01 -08:00
|
|
|
int yearDays;
|
2010-08-17 10:42:57 -07:00
|
|
|
if (yearStartTime > localTime) {
|
|
|
|
year--;
|
|
|
|
yearStartTime -= (msPerDay * DaysInYear(year));
|
|
|
|
yearDays = DaysInYear(year);
|
|
|
|
} else {
|
|
|
|
yearDays = DaysInYear(year);
|
2012-02-24 14:19:52 -08:00
|
|
|
double nextStart = yearStartTime + (msPerDay * yearDays);
|
2010-08-17 10:42:57 -07:00
|
|
|
if (nextStart <= localTime) {
|
|
|
|
year++;
|
|
|
|
yearStartTime = nextStart;
|
|
|
|
yearDays = DaysInYear(year);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
uint64_t yearTime = uint64_t(localTime - yearStartTime);
|
2012-03-01 18:54:01 -08:00
|
|
|
int yearSeconds = uint32_t(yearTime / 1000);
|
2010-08-17 10:42:57 -07:00
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int day = yearSeconds / int(SecondsPerDay);
|
2010-08-17 10:42:57 -07:00
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int step = -1, next = 30;
|
|
|
|
int month;
|
2010-08-17 10:42:57 -07:00
|
|
|
|
|
|
|
do {
|
|
|
|
if (day <= next) {
|
|
|
|
month = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
next += ((yearDays == 366) ? 29 : 28);
|
|
|
|
if (day <= next) {
|
|
|
|
month = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
month = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
month = 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
month = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
month = 5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
month = 6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
month = 7;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
month = 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 31)) {
|
|
|
|
month = 9;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
if (day <= (next += 30)) {
|
|
|
|
month = 10;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
step = next;
|
|
|
|
month = 11;
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
|
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
|
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int weekday = WeekDay(localTime);
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
|
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int seconds = yearSeconds % 60;
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
|
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int minutes = (yearSeconds / 60) % 60;
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
|
|
|
|
|
2012-03-01 18:54:01 -08:00
|
|
|
int hours = (yearSeconds / (60 * 60)) % 24;
|
2010-08-17 10:42:57 -07:00
|
|
|
obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
inline bool
|
|
|
|
GetCachedLocalTime(JSContext *cx, JSObject *obj, double *time)
|
2011-01-26 13:37:45 -08:00
|
|
|
{
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!obj || !CacheLocalTime(cx, obj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2010-08-17 10:42:57 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
*time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
|
2009-10-28 04:57:31 -07:00
|
|
|
return true;
|
2011-01-26 13:37:45 -08:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
IsDate(const Value &v)
|
|
|
|
{
|
|
|
|
return v.isObject() && v.toObject().hasClass(&DateClass);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* See ECMA 15.9.5.4 thru 15.9.5.23
|
|
|
|
*/
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getTime_impl(JSContext *cx, CallArgs args)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(args.thisv().toObject().getDateUTCTime());
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getTime(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getTime_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getYear_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-06-01 23:39:09 -07:00
|
|
|
Value yearVal = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
|
2010-08-17 10:42:57 -07:00
|
|
|
if (yearVal.isInt32()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
|
2012-03-01 18:54:01 -08:00
|
|
|
int year = yearVal.toInt32() - 1900;
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setInt32(year);
|
2010-08-17 10:42:57 -07:00
|
|
|
} else {
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(yearVal);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getYear(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getYear_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getFullYear_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-09-08 21:18:23 -07:00
|
|
|
return false;
|
2010-08-17 10:42:57 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR));
|
2011-09-08 21:18:23 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getFullYear(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getFullYear_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCFullYear_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = YearFromTime(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCFullYear_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getMonth_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getMonth(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getMonth_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCMonth_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double d = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-07-09 14:28:20 -07:00
|
|
|
args.rval().setNumber(MonthFromTime(d));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCMonth_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getDate_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getDate(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getDate_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCDate_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = DateFromTime(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCDate_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getDay_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getDay(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getDay_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCDay_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = WeekDay(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCDay_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getHours_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getHours(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getHours_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCHours_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = HourFromTime(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCHours_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getMinutes_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getMinutes_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCMinutes_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = MinFromTime(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCMinutes_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* Date.getSeconds is mapped to getUTCSeconds */
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getUTCSeconds_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!CacheLocalTime(cx, thisObj))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS));
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCSeconds_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* Date.getMilliseconds is mapped to getUTCMilliseconds */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
date_getUTCMilliseconds_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double result = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(result))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = msFromTime(result);
|
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getUTCMilliseconds_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_getTimezoneOffset_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-07-21 14:39:42 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-06-01 23:39:09 -07:00
|
|
|
double utctime = thisObj->getDateUTCTime().toNumber();
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2011-09-08 21:18:23 -07:00
|
|
|
double localtime;
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, thisObj, &localtime))
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-08-01 21:33:52 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
2007-08-01 21:33:52 -07:00
|
|
|
* Return the time zone offset in minutes for the current locale that is
|
|
|
|
* appropriate for this time. This value would be a constant except for
|
|
|
|
* daylight savings time.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2011-09-08 21:18:23 -07:00
|
|
|
double result = (utctime - localtime) / msPerMinute;
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setNumber(result);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_getTimezoneOffset_impl, args);
|
|
|
|
}
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setTime_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2011-09-08 21:02:26 -07:00
|
|
|
if (args.length() == 0) {
|
2012-07-30 04:19:09 -07:00
|
|
|
SetDateToNaN(cx, thisObj, args.rval().address());
|
2009-10-24 11:42:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double result;
|
2011-09-08 21:02:26 -07:00
|
|
|
if (!ToNumber(cx, args[0], &result))
|
2009-10-24 11:42:29 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, TimeClip(result), args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static JSBool
|
|
|
|
date_setTime(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setTime_impl, args);
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
static bool
|
|
|
|
GetMsecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *millis)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
if (args.length() <= i) {
|
|
|
|
*millis = msFromTime(t);
|
2009-10-24 11:42:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
return ToNumber(cx, args[i], millis);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
static bool
|
|
|
|
GetSecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *sec)
|
|
|
|
{
|
|
|
|
if (args.length() <= i) {
|
|
|
|
*sec = SecFromTime(t);
|
2012-04-06 18:06:14 -07:00
|
|
|
return true;
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
return ToNumber(cx, args[i], sec);
|
|
|
|
}
|
2012-04-06 18:06:14 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
static bool
|
|
|
|
GetMinsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *mins)
|
|
|
|
{
|
|
|
|
if (args.length() <= i) {
|
|
|
|
*mins = MinFromTime(t);
|
2012-04-06 18:06:14 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
return ToNumber(cx, args[i], mins);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.28. */
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setMilliseconds_impl(JSContext *cx, CallArgs args)
|
2012-07-06 13:53:10 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* Step 2. */
|
|
|
|
double milli;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &milli))
|
|
|
|
return false;
|
|
|
|
double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* Step 3. */
|
|
|
|
double u = TimeClip(UTC(MakeDate(Day(t), time), cx));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* Steps 4-5. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setMilliseconds_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.29. */
|
|
|
|
static bool
|
|
|
|
date_setUTCMilliseconds_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double milli;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &milli))
|
|
|
|
return false;
|
|
|
|
double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double v = TimeClip(MakeDate(Day(t), time));
|
|
|
|
|
|
|
|
/* Steps 4-5. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCMilliseconds_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.30. */
|
|
|
|
static bool
|
|
|
|
date_setSeconds_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double s;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double u = TimeClip(UTC(date, cx));
|
|
|
|
|
|
|
|
/* Steps 6-7. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.31. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setSeconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setSeconds_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setUTCSeconds_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double s;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double v = TimeClip(date);
|
|
|
|
|
|
|
|
/* Steps 6-7. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.32. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setUTCSeconds(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCSeconds_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setMinutes_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double m;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double s;
|
|
|
|
if (!GetSecsOrDefault(cx, args, 1, t, &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double u = TimeClip(UTC(date, cx));
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.33. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setMinutes(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setMinutes_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setUTCMinutes_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double m;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double s;
|
|
|
|
if (!GetSecsOrDefault(cx, args, 1, t, &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double v = TimeClip(date);
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.34. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCMinutes_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setHours_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double h;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &h))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double m;
|
|
|
|
if (!GetMinsOrDefault(cx, args, 1, t, &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double s;
|
|
|
|
if (!GetSecsOrDefault(cx, args, 2, t, &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double date = MakeDate(Day(t), MakeTime(h, m, s, milli));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double u = TimeClip(UTC(date, cx));
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:10 -07:00
|
|
|
/* ES5 15.9.5.35. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setHours(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:10 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setHours_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:10 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setUTCHours_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:10 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double h;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &h))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double m;
|
|
|
|
if (!GetMinsOrDefault(cx, args, 1, t, &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double s;
|
|
|
|
if (!GetSecsOrDefault(cx, args, 2, t, &s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double milli;
|
|
|
|
if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double newDate = MakeDate(Day(t), MakeTime(h, m, s, milli));
|
|
|
|
|
|
|
|
/* Step 7. */
|
|
|
|
double v = TimeClip(newDate);
|
|
|
|
|
|
|
|
/* Steps 8-9. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* ES5 15.9.5.36. */
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setUTCHours(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCHours_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setDate_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 2. */
|
|
|
|
double dt;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt))
|
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 3. */
|
|
|
|
double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
|
2012-04-06 18:06:14 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 4. */
|
|
|
|
double u = TimeClip(UTC(newDate, cx));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Steps 5-6. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2012-07-06 13:53:11 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* ES5 15.9.5.37. */
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setDate(JSContext *cx, unsigned argc, Value *vp)
|
2012-07-06 13:53:11 -07:00
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setDate_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setUTCDate_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 2. */
|
|
|
|
double dt;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &dt))
|
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 3. */
|
|
|
|
double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 4. */
|
|
|
|
double v = TimeClip(newDate);
|
|
|
|
|
|
|
|
/* Steps 5-6. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static JSBool
|
|
|
|
date_setUTCDate(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCDate_impl, args);
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
static bool
|
|
|
|
GetDateOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *date)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:11 -07:00
|
|
|
if (args.length() <= i) {
|
|
|
|
*date = DateFromTime(t);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return ToNumber(cx, args[i], date);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
static bool
|
|
|
|
GetMonthOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *month)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:11 -07:00
|
|
|
if (args.length() <= i) {
|
|
|
|
*month = MonthFromTime(t);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return ToNumber(cx, args[i], month);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* ES5 15.9.5.38. */
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setMonth_impl(JSContext *cx, CallArgs args)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 13:53:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:11 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = LocalTime(thisObj->getDateUTCTime().toNumber(), cx);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double m;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double dt;
|
|
|
|
if (!GetDateOrDefault(cx, args, 1, t, &dt))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double u = TimeClip(UTC(newDate, cx));
|
|
|
|
|
|
|
|
/* Steps 6-7. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setMonth(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:11 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setMonth_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.39. */
|
|
|
|
static bool
|
|
|
|
date_setUTCMonth_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:11 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = thisObj->getDateUTCTime().toNumber();
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double m;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double dt;
|
|
|
|
if (!GetDateOrDefault(cx, args, 1, t, &dt))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double v = TimeClip(newDate);
|
|
|
|
|
|
|
|
/* Steps 6-7. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2012-07-06 13:53:11 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static JSBool
|
|
|
|
date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCMonth_impl, args);
|
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
static double
|
|
|
|
ThisLocalTimeOrZero(Handle<JSObject*> date, JSContext *cx)
|
|
|
|
{
|
|
|
|
double t = date->getDateUTCTime().toNumber();
|
|
|
|
if (MOZ_DOUBLE_IS_NaN(t))
|
|
|
|
return +0;
|
|
|
|
return LocalTime(t, cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
ThisUTCTimeOrZero(Handle<JSObject*> date)
|
|
|
|
{
|
|
|
|
double t = date->getDateUTCTime().toNumber();
|
|
|
|
return MOZ_DOUBLE_IS_NaN(t) ? +0 : t;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* ES5 15.9.5.40. */
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_setFullYear_impl(JSContext *cx, CallArgs args)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 13:53:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:11 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = ThisLocalTimeOrZero(thisObj, cx);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double y;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double m;
|
|
|
|
if (!GetMonthOrDefault(cx, args, 1, t, &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double dt;
|
|
|
|
if (!GetDateOrDefault(cx, args, 2, t, &dt))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double u = TimeClip(UTC(newDate, cx));
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, u, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setFullYear(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 13:53:11 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setFullYear_impl, args);
|
|
|
|
}
|
2012-07-06 13:53:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.41. */
|
|
|
|
static bool
|
|
|
|
date_setUTCFullYear_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 13:53:11 -07:00
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
double t = ThisUTCTimeOrZero(thisObj);
|
|
|
|
|
|
|
|
/* Step 2. */
|
|
|
|
double y;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
double m;
|
|
|
|
if (!GetMonthOrDefault(cx, args, 1, t, &m))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
double dt;
|
|
|
|
if (!GetDateOrDefault(cx, args, 2, t, &dt))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
double newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double v = TimeClip(newDate);
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, v, args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setUTCFullYear_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 Annex B.2.5. */
|
|
|
|
static bool
|
|
|
|
date_setYear_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 1. */
|
|
|
|
double t = ThisLocalTimeOrZero(thisObj, cx);
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 2. */
|
|
|
|
double y;
|
|
|
|
if (!ToNumber(cx, args.length() > 0 ? args[0] : UndefinedValue(), &y))
|
2009-10-24 11:42:29 -07:00
|
|
|
return false;
|
2012-07-06 13:53:11 -07:00
|
|
|
|
|
|
|
/* Step 3. */
|
|
|
|
if (MOZ_DOUBLE_IS_NaN(y)) {
|
2012-07-30 04:19:09 -07:00
|
|
|
SetDateToNaN(cx, thisObj, args.rval().address());
|
2009-10-24 11:42:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 4. */
|
|
|
|
double yint = ToInteger(y);
|
|
|
|
if (0 <= yint && yint <= 99)
|
|
|
|
yint += 1900;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 13:53:11 -07:00
|
|
|
/* Step 5. */
|
|
|
|
double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t));
|
|
|
|
|
|
|
|
/* Step 6. */
|
|
|
|
double u = UTC(MakeDate(day, TimeWithinDay(t)), cx);
|
|
|
|
|
|
|
|
/* Steps 7-8. */
|
2012-07-30 04:19:09 -07:00
|
|
|
return SetUTCTime(cx, thisObj, TimeClip(u), args.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static JSBool
|
|
|
|
date_setYear(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_setYear_impl, args);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* constants for toString, toUTCString */
|
|
|
|
static char js_NaN_date_str[] = "Invalid Date";
|
|
|
|
static const char* days[] =
|
|
|
|
{
|
|
|
|
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
|
|
|
|
};
|
|
|
|
static const char* months[] =
|
|
|
|
{
|
|
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
|
|
};
|
|
|
|
|
2008-10-17 11:57:34 -07:00
|
|
|
|
|
|
|
// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
|
|
|
|
// requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
|
|
|
|
static void
|
2012-02-24 14:19:52 -08:00
|
|
|
print_gmt_string(char* buf, size_t size, double utctime)
|
2008-10-17 11:57:34 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
JS_ASSERT(TimeClip(utctime) == utctime);
|
2008-10-17 11:57:34 -07:00
|
|
|
JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
|
2012-07-09 14:28:20 -07:00
|
|
|
days[int(WeekDay(utctime))],
|
|
|
|
int(DateFromTime(utctime)),
|
|
|
|
months[int(MonthFromTime(utctime))],
|
|
|
|
int(YearFromTime(utctime)),
|
|
|
|
int(HourFromTime(utctime)),
|
|
|
|
int(MinFromTime(utctime)),
|
|
|
|
int(SecFromTime(utctime)));
|
2008-10-17 11:57:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-02-24 14:19:52 -08:00
|
|
|
print_iso_string(char* buf, size_t size, double utctime)
|
2008-10-17 11:57:34 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
JS_ASSERT(TimeClip(utctime) == utctime);
|
2008-10-17 11:57:34 -07:00
|
|
|
JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
|
2012-07-09 14:28:20 -07:00
|
|
|
int(YearFromTime(utctime)),
|
|
|
|
int(MonthFromTime(utctime)) + 1,
|
|
|
|
int(DateFromTime(utctime)),
|
|
|
|
int(HourFromTime(utctime)),
|
|
|
|
int(MinFromTime(utctime)),
|
|
|
|
int(SecFromTime(utctime)),
|
|
|
|
int(msFromTime(utctime)));
|
2008-10-17 11:57:34 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 15:35:45 -07:00
|
|
|
/* ES5 B.2.6. */
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_toGMTString_impl(JSContext *cx, CallArgs args)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double utctime = args.thisv().toObject().getDateUTCTime().toNumber();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-01-26 13:37:45 -08:00
|
|
|
char buf[100];
|
2012-07-06 15:35:45 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(utctime))
|
2007-03-22 10:30:00 -07:00
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
2012-07-06 15:35:45 -07:00
|
|
|
else
|
|
|
|
print_gmt_string(buf, sizeof buf, utctime);
|
2011-01-26 13:37:45 -08:00
|
|
|
|
|
|
|
JSString *str = JS_NewStringCopyZ(cx, buf);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!str)
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2011-09-08 21:18:23 -07:00
|
|
|
args.rval().setString(str);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 15:35:45 -07:00
|
|
|
/* ES5 15.9.5.43. */
|
2008-10-17 11:57:34 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toGMTString(JSContext *cx, unsigned argc, Value *vp)
|
2008-10-17 11:57:34 -07:00
|
|
|
{
|
2012-07-06 15:35:45 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toGMTString_impl, args);
|
|
|
|
}
|
2012-07-06 15:35:45 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_toISOString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 15:35:45 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
double utctime = args.thisv().toObject().getDateUTCTime().toNumber();
|
2012-07-06 15:35:45 -07:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(utctime)) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DATE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[100];
|
|
|
|
print_iso_string(buf, sizeof buf, utctime);
|
|
|
|
|
|
|
|
JSString *str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
args.rval().setString(str);
|
|
|
|
return true;
|
|
|
|
|
2008-10-17 11:57:34 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static JSBool
|
|
|
|
date_toISOString(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toISOString_impl, args);
|
|
|
|
}
|
|
|
|
|
2010-08-13 10:42:31 -07:00
|
|
|
/* ES5 15.9.5.44. */
|
2010-10-25 16:47:11 -07:00
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_toJSON(JSContext *cx, unsigned argc, Value *vp)
|
2010-08-13 10:42:31 -07:00
|
|
|
{
|
2012-08-12 18:50:49 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
|
2010-08-13 10:42:31 -07:00
|
|
|
/* Step 1. */
|
2012-08-12 18:50:49 -07:00
|
|
|
RootedObject obj(cx, ToObject(cx, args.thisv()));
|
2010-08-13 10:42:31 -07:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 2. */
|
2011-04-01 15:24:21 -07:00
|
|
|
Value tv = ObjectValue(*obj);
|
|
|
|
if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
|
2010-08-13 10:42:31 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 3. */
|
2012-01-23 03:43:16 -08:00
|
|
|
if (tv.isDouble() && !MOZ_DOUBLE_IS_FINITE(tv.toDouble())) {
|
2012-08-12 18:50:49 -07:00
|
|
|
args.rval().setNull();
|
2010-08-13 10:42:31 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 4. */
|
2012-07-30 04:19:09 -07:00
|
|
|
RootedValue toISO(cx);
|
2011-09-15 11:44:10 -07:00
|
|
|
if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
|
2010-08-13 10:42:31 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
if (!js_IsCallable(toISO)) {
|
|
|
|
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
|
|
|
|
JSMSG_BAD_TOISOSTRING_PROP);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 6. */
|
2012-08-12 18:50:49 -07:00
|
|
|
InvokeArgsGuard ag;
|
|
|
|
if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
|
2010-08-13 10:42:31 -07:00
|
|
|
return false;
|
|
|
|
|
2012-08-12 18:50:49 -07:00
|
|
|
ag.setCallee(toISO);
|
|
|
|
ag.setThis(ObjectValue(*obj));
|
2010-08-13 10:42:31 -07:00
|
|
|
|
2012-08-12 18:50:49 -07:00
|
|
|
if (!Invoke(cx, ag))
|
2010-08-13 10:42:31 -07:00
|
|
|
return false;
|
2012-08-12 18:50:49 -07:00
|
|
|
args.rval().set(ag.rval());
|
2010-08-13 10:42:31 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* for Date.toLocaleString; interface to PRMJTime date struct.
|
|
|
|
*/
|
|
|
|
static void
|
2012-02-24 14:19:52 -08:00
|
|
|
new_explode(double timeval, PRMJTime *split, JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-09 14:28:20 -07:00
|
|
|
double year = YearFromTime(timeval);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
split->tm_usec = int32_t(msFromTime(timeval)) * 1000;
|
|
|
|
split->tm_sec = int8_t(SecFromTime(timeval));
|
|
|
|
split->tm_min = int8_t(MinFromTime(timeval));
|
|
|
|
split->tm_hour = int8_t(HourFromTime(timeval));
|
|
|
|
split->tm_mday = int8_t(DateFromTime(timeval));
|
|
|
|
split->tm_mon = int8_t(MonthFromTime(timeval));
|
|
|
|
split->tm_wday = int8_t(WeekDay(timeval));
|
2007-11-12 22:39:16 -08:00
|
|
|
split->tm_year = year;
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-08 19:54:10 -08:00
|
|
|
split->tm_yday = int16_t(DayWithinYear(timeval, year));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* not sure how this affects things, but it doesn't seem
|
|
|
|
to matter. */
|
2010-05-26 17:00:28 -07:00
|
|
|
split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum formatspec {
|
|
|
|
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
|
|
|
|
} formatspec;
|
|
|
|
|
|
|
|
/* helper function */
|
|
|
|
static JSBool
|
2012-02-24 14:19:52 -08:00
|
|
|
date_format(JSContext *cx, double date, formatspec format, CallReceiver call)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
JSString *str;
|
|
|
|
char tzbuf[100];
|
|
|
|
JSBool usetz;
|
|
|
|
size_t i, tzlen;
|
|
|
|
PRMJTime split;
|
|
|
|
|
2012-01-23 03:43:16 -08:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(date)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
|
|
|
} else {
|
2012-07-09 14:28:20 -07:00
|
|
|
JS_ASSERT(TimeClip(date) == date);
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double local = LocalTime(date, cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* offset from GMT in minutes. The offset includes daylight savings,
|
|
|
|
if it applies. */
|
2012-03-01 18:54:01 -08:00
|
|
|
int minutes = (int) floor(AdjustTime(date, cx) / msPerMinute);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* map 510 minutes to 0830 hours */
|
2012-02-28 15:11:11 -08:00
|
|
|
int offset = (minutes / 60) * 100 + minutes % 60;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
|
|
|
|
* printed as 'GMT-0800' rather than as 'PST' to avoid
|
|
|
|
* operating-system dependence on strftime (which
|
|
|
|
* PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
|
|
|
|
* PST as 'Pacific Standard Time.' This way we always know
|
|
|
|
* what we're getting, and can parse it if we produce it.
|
|
|
|
* The OS TZA string is included as a comment.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* get a timezone string from the OS to include as a
|
|
|
|
comment. */
|
2010-05-26 17:00:28 -07:00
|
|
|
new_explode(date, &split, cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
|
|
|
|
|
|
|
|
/* Decide whether to use the resulting timezone string.
|
|
|
|
*
|
|
|
|
* Reject it if it contains any non-ASCII, non-alphanumeric
|
|
|
|
* characters. It's then likely in some other character
|
|
|
|
* encoding, and we probably won't display it correctly.
|
|
|
|
*/
|
|
|
|
usetz = JS_TRUE;
|
|
|
|
tzlen = strlen(tzbuf);
|
|
|
|
if (tzlen > 100) {
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < tzlen; i++) {
|
|
|
|
jschar c = tzbuf[i];
|
|
|
|
if (c > 127 ||
|
|
|
|
!(isalpha(c) || isdigit(c) ||
|
|
|
|
c == ' ' || c == '(' || c == ')')) {
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Also reject it if it's not parenthesized or if it's '()'. */
|
|
|
|
if (tzbuf[0] != '(' || tzbuf[1] == ')')
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
} else
|
|
|
|
usetz = JS_FALSE;
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case FORMATSPEC_FULL:
|
|
|
|
/*
|
|
|
|
* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
|
|
|
|
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
|
|
|
|
*/
|
|
|
|
/* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
"%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
|
2012-07-09 14:28:20 -07:00
|
|
|
days[int(WeekDay(local))],
|
|
|
|
months[int(MonthFromTime(local))],
|
|
|
|
int(DateFromTime(local)),
|
|
|
|
int(YearFromTime(local)),
|
|
|
|
int(HourFromTime(local)),
|
|
|
|
int(MinFromTime(local)),
|
|
|
|
int(SecFromTime(local)),
|
2007-03-22 10:30:00 -07:00
|
|
|
offset,
|
|
|
|
usetz ? " " : "",
|
|
|
|
usetz ? tzbuf : "");
|
|
|
|
break;
|
|
|
|
case FORMATSPEC_DATE:
|
|
|
|
/* Tue Oct 31 2000 */
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
"%s %s %.2d %.4d",
|
2012-07-09 14:28:20 -07:00
|
|
|
days[int(WeekDay(local))],
|
|
|
|
months[int(MonthFromTime(local))],
|
|
|
|
int(DateFromTime(local)),
|
|
|
|
int(YearFromTime(local)));
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
case FORMATSPEC_TIME:
|
|
|
|
/* 09:41:40 GMT-0800 (PST) */
|
|
|
|
JS_snprintf(buf, sizeof buf,
|
|
|
|
"%.2d:%.2d:%.2d GMT%+.4d%s%s",
|
2012-07-09 14:28:20 -07:00
|
|
|
int(HourFromTime(local)),
|
|
|
|
int(MinFromTime(local)),
|
|
|
|
int(SecFromTime(local)),
|
2007-03-22 10:30:00 -07:00
|
|
|
offset,
|
|
|
|
usetz ? " " : "",
|
|
|
|
usetz ? tzbuf : "");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
2011-09-08 21:02:26 -07:00
|
|
|
call.rval().setString(str);
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-09-08 21:18:23 -07:00
|
|
|
static bool
|
|
|
|
ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *format)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:18:23 -07:00
|
|
|
double utctime = obj->getDateUTCTime().toNumber();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-08 21:18:23 -07:00
|
|
|
char buf[100];
|
2012-01-23 03:43:16 -08:00
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(utctime)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
|
|
|
|
} else {
|
2012-02-28 15:11:11 -08:00
|
|
|
int result_len;
|
2012-02-24 14:19:52 -08:00
|
|
|
double local = LocalTime(utctime, cx);
|
2011-09-08 21:18:23 -07:00
|
|
|
PRMJTime split;
|
2010-05-26 17:00:28 -07:00
|
|
|
new_explode(local, &split, cx);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-06 15:26:11 -07:00
|
|
|
/* Let PRMJTime format it. */
|
2007-03-22 10:30:00 -07:00
|
|
|
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
|
|
|
|
|
|
|
|
/* If it failed, default to toString. */
|
|
|
|
if (result_len == 0)
|
2011-09-08 21:02:26 -07:00
|
|
|
return date_format(cx, utctime, FORMATSPEC_FULL, call);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* Hacked check against undesired 2-digit year 00/00/00 form. */
|
|
|
|
if (strcmp(format, "%x") == 0 && result_len >= 6 &&
|
|
|
|
/* Format %x means use OS settings, which may have 2-digit yr, so
|
|
|
|
hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
|
|
|
|
!isdigit(buf[result_len - 3]) &&
|
|
|
|
isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
|
|
|
|
/* ...but not if starts with 4-digit year, like 2022/3/11. */
|
|
|
|
!(isdigit(buf[0]) && isdigit(buf[1]) &&
|
|
|
|
isdigit(buf[2]) && isdigit(buf[3]))) {
|
|
|
|
JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
|
|
|
|
"%d", js_DateGetYear(cx, obj));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
|
2012-07-30 04:19:09 -07:00
|
|
|
return cx->localeCallbacks->localeToUnicode(cx, buf, call.rval().address());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-08 21:18:23 -07:00
|
|
|
JSString *str = JS_NewStringCopyZ(cx, buf);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!str)
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2011-09-08 21:02:26 -07:00
|
|
|
call.rval().setString(str);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 15:26:11 -07:00
|
|
|
static bool
|
|
|
|
ToLocaleStringHelper(JSContext *cx, CallReceiver call, Handle<JSObject*> thisObj)
|
2011-09-08 21:18:23 -07:00
|
|
|
{
|
2011-01-26 13:37:45 -08:00
|
|
|
/*
|
|
|
|
* Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
|
|
|
|
* with msvc; '%#c' requests that a full year be used in the result string.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2012-07-06 15:26:11 -07:00
|
|
|
return ToLocaleHelper(cx, call, thisObj,
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(_WIN32) && !defined(__MWERKS__)
|
2012-07-06 15:26:11 -07:00
|
|
|
"%#c"
|
2007-03-22 10:30:00 -07:00
|
|
|
#else
|
2012-07-06 15:26:11 -07:00
|
|
|
"%c"
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2012-07-06 15:26:11 -07:00
|
|
|
);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-06 15:26:11 -07:00
|
|
|
/* ES5 15.9.5.5. */
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_toLocaleString_impl(JSContext *cx, CallArgs args)
|
2011-10-04 10:48:36 -07:00
|
|
|
{
|
2012-07-03 17:44:22 -07:00
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 15:26:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 15:26:11 -07:00
|
|
|
return ToLocaleStringHelper(cx, args, thisObj);
|
2011-10-04 10:48:36 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 15:26:11 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toLocaleString_impl, args);
|
|
|
|
}
|
2012-07-06 15:26:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.6. */
|
|
|
|
static bool
|
|
|
|
date_toLocaleDateString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 15:26:11 -07:00
|
|
|
|
2011-01-26 13:37:45 -08:00
|
|
|
/*
|
|
|
|
* Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
|
|
|
|
* with msvc; '%#x' requests that a full year be used in the result string.
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2012-07-06 15:26:11 -07:00
|
|
|
static const char format[] =
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(_WIN32) && !defined(__MWERKS__)
|
|
|
|
"%#x"
|
|
|
|
#else
|
|
|
|
"%x"
|
|
|
|
#endif
|
2012-07-06 15:26:11 -07:00
|
|
|
;
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 15:26:11 -07:00
|
|
|
return ToLocaleHelper(cx, args, thisObj, format);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toLocaleDateString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-06 15:26:11 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toLocaleDateString_impl, args);
|
|
|
|
}
|
2012-07-06 15:26:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.7. */
|
|
|
|
static bool
|
|
|
|
date_toLocaleTimeString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2012-07-06 15:26:11 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2012-07-06 15:26:11 -07:00
|
|
|
return ToLocaleHelper(cx, args, thisObj, "%X");
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toLocaleTimeString_impl, args);
|
|
|
|
}
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_toLocaleFormat_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-01-26 13:37:45 -08:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
|
|
|
|
|
|
|
if (args.length() == 0)
|
2012-07-06 15:26:11 -07:00
|
|
|
return ToLocaleStringHelper(cx, args, thisObj);
|
|
|
|
|
2011-12-01 19:35:44 -08:00
|
|
|
JSString *fmt = ToString(cx, args[0]);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!fmt)
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args[0].setString(fmt);
|
2010-11-11 12:40:29 -08:00
|
|
|
JSAutoByteString fmtbytes(cx, fmt);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!fmtbytes)
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-06-01 23:39:09 -07:00
|
|
|
return ToLocaleHelper(cx, args, thisObj, fmtbytes.ptr());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toLocaleFormat_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.4. */
|
|
|
|
static bool
|
|
|
|
date_toTimeString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(),
|
|
|
|
FORMATSPEC_TIME, args);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toTimeString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toTimeString_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
/* ES5 15.9.5.3. */
|
|
|
|
static bool
|
|
|
|
date_toDateString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(),
|
|
|
|
FORMATSPEC_DATE, args);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-07-03 17:44:22 -07:00
|
|
|
date_toDateString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toDateString_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
#if JS_HAS_TOSOURCE
|
|
|
|
static bool
|
|
|
|
date_toSource_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
2011-09-08 21:18:23 -07:00
|
|
|
|
2011-12-06 02:31:00 -08:00
|
|
|
StringBuffer sb(cx);
|
2012-06-01 23:39:09 -07:00
|
|
|
if (!sb.append("(new Date(") ||
|
2012-07-03 17:44:22 -07:00
|
|
|
!NumberValueToStringBuffer(cx, args.thisv().toObject().getDateUTCTime(), sb) ||
|
2011-12-06 02:31:00 -08:00
|
|
|
!sb.append("))"))
|
|
|
|
{
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-12-06 02:31:00 -08:00
|
|
|
JSString *str = sb.finishString();
|
2010-12-09 02:22:15 -08:00
|
|
|
if (!str)
|
2011-01-26 13:37:45 -08:00
|
|
|
return false;
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setString(str);
|
2011-01-26 13:37:45 -08:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-07-03 17:44:22 -07:00
|
|
|
|
|
|
|
static JSBool
|
|
|
|
date_toSource(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toSource_impl, args);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_toString_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
return date_format(cx, args.thisv().toObject().getDateUTCTime().toNumber(),
|
|
|
|
FORMATSPEC_FULL, args);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_toString(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_toString_impl, args);
|
|
|
|
}
|
2011-09-08 21:02:26 -07:00
|
|
|
|
2012-07-03 17:44:22 -07:00
|
|
|
static bool
|
|
|
|
date_valueOf_impl(JSContext *cx, CallArgs args)
|
|
|
|
{
|
|
|
|
JS_ASSERT(IsDate(args.thisv()));
|
|
|
|
|
|
|
|
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
2007-08-01 21:33:52 -07:00
|
|
|
|
2012-07-30 04:19:09 -07:00
|
|
|
args.rval().set(thisObj->getDateUTCTime());
|
2012-07-03 17:44:22 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
date_valueOf(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-10-07 11:58:45 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-07-03 17:44:22 -07:00
|
|
|
return CallNonGenericMethod(cx, IsDate, date_valueOf_impl, args);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSFunctionSpec date_static_methods[] = {
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN("UTC", date_UTC, MAXARGS,0),
|
|
|
|
JS_FN("parse", date_parse, 1,0),
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("now", date_now, 0,0),
|
2007-08-01 21:33:52 -07:00
|
|
|
JS_FS_END
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static JSFunctionSpec date_methods[] = {
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN("getTime", date_getTime, 0,0),
|
|
|
|
JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0),
|
|
|
|
JS_FN("getYear", date_getYear, 0,0),
|
|
|
|
JS_FN("getFullYear", date_getFullYear, 0,0),
|
|
|
|
JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0),
|
|
|
|
JS_FN("getMonth", date_getMonth, 0,0),
|
|
|
|
JS_FN("getUTCMonth", date_getUTCMonth, 0,0),
|
|
|
|
JS_FN("getDate", date_getDate, 0,0),
|
|
|
|
JS_FN("getUTCDate", date_getUTCDate, 0,0),
|
|
|
|
JS_FN("getDay", date_getDay, 0,0),
|
|
|
|
JS_FN("getUTCDay", date_getUTCDay, 0,0),
|
|
|
|
JS_FN("getHours", date_getHours, 0,0),
|
|
|
|
JS_FN("getUTCHours", date_getUTCHours, 0,0),
|
|
|
|
JS_FN("getMinutes", date_getMinutes, 0,0),
|
|
|
|
JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0),
|
|
|
|
JS_FN("getSeconds", date_getUTCSeconds, 0,0),
|
|
|
|
JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0),
|
|
|
|
JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0),
|
|
|
|
JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0),
|
|
|
|
JS_FN("setTime", date_setTime, 1,0),
|
|
|
|
JS_FN("setYear", date_setYear, 1,0),
|
|
|
|
JS_FN("setFullYear", date_setFullYear, 3,0),
|
|
|
|
JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0),
|
|
|
|
JS_FN("setMonth", date_setMonth, 2,0),
|
|
|
|
JS_FN("setUTCMonth", date_setUTCMonth, 2,0),
|
|
|
|
JS_FN("setDate", date_setDate, 1,0),
|
|
|
|
JS_FN("setUTCDate", date_setUTCDate, 1,0),
|
|
|
|
JS_FN("setHours", date_setHours, 4,0),
|
|
|
|
JS_FN("setUTCHours", date_setUTCHours, 4,0),
|
|
|
|
JS_FN("setMinutes", date_setMinutes, 3,0),
|
|
|
|
JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0),
|
|
|
|
JS_FN("setSeconds", date_setSeconds, 2,0),
|
|
|
|
JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0),
|
|
|
|
JS_FN("setMilliseconds", date_setMilliseconds, 1,0),
|
|
|
|
JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
|
|
|
|
JS_FN("toUTCString", date_toGMTString, 0,0),
|
|
|
|
JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
|
|
|
|
JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
|
|
|
|
JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
|
|
|
|
JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
|
|
|
|
JS_FN("toDateString", date_toDateString, 0,0),
|
|
|
|
JS_FN("toTimeString", date_toTimeString, 0,0),
|
|
|
|
JS_FN("toISOString", date_toISOString, 0,0),
|
|
|
|
JS_FN(js_toJSON_str, date_toJSON, 1,0),
|
2007-03-22 10:30:00 -07:00
|
|
|
#if JS_HAS_TOSOURCE
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN(js_toSource_str, date_toSource, 0,0),
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN(js_toString_str, date_toString, 0,0),
|
|
|
|
JS_FN(js_valueOf_str, date_valueOf, 0,0),
|
2007-08-01 21:33:52 -07:00
|
|
|
JS_FS_END
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2008-10-06 17:28:22 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_Date(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
/* Date called as function. */
|
|
|
|
if (!IsConstructing(args))
|
|
|
|
return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args);
|
2010-08-16 12:35:04 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* Date called as constructor. */
|
2012-02-24 14:19:52 -08:00
|
|
|
double d;
|
2011-09-08 21:02:26 -07:00
|
|
|
if (args.length() == 0) {
|
2012-06-10 16:44:50 -07:00
|
|
|
/* ES5 15.9.3.3. */
|
2009-10-24 11:42:29 -07:00
|
|
|
d = NowAsMillis();
|
2011-09-08 21:02:26 -07:00
|
|
|
} else if (args.length() == 1) {
|
2012-06-10 16:44:50 -07:00
|
|
|
/* ES5 15.9.3.2. */
|
|
|
|
|
|
|
|
/* Step 1. */
|
|
|
|
if (!ToPrimitive(cx, &args[0]))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (args[0].isString()) {
|
|
|
|
/* Step 2. */
|
2011-12-01 19:35:44 -08:00
|
|
|
JSString *str = ToString(cx, args[0]);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!str)
|
2010-08-16 12:35:04 -07:00
|
|
|
return false;
|
2011-09-08 21:02:26 -07:00
|
|
|
args[0].setString(str);
|
2010-12-06 10:26:58 -08:00
|
|
|
JSLinearString *linearStr = str->ensureLinear(cx);
|
|
|
|
if (!linearStr)
|
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-12-06 10:26:58 -08:00
|
|
|
if (!date_parseString(linearStr, &d, cx))
|
2009-10-24 11:42:29 -07:00
|
|
|
d = js_NaN;
|
|
|
|
else
|
2012-04-19 16:22:08 -07:00
|
|
|
d = TimeClip(d);
|
2012-06-10 16:44:50 -07:00
|
|
|
} else {
|
|
|
|
/* Step 3. */
|
|
|
|
if (!ToNumber(cx, args[0], &d))
|
|
|
|
return false;
|
|
|
|
d = TimeClip(d);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
} else {
|
2012-02-24 14:19:52 -08:00
|
|
|
double msec_time;
|
2011-09-08 21:02:26 -07:00
|
|
|
if (!date_msecFromArgs(cx, args, &msec_time))
|
2010-08-16 12:35:04 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(msec_time)) {
|
2010-05-26 17:00:28 -07:00
|
|
|
msec_time = UTC(msec_time, cx);
|
2012-04-19 16:22:08 -07:00
|
|
|
msec_time = TimeClip(msec_time);
|
2007-08-13 13:45:32 -07:00
|
|
|
}
|
2009-10-24 11:42:29 -07:00
|
|
|
d = msec_time;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-08-10 16:38:08 -07:00
|
|
|
|
|
|
|
JSObject *obj = js_NewDateObjectMsec(cx, d);
|
|
|
|
if (!obj)
|
2010-08-16 12:35:04 -07:00
|
|
|
return false;
|
2010-08-10 16:38:08 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
args.rval().setObject(*obj);
|
2010-08-16 12:35:04 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
js_InitDateClass(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
2011-05-03 12:18:36 -07:00
|
|
|
JS_ASSERT(obj->isNative());
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
UpdateLocalTZA();
|
2011-05-03 12:18:36 -07:00
|
|
|
|
2012-05-24 16:05:18 -07:00
|
|
|
Rooted<GlobalObject*> global(cx, &obj->asGlobal());
|
2011-05-03 12:18:36 -07:00
|
|
|
|
2012-05-24 16:05:18 -07:00
|
|
|
RootedObject dateProto(cx, global->createBlankPrototype(cx, &DateClass));
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!dateProto)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
2011-05-03 12:18:36 -07:00
|
|
|
SetDateToNaN(cx, dateProto);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-08 03:00:11 -07:00
|
|
|
RootedFunction ctor(cx, global->createConstructor(cx, js_Date, CLASS_NAME(cx, Date), MAXARGS));
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!ctor)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
|
|
|
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!LinkConstructorAndPrototype(cx, ctor, dateProto))
|
|
|
|
return NULL;
|
2010-06-26 14:08:58 -07:00
|
|
|
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!DefinePropertiesAndBrand(cx, ctor, NULL, date_static_methods))
|
|
|
|
return NULL;
|
2009-10-24 11:42:29 -07:00
|
|
|
|
2010-06-26 14:08:58 -07:00
|
|
|
/*
|
2011-05-03 12:18:36 -07:00
|
|
|
* Define all Date.prototype.* functions, then brand for trace-jitted code.
|
|
|
|
* Date.prototype.toGMTString has the same initial value as
|
|
|
|
* Date.prototype.toUTCString.
|
2010-06-26 14:08:58 -07:00
|
|
|
*/
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!JS_DefineFunctions(cx, dateProto, date_methods))
|
|
|
|
return NULL;
|
2012-07-30 04:19:09 -07:00
|
|
|
RootedValue toUTCStringFun(cx);
|
2012-05-24 16:05:18 -07:00
|
|
|
RootedId toUTCStringId(cx, NameToId(cx->runtime->atomState.toUTCStringAtom));
|
|
|
|
RootedId toGMTStringId(cx, NameToId(cx->runtime->atomState.toGMTStringAtom));
|
2012-05-19 15:03:45 -07:00
|
|
|
if (!baseops::GetProperty(cx, dateProto, toUTCStringId, &toUTCStringFun) ||
|
2012-07-30 04:19:09 -07:00
|
|
|
!baseops::DefineGeneric(cx, dateProto, toGMTStringId, toUTCStringFun,
|
2012-06-14 19:13:27 -07:00
|
|
|
JS_PropertyStub, JS_StrictPropertyStub, 0))
|
2011-05-03 12:18:36 -07:00
|
|
|
{
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
2010-06-26 14:08:58 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-03 12:18:36 -07:00
|
|
|
if (!DefineConstructorAndPrototype(cx, global, JSProto_Date, ctor, dateProto))
|
|
|
|
return NULL;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-03 12:18:36 -07:00
|
|
|
return dateProto;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(JSObject *)
|
2012-02-24 14:19:52 -08:00
|
|
|
js_NewDateObjectMsec(JSContext *cx, double msec_time)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-02 17:23:26 -07:00
|
|
|
JSObject *obj = NewBuiltinClassInstance(cx, &DateClass);
|
2011-10-10 11:41:03 -07:00
|
|
|
if (!obj)
|
2010-10-13 11:49:22 -07:00
|
|
|
return NULL;
|
|
|
|
if (!SetUTCTime(cx, obj, msec_time))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(JSObject *)
|
|
|
|
js_NewDateObject(JSContext* cx, int year, int mon, int mday,
|
|
|
|
int hour, int min, int sec)
|
|
|
|
{
|
|
|
|
JSObject *obj;
|
2012-02-24 14:19:52 -08:00
|
|
|
double msec_time;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-01-03 18:23:55 -08:00
|
|
|
JS_ASSERT(mon < 12);
|
2007-03-22 10:30:00 -07:00
|
|
|
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
|
2010-05-26 17:00:28 -07:00
|
|
|
obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
|
2007-03-22 10:30:00 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
void
|
|
|
|
js_ClearDateCaches()
|
|
|
|
{
|
|
|
|
UpdateLocalTZA();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
JS_FRIEND_API(JSBool)
|
|
|
|
js_DateIsValid(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-01-23 03:43:16 -08:00
|
|
|
return obj->isDate() && !MOZ_DOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetYear(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double localtime;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/* Preserve legacy API behavior of returning 0 for invalid dates. */
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (int) YearFromTime(localtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetMonth(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double localtime;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (int) MonthFromTime(localtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetDate(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double localtime;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (int) DateFromTime(localtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetHours(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double localtime;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (int) HourFromTime(localtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetMinutes(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double localtime;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-13 15:56:08 -07:00
|
|
|
if (!GetCachedLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (int) MinFromTime(localtime);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FRIEND_API(int)
|
|
|
|
js_DateGetSeconds(JSContext *cx, JSObject* obj)
|
|
|
|
{
|
2012-05-19 12:56:17 -07:00
|
|
|
if (!obj->isDate())
|
2011-09-08 21:02:26 -07:00
|
|
|
return 0;
|
2012-05-19 12:56:17 -07:00
|
|
|
|
2011-09-08 21:02:26 -07:00
|
|
|
double utctime = obj->getDateUTCTime().toNumber();
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_NaN(utctime))
|
2007-03-22 10:30:00 -07:00
|
|
|
return 0;
|
|
|
|
return (int) SecFromTime(utctime);
|
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
JS_FRIEND_API(double)
|
2012-07-23 13:37:31 -07:00
|
|
|
js_DateGetMsecSinceEpoch(JSContext *cx, RawObject obj)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-08 21:02:26 -07:00
|
|
|
return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-02-10 03:45:36 -08:00
|
|
|
|