#include "config.h"
#include "date_object.h"
#include "date_object.lut.h"
#include "internal.h"
#if HAVE(ERRNO_H)
#include <errno.h>
#endif
#if HAVE(SYS_PARAM_H)
#include <sys/param.h>
#endif
#if HAVE(SYS_TIME_H)
#include <sys/time.h>
#endif
#if HAVE(SYS_TIMEB_H)
#include <sys/timeb.h>
#endif
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "error_object.h"
#include "operations.h"
#include "DateMath.h"
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/UnusedParam.h>
#include <CoreFoundation/CoreFoundation.h>
using namespace WTF;
namespace KJS {
static double parseDate(const UString&);
static double timeClip(double);
inline int gmtoffset(const GregorianDateTime& t)
{
return t.utcOffset;
}
class DateObjectFuncImp : public InternalFunctionImp {
public:
DateObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier& );
virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
enum { Parse, UTC };
private:
int id;
};
static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
{
if (string == "short")
return kCFDateFormatterShortStyle;
if (string == "medium")
return kCFDateFormatterMediumStyle;
if (string == "long")
return kCFDateFormatterLongStyle;
if (string == "full")
return kCFDateFormatterFullStyle;
return defaultStyle;
}
static UString formatLocaleDate(ExecState *exec, double time, bool includeDate, bool includeTime, const List &args)
{
CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
bool useCustomFormat = false;
UString customFormatString;
UString arg0String = args[0]->toString(exec);
if (arg0String == "custom" && !args[1]->isUndefined()) {
useCustomFormat = true;
customFormatString = args[1]->toString(exec);
} else if (includeDate && includeTime && !args[1]->isUndefined()) {
dateStyle = styleFromArgString(arg0String, dateStyle);
timeStyle = styleFromArgString(args[1]->toString(exec), timeStyle);
} else if (includeDate && !args[0]->isUndefined()) {
dateStyle = styleFromArgString(arg0String, dateStyle);
} else if (includeTime && !args[0]->isUndefined()) {
timeStyle = styleFromArgString(arg0String, timeStyle);
}
CFLocaleRef locale = CFLocaleCopyCurrent();
CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
CFRelease(locale);
if (useCustomFormat) {
CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size());
CFDateFormatterSetFormat(formatter, customFormatCFString);
CFRelease(customFormatCFString);
}
CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970);
CFRelease(formatter);
UChar buffer[200];
const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]);
size_t length = CFStringGetLength(string);
ASSERT(length <= bufferLength);
if (length > bufferLength)
length = bufferLength;
CFStringGetCharacters(string, CFRangeMake(0, length), reinterpret_cast<UniChar *>(buffer));
CFRelease(string);
return UString(buffer, length);
}
static UString formatDate(const GregorianDateTime &t)
{
char buffer[100];
snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
weekdayName[(t.weekDay + 6) % 7],
monthName[t.month], t.monthDay, t.year + 1900);
return buffer;
}
static UString formatDateUTCVariant(const GregorianDateTime &t)
{
char buffer[100];
snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
weekdayName[(t.weekDay + 6) % 7],
t.monthDay, monthName[t.month], t.year + 1900);
return buffer;
}
static UString formatTime(const GregorianDateTime &t, bool utc)
{
char buffer[100];
if (utc) {
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
} else {
int offset = abs(gmtoffset(t));
char tzname[70];
struct tm gtm = t;
strftime(tzname, sizeof(tzname), "%Z", >m);
if (tzname[0]) {
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)",
t.hour, t.minute, t.second,
gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname);
} else {
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
t.hour, t.minute, t.second,
gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
}
}
return UString(buffer);
}
static void fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t)
{
double milliseconds = 0;
int idx = 0;
int numArgs = args.size();
if (numArgs > maxArgs)
numArgs = maxArgs;
if (maxArgs >= 4 && idx < numArgs) {
t->hour = 0;
milliseconds += args[idx++]->toInt32(exec) * msPerHour;
}
if (maxArgs >= 3 && idx < numArgs) {
t->minute = 0;
milliseconds += args[idx++]->toInt32(exec) * msPerMinute;
}
if (maxArgs >= 2 && idx < numArgs) {
t->second = 0;
milliseconds += args[idx++]->toInt32(exec) * msPerSecond;
}
if (idx < numArgs)
milliseconds += args[idx]->toNumber(exec);
else
milliseconds += *ms;
*ms = milliseconds;
}
static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
{
int idx = 0;
int numArgs = args.size();
if (numArgs > maxArgs)
numArgs = maxArgs;
if (maxArgs >= 3 && idx < numArgs)
t->year = args[idx++]->toInt32(exec) - 1900;
if (maxArgs >= 2 && idx < numArgs)
t->month = args[idx++]->toInt32(exec);
if (idx < numArgs) {
t->monthDay = 0;
*ms += args[idx]->toInt32(exec) * msPerDay;
}
}
const ClassInfo DateInstance::info = {"Date", 0, 0};
DateInstance::DateInstance(JSObject *proto)
: JSWrapperObject(proto)
{
}
bool DateInstance::getTime(GregorianDateTime &t, int &offset) const
{
double milli = internalValue()->getNumber();
if (isnan(milli))
return false;
msToGregorianDateTime(milli, false, t);
offset = gmtoffset(t);
return true;
}
bool DateInstance::getUTCTime(GregorianDateTime &t) const
{
double milli = internalValue()->getNumber();
if (isnan(milli))
return false;
msToGregorianDateTime(milli, true, t);
return true;
}
bool DateInstance::getTime(double &milli, int &offset) const
{
milli = internalValue()->getNumber();
if (isnan(milli))
return false;
GregorianDateTime t;
msToGregorianDateTime(milli, false, t);
offset = gmtoffset(t);
return true;
}
bool DateInstance::getUTCTime(double &milli) const
{
milli = internalValue()->getNumber();
if (isnan(milli))
return false;
return true;
}
static inline bool isTime_tSigned()
{
time_t minusOne = (time_t)(-1);
return minusOne < 0;
}
const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable};
DatePrototype::DatePrototype(ExecState *, ObjectPrototype *objectProto)
: DateInstance(objectProto)
{
setInternalValue(jsNaN());
}
bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticFunctionSlot<JSObject>(exec, &dateTable, this, propertyName, slot);
}
DateObjectImp::DateObjectImp(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto)
: InternalFunctionImp(funcProto, dateProto->classInfo()->className)
{
static const Identifier* parsePropertyName = new Identifier("parse");
static const Identifier* UTCPropertyName = new Identifier("UTC");
putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::Parse, 1, *parsePropertyName), DontEnum);
putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::UTC, 7, *UTCPropertyName), DontEnum);
putDirect(exec->propertyNames().length, 7, ReadOnly|DontDelete|DontEnum);
}
bool DateObjectImp::implementsConstruct() const
{
return true;
}
JSObject *DateObjectImp::construct(ExecState *exec, const List &args)
{
int numArgs = args.size();
double value;
if (numArgs == 0) { value = getCurrentUTCTime();
} else if (numArgs == 1) {
if (args[0]->isObject(&DateInstance::info))
value = static_cast<DateInstance*>(args[0])->internalValue()->toNumber(exec);
else {
JSValue* primitive = args[0]->toPrimitive(exec);
if (primitive->isString())
value = parseDate(primitive->getString());
else
value = primitive->toNumber(exec);
}
} else {
if (isnan(args[0]->toNumber(exec))
|| isnan(args[1]->toNumber(exec))
|| (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
|| (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
|| (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
|| (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
|| (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
value = NaN;
} else {
GregorianDateTime t;
int year = args[0]->toInt32(exec);
t.year = (year >= 0 && year <= 99) ? year : year - 1900;
t.month = args[1]->toInt32(exec);
t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
t.hour = args[3]->toInt32(exec);
t.minute = args[4]->toInt32(exec);
t.second = args[5]->toInt32(exec);
t.isDST = -1;
double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
value = gregorianDateTimeToMS(t, ms, false);
}
}
DateInstance *ret = new DateInstance(exec->lexicalGlobalObject()->datePrototype());
ret->setInternalValue(jsNumber(timeClip(value)));
return ret;
}
JSValue *DateObjectImp::callAsFunction(ExecState * , JSObject * , const List &)
{
time_t t = time(0);
GregorianDateTime ts(*localtime(&t));
return jsString(formatDate(ts) + " " + formatTime(ts, false));
}
DateObjectFuncImp::DateObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
: InternalFunctionImp(funcProto, name), id(i)
{
putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
}
JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
{
if (id == Parse) {
return jsNumber(parseDate(args[0]->toString(exec)));
}
else { int n = args.size();
if (isnan(args[0]->toNumber(exec))
|| isnan(args[1]->toNumber(exec))
|| (n >= 3 && isnan(args[2]->toNumber(exec)))
|| (n >= 4 && isnan(args[3]->toNumber(exec)))
|| (n >= 5 && isnan(args[4]->toNumber(exec)))
|| (n >= 6 && isnan(args[5]->toNumber(exec)))
|| (n >= 7 && isnan(args[6]->toNumber(exec)))) {
return jsNaN();
}
GregorianDateTime t;
memset(&t, 0, sizeof(t));
int year = args[0]->toInt32(exec);
t.year = (year >= 0 && year <= 99) ? year : year - 1900;
t.month = args[1]->toInt32(exec);
t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
t.hour = args[3]->toInt32(exec);
t.minute = args[4]->toInt32(exec);
t.second = args[5]->toInt32(exec);
double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
return jsNumber(gregorianDateTimeToMS(t, ms, true));
}
}
static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
{
double days = (day - 32075)
+ floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
+ 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
- floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
- 2440588;
return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
}
static const struct KnownZone {
#if !PLATFORM(WIN_OS)
const
#endif
char tzName[4];
int tzOffset;
} known_zones[] = {
{ "UT", 0 },
{ "GMT", 0 },
{ "EST", -300 },
{ "EDT", -240 },
{ "CST", -360 },
{ "CDT", -300 },
{ "MST", -420 },
{ "MDT", -360 },
{ "PST", -480 },
{ "PDT", -420 }
};
inline static void skipSpacesAndComments(const char*& s)
{
int nesting = 0;
char ch;
while ((ch = *s)) {
if (!isASCIISpace(ch)) {
if (ch == '(')
nesting++;
else if (ch == ')' && nesting > 0)
nesting--;
else if (nesting == 0)
break;
}
s++;
}
}
static int findMonth(const char* monthStr)
{
ASSERT(monthStr);
char needle[4];
for (int i = 0; i < 3; ++i) {
if (!*monthStr)
return -1;
needle[i] = static_cast<char>(toASCIILower(*monthStr++));
}
needle[3] = '\0';
const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
const char *str = strstr(haystack, needle);
if (str) {
int position = static_cast<int>(str - haystack);
if (position % 3 == 0)
return position / 3;
}
return -1;
}
static double parseDate(const UString &date)
{
CString dateCString = date.UTF8String();
const char *dateString = dateCString.c_str();
skipSpacesAndComments(dateString);
long month = -1;
const char *wordStart = dateString;
while (*dateString && !isASCIIDigit(*dateString)) {
if (isASCIISpace(*dateString) || *dateString == '(') {
if (dateString - wordStart >= 3)
month = findMonth(wordStart);
skipSpacesAndComments(dateString);
wordStart = dateString;
} else
dateString++;
}
if (month == -1 && wordStart != dateString)
month = findMonth(wordStart);
skipSpacesAndComments(dateString);
if (!*dateString)
return NaN;
char *newPosStr;
errno = 0;
long day = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
if (!*dateString)
return NaN;
if (day < 0)
return NaN;
long year = 0;
if (day > 31) {
if (*dateString != '/')
return NaN;
if (!*++dateString)
return NaN;
year = day;
month = strtol(dateString, &newPosStr, 10) - 1;
if (errno)
return NaN;
dateString = newPosStr;
if (*dateString++ != '/' || !*dateString)
return NaN;
day = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
} else if (*dateString == '/' && month == -1) {
dateString++;
month = day - 1; day = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
if (day < 1 || day > 31)
return NaN;
dateString = newPosStr;
if (*dateString == '/')
dateString++;
if (!*dateString)
return NaN;
} else {
if (*dateString == '-')
dateString++;
skipSpacesAndComments(dateString);
if (*dateString == ',')
dateString++;
if (month == -1) { month = findMonth(dateString);
if (month == -1)
return NaN;
while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
dateString++;
if (!*dateString)
return NaN;
if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
return NaN;
dateString++;
}
}
if (month < 0 || month > 11)
return NaN;
if (year <= 0 && *dateString) {
year = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
}
long hour = 0;
long minute = 0;
long second = 0;
if (!*newPosStr)
dateString = newPosStr;
else {
if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
if (*newPosStr != ':')
return NaN;
year = -1;
} else {
dateString = ++newPosStr;
skipSpacesAndComments(dateString);
}
hour = strtol(dateString, &newPosStr, 10);
if (newPosStr != dateString) {
dateString = newPosStr;
if (hour < 0 || hour > 23)
return NaN;
if (!*dateString)
return NaN;
if (*dateString++ != ':')
return NaN;
minute = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
if (minute < 0 || minute > 59)
return NaN;
if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
return NaN;
if (*dateString ==':') {
dateString++;
second = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
if (second < 0 || second > 59)
return NaN;
}
skipSpacesAndComments(dateString);
if (strncasecmp(dateString, "AM", 2) == 0) {
if (hour > 12)
return NaN;
if (hour == 12)
hour = 0;
dateString += 2;
skipSpacesAndComments(dateString);
} else if (strncasecmp(dateString, "PM", 2) == 0) {
if (hour > 12)
return NaN;
if (hour != 12)
hour += 12;
dateString += 2;
skipSpacesAndComments(dateString);
}
}
}
bool haveTZ = false;
int offset = 0;
if (*dateString) {
if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
dateString += 3;
haveTZ = true;
}
if (*dateString == '+' || *dateString == '-') {
long o = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
if (o < -9959 || o > 9959)
return NaN;
int sgn = (o < 0) ? -1 : 1;
o = abs(o);
if (*dateString != ':') {
offset = ((o / 100) * 60 + (o % 100)) * sgn;
} else { long o2 = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
offset = (o * 60 + o2) * sgn;
}
haveTZ = true;
} else {
for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
offset = known_zones[i].tzOffset;
dateString += strlen(known_zones[i].tzName);
haveTZ = true;
break;
}
}
}
}
skipSpacesAndComments(dateString);
if (*dateString && year == -1) {
year = strtol(dateString, &newPosStr, 10);
if (errno)
return NaN;
dateString = newPosStr;
}
skipSpacesAndComments(dateString);
if (*dateString)
return NaN;
if (year >= 0 && year < 100) {
if (year < 50)
year += 2000;
else
year += 1900;
}
if (!haveTZ) {
GregorianDateTime t;
memset(&t, 0, sizeof(tm));
t.monthDay = day;
t.month = month;
t.year = year - 1900;
t.isDST = -1;
t.second = second;
t.minute = minute;
t.hour = hour;
return gregorianDateTimeToMS(t, 0, false);
}
return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
}
double timeClip(double t)
{
if (!isfinite(t))
return NaN;
if (fabs(t) > 8.64E15)
return NaN;
return trunc(t);
}
JSValue* dateProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsString(formatDate(t) + " " + formatTime(t, utc));
}
JSValue* dateProtoFuncToUTCString(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
}
JSValue* dateProtoFuncToDateString(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsString(formatDate(t));
}
JSValue* dateProtoFuncToTimeString(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsString(formatTime(t, utc));
}
JSValue* dateProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List& args)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
double secs = floor(milli / msPerSecond);
return jsString(formatLocaleDate(exec, secs, true, true, args));
}
JSValue* dateProtoFuncToLocaleDateString(ExecState* exec, JSObject* thisObj, const List& args)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
double secs = floor(milli / msPerSecond);
return jsString(formatLocaleDate(exec, secs, true, false, args));
}
JSValue* dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject* thisObj, const List& args)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
double secs = floor(milli / msPerSecond);
return jsString(formatLocaleDate(exec, secs, false, true, args));
}
JSValue* dateProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
return jsNumber(milli);
}
JSValue* dateProtoFuncGetTime(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
return jsNumber(milli);
}
JSValue* dateProtoFuncGetFullYear(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(1900 + t.year);
}
JSValue* dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(1900 + t.year);
}
JSValue* dateProtoFuncToGMTString(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsString("Invalid Date");
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
}
JSValue* dateProtoFuncGetMonth(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.month);
}
JSValue* dateProtoFuncGetUTCMonth(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.month);
}
JSValue* dateProtoFuncGetDate(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.monthDay);
}
JSValue* dateProtoFuncGetUTCDate(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.monthDay);
}
JSValue* dateProtoFuncGetDay(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.weekDay);
}
JSValue* dateProtoFuncGetUTCDay(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.weekDay);
}
JSValue* dateProtoFuncGetHours(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.hour);
}
JSValue* dateProtoFuncGetUTCHours(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.hour);
}
JSValue* dateProtoFuncGetMinutes(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.minute);
}
JSValue* dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.minute);
}
JSValue* dateProtoFuncGetSeconds(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.second);
}
JSValue* dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = true;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(t.second);
}
JSValue* dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
return jsNumber(ms);
}
JSValue* dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
return jsNumber(ms);
}
JSValue* dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
return jsNumber(-gmtoffset(t) / minutesPerHour);
}
JSValue* dateProtoFuncSetTime(ExecState* exec, JSObject* thisObj, const List& args)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
double milli = timeClip(args[0]->toNumber(exec));
JSValue* result = jsNumber(milli);
thisDateObj->setInternalValue(result);
return result;
}
static JSValue* setNewValueFromTimeArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
GregorianDateTime t;
msToGregorianDateTime(milli, inputIsUTC, t);
fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t);
JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
thisDateObj->setInternalValue(result);
return result;
}
static JSValue* setNewValueFromDateArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
GregorianDateTime t;
msToGregorianDateTime(milli, inputIsUTC, t);
fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t);
JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
thisDateObj->setInternalValue(result);
return result;
}
JSValue* dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
}
JSValue* dateProtoFuncSetSeconds(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
}
JSValue* dateProtoFuncSetMinutes(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
}
JSValue* dateProtoFuncSetHours(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCHours(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
}
JSValue* dateProtoFuncSetDate(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCDate(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
}
JSValue* dateProtoFuncSetMonth(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCMonth(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
}
JSValue* dateProtoFuncSetFullYear(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
}
JSValue* dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject* thisObj, const List& args)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
}
JSValue* dateProtoFuncSetYear(ExecState* exec, JSObject* thisObj, const List& args)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
thisDateObj->setInternalValue(result);
return result;
}
JSValue* dateProtoFuncGetYear(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&DateInstance::info))
return throwError(exec, TypeError);
const bool utc = false;
DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
JSValue* v = thisDateObj->internalValue();
double milli = v->toNumber(exec);
if (isnan(milli))
return jsNaN();
GregorianDateTime t;
msToGregorianDateTime(milli, utc, t);
if (exec->dynamicGlobalObject()->compatMode() == IECompat)
return jsNumber(1900 + t.year);
return jsNumber(t.year);
}
}