1/* 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 4 * Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved. 5 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 20 * USA 21 * 22 */ 23 24#include "config.h" 25#include "DatePrototype.h" 26 27#include "DateConversion.h" 28#include "DateInstance.h" 29#include "Error.h" 30#include "JSDateMath.h" 31#include "JSGlobalObject.h" 32#include "JSString.h" 33#include "Lookup.h" 34#include "ObjectPrototype.h" 35#include "JSCInlines.h" 36#include <limits.h> 37#include <locale.h> 38#include <math.h> 39#include <stdlib.h> 40#include <time.h> 41#include <wtf/Assertions.h> 42#include <wtf/MathExtras.h> 43#include <wtf/StringExtras.h> 44 45#if HAVE(LANGINFO_H) 46#include <langinfo.h> 47#endif 48 49#if HAVE(SYS_PARAM_H) 50#include <sys/param.h> 51#endif 52 53#if HAVE(SYS_TIME_H) 54#include <sys/time.h> 55#endif 56 57#if HAVE(SYS_TIMEB_H) 58#include <sys/timeb.h> 59#endif 60 61#if !(OS(DARWIN) && USE(CF)) 62#include <unicode/udat.h> 63#endif 64 65#if USE(CF) 66#include <CoreFoundation/CoreFoundation.h> 67#endif 68 69using namespace WTF; 70 71namespace JSC { 72 73static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*); 74static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*); 75static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*); 76static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*); 77static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*); 78static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*); 79static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*); 80static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*); 81static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*); 82static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*); 83static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*); 84static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*); 85static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*); 86static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*); 87static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*); 88static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*); 89static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*); 90static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*); 91static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*); 92static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*); 93static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*); 94static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*); 95static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*); 96static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*); 97static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*); 98static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*); 99static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*); 100static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*); 101static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*); 102static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*); 103static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*); 104static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*); 105static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*); 106static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*); 107static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*); 108static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*); 109static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*); 110static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*); 111static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*); 112static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*); 113static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*); 114static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*); 115static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*); 116static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*); 117static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*); 118 119} 120 121#include "DatePrototype.lut.h" 122 123namespace JSC { 124 125enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; 126 127#if OS(DARWIN) && USE(CF) 128 129// FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)? 130// Instead we should consider using this whenever USE(CF) is true. 131 132static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle) 133{ 134 if (string == "short") 135 return kCFDateFormatterShortStyle; 136 if (string == "medium") 137 return kCFDateFormatterMediumStyle; 138 if (string == "long") 139 return kCFDateFormatterLongStyle; 140 if (string == "full") 141 return kCFDateFormatterFullStyle; 142 return defaultStyle; 143} 144 145static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format) 146{ 147 CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); 148 CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); 149 150 bool useCustomFormat = false; 151 String customFormatString; 152 153 String arg0String = exec->argument(0).toString(exec)->value(exec); 154 if (arg0String == "custom" && !exec->argument(1).isUndefined()) { 155 useCustomFormat = true; 156 customFormatString = exec->argument(1).toString(exec)->value(exec); 157 } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) { 158 dateStyle = styleFromArgString(arg0String, dateStyle); 159 timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle); 160 } else if (format != LocaleTime && !exec->argument(0).isUndefined()) 161 dateStyle = styleFromArgString(arg0String, dateStyle); 162 else if (format != LocaleDate && !exec->argument(0).isUndefined()) 163 timeStyle = styleFromArgString(arg0String, timeStyle); 164 165 CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970; 166 167 auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle)); 168 if (useCustomFormat) 169 CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get()); 170 return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get()); 171} 172 173#elif !UCONFIG_NO_FORMATTING 174 175static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format) 176{ 177 UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE); 178 UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE); 179 180 UErrorCode status = U_ZERO_ERROR; 181 UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status); 182 if (!df) 183 return jsEmptyString(exec); 184 185 UChar buffer[128]; 186 int32_t length; 187 length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status); 188 udat_close(df); 189 if (status != U_ZERO_ERROR) 190 return jsEmptyString(exec); 191 192 return jsNontrivialString(exec, String(buffer, length)); 193} 194 195#else 196 197static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format) 198{ 199#if OS(WINDOWS) 200 SYSTEMTIME systemTime; 201 memset(&systemTime, 0, sizeof(systemTime)); 202 systemTime.wYear = gdt.year(); 203 systemTime.wMonth = gdt.month() + 1; 204 systemTime.wDay = gdt.monthDay(); 205 systemTime.wDayOfWeek = gdt.weekDay(); 206 systemTime.wHour = gdt.hour(); 207 systemTime.wMinute = gdt.minute(); 208 systemTime.wSecond = gdt.second(); 209 210 Vector<UChar, 128> buffer; 211 size_t length = 0; 212 213 if (format == LocaleDate) { 214 buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0)); 215 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size()); 216 } else if (format == LocaleTime) { 217 buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0)); 218 length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size()); 219 } else if (format == LocaleDateAndTime) { 220 buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0)); 221 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size()); 222 if (length) { 223 buffer[length - 1] = ' '; 224 length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length); 225 } 226 } else 227 RELEASE_ASSERT_NOT_REACHED(); 228 229 // Remove terminating null character. 230 if (length) 231 length--; 232 233 return jsNontrivialString(exec, String(buffer.data(), length)); 234 235#else // OS(WINDOWS) 236 237#if HAVE(LANGINFO_H) 238 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT }; 239#else 240 static const char* const formatStrings[] = { "%#c", "%#x", "%X" }; 241#endif 242 243 // Offset year if needed 244 struct tm localTM = gdt; 245 int year = gdt.year(); 246 bool yearNeedsOffset = year < 1900 || year > 2038; 247 if (yearNeedsOffset) 248 localTM.tm_year = equivalentYearForDST(year) - 1900; 249 250#if HAVE(LANGINFO_H) 251 // We do not allow strftime to generate dates with 2-digits years, 252 // both to avoid ambiguity, and a crash in strncpy, for years that 253 // need offset. 254 char* formatString = strdup(nl_langinfo(formats[format])); 255 char* yPos = strchr(formatString, 'y'); 256 if (yPos) 257 *yPos = 'Y'; 258#endif 259 260 // Do the formatting 261 const int bufsize = 128; 262 char timebuffer[bufsize]; 263 264#if HAVE(LANGINFO_H) 265 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM); 266 free(formatString); 267#else 268 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM); 269#endif 270 271 if (ret == 0) 272 return jsEmptyString(exec); 273 274 // Copy original into the buffer 275 if (yearNeedsOffset && format != LocaleTime) { 276 static const int yearLen = 5; // FIXME will be a problem in the year 10,000 277 char yearString[yearLen]; 278 279 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900); 280 char* yearLocation = strstr(timebuffer, yearString); 281 snprintf(yearString, yearLen, "%d", year); 282 283 strncpy(yearLocation, yearString, yearLen - 1); 284 } 285 286 // Convert multi-byte result to UNICODE. 287 // If __STDC_ISO_10646__ is defined, wide character represents 288 // UTF-16 (or UTF-32) code point. In most modern Unix like system 289 // (e.g. Linux with glibc 2.2 and above) the macro is defined, 290 // and wide character represents UTF-32 code point. 291 // Here we static_cast potential UTF-32 to UTF-16, it should be 292 // safe because date and (or) time related characters in different languages 293 // should be in UNICODE BMP. If mbstowcs fails, we just fall 294 // back on using multi-byte result as-is. 295#ifdef __STDC_ISO_10646__ 296 UChar buffer[bufsize]; 297 wchar_t tempbuffer[bufsize]; 298 size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1); 299 if (length != static_cast<size_t>(-1)) { 300 for (size_t i = 0; i < length; ++i) 301 buffer[i] = static_cast<UChar>(tempbuffer[i]); 302 return jsNontrivialString(exec, String(buffer, length)); 303 } 304#endif 305 306 return jsNontrivialString(exec, timebuffer); 307#endif // OS(WINDOWS) 308} 309 310static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format) 311{ 312 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec); 313 if (!gregorianDateTime) 314 return jsNontrivialString(exec, ASCIILiteral("Invalid Date")); 315 return formatLocaleDate(exec, *gregorianDateTime, format); 316} 317 318#endif // OS(DARWIN) && USE(CF) 319 320static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant) 321{ 322 JSValue thisValue = exec->thisValue(); 323 if (!thisValue.inherits(DateInstance::info())) 324 return throwVMTypeError(exec); 325 326 DateInstance* thisDateObj = asDateInstance(thisValue); 327 328 const GregorianDateTime* gregorianDateTime = asUTCVariant 329 ? thisDateObj->gregorianDateTimeUTC(exec) 330 : thisDateObj->gregorianDateTime(exec); 331 if (!gregorianDateTime) 332 return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date")))); 333 334 return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant))); 335} 336 337// Converts a list of arguments sent to a Date member function into milliseconds, updating 338// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. 339// 340// Format of member function: f([hour,] [min,] [sec,] [ms]) 341static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t) 342{ 343 double milliseconds = 0; 344 bool ok = true; 345 int idx = 0; 346 int numArgs = exec->argumentCount(); 347 348 // JS allows extra trailing arguments -- ignore them 349 if (numArgs > maxArgs) 350 numArgs = maxArgs; 351 352 // hours 353 if (maxArgs >= 4 && idx < numArgs) { 354 t->setHour(0); 355 double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 356 ok = std::isfinite(hours); 357 milliseconds += hours * msPerHour; 358 } 359 360 // minutes 361 if (maxArgs >= 3 && idx < numArgs && ok) { 362 t->setMinute(0); 363 double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 364 ok = std::isfinite(minutes); 365 milliseconds += minutes * msPerMinute; 366 } 367 368 // seconds 369 if (maxArgs >= 2 && idx < numArgs && ok) { 370 t->setSecond(0); 371 double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 372 ok = std::isfinite(seconds); 373 milliseconds += seconds * msPerSecond; 374 } 375 376 if (!ok) 377 return false; 378 379 // milliseconds 380 if (idx < numArgs) { 381 double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec); 382 ok = std::isfinite(millis); 383 milliseconds += millis; 384 } else 385 milliseconds += *ms; 386 387 *ms = milliseconds; 388 return ok; 389} 390 391// Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating 392// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. 393// 394// Format of member function: f([years,] [months,] [days]) 395static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t) 396{ 397 int idx = 0; 398 bool ok = true; 399 int numArgs = exec->argumentCount(); 400 401 // JS allows extra trailing arguments -- ignore them 402 if (numArgs > maxArgs) 403 numArgs = maxArgs; 404 405 // years 406 if (maxArgs >= 3 && idx < numArgs) { 407 double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 408 ok = std::isfinite(years); 409 t->setYear(toInt32(years)); 410 } 411 // months 412 if (maxArgs >= 2 && idx < numArgs && ok) { 413 double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 414 ok = std::isfinite(months); 415 t->setMonth(toInt32(months)); 416 } 417 // days 418 if (idx < numArgs && ok) { 419 double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec); 420 ok = std::isfinite(days); 421 t->setMonthDay(0); 422 *ms += days * msPerDay; 423 } 424 425 return ok; 426} 427 428const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)}; 429 430/* Source for DatePrototype.lut.h 431@begin dateTable 432 toString dateProtoFuncToString DontEnum|Function 0 433 toISOString dateProtoFuncToISOString DontEnum|Function 0 434 toUTCString dateProtoFuncToUTCString DontEnum|Function 0 435 toDateString dateProtoFuncToDateString DontEnum|Function 0 436 toTimeString dateProtoFuncToTimeString DontEnum|Function 0 437 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0 438 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0 439 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0 440 valueOf dateProtoFuncGetTime DontEnum|Function 0 441 getTime dateProtoFuncGetTime DontEnum|Function 0 442 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0 443 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0 444 toGMTString dateProtoFuncToGMTString DontEnum|Function 0 445 getMonth dateProtoFuncGetMonth DontEnum|Function 0 446 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0 447 getDate dateProtoFuncGetDate DontEnum|Function 0 448 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0 449 getDay dateProtoFuncGetDay DontEnum|Function 0 450 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0 451 getHours dateProtoFuncGetHours DontEnum|Function 0 452 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0 453 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0 454 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0 455 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0 456 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0 457 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0 458 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0 459 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0 460 setTime dateProtoFuncSetTime DontEnum|Function 1 461 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1 462 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1 463 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2 464 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2 465 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3 466 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3 467 setHours dateProtoFuncSetHours DontEnum|Function 4 468 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4 469 setDate dateProtoFuncSetDate DontEnum|Function 1 470 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1 471 setMonth dateProtoFuncSetMonth DontEnum|Function 2 472 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2 473 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3 474 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3 475 setYear dateProtoFuncSetYear DontEnum|Function 1 476 getYear dateProtoFuncGetYear DontEnum|Function 0 477 toJSON dateProtoFuncToJSON DontEnum|Function 1 478@end 479*/ 480 481// ECMA 15.9.4 482 483DatePrototype::DatePrototype(VM& vm, Structure* structure) 484 : DateInstance(vm, structure) 485{ 486} 487 488void DatePrototype::finishCreation(VM& vm, JSGlobalObject*) 489{ 490 Base::finishCreation(vm); 491 ASSERT(inherits(info())); 492 493 // The constructor will be added later, after DateConstructor has been built. 494} 495 496bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) 497{ 498 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec->vm()), jsCast<DatePrototype*>(object), propertyName, slot); 499} 500 501// Functions 502 503EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec) 504{ 505 const bool asUTCVariant = false; 506 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant); 507} 508 509EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec) 510{ 511 const bool asUTCVariant = true; 512 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant); 513} 514 515EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec) 516{ 517 JSValue thisValue = exec->thisValue(); 518 if (!thisValue.inherits(DateInstance::info())) 519 return throwVMTypeError(exec); 520 521 DateInstance* thisDateObj = asDateInstance(thisValue); 522 if (!std::isfinite(thisDateObj->internalNumber())) 523 return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date"))); 524 525 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 526 if (!gregorianDateTime) 527 return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date")))); 528 // 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) 529 // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination. 530 char buffer[28]; 531 // 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). 532 int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond)); 533 if (ms < 0) 534 ms += msPerSecond; 535 536 int charactersWritten; 537 if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0) 538 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); 539 else 540 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); 541 542 ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer)); 543 if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer)) 544 return JSValue::encode(jsEmptyString(exec)); 545 546 return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten))); 547} 548 549EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec) 550{ 551 const bool asUTCVariant = false; 552 return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant); 553} 554 555EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec) 556{ 557 const bool asUTCVariant = false; 558 return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant); 559} 560 561EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec) 562{ 563 JSValue thisValue = exec->thisValue(); 564 if (!thisValue.inherits(DateInstance::info())) 565 return throwVMTypeError(exec); 566 567 DateInstance* thisDateObj = asDateInstance(thisValue); 568 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime)); 569} 570 571EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec) 572{ 573 JSValue thisValue = exec->thisValue(); 574 if (!thisValue.inherits(DateInstance::info())) 575 return throwVMTypeError(exec); 576 577 DateInstance* thisDateObj = asDateInstance(thisValue); 578 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate)); 579} 580 581EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec) 582{ 583 JSValue thisValue = exec->thisValue(); 584 if (!thisValue.inherits(DateInstance::info())) 585 return throwVMTypeError(exec); 586 587 DateInstance* thisDateObj = asDateInstance(thisValue); 588 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime)); 589} 590 591EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec) 592{ 593 JSValue thisValue = exec->thisValue(); 594 if (!thisValue.inherits(DateInstance::info())) 595 return throwVMTypeError(exec); 596 597 return JSValue::encode(asDateInstance(thisValue)->internalValue()); 598} 599 600EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec) 601{ 602 JSValue thisValue = exec->thisValue(); 603 if (!thisValue.inherits(DateInstance::info())) 604 return throwVMTypeError(exec); 605 606 DateInstance* thisDateObj = asDateInstance(thisValue); 607 608 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 609 if (!gregorianDateTime) 610 return JSValue::encode(jsNaN()); 611 return JSValue::encode(jsNumber(gregorianDateTime->year())); 612} 613 614EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec) 615{ 616 JSValue thisValue = exec->thisValue(); 617 if (!thisValue.inherits(DateInstance::info())) 618 return throwVMTypeError(exec); 619 620 DateInstance* thisDateObj = asDateInstance(thisValue); 621 622 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 623 if (!gregorianDateTime) 624 return JSValue::encode(jsNaN()); 625 return JSValue::encode(jsNumber(gregorianDateTime->year())); 626} 627 628EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec) 629{ 630 const bool asUTCVariant = true; 631 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant); 632} 633 634EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec) 635{ 636 JSValue thisValue = exec->thisValue(); 637 if (!thisValue.inherits(DateInstance::info())) 638 return throwVMTypeError(exec); 639 640 DateInstance* thisDateObj = asDateInstance(thisValue); 641 642 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 643 if (!gregorianDateTime) 644 return JSValue::encode(jsNaN()); 645 return JSValue::encode(jsNumber(gregorianDateTime->month())); 646} 647 648EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec) 649{ 650 JSValue thisValue = exec->thisValue(); 651 if (!thisValue.inherits(DateInstance::info())) 652 return throwVMTypeError(exec); 653 654 DateInstance* thisDateObj = asDateInstance(thisValue); 655 656 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 657 if (!gregorianDateTime) 658 return JSValue::encode(jsNaN()); 659 return JSValue::encode(jsNumber(gregorianDateTime->month())); 660} 661 662EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec) 663{ 664 JSValue thisValue = exec->thisValue(); 665 if (!thisValue.inherits(DateInstance::info())) 666 return throwVMTypeError(exec); 667 668 DateInstance* thisDateObj = asDateInstance(thisValue); 669 670 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 671 if (!gregorianDateTime) 672 return JSValue::encode(jsNaN()); 673 return JSValue::encode(jsNumber(gregorianDateTime->monthDay())); 674} 675 676EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec) 677{ 678 JSValue thisValue = exec->thisValue(); 679 if (!thisValue.inherits(DateInstance::info())) 680 return throwVMTypeError(exec); 681 682 DateInstance* thisDateObj = asDateInstance(thisValue); 683 684 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 685 if (!gregorianDateTime) 686 return JSValue::encode(jsNaN()); 687 return JSValue::encode(jsNumber(gregorianDateTime->monthDay())); 688} 689 690EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec) 691{ 692 JSValue thisValue = exec->thisValue(); 693 if (!thisValue.inherits(DateInstance::info())) 694 return throwVMTypeError(exec); 695 696 DateInstance* thisDateObj = asDateInstance(thisValue); 697 698 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 699 if (!gregorianDateTime) 700 return JSValue::encode(jsNaN()); 701 return JSValue::encode(jsNumber(gregorianDateTime->weekDay())); 702} 703 704EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec) 705{ 706 JSValue thisValue = exec->thisValue(); 707 if (!thisValue.inherits(DateInstance::info())) 708 return throwVMTypeError(exec); 709 710 DateInstance* thisDateObj = asDateInstance(thisValue); 711 712 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 713 if (!gregorianDateTime) 714 return JSValue::encode(jsNaN()); 715 return JSValue::encode(jsNumber(gregorianDateTime->weekDay())); 716} 717 718EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec) 719{ 720 JSValue thisValue = exec->thisValue(); 721 if (!thisValue.inherits(DateInstance::info())) 722 return throwVMTypeError(exec); 723 724 DateInstance* thisDateObj = asDateInstance(thisValue); 725 726 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 727 if (!gregorianDateTime) 728 return JSValue::encode(jsNaN()); 729 return JSValue::encode(jsNumber(gregorianDateTime->hour())); 730} 731 732EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec) 733{ 734 JSValue thisValue = exec->thisValue(); 735 if (!thisValue.inherits(DateInstance::info())) 736 return throwVMTypeError(exec); 737 738 DateInstance* thisDateObj = asDateInstance(thisValue); 739 740 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 741 if (!gregorianDateTime) 742 return JSValue::encode(jsNaN()); 743 return JSValue::encode(jsNumber(gregorianDateTime->hour())); 744} 745 746EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec) 747{ 748 JSValue thisValue = exec->thisValue(); 749 if (!thisValue.inherits(DateInstance::info())) 750 return throwVMTypeError(exec); 751 752 DateInstance* thisDateObj = asDateInstance(thisValue); 753 754 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 755 if (!gregorianDateTime) 756 return JSValue::encode(jsNaN()); 757 return JSValue::encode(jsNumber(gregorianDateTime->minute())); 758} 759 760EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec) 761{ 762 JSValue thisValue = exec->thisValue(); 763 if (!thisValue.inherits(DateInstance::info())) 764 return throwVMTypeError(exec); 765 766 DateInstance* thisDateObj = asDateInstance(thisValue); 767 768 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 769 if (!gregorianDateTime) 770 return JSValue::encode(jsNaN()); 771 return JSValue::encode(jsNumber(gregorianDateTime->minute())); 772} 773 774EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec) 775{ 776 JSValue thisValue = exec->thisValue(); 777 if (!thisValue.inherits(DateInstance::info())) 778 return throwVMTypeError(exec); 779 780 DateInstance* thisDateObj = asDateInstance(thisValue); 781 782 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 783 if (!gregorianDateTime) 784 return JSValue::encode(jsNaN()); 785 return JSValue::encode(jsNumber(gregorianDateTime->second())); 786} 787 788EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec) 789{ 790 JSValue thisValue = exec->thisValue(); 791 if (!thisValue.inherits(DateInstance::info())) 792 return throwVMTypeError(exec); 793 794 DateInstance* thisDateObj = asDateInstance(thisValue); 795 796 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); 797 if (!gregorianDateTime) 798 return JSValue::encode(jsNaN()); 799 return JSValue::encode(jsNumber(gregorianDateTime->second())); 800} 801 802EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec) 803{ 804 JSValue thisValue = exec->thisValue(); 805 if (!thisValue.inherits(DateInstance::info())) 806 return throwVMTypeError(exec); 807 808 DateInstance* thisDateObj = asDateInstance(thisValue); 809 double milli = thisDateObj->internalNumber(); 810 if (std::isnan(milli)) 811 return JSValue::encode(jsNaN()); 812 813 double secs = floor(milli / msPerSecond); 814 double ms = milli - secs * msPerSecond; 815 return JSValue::encode(jsNumber(ms)); 816} 817 818EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec) 819{ 820 JSValue thisValue = exec->thisValue(); 821 if (!thisValue.inherits(DateInstance::info())) 822 return throwVMTypeError(exec); 823 824 DateInstance* thisDateObj = asDateInstance(thisValue); 825 double milli = thisDateObj->internalNumber(); 826 if (std::isnan(milli)) 827 return JSValue::encode(jsNaN()); 828 829 double secs = floor(milli / msPerSecond); 830 double ms = milli - secs * msPerSecond; 831 return JSValue::encode(jsNumber(ms)); 832} 833 834EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec) 835{ 836 JSValue thisValue = exec->thisValue(); 837 if (!thisValue.inherits(DateInstance::info())) 838 return throwVMTypeError(exec); 839 840 DateInstance* thisDateObj = asDateInstance(thisValue); 841 842 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 843 if (!gregorianDateTime) 844 return JSValue::encode(jsNaN()); 845 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour)); 846} 847 848EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec) 849{ 850 JSValue thisValue = exec->thisValue(); 851 if (!thisValue.inherits(DateInstance::info())) 852 return throwVMTypeError(exec); 853 854 DateInstance* thisDateObj = asDateInstance(thisValue); 855 856 double milli = timeClip(exec->argument(0).toNumber(exec)); 857 JSValue result = jsNumber(milli); 858 thisDateObj->setInternalValue(exec->vm(), result); 859 return JSValue::encode(result); 860} 861 862static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) 863{ 864 JSValue thisValue = exec->thisValue(); 865 if (!thisValue.inherits(DateInstance::info())) 866 return throwVMTypeError(exec); 867 868 DateInstance* thisDateObj = asDateInstance(thisValue); 869 double milli = thisDateObj->internalNumber(); 870 VM& vm = exec->vm(); 871 872 if (!exec->argumentCount() || std::isnan(milli)) { 873 JSValue result = jsNaN(); 874 thisDateObj->setInternalValue(vm, result); 875 return JSValue::encode(result); 876 } 877 878 double secs = floor(milli / msPerSecond); 879 double ms = milli - secs * msPerSecond; 880 881 const GregorianDateTime* other = inputIsUTC 882 ? thisDateObj->gregorianDateTimeUTC(exec) 883 : thisDateObj->gregorianDateTime(exec); 884 if (!other) 885 return JSValue::encode(jsNaN()); 886 887 GregorianDateTime gregorianDateTime; 888 gregorianDateTime.copyFrom(*other); 889 if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { 890 JSValue result = jsNaN(); 891 thisDateObj->setInternalValue(vm, result); 892 return JSValue::encode(result); 893 } 894 895 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC)); 896 thisDateObj->setInternalValue(vm, result); 897 return JSValue::encode(result); 898} 899 900static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) 901{ 902 JSValue thisValue = exec->thisValue(); 903 if (!thisValue.inherits(DateInstance::info())) 904 return throwVMTypeError(exec); 905 906 DateInstance* thisDateObj = asDateInstance(thisValue); 907 if (!exec->argumentCount()) { 908 JSValue result = jsNaN(); 909 thisDateObj->setInternalValue(exec->vm(), result); 910 return JSValue::encode(result); 911 } 912 913 VM& vm = exec->vm(); 914 double milli = thisDateObj->internalNumber(); 915 double ms = 0; 916 917 GregorianDateTime gregorianDateTime; 918 if (numArgsToUse == 3 && std::isnan(milli)) 919 msToGregorianDateTime(vm, 0, true, gregorianDateTime); 920 else { 921 ms = milli - floor(milli / msPerSecond) * msPerSecond; 922 const GregorianDateTime* other = inputIsUTC 923 ? thisDateObj->gregorianDateTimeUTC(exec) 924 : thisDateObj->gregorianDateTime(exec); 925 if (!other) 926 return JSValue::encode(jsNaN()); 927 gregorianDateTime.copyFrom(*other); 928 } 929 930 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { 931 JSValue result = jsNaN(); 932 thisDateObj->setInternalValue(vm, result); 933 return JSValue::encode(result); 934 } 935 936 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC)); 937 thisDateObj->setInternalValue(vm, result); 938 return JSValue::encode(result); 939} 940 941EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec) 942{ 943 const bool inputIsUTC = false; 944 return setNewValueFromTimeArgs(exec, 1, inputIsUTC); 945} 946 947EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec) 948{ 949 const bool inputIsUTC = true; 950 return setNewValueFromTimeArgs(exec, 1, inputIsUTC); 951} 952 953EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec) 954{ 955 const bool inputIsUTC = false; 956 return setNewValueFromTimeArgs(exec, 2, inputIsUTC); 957} 958 959EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec) 960{ 961 const bool inputIsUTC = true; 962 return setNewValueFromTimeArgs(exec, 2, inputIsUTC); 963} 964 965EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec) 966{ 967 const bool inputIsUTC = false; 968 return setNewValueFromTimeArgs(exec, 3, inputIsUTC); 969} 970 971EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec) 972{ 973 const bool inputIsUTC = true; 974 return setNewValueFromTimeArgs(exec, 3, inputIsUTC); 975} 976 977EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec) 978{ 979 const bool inputIsUTC = false; 980 return setNewValueFromTimeArgs(exec, 4, inputIsUTC); 981} 982 983EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec) 984{ 985 const bool inputIsUTC = true; 986 return setNewValueFromTimeArgs(exec, 4, inputIsUTC); 987} 988 989EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec) 990{ 991 const bool inputIsUTC = false; 992 return setNewValueFromDateArgs(exec, 1, inputIsUTC); 993} 994 995EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec) 996{ 997 const bool inputIsUTC = true; 998 return setNewValueFromDateArgs(exec, 1, inputIsUTC); 999} 1000 1001EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec) 1002{ 1003 const bool inputIsUTC = false; 1004 return setNewValueFromDateArgs(exec, 2, inputIsUTC); 1005} 1006 1007EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec) 1008{ 1009 const bool inputIsUTC = true; 1010 return setNewValueFromDateArgs(exec, 2, inputIsUTC); 1011} 1012 1013EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec) 1014{ 1015 const bool inputIsUTC = false; 1016 return setNewValueFromDateArgs(exec, 3, inputIsUTC); 1017} 1018 1019EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec) 1020{ 1021 const bool inputIsUTC = true; 1022 return setNewValueFromDateArgs(exec, 3, inputIsUTC); 1023} 1024 1025EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) 1026{ 1027 JSValue thisValue = exec->thisValue(); 1028 if (!thisValue.inherits(DateInstance::info())) 1029 return throwVMTypeError(exec); 1030 1031 VM& vm = exec->vm(); 1032 DateInstance* thisDateObj = asDateInstance(thisValue); 1033 if (!exec->argumentCount()) { 1034 JSValue result = jsNaN(); 1035 thisDateObj->setInternalValue(vm, result); 1036 return JSValue::encode(result); 1037 } 1038 1039 double milli = thisDateObj->internalNumber(); 1040 double ms = 0; 1041 1042 GregorianDateTime gregorianDateTime; 1043 if (std::isnan(milli)) 1044 // Based on ECMA 262 B.2.5 (setYear) 1045 // the time must be reset to +0 if it is NaN. 1046 msToGregorianDateTime(vm, 0, true, gregorianDateTime); 1047 else { 1048 double secs = floor(milli / msPerSecond); 1049 ms = milli - secs * msPerSecond; 1050 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) 1051 gregorianDateTime.copyFrom(*other); 1052 } 1053 1054 double year = exec->argument(0).toIntegerPreserveNaN(exec); 1055 if (!std::isfinite(year)) { 1056 JSValue result = jsNaN(); 1057 thisDateObj->setInternalValue(vm, result); 1058 return JSValue::encode(result); 1059 } 1060 1061 gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year)); 1062 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, false)); 1063 thisDateObj->setInternalValue(vm, result); 1064 return JSValue::encode(result); 1065} 1066 1067EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec) 1068{ 1069 JSValue thisValue = exec->thisValue(); 1070 if (!thisValue.inherits(DateInstance::info())) 1071 return throwVMTypeError(exec); 1072 1073 DateInstance* thisDateObj = asDateInstance(thisValue); 1074 1075 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); 1076 if (!gregorianDateTime) 1077 return JSValue::encode(jsNaN()); 1078 1079 // NOTE: IE returns the full year even in getYear. 1080 return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900)); 1081} 1082 1083EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec) 1084{ 1085 JSValue thisValue = exec->thisValue(); 1086 JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode)); 1087 if (exec->hadException()) 1088 return JSValue::encode(jsNull()); 1089 1090 JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString); 1091 if (exec->hadException()) 1092 return JSValue::encode(jsNull()); 1093 1094 CallData callData; 1095 CallType callType = getCallData(toISOValue, callData); 1096 if (callType == CallTypeNone) 1097 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function"))); 1098 1099 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList()); 1100 if (exec->hadException()) 1101 return JSValue::encode(jsNull()); 1102 if (result.isObject()) 1103 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value"))); 1104 return JSValue::encode(result); 1105} 1106 1107} // namespace JSC 1108