EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); 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 dateProtoFuncGetDay(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); if (!gregorianDateTime) return JSValue::encode(jsNaN(exec)); return JSValue::encode(jsNumber(exec, gregorianDateTime->weekDay)); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); 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); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); 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)); }
JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (isnan(milli)) return jsNaN(exec); double secs = floor(milli / msPerSecond); double ms = milli - secs * msPerSecond; return jsNumber(exec, ms); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); if (!gregorianDateTime) return JSValue::encode(jsNontrivialString(exec, "Invalid Date")); DateConversionBuffer time; formatTime(*gregorianDateTime, time); return JSValue::encode(jsNontrivialString(exec, time)); }
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()); // NOTE: IE returns the full year even in getYear. return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900)); }
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)); }
JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(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); return jsNumber(exec, -gmtoffset(t) / minutesPerHour); }
JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(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.second); }
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)); }
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))); }
// 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; }
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); }
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 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 JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (args.isEmpty() || isnan(milli)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } double secs = floor(milli / msPerSecond); double ms = milli - secs * msPerSecond; GregorianDateTime t; thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); if (!fillStructuresUsingTimeArgs(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; }
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)); }
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; }
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 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); }
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); }
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); }
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; }