#include "config.h"
#include "DatePrototype.h"
#include "DateConversion.h"
#include "DateInstance.h"
#include "Error.h"
#include "JSDateMath.h"
#include "JSGlobalObject.h"
#include "JSString.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
#include "JSCInlines.h"
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
#if HAVE(LANGINFO_H)
#include <langinfo.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
#if !(OS(DARWIN) && USE(CF))
#include <unicode/udat.h>
#endif
#if USE(CF)
#include <CoreFoundation/CoreFoundation.h>
#endif
using namespace WTF;
namespace JSC {
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
}
#include "DatePrototype.lut.h"
namespace JSC {
enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
#if OS(DARWIN) && USE(CF)
static CFDateFormatterStyle styleFromArgString(const String& 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 JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
{
CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
bool useCustomFormat = false;
String customFormatString;
String arg0String = exec->argument(0).toString(exec)->value(exec);
if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
useCustomFormat = true;
customFormatString = exec->argument(1).toString(exec)->value(exec);
} else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
dateStyle = styleFromArgString(arg0String, dateStyle);
timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle);
} else if (format != LocaleTime && !exec->argument(0).isUndefined())
dateStyle = styleFromArgString(arg0String, dateStyle);
else if (format != LocaleDate && !exec->argument(0).isUndefined())
timeStyle = styleFromArgString(arg0String, timeStyle);
CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
if (useCustomFormat)
CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
}
#elif !UCONFIG_NO_FORMATTING
static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
{
UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
UErrorCode status = U_ZERO_ERROR;
UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
if (!df)
return jsEmptyString(exec);
UChar buffer[128];
int32_t length;
length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
udat_close(df);
if (status != U_ZERO_ERROR)
return jsEmptyString(exec);
return jsNontrivialString(exec, String(buffer, length));
}
#else
static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
{
#if OS(WINDOWS)
SYSTEMTIME systemTime;
memset(&systemTime, 0, sizeof(systemTime));
systemTime.wYear = gdt.year();
systemTime.wMonth = gdt.month() + 1;
systemTime.wDay = gdt.monthDay();
systemTime.wDayOfWeek = gdt.weekDay();
systemTime.wHour = gdt.hour();
systemTime.wMinute = gdt.minute();
systemTime.wSecond = gdt.second();
Vector<UChar, 128> buffer;
size_t length = 0;
if (format == LocaleDate) {
buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
} else if (format == LocaleTime) {
buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
} else if (format == LocaleDateAndTime) {
buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
if (length) {
buffer[length - 1] = ' ';
length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
}
} else
RELEASE_ASSERT_NOT_REACHED();
if (length)
length--;
return jsNontrivialString(exec, String(buffer.data(), length));
#else // OS(WINDOWS)
#if HAVE(LANGINFO_H)
static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
#else
static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
#endif
struct tm localTM = gdt;
int year = gdt.year();
bool yearNeedsOffset = year < 1900 || year > 2038;
if (yearNeedsOffset)
localTM.tm_year = equivalentYearForDST(year) - 1900;
#if HAVE(LANGINFO_H)
char* formatString = strdup(nl_langinfo(formats[format]));
char* yPos = strchr(formatString, 'y');
if (yPos)
*yPos = 'Y';
#endif
const int bufsize = 128;
char timebuffer[bufsize];
#if HAVE(LANGINFO_H)
size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
free(formatString);
#else
size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
#endif
if (ret == 0)
return jsEmptyString(exec);
if (yearNeedsOffset && format != LocaleTime) {
static const int yearLen = 5; char yearString[yearLen];
snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
char* yearLocation = strstr(timebuffer, yearString);
snprintf(yearString, yearLen, "%d", year);
strncpy(yearLocation, yearString, yearLen - 1);
}
#ifdef __STDC_ISO_10646__
UChar buffer[bufsize];
wchar_t tempbuffer[bufsize];
size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
if (length != static_cast<size_t>(-1)) {
for (size_t i = 0; i < length; ++i)
buffer[i] = static_cast<UChar>(tempbuffer[i]);
return jsNontrivialString(exec, String(buffer, length));
}
#endif
return jsNontrivialString(exec, timebuffer);
#endif // OS(WINDOWS)
}
static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
{
const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
if (!gregorianDateTime)
return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
return formatLocaleDate(exec, *gregorianDateTime, format);
}
#endif // OS(DARWIN) && USE(CF)
static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = asUTCVariant
? thisDateObj->gregorianDateTimeUTC(exec)
: thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
}
static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
{
double milliseconds = 0;
bool ok = true;
int idx = 0;
int numArgs = exec->argumentCount();
if (numArgs > maxArgs)
numArgs = maxArgs;
if (maxArgs >= 4 && idx < numArgs) {
t->setHour(0);
double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(hours);
milliseconds += hours * msPerHour;
}
if (maxArgs >= 3 && idx < numArgs && ok) {
t->setMinute(0);
double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(minutes);
milliseconds += minutes * msPerMinute;
}
if (maxArgs >= 2 && idx < numArgs && ok) {
t->setSecond(0);
double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(seconds);
milliseconds += seconds * msPerSecond;
}
if (!ok)
return false;
if (idx < numArgs) {
double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
ok = std::isfinite(millis);
milliseconds += millis;
} else
milliseconds += *ms;
*ms = milliseconds;
return ok;
}
static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
{
int idx = 0;
bool ok = true;
int numArgs = exec->argumentCount();
if (numArgs > maxArgs)
numArgs = maxArgs;
if (maxArgs >= 3 && idx < numArgs) {
double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(years);
t->setYear(toInt32(years));
}
if (maxArgs >= 2 && idx < numArgs && ok) {
double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(months);
t->setMonth(toInt32(months));
}
if (idx < numArgs && ok) {
double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
ok = std::isfinite(days);
t->setMonthDay(0);
*ms += days * msPerDay;
}
return ok;
}
const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
DatePrototype::DatePrototype(VM& vm, Structure* structure)
: DateInstance(vm, structure)
{
}
void DatePrototype::finishCreation(VM& vm, JSGlobalObject*)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
}
bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec->vm()), jsCast<DatePrototype*>(object), propertyName, slot);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
{
const bool asUTCVariant = false;
return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
{
const bool asUTCVariant = true;
return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
if (!std::isfinite(thisDateObj->internalNumber()))
return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
char buffer[28];
int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
if (ms < 0)
ms += msPerSecond;
int charactersWritten;
if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
else
charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
return JSValue::encode(jsEmptyString(exec));
return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
{
const bool asUTCVariant = false;
return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
{
const bool asUTCVariant = false;
return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
return JSValue::encode(asDateInstance(thisValue)->internalValue());
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->year()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->year()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
{
const bool asUTCVariant = true;
return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->month()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->month()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->hour()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->hour()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->minute()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->minute()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->second()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->second()));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
if (std::isnan(milli))
return JSValue::encode(jsNaN());
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
return JSValue::encode(jsNumber(ms));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
if (std::isnan(milli))
return JSValue::encode(jsNaN());
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
return JSValue::encode(jsNumber(ms));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = timeClip(exec->argument(0).toNumber(exec));
JSValue result = jsNumber(milli);
thisDateObj->setInternalValue(exec->vm(), result);
return JSValue::encode(result);
}
static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
double milli = thisDateObj->internalNumber();
VM& vm = exec->vm();
if (!exec->argumentCount() || std::isnan(milli)) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
double secs = floor(milli / msPerSecond);
double ms = milli - secs * msPerSecond;
const GregorianDateTime* other = inputIsUTC
? thisDateObj->gregorianDateTimeUTC(exec)
: thisDateObj->gregorianDateTime(exec);
if (!other)
return JSValue::encode(jsNaN());
GregorianDateTime gregorianDateTime;
gregorianDateTime.copyFrom(*other);
if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
if (!exec->argumentCount()) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(exec->vm(), result);
return JSValue::encode(result);
}
VM& vm = exec->vm();
double milli = thisDateObj->internalNumber();
double ms = 0;
GregorianDateTime gregorianDateTime;
if (numArgsToUse == 3 && std::isnan(milli))
msToGregorianDateTime(vm, 0, true, gregorianDateTime);
else {
ms = milli - floor(milli / msPerSecond) * msPerSecond;
const GregorianDateTime* other = inputIsUTC
? thisDateObj->gregorianDateTimeUTC(exec)
: thisDateObj->gregorianDateTime(exec);
if (!other)
return JSValue::encode(jsNaN());
gregorianDateTime.copyFrom(*other);
}
if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, 1, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, 1, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, 2, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, 2, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
{
const bool inputIsUTC = false;
return setNewValueFromDateArgs(exec, 3, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
{
const bool inputIsUTC = true;
return setNewValueFromDateArgs(exec, 3, inputIsUTC);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
VM& vm = exec->vm();
DateInstance* thisDateObj = asDateInstance(thisValue);
if (!exec->argumentCount()) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
double milli = thisDateObj->internalNumber();
double ms = 0;
GregorianDateTime gregorianDateTime;
if (std::isnan(milli))
msToGregorianDateTime(vm, 0, true, gregorianDateTime);
else {
double secs = floor(milli / msPerSecond);
ms = milli - secs * msPerSecond;
if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
gregorianDateTime.copyFrom(*other);
}
double year = exec->argument(0).toIntegerPreserveNaN(exec);
if (!std::isfinite(year)) {
JSValue result = jsNaN();
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, false));
thisDateObj->setInternalValue(vm, result);
return JSValue::encode(result);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
DateInstance* thisDateObj = asDateInstance(thisValue);
const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
if (!gregorianDateTime)
return JSValue::encode(jsNaN());
return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
{
JSValue thisValue = exec->thisValue();
JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
if (exec->hadException())
return JSValue::encode(jsNull());
JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
if (exec->hadException())
return JSValue::encode(jsNull());
CallData callData;
CallType callType = getCallData(toISOValue, callData);
if (callType == CallTypeNone)
return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function")));
JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
if (exec->hadException())
return JSValue::encode(jsNull());
if (result.isObject())
return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value")));
return JSValue::encode(result);
}
}