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"
34 #include "ObjectPrototype.h"
35 #include "JSCInlines.h"
41 #include <wtf/Assertions.h>
42 #include <wtf/MathExtras.h>
43 #include <wtf/StringExtras.h>
50 #include <sys/param.h>
58 #include <sys/timeb.h>
61 #if !(OS(DARWIN) && USE(CF))
62 #include <unicode/udat.h>
66 #include <CoreFoundation/CoreFoundation.h>
73 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
74 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
75 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
76 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
77 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
78 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
79 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
80 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
81 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
82 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
83 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
84 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
85 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
86 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
87 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
88 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
89 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
90 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
91 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
92 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
93 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
94 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
95 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
96 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
97 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
98 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
99 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
100 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
101 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
102 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
103 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
104 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
105 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
106 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
107 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
108 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
109 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
110 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
111 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
112 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
113 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
114 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
115 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
116 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
117 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 CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
167 auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
169 CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
170 return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
173 #elif !UCONFIG_NO_FORMATTING
175 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
177 UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
178 UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
180 UErrorCode status = U_ZERO_ERROR;
181 UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
183 return jsEmptyString(exec);
187 length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
189 if (status != U_ZERO_ERROR)
190 return jsEmptyString(exec);
192 return jsNontrivialString(exec, String(buffer, length));
197 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
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();
210 Vector<UChar, 128> buffer;
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());
223 buffer[length - 1] = ' ';
224 length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
227 RELEASE_ASSERT_NOT_REACHED();
229 // Remove terminating null character.
233 return jsNontrivialString(exec, String(buffer.data(), length));
238 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
240 static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
243 // Offset year if needed
244 struct tm localTM = gdt;
245 int year = gdt.year();
246 bool yearNeedsOffset = year < 1900 || year > 2038;
248 localTM.tm_year = equivalentYearForDST(year) - 1900;
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
254 char* formatString = strdup(nl_langinfo(formats[format]));
255 char* yPos = strchr(formatString, 'y');
261 const int bufsize = 128;
262 char timebuffer[bufsize];
265 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
268 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
272 return jsEmptyString(exec);
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];
279 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
280 char* yearLocation = strstr(timebuffer, yearString);
281 snprintf(yearString, yearLen, "%d", year);
283 strncpy(yearLocation, yearString, yearLen - 1);
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));
306 return jsNontrivialString(exec, timebuffer);
307 #endif // OS(WINDOWS)
310 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
312 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
313 if (!gregorianDateTime)
314 return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
315 return formatLocaleDate(exec, *gregorianDateTime, format);
318 #endif // OS(DARWIN) && USE(CF)
320 static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
322 JSValue thisValue = exec->thisValue();
323 if (!thisValue.inherits(DateInstance::info()))
324 return throwVMTypeError(exec);
326 DateInstance* thisDateObj = asDateInstance(thisValue);
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"))));
334 return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
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.
340 // Format of member function: f([hour,] [min,] [sec,] [ms])
341 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
343 double milliseconds = 0;
346 int numArgs = exec->argumentCount();
348 // JS allows extra trailing arguments -- ignore them
349 if (numArgs > maxArgs)
353 if (maxArgs >= 4 && idx < numArgs) {
355 double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
356 ok = std::isfinite(hours);
357 milliseconds += hours * msPerHour;
361 if (maxArgs >= 3 && idx < numArgs && ok) {
363 double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
364 ok = std::isfinite(minutes);
365 milliseconds += minutes * msPerMinute;
369 if (maxArgs >= 2 && idx < numArgs && ok) {
371 double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
372 ok = std::isfinite(seconds);
373 milliseconds += seconds * msPerSecond;
381 double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
382 ok = std::isfinite(millis);
383 milliseconds += millis;
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.
394 // Format of member function: f([years,] [months,] [days])
395 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
399 int numArgs = exec->argumentCount();
401 // JS allows extra trailing arguments -- ignore them
402 if (numArgs > maxArgs)
406 if (maxArgs >= 3 && idx < numArgs) {
407 double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
408 ok = std::isfinite(years);
409 t->setYear(toInt32(years));
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));
418 if (idx < numArgs && ok) {
419 double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
420 ok = std::isfinite(days);
422 *ms += days * msPerDay;
428 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, &dateTable, CREATE_METHOD_TABLE(DatePrototype)};
430 /* Source for DatePrototype.lut.h
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
483 DatePrototype::DatePrototype(VM& vm, Structure* structure)
484 : DateInstance(vm, structure)
488 void DatePrototype::finishCreation(VM& vm, JSGlobalObject*)
490 Base::finishCreation(vm);
491 ASSERT(inherits(info()));
493 // The constructor will be added later, after DateConstructor has been built.
496 bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
498 return getStaticFunctionSlot<JSObject>(exec, dateTable, jsCast<DatePrototype*>(object), propertyName, slot);
503 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
505 const bool asUTCVariant = false;
506 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
509 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
511 const bool asUTCVariant = true;
512 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
515 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
517 JSValue thisValue = exec->thisValue();
518 if (!thisValue.inherits(DateInstance::info()))
519 return throwVMTypeError(exec);
521 DateInstance* thisDateObj = asDateInstance(thisValue);
522 if (!std::isfinite(thisDateObj->internalNumber()))
523 return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
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.
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));
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);
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);
542 ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
543 if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
544 return JSValue::encode(jsEmptyString(exec));
546 return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
549 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
551 const bool asUTCVariant = false;
552 return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
555 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
557 const bool asUTCVariant = false;
558 return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
561 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
563 JSValue thisValue = exec->thisValue();
564 if (!thisValue.inherits(DateInstance::info()))
565 return throwVMTypeError(exec);
567 DateInstance* thisDateObj = asDateInstance(thisValue);
568 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
571 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
573 JSValue thisValue = exec->thisValue();
574 if (!thisValue.inherits(DateInstance::info()))
575 return throwVMTypeError(exec);
577 DateInstance* thisDateObj = asDateInstance(thisValue);
578 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
581 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
583 JSValue thisValue = exec->thisValue();
584 if (!thisValue.inherits(DateInstance::info()))
585 return throwVMTypeError(exec);
587 DateInstance* thisDateObj = asDateInstance(thisValue);
588 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
591 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
593 JSValue thisValue = exec->thisValue();
594 if (!thisValue.inherits(DateInstance::info()))
595 return throwVMTypeError(exec);
597 return JSValue::encode(asDateInstance(thisValue)->internalValue());
600 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
602 JSValue thisValue = exec->thisValue();
603 if (!thisValue.inherits(DateInstance::info()))
604 return throwVMTypeError(exec);
606 DateInstance* thisDateObj = asDateInstance(thisValue);
608 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
609 if (!gregorianDateTime)
610 return JSValue::encode(jsNaN());
611 return JSValue::encode(jsNumber(gregorianDateTime->year()));
614 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
616 JSValue thisValue = exec->thisValue();
617 if (!thisValue.inherits(DateInstance::info()))
618 return throwVMTypeError(exec);
620 DateInstance* thisDateObj = asDateInstance(thisValue);
622 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
623 if (!gregorianDateTime)
624 return JSValue::encode(jsNaN());
625 return JSValue::encode(jsNumber(gregorianDateTime->year()));
628 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
630 const bool asUTCVariant = true;
631 return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
634 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
636 JSValue thisValue = exec->thisValue();
637 if (!thisValue.inherits(DateInstance::info()))
638 return throwVMTypeError(exec);
640 DateInstance* thisDateObj = asDateInstance(thisValue);
642 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
643 if (!gregorianDateTime)
644 return JSValue::encode(jsNaN());
645 return JSValue::encode(jsNumber(gregorianDateTime->month()));
648 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
650 JSValue thisValue = exec->thisValue();
651 if (!thisValue.inherits(DateInstance::info()))
652 return throwVMTypeError(exec);
654 DateInstance* thisDateObj = asDateInstance(thisValue);
656 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
657 if (!gregorianDateTime)
658 return JSValue::encode(jsNaN());
659 return JSValue::encode(jsNumber(gregorianDateTime->month()));
662 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
664 JSValue thisValue = exec->thisValue();
665 if (!thisValue.inherits(DateInstance::info()))
666 return throwVMTypeError(exec);
668 DateInstance* thisDateObj = asDateInstance(thisValue);
670 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
671 if (!gregorianDateTime)
672 return JSValue::encode(jsNaN());
673 return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
676 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
678 JSValue thisValue = exec->thisValue();
679 if (!thisValue.inherits(DateInstance::info()))
680 return throwVMTypeError(exec);
682 DateInstance* thisDateObj = asDateInstance(thisValue);
684 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
685 if (!gregorianDateTime)
686 return JSValue::encode(jsNaN());
687 return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
690 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
692 JSValue thisValue = exec->thisValue();
693 if (!thisValue.inherits(DateInstance::info()))
694 return throwVMTypeError(exec);
696 DateInstance* thisDateObj = asDateInstance(thisValue);
698 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
699 if (!gregorianDateTime)
700 return JSValue::encode(jsNaN());
701 return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
704 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
706 JSValue thisValue = exec->thisValue();
707 if (!thisValue.inherits(DateInstance::info()))
708 return throwVMTypeError(exec);
710 DateInstance* thisDateObj = asDateInstance(thisValue);
712 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
713 if (!gregorianDateTime)
714 return JSValue::encode(jsNaN());
715 return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
718 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
720 JSValue thisValue = exec->thisValue();
721 if (!thisValue.inherits(DateInstance::info()))
722 return throwVMTypeError(exec);
724 DateInstance* thisDateObj = asDateInstance(thisValue);
726 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
727 if (!gregorianDateTime)
728 return JSValue::encode(jsNaN());
729 return JSValue::encode(jsNumber(gregorianDateTime->hour()));
732 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
734 JSValue thisValue = exec->thisValue();
735 if (!thisValue.inherits(DateInstance::info()))
736 return throwVMTypeError(exec);
738 DateInstance* thisDateObj = asDateInstance(thisValue);
740 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
741 if (!gregorianDateTime)
742 return JSValue::encode(jsNaN());
743 return JSValue::encode(jsNumber(gregorianDateTime->hour()));
746 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
748 JSValue thisValue = exec->thisValue();
749 if (!thisValue.inherits(DateInstance::info()))
750 return throwVMTypeError(exec);
752 DateInstance* thisDateObj = asDateInstance(thisValue);
754 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
755 if (!gregorianDateTime)
756 return JSValue::encode(jsNaN());
757 return JSValue::encode(jsNumber(gregorianDateTime->minute()));
760 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
762 JSValue thisValue = exec->thisValue();
763 if (!thisValue.inherits(DateInstance::info()))
764 return throwVMTypeError(exec);
766 DateInstance* thisDateObj = asDateInstance(thisValue);
768 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
769 if (!gregorianDateTime)
770 return JSValue::encode(jsNaN());
771 return JSValue::encode(jsNumber(gregorianDateTime->minute()));
774 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
776 JSValue thisValue = exec->thisValue();
777 if (!thisValue.inherits(DateInstance::info()))
778 return throwVMTypeError(exec);
780 DateInstance* thisDateObj = asDateInstance(thisValue);
782 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
783 if (!gregorianDateTime)
784 return JSValue::encode(jsNaN());
785 return JSValue::encode(jsNumber(gregorianDateTime->second()));
788 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
790 JSValue thisValue = exec->thisValue();
791 if (!thisValue.inherits(DateInstance::info()))
792 return throwVMTypeError(exec);
794 DateInstance* thisDateObj = asDateInstance(thisValue);
796 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
797 if (!gregorianDateTime)
798 return JSValue::encode(jsNaN());
799 return JSValue::encode(jsNumber(gregorianDateTime->second()));
802 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
804 JSValue thisValue = exec->thisValue();
805 if (!thisValue.inherits(DateInstance::info()))
806 return throwVMTypeError(exec);
808 DateInstance* thisDateObj = asDateInstance(thisValue);
809 double milli = thisDateObj->internalNumber();
810 if (std::isnan(milli))
811 return JSValue::encode(jsNaN());
813 double secs = floor(milli / msPerSecond);
814 double ms = milli - secs * msPerSecond;
815 return JSValue::encode(jsNumber(ms));
818 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
820 JSValue thisValue = exec->thisValue();
821 if (!thisValue.inherits(DateInstance::info()))
822 return throwVMTypeError(exec);
824 DateInstance* thisDateObj = asDateInstance(thisValue);
825 double milli = thisDateObj->internalNumber();
826 if (std::isnan(milli))
827 return JSValue::encode(jsNaN());
829 double secs = floor(milli / msPerSecond);
830 double ms = milli - secs * msPerSecond;
831 return JSValue::encode(jsNumber(ms));
834 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
836 JSValue thisValue = exec->thisValue();
837 if (!thisValue.inherits(DateInstance::info()))
838 return throwVMTypeError(exec);
840 DateInstance* thisDateObj = asDateInstance(thisValue);
842 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
843 if (!gregorianDateTime)
844 return JSValue::encode(jsNaN());
845 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
848 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
850 JSValue thisValue = exec->thisValue();
851 if (!thisValue.inherits(DateInstance::info()))
852 return throwVMTypeError(exec);
854 DateInstance* thisDateObj = asDateInstance(thisValue);
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);
862 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
864 JSValue thisValue = exec->thisValue();
865 if (!thisValue.inherits(DateInstance::info()))
866 return throwVMTypeError(exec);
868 DateInstance* thisDateObj = asDateInstance(thisValue);
869 double milli = thisDateObj->internalNumber();
872 if (!exec->argumentCount() || std::isnan(milli)) {
873 JSValue result = jsNaN();
874 thisDateObj->setInternalValue(vm, result);
875 return JSValue::encode(result);
878 double secs = floor(milli / msPerSecond);
879 double ms = milli - secs * msPerSecond;
881 const GregorianDateTime* other = inputTimeType == WTF::UTCTime
882 ? thisDateObj->gregorianDateTimeUTC(exec)
883 : thisDateObj->gregorianDateTime(exec);
885 return JSValue::encode(jsNaN());
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);
895 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
896 thisDateObj->setInternalValue(vm, result);
897 return JSValue::encode(result);
900 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
902 JSValue thisValue = exec->thisValue();
903 if (!thisValue.inherits(DateInstance::info()))
904 return throwVMTypeError(exec);
906 DateInstance* thisDateObj = asDateInstance(thisValue);
907 if (!exec->argumentCount()) {
908 JSValue result = jsNaN();
909 thisDateObj->setInternalValue(exec->vm(), result);
910 return JSValue::encode(result);
914 double milli = thisDateObj->internalNumber();
917 GregorianDateTime gregorianDateTime;
918 if (numArgsToUse == 3 && std::isnan(milli))
919 msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
921 ms = milli - floor(milli / msPerSecond) * msPerSecond;
922 const GregorianDateTime* other = inputTimeType == WTF::UTCTime
923 ? thisDateObj->gregorianDateTimeUTC(exec)
924 : thisDateObj->gregorianDateTime(exec);
926 return JSValue::encode(jsNaN());
927 gregorianDateTime.copyFrom(*other);
930 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
931 JSValue result = jsNaN();
932 thisDateObj->setInternalValue(vm, result);
933 return JSValue::encode(result);
936 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
937 thisDateObj->setInternalValue(vm, result);
938 return JSValue::encode(result);
941 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
943 return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime);
946 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
948 return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime);
951 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
953 return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime);
956 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
958 return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime);
961 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
963 return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime);
966 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
968 return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime);
971 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
973 return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime);
976 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
978 return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime);
981 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
983 return setNewValueFromDateArgs(exec, 1, WTF::LocalTime);
986 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
988 return setNewValueFromDateArgs(exec, 1, WTF::UTCTime);
991 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
993 return setNewValueFromDateArgs(exec, 2, WTF::LocalTime);
996 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
998 return setNewValueFromDateArgs(exec, 2, WTF::UTCTime);
1001 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1003 return setNewValueFromDateArgs(exec, 3, WTF::LocalTime);
1006 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1008 return setNewValueFromDateArgs(exec, 3, WTF::UTCTime);
1011 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1013 JSValue thisValue = exec->thisValue();
1014 if (!thisValue.inherits(DateInstance::info()))
1015 return throwVMTypeError(exec);
1017 VM& vm = exec->vm();
1018 DateInstance* thisDateObj = asDateInstance(thisValue);
1019 if (!exec->argumentCount()) {
1020 JSValue result = jsNaN();
1021 thisDateObj->setInternalValue(vm, result);
1022 return JSValue::encode(result);
1025 double milli = thisDateObj->internalNumber();
1028 GregorianDateTime gregorianDateTime;
1029 if (std::isnan(milli))
1030 // Based on ECMA 262 B.2.5 (setYear)
1031 // the time must be reset to +0 if it is NaN.
1032 msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
1034 double secs = floor(milli / msPerSecond);
1035 ms = milli - secs * msPerSecond;
1036 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1037 gregorianDateTime.copyFrom(*other);
1040 double year = exec->argument(0).toIntegerPreserveNaN(exec);
1041 if (!std::isfinite(year)) {
1042 JSValue result = jsNaN();
1043 thisDateObj->setInternalValue(vm, result);
1044 return JSValue::encode(result);
1047 gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
1048 JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, WTF::LocalTime));
1049 thisDateObj->setInternalValue(vm, result);
1050 return JSValue::encode(result);
1053 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1055 JSValue thisValue = exec->thisValue();
1056 if (!thisValue.inherits(DateInstance::info()))
1057 return throwVMTypeError(exec);
1059 DateInstance* thisDateObj = asDateInstance(thisValue);
1061 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1062 if (!gregorianDateTime)
1063 return JSValue::encode(jsNaN());
1065 // NOTE: IE returns the full year even in getYear.
1066 return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
1069 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1071 JSValue thisValue = exec->thisValue();
1072 JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
1073 if (exec->hadException())
1074 return JSValue::encode(jsNull());
1076 JSValue timeValue = object->toPrimitive(exec, PreferNumber);
1077 if (exec->hadException())
1078 return JSValue::encode(jsNull());
1079 if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble())))
1080 return JSValue::encode(jsNull());
1082 JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
1083 if (exec->hadException())
1084 return JSValue::encode(jsNull());
1087 CallType callType = getCallData(toISOValue, callData);
1088 if (callType == CallTypeNone)
1089 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function")));
1091 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1092 if (exec->hadException())
1093 return JSValue::encode(jsNull());
1094 if (result.isObject())
1095 return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value")));
1096 return JSValue::encode(result);