JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); const bool utc = true; DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (isnan(milli)) return jsNaN(exec); GregorianDateTime t; thisDateObj->msToGregorianDateTime(milli, utc, t); return jsNumber(exec, t.hour); }
JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); const bool utc = true; DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (isnan(milli)) return jsNontrivialString(exec, "Invalid Date"); GregorianDateTime t; thisDateObj->msToGregorianDateTime(milli, utc, t); return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); }
// ECMA 15.9.3 JSObject* constructDate(ExecState* exec, const ArgList& args) { int numArgs = args.size(); double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 value = getCurrentUTCTime(); else if (numArgs == 1) { if (args.at(exec, 0)->isObject(&DateInstance::info)) value = asDateInstance(args.at(exec, 0))->internalNumber(); else { JSValue* primitive = args.at(exec, 0)->toPrimitive(exec); if (primitive->isString()) value = parseDate(primitive->getString()); else value = primitive->toNumber(exec); } } else { if (isnan(args.at(exec, 0)->toNumber(exec)) || isnan(args.at(exec, 1)->toNumber(exec)) || (numArgs >= 3 && isnan(args.at(exec, 2)->toNumber(exec))) || (numArgs >= 4 && isnan(args.at(exec, 3)->toNumber(exec))) || (numArgs >= 5 && isnan(args.at(exec, 4)->toNumber(exec))) || (numArgs >= 6 && isnan(args.at(exec, 5)->toNumber(exec))) || (numArgs >= 7 && isnan(args.at(exec, 6)->toNumber(exec)))) value = NaN; else { GregorianDateTime t; int year = args.at(exec, 0)->toInt32(exec); t.year = (year >= 0 && year <= 99) ? year : year - 1900; t.month = args.at(exec, 1)->toInt32(exec); t.monthDay = (numArgs >= 3) ? args.at(exec, 2)->toInt32(exec) : 1; t.hour = args.at(exec, 3)->toInt32(exec); t.minute = args.at(exec, 4)->toInt32(exec); t.second = args.at(exec, 5)->toInt32(exec); t.isDST = -1; double ms = (numArgs >= 7) ? args.at(exec, 6)->toNumber(exec) : 0; value = gregorianDateTimeToMS(t, ms, false); } } DateInstance* result = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure()); result->setInternalValue(jsNumber(exec, timeClip(value))); return result; }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); if (!gregorianDateTime) return JSValue::encode(jsNontrivialString(exec, "Invalid Date")); DateConversionBuffer date; DateConversionBuffer time; formatDateUTCVariant(*gregorianDateTime, date); formatTimeUTC(*gregorianDateTime, time); return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time)); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); if (!gregorianDateTime) return JSValue::encode(jsNontrivialString(exec, "Invalid Date")); // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) // 6 for formatting and one for null termination = 27. We add one extra character to allow us to force null termination. char buffer[28]; snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000))); buffer[sizeof(buffer) - 1] = 0; return JSValue::encode(jsNontrivialString(exec, buffer)); }
JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); const bool utc = false; DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (isnan(milli)) return jsNaN(exec); GregorianDateTime t; thisDateObj->msToGregorianDateTime(milli, utc, t); // NOTE: IE returns the full year even in getYear. return jsNumber(exec, t.year); }
// ECMA 15.9.3 AJObject* constructDate(ExecState* exec, const ArgList& args) { int numArgs = args.size(); double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 value = jsCurrentTime(); else if (numArgs == 1) { if (args.at(0).inherits(&DateInstance::info)) value = asDateInstance(args.at(0))->internalNumber(); else { AJValue primitive = args.at(0).toPrimitive(exec); if (primitive.isString()) value = parseDate(exec, primitive.getString(exec)); else value = primitive.toNumber(exec); } } else { if (isnan(args.at(0).toNumber(exec)) || isnan(args.at(1).toNumber(exec)) || (numArgs >= 3 && isnan(args.at(2).toNumber(exec))) || (numArgs >= 4 && isnan(args.at(3).toNumber(exec))) || (numArgs >= 5 && isnan(args.at(4).toNumber(exec))) || (numArgs >= 6 && isnan(args.at(5).toNumber(exec))) || (numArgs >= 7 && isnan(args.at(6).toNumber(exec)))) value = NaN; else { GregorianDateTime t; int year = args.at(0).toInt32(exec); t.year = (year >= 0 && year <= 99) ? year : year - 1900; t.month = args.at(1).toInt32(exec); t.monthDay = (numArgs >= 3) ? args.at(2).toInt32(exec) : 1; t.hour = args.at(3).toInt32(exec); t.minute = args.at(4).toInt32(exec); t.second = args.at(5).toInt32(exec); t.isDST = -1; double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0; value = gregorianDateTimeToMS(exec, t, ms, false); } } return new (exec) DateInstance(exec, value); }
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)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. 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); }
JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); const bool utc = false; DateInstance* thisDateObj = asDateInstance(thisValue); if (args.isEmpty()) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime t; if (isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. thisDateObj->msToGregorianDateTime(0, true, t); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; thisDateObj->msToGregorianDateTime(milli, utc, t); } bool ok = true; int32_t year = args.at(0).toInt32(exec, ok); if (!ok) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } t.year = (year > 99 || year < 0) ? year - 1900 : year; JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, utc)); thisDateObj->setInternalValue(result); return result; }
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return JSValue::encode(result); } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime gregorianDateTime; if (isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. msToGregorianDateTime(exec, 0, true, gregorianDateTime); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) gregorianDateTime.copyFrom(*other); } bool ok = true; int32_t year = exec->argument(0).toInt32(exec, ok); if (!ok) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return JSValue::encode(result); } gregorianDateTime.year = (year > 99 || year < 0) ? year - 1900 : year; JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, false)); thisDateObj->setInternalValue(result); return JSValue::encode(result); }
JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); const bool utc = true; DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (!isfinite(milli)) return jsNontrivialString(exec, "Invalid Date"); GregorianDateTime t; thisDateObj->msToGregorianDateTime(milli, utc, t); // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) // 6 for formatting and one for null termination = 23. We add one extra character to allow us to force null termination. char buffer[24]; snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.year, t.month + 1, t.monthDay, t.hour, t.minute, t.second); buffer[sizeof(buffer) - 1] = 0; return jsNontrivialString(exec, buffer); }
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); }
static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (!exec->argumentCount() || isnan(milli)) { JSValue result = jsNaN(); thisDateObj->setInternalValue(exec->globalData(), 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(exec->globalData(), result); return JSValue::encode(result); } JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(exec->globalData(), result); return JSValue::encode(result); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); if (!isfinite(thisDateObj->internalNumber())) return throwVMError(exec, createRangeError(exec, "Invalid Date")); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); if (!gregorianDateTime) return JSValue::encode(jsNontrivialString(exec, "Invalid Date")); // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination. char buffer[29]; // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1). if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900) snprintf(buffer, sizeof(buffer) - 1, "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000))); else snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000))); buffer[sizeof(buffer) - 1] = 0; return JSValue::encode(jsNontrivialString(exec, buffer)); }
// ECMA 15.9.3 JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { VM& vm = exec->vm(); int numArgs = args.size(); double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 value = NORMAL_OR_DETERMINISTIC_FUNCTION(jsCurrentTime(), deterministicCurrentTime(globalObject)); else if (numArgs == 1) { if (args.at(0).inherits(DateInstance::info())) value = asDateInstance(args.at(0))->internalNumber(); else { JSValue primitive = args.at(0).toPrimitive(exec); if (primitive.isString()) value = parseDate(vm, primitive.getString(exec)); else value = primitive.toNumber(exec); } } else value = millisecondsFromComponents(exec, args, WTF::LocalTime); return DateInstance::create(vm, globalObject->dateStructure(), value); }
static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); if (args.isEmpty()) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime t; if (numArgsToUse == 3 && isnan(milli)) // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear) // the time must be reset to +0 if it is NaN. thisDateObj->msToGregorianDateTime(0, true, t); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); } if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; }