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.
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.
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.
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
25 #include "DatePrototype.h"
27 #include "DateConversion.h"
28 #include "DateInstance.h"
30 #include "JSDateMath.h"
31 #include "JSGlobalObject.h"
33 #include "JSStringBuilder.h"
35 #include "ObjectPrototype.h"
36 #include "Operations.h"
38 #if !PLATFORM(MAC) && HAVE(LANGINFO_H)
47 #include <wtf/Assertions.h>
48 #include <wtf/MathExtras.h>
49 #include <wtf/StringExtras.h>
52 #include <sys/param.h>
60 #include <sys/timeb.h>
63 #if OS(DARWIN) && USE(CF)
64 #include <CoreFoundation/CoreFoundation.h>
65 #elif USE(ICU_UNICODE)
66 #include <unicode/udat.h>
73 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
74 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
75 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
76 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
77 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
78 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
79 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
80 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
81 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
82 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
83 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
84 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
85 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
86 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
87 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
88 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
89 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
90 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
91 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
92 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
93 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
94 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
95 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
96 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
97 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
98 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
99 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
100 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
101 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
102 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
103 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
104 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
105 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
106 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
107 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
108 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
109 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
110 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
111 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
112 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
113 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
114 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
115 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
116 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
117 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
121 #include "DatePrototype.lut.h"
125 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
127 #if OS(DARWIN) && USE(CF)
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.
132 static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
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;
145 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
147 CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
148 CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
150 bool useCustomFormat = false;
151 String customFormatString;
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);
165 CFLocaleRef locale = CFLocaleCopyCurrent();
166 CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
169 if (useCustomFormat) {
170 CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
171 CFDateFormatterSetFormat(formatter, customFormatCFString);
172 CFRelease(customFormatCFString);
175 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
177 CFRelease(formatter);
179 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
180 // That's not great error handling, but it just won't happen so it doesn't matter.
182 const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
183 size_t length = CFStringGetLength(string);
184 ASSERT(length <= bufferLength);
185 if (length > bufferLength)
186 length = bufferLength;
187 CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
191 return jsNontrivialString(exec, String(buffer, length));
194 #elif USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING
196 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
198 UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
199 UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
201 UErrorCode status = U_ZERO_ERROR;
202 UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
204 return jsEmptyString(exec);
208 length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
210 if (status != U_ZERO_ERROR)
211 return jsEmptyString(exec);
213 return jsNontrivialString(exec, String(buffer, length));
218 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
221 SYSTEMTIME systemTime;
222 memset(&systemTime, 0, sizeof(systemTime));
223 systemTime.wYear = gdt.year();
224 systemTime.wMonth = gdt.month() + 1;
225 systemTime.wDay = gdt.monthDay();
226 systemTime.wDayOfWeek = gdt.weekDay();
227 systemTime.wHour = gdt.hour();
228 systemTime.wMinute = gdt.minute();
229 systemTime.wSecond = gdt.second();
231 Vector<UChar, 128> buffer;
234 if (format == LocaleDate) {
235 buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
236 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
237 } else if (format == LocaleTime) {
238 buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
239 length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
240 } else if (format == LocaleDateAndTime) {
241 buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
242 length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
244 buffer[length - 1] = ' ';
245 length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
248 RELEASE_ASSERT_NOT_REACHED();
250 // Remove terminating null character.
254 return jsNontrivialString(exec, String(buffer.data(), length));
259 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
261 static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
264 // Offset year if needed
265 struct tm localTM = gdt;
266 int year = gdt.year();
267 bool yearNeedsOffset = year < 1900 || year > 2038;
269 localTM.tm_year = equivalentYearForDST(year) - 1900;
272 // We do not allow strftime to generate dates with 2-digits years,
273 // both to avoid ambiguity, and a crash in strncpy, for years that
275 char* formatString = strdup(nl_langinfo(formats[format]));
276 char* yPos = strchr(formatString, 'y');
282 const int bufsize = 128;
283 char timebuffer[bufsize];
286 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
289 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
293 return jsEmptyString(exec);
295 // Copy original into the buffer
296 if (yearNeedsOffset && format != LocaleTime) {
297 static const int yearLen = 5; // FIXME will be a problem in the year 10,000
298 char yearString[yearLen];
300 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
301 char* yearLocation = strstr(timebuffer, yearString);
302 snprintf(yearString, yearLen, "%d", year);
304 strncpy(yearLocation, yearString, yearLen - 1);
307 // Convert multi-byte result to UNICODE.
308 // If __STDC_ISO_10646__ is defined, wide character represents
309 // UTF-16 (or UTF-32) code point. In most modern Unix like system
310 // (e.g. Linux with glibc 2.2 and above) the macro is defined,
311 // and wide character represents UTF-32 code point.
312 // Here we static_cast potential UTF-32 to UTF-16, it should be
313 // safe because date and (or) time related characters in different languages
314 // should be in UNICODE BMP. If mbstowcs fails, we just fall
315 // back on using multi-byte result as-is.
316 #ifdef __STDC_ISO_10646__
317 UChar buffer[bufsize];
318 wchar_t tempbuffer[bufsize];
319 size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
320 if (length != static_cast<size_t>(-1)) {
321 for (size_t i = 0; i < length; ++i)
322 buffer[i] = static_cast<UChar>(tempbuffer[i]);
323 return jsNontrivialString(exec, String(buffer, length));
327 return jsNontrivialString(exec, timebuffer);
328 #endif // OS(WINDOWS)
331 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
333 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
334 if (!gregorianDateTime)
335 return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
336 return formatLocaleDate(exec, *gregorianDateTime, format);
339 #endif // OS(DARWIN) && USE(CF)
341 static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
343 JSValue thisValue = exec->hostThisValue();
344 if (!thisValue.inherits(&DateInstance::s_info))
345 return throwVMTypeError(exec);
347 DateInstance* thisDateObj = asDateInstance(thisValue);
349 const GregorianDateTime* gregorianDateTime = asUTCVariant
350 ? thisDateObj->gregorianDateTimeUTC(exec)
351 : thisDateObj->gregorianDateTime(exec);
352 if (!gregorianDateTime)
353 return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
355 return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
358 // Converts a list of arguments sent to a Date member function into milliseconds, updating
359 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
361 // Format of member function: f([hour,] [min,] [sec,] [ms])
362 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
364 double milliseconds = 0;
367 int numArgs = exec->argumentCount();
369 // JS allows extra trailing arguments -- ignore them
370 if (numArgs > maxArgs)
374 if (maxArgs >= 4 && idx < numArgs) {
376 double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
377 ok = std::isfinite(hours);
378 milliseconds += hours * msPerHour;
382 if (maxArgs >= 3 && idx < numArgs && ok) {
384 double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
385 ok = std::isfinite(minutes);
386 milliseconds += minutes * msPerMinute;
390 if (maxArgs >= 2 && idx < numArgs && ok) {
392 double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
393 ok = std::isfinite(seconds);
394 milliseconds += seconds * msPerSecond;
402 double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
403 ok = std::isfinite(millis);
404 milliseconds += millis;
412 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
413 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
415 // Format of member function: f([years,] [months,] [days])
416 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
420 int numArgs = exec->argumentCount();
422 // JS allows extra trailing arguments -- ignore them
423 if (numArgs > maxArgs)
427 if (maxArgs >= 3 && idx < numArgs) {
428 double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
429 ok = std::isfinite(years);
430 t->setYear(toInt32(years));
433 if (maxArgs >= 2 && idx < numArgs && ok) {
434 double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
435 ok = std::isfinite(months);
436 t->setMonth(toInt32(months));
439 if (idx < numArgs && ok) {
440 double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
441 ok = std::isfinite(days);
443 *ms += days * msPerDay;
449 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
451 /* Source for DatePrototype.lut.h
453 toString dateProtoFuncToString DontEnum|Function 0
454 toISOString dateProtoFuncToISOString DontEnum|Function 0
455 toUTCString dateProtoFuncToUTCString DontEnum|Function 0
456 toDateString dateProtoFuncToDateString DontEnum|Function 0
457 toTimeString dateProtoFuncToTimeString DontEnum|Function 0
458 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
459 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
460 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
461 valueOf dateProtoFuncGetTime DontEnum|Function 0
462 getTime dateProtoFuncGetTime DontEnum|Function 0
463 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
464 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
465 toGMTString dateProtoFuncToGMTString DontEnum|Function 0
466 getMonth dateProtoFuncGetMonth DontEnum|Function 0
467 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
468 getDate dateProtoFuncGetDate DontEnum|Function 0
469 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
470 getDay dateProtoFuncGetDay DontEnum|Function 0
471 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
472 getHours dateProtoFuncGetHours DontEnum|Function 0
473 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
474 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
475 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
476 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
477 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
478 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
479 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
480 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
481 setTime dateProtoFuncSetTime DontEnum|Function 1
482 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
483 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
484 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
485 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
486 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
487 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
488 setHours dateProtoFuncSetHours DontEnum|Function 4
489 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
490 setDate dateProtoFuncSetDate DontEnum|Function 1
491 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
492 setMonth dateProtoFuncSetMonth DontEnum|Function 2
493 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
494 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
495 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
496 setYear dateProtoFuncSetYear DontEnum|Function 1
497 getYear dateProtoFuncGetYear DontEnum|Function 0
498 toJSON dateProtoFuncToJSON DontEnum|Function 1
504 DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
505 : DateInstance(exec, structure)
509 void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
511 Base::finishCreation(exec->vm());
512 ASSERT(inherits(&s_info));
514 // The constructor will be added later, after DateConstructor has been built.
517 bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
519 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, slot);
522 bool DatePrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
524 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, descriptor);
529 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
531 const bool asUTCVariant = false;
532 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
535 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
537 const bool asUTCVariant = true;
538 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
541 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
543 JSValue thisValue = exec->hostThisValue();
544 if (!thisValue.inherits(&DateInstance::s_info))
545 return throwVMTypeError(exec);
547 DateInstance* thisDateObj = asDateInstance(thisValue);
548 if (!std::isfinite(thisDateObj->internalNumber()))
549 return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
551 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
552 if (!gregorianDateTime)
553 return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
554 // 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)
555 // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
557 // 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).
558 int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
562 int charactersWritten;
563 if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
564 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);
566 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);
568 ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
569 if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
570 return JSValue::encode(jsEmptyString(exec));
572 return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
575 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
577 const bool asUTCVariant = false;
578 return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
581 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
583 const bool asUTCVariant = false;
584 return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
587 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
589 JSValue thisValue = exec->hostThisValue();
590 if (!thisValue.inherits(&DateInstance::s_info))
591 return throwVMTypeError(exec);
593 DateInstance* thisDateObj = asDateInstance(thisValue);
594 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
597 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
599 JSValue thisValue = exec->hostThisValue();
600 if (!thisValue.inherits(&DateInstance::s_info))
601 return throwVMTypeError(exec);
603 DateInstance* thisDateObj = asDateInstance(thisValue);
604 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
607 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
609 JSValue thisValue = exec->hostThisValue();
610 if (!thisValue.inherits(&DateInstance::s_info))
611 return throwVMTypeError(exec);
613 DateInstance* thisDateObj = asDateInstance(thisValue);
614 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
617 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
619 JSValue thisValue = exec->hostThisValue();
620 if (!thisValue.inherits(&DateInstance::s_info))
621 return throwVMTypeError(exec);
623 return JSValue::encode(asDateInstance(thisValue)->internalValue());
626 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
628 JSValue thisValue = exec->hostThisValue();
629 if (!thisValue.inherits(&DateInstance::s_info))
630 return throwVMTypeError(exec);
632 DateInstance* thisDateObj = asDateInstance(thisValue);
634 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
635 if (!gregorianDateTime)
636 return JSValue::encode(jsNaN());
637 return JSValue::encode(jsNumber(gregorianDateTime->year()));
640 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
642 JSValue thisValue = exec->hostThisValue();
643 if (!thisValue.inherits(&DateInstance::s_info))
644 return throwVMTypeError(exec);
646 DateInstance* thisDateObj = asDateInstance(thisValue);
648 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
649 if (!gregorianDateTime)
650 return JSValue::encode(jsNaN());
651 return JSValue::encode(jsNumber(gregorianDateTime->year()));
654 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
656 const bool asUTCVariant = true;
657 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
660 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
662 JSValue thisValue = exec->hostThisValue();
663 if (!thisValue.inherits(&DateInstance::s_info))
664 return throwVMTypeError(exec);
666 DateInstance* thisDateObj = asDateInstance(thisValue);
668 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
669 if (!gregorianDateTime)
670 return JSValue::encode(jsNaN());
671 return JSValue::encode(jsNumber(gregorianDateTime->month()));
674 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
676 JSValue thisValue = exec->hostThisValue();
677 if (!thisValue.inherits(&DateInstance::s_info))
678 return throwVMTypeError(exec);
680 DateInstance* thisDateObj = asDateInstance(thisValue);
682 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
683 if (!gregorianDateTime)
684 return JSValue::encode(jsNaN());
685 return JSValue::encode(jsNumber(gregorianDateTime->month()));
688 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
690 JSValue thisValue = exec->hostThisValue();
691 if (!thisValue.inherits(&DateInstance::s_info))
692 return throwVMTypeError(exec);
694 DateInstance* thisDateObj = asDateInstance(thisValue);
696 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
697 if (!gregorianDateTime)
698 return JSValue::encode(jsNaN());
699 return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
702 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
704 JSValue thisValue = exec->hostThisValue();
705 if (!thisValue.inherits(&DateInstance::s_info))
706 return throwVMTypeError(exec);
708 DateInstance* thisDateObj = asDateInstance(thisValue);
710 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
711 if (!gregorianDateTime)
712 return JSValue::encode(jsNaN());
713 return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
716 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
718 JSValue thisValue = exec->hostThisValue();
719 if (!thisValue.inherits(&DateInstance::s_info))
720 return throwVMTypeError(exec);
722 DateInstance* thisDateObj = asDateInstance(thisValue);
724 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
725 if (!gregorianDateTime)
726 return JSValue::encode(jsNaN());
727 return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
730 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
732 JSValue thisValue = exec->hostThisValue();
733 if (!thisValue.inherits(&DateInstance::s_info))
734 return throwVMTypeError(exec);
736 DateInstance* thisDateObj = asDateInstance(thisValue);
738 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
739 if (!gregorianDateTime)
740 return JSValue::encode(jsNaN());
741 return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
744 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
746 JSValue thisValue = exec->hostThisValue();
747 if (!thisValue.inherits(&DateInstance::s_info))
748 return throwVMTypeError(exec);
750 DateInstance* thisDateObj = asDateInstance(thisValue);
752 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
753 if (!gregorianDateTime)
754 return JSValue::encode(jsNaN());
755 return JSValue::encode(jsNumber(gregorianDateTime->hour()));
758 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
760 JSValue thisValue = exec->hostThisValue();
761 if (!thisValue.inherits(&DateInstance::s_info))
762 return throwVMTypeError(exec);
764 DateInstance* thisDateObj = asDateInstance(thisValue);
766 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
767 if (!gregorianDateTime)
768 return JSValue::encode(jsNaN());
769 return JSValue::encode(jsNumber(gregorianDateTime->hour()));
772 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
774 JSValue thisValue = exec->hostThisValue();
775 if (!thisValue.inherits(&DateInstance::s_info))
776 return throwVMTypeError(exec);
778 DateInstance* thisDateObj = asDateInstance(thisValue);
780 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
781 if (!gregorianDateTime)
782 return JSValue::encode(jsNaN());
783 return JSValue::encode(jsNumber(gregorianDateTime->minute()));
786 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
788 JSValue thisValue = exec->hostThisValue();
789 if (!thisValue.inherits(&DateInstance::s_info))
790 return throwVMTypeError(exec);
792 DateInstance* thisDateObj = asDateInstance(thisValue);
794 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
795 if (!gregorianDateTime)
796 return JSValue::encode(jsNaN());
797 return JSValue::encode(jsNumber(gregorianDateTime->minute()));
800 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
802 JSValue thisValue = exec->hostThisValue();
803 if (!thisValue.inherits(&DateInstance::s_info))
804 return throwVMTypeError(exec);
806 DateInstance* thisDateObj = asDateInstance(thisValue);
808 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
809 if (!gregorianDateTime)
810 return JSValue::encode(jsNaN());
811 return JSValue::encode(jsNumber(gregorianDateTime->second()));
814 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
816 JSValue thisValue = exec->hostThisValue();
817 if (!thisValue.inherits(&DateInstance::s_info))
818 return throwVMTypeError(exec);
820 DateInstance* thisDateObj = asDateInstance(thisValue);
822 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
823 if (!gregorianDateTime)
824 return JSValue::encode(jsNaN());
825 return JSValue::encode(jsNumber(gregorianDateTime->second()));
828 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
830 JSValue thisValue = exec->hostThisValue();
831 if (!thisValue.inherits(&DateInstance::s_info))
832 return throwVMTypeError(exec);
834 DateInstance* thisDateObj = asDateInstance(thisValue);
835 double milli = thisDateObj->internalNumber();
836 if (std::isnan(milli))
837 return JSValue::encode(jsNaN());
839 double secs = floor(milli / msPerSecond);
840 double ms = milli - secs * msPerSecond;
841 return JSValue::encode(jsNumber(ms));
844 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
846 JSValue thisValue = exec->hostThisValue();
847 if (!thisValue.inherits(&DateInstance::s_info))
848 return throwVMTypeError(exec);
850 DateInstance* thisDateObj = asDateInstance(thisValue);
851 double milli = thisDateObj->internalNumber();
852 if (std::isnan(milli))
853 return JSValue::encode(jsNaN());
855 double secs = floor(milli / msPerSecond);
856 double ms = milli - secs * msPerSecond;
857 return JSValue::encode(jsNumber(ms));
860 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
862 JSValue thisValue = exec->hostThisValue();
863 if (!thisValue.inherits(&DateInstance::s_info))
864 return throwVMTypeError(exec);
866 DateInstance* thisDateObj = asDateInstance(thisValue);
868 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
869 if (!gregorianDateTime)
870 return JSValue::encode(jsNaN());
871 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
874 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
876 JSValue thisValue = exec->hostThisValue();
877 if (!thisValue.inherits(&DateInstance::s_info))
878 return throwVMTypeError(exec);
880 DateInstance* thisDateObj = asDateInstance(thisValue);
882 double milli = timeClip(exec->argument(0).toNumber(exec));
883 JSValue result = jsNumber(milli);
884 thisDateObj->setInternalValue(exec->vm(), result);
885 return JSValue::encode(result);
888 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
890 JSValue thisValue = exec->hostThisValue();
891 if (!thisValue.inherits(&DateInstance::s_info))
892 return throwVMTypeError(exec);
894 DateInstance* thisDateObj = asDateInstance(thisValue);
895 double milli = thisDateObj->internalNumber();
897 if (!exec->argumentCount() || std::isnan(milli)) {
898 JSValue result = jsNaN();
899 thisDateObj->setInternalValue(exec->vm(), result);
900 return JSValue::encode(result);
903 double secs = floor(milli / msPerSecond);
904 double ms = milli - secs * msPerSecond;
906 const GregorianDateTime* other = inputIsUTC
907 ? thisDateObj->gregorianDateTimeUTC(exec)
908 : thisDateObj->gregorianDateTime(exec);
910 return JSValue::encode(jsNaN());
912 GregorianDateTime gregorianDateTime;
913 gregorianDateTime.copyFrom(*other);
914 if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
915 JSValue result = jsNaN();
916 thisDateObj->setInternalValue(exec->vm(), result);
917 return JSValue::encode(result);
920 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
921 thisDateObj->setInternalValue(exec->vm(), result);
922 return JSValue::encode(result);
925 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
927 JSValue thisValue = exec->hostThisValue();
928 if (!thisValue.inherits(&DateInstance::s_info))
929 return throwVMTypeError(exec);
931 DateInstance* thisDateObj = asDateInstance(thisValue);
932 if (!exec->argumentCount()) {
933 JSValue result = jsNaN();
934 thisDateObj->setInternalValue(exec->vm(), result);
935 return JSValue::encode(result);
938 double milli = thisDateObj->internalNumber();
941 GregorianDateTime gregorianDateTime;
942 if (numArgsToUse == 3 && std::isnan(milli))
943 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
945 ms = milli - floor(milli / msPerSecond) * msPerSecond;
946 const GregorianDateTime* other = inputIsUTC
947 ? thisDateObj->gregorianDateTimeUTC(exec)
948 : thisDateObj->gregorianDateTime(exec);
950 return JSValue::encode(jsNaN());
951 gregorianDateTime.copyFrom(*other);
954 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
955 JSValue result = jsNaN();
956 thisDateObj->setInternalValue(exec->vm(), result);
957 return JSValue::encode(result);
960 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
961 thisDateObj->setInternalValue(exec->vm(), result);
962 return JSValue::encode(result);
965 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
967 const bool inputIsUTC = false;
968 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
971 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
973 const bool inputIsUTC = true;
974 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
977 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
979 const bool inputIsUTC = false;
980 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
983 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
985 const bool inputIsUTC = true;
986 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
989 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
991 const bool inputIsUTC = false;
992 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
995 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
997 const bool inputIsUTC = true;
998 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
1001 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
1003 const bool inputIsUTC = false;
1004 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
1007 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
1009 const bool inputIsUTC = true;
1010 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
1013 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
1015 const bool inputIsUTC = false;
1016 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1019 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
1021 const bool inputIsUTC = true;
1022 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1025 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1027 const bool inputIsUTC = false;
1028 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1031 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1033 const bool inputIsUTC = true;
1034 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1037 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1039 const bool inputIsUTC = false;
1040 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1043 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1045 const bool inputIsUTC = true;
1046 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1049 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1051 JSValue thisValue = exec->hostThisValue();
1052 if (!thisValue.inherits(&DateInstance::s_info))
1053 return throwVMTypeError(exec);
1055 DateInstance* thisDateObj = asDateInstance(thisValue);
1056 if (!exec->argumentCount()) {
1057 JSValue result = jsNaN();
1058 thisDateObj->setInternalValue(exec->vm(), result);
1059 return JSValue::encode(result);
1062 double milli = thisDateObj->internalNumber();
1065 GregorianDateTime gregorianDateTime;
1066 if (std::isnan(milli))
1067 // Based on ECMA 262 B.2.5 (setYear)
1068 // the time must be reset to +0 if it is NaN.
1069 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1071 double secs = floor(milli / msPerSecond);
1072 ms = milli - secs * msPerSecond;
1073 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1074 gregorianDateTime.copyFrom(*other);
1077 double year = exec->argument(0).toIntegerPreserveNaN(exec);
1078 if (!std::isfinite(year)) {
1079 JSValue result = jsNaN();
1080 thisDateObj->setInternalValue(exec->vm(), result);
1081 return JSValue::encode(result);
1084 gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
1085 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1086 thisDateObj->setInternalValue(exec->vm(), result);
1087 return JSValue::encode(result);
1090 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1092 JSValue thisValue = exec->hostThisValue();
1093 if (!thisValue.inherits(&DateInstance::s_info))
1094 return throwVMTypeError(exec);
1096 DateInstance* thisDateObj = asDateInstance(thisValue);
1098 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1099 if (!gregorianDateTime)
1100 return JSValue::encode(jsNaN());
1102 // NOTE: IE returns the full year even in getYear.
1103 return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
1106 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1108 JSValue thisValue = exec->hostThisValue();
1109 JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
1110 if (exec->hadException())
1111 return JSValue::encode(jsNull());
1113 JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
1114 if (exec->hadException())
1115 return JSValue::encode(jsNull());
1118 CallType callType = getCallData(toISOValue, callData);
1119 if (callType == CallTypeNone)
1120 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function")));
1122 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1123 if (exec->hadException())
1124 return JSValue::encode(jsNull());
1125 if (result.isObject())
1126 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value")));
1127 return JSValue::encode(result);