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"
37 #if !PLATFORM(MAC) && HAVE(LANGINFO_H)
46 #include <wtf/Assertions.h>
47 #include <wtf/MathExtras.h>
48 #include <wtf/StringExtras.h>
49 #include <wtf/UnusedParam.h>
52 #include <sys/param.h>
60 #include <sys/timeb.h>
63 #if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX)
64 #include <CoreFoundation/CoreFoundation.h>
65 #elif USE(ICU_UNICODE)
66 #include <unicode/udat.h>
69 #if OS(WINCE) && !PLATFORM(QT)
70 extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
77 ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
79 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
80 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
81 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
82 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
83 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
84 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
85 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
86 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
87 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
88 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
89 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
90 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
91 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
92 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
93 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
94 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
95 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
96 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
97 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
98 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
99 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
100 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
101 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
102 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
103 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
104 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
105 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
106 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
107 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
108 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
109 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
110 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
111 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
112 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
113 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
114 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
115 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
116 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
117 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
118 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
119 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
120 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
121 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
122 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
123 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
127 #include "DatePrototype.lut.h"
131 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
133 #if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX)
135 // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
136 // Instead we should consider using this whenever USE(CF) is true.
138 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
140 if (string == "short")
141 return kCFDateFormatterShortStyle;
142 if (string == "medium")
143 return kCFDateFormatterMediumStyle;
144 if (string == "long")
145 return kCFDateFormatterLongStyle;
146 if (string == "full")
147 return kCFDateFormatterFullStyle;
151 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
153 CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
154 CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
156 bool useCustomFormat = false;
157 UString customFormatString;
159 UString arg0String = exec->argument(0).toString(exec)->value(exec);
160 if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
161 useCustomFormat = true;
162 customFormatString = exec->argument(1).toString(exec)->value(exec);
163 } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
164 dateStyle = styleFromArgString(arg0String, dateStyle);
165 timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle);
166 } else if (format != LocaleTime && !exec->argument(0).isUndefined())
167 dateStyle = styleFromArgString(arg0String, dateStyle);
168 else if (format != LocaleDate && !exec->argument(0).isUndefined())
169 timeStyle = styleFromArgString(arg0String, timeStyle);
171 CFLocaleRef locale = CFLocaleCopyCurrent();
172 CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
175 if (useCustomFormat) {
176 CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
177 CFDateFormatterSetFormat(formatter, customFormatCFString);
178 CFRelease(customFormatCFString);
181 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
183 CFRelease(formatter);
185 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
186 // That's not great error handling, but it just won't happen so it doesn't matter.
188 const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
189 size_t length = CFStringGetLength(string);
190 ASSERT(length <= bufferLength);
191 if (length > bufferLength)
192 length = bufferLength;
193 CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
197 return jsNontrivialString(exec, UString(buffer, length));
200 #elif USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING
202 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format)
204 UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
205 UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
207 UErrorCode status = U_ZERO_ERROR;
208 UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
210 return jsEmptyString(exec);
214 length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
216 if (status != U_ZERO_ERROR)
217 return jsEmptyString(exec);
219 return jsNontrivialString(exec, UString(buffer, length));
224 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
227 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
228 #elif (OS(WINCE) && !PLATFORM(QT))
229 // strftime() does not support '#' on WinCE
230 static const char* const formatStrings[] = { "%c", "%x", "%X" };
232 static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
235 // Offset year if needed
236 struct tm localTM = gdt;
237 int year = gdt.year + 1900;
238 bool yearNeedsOffset = year < 1900 || year > 2038;
240 localTM.tm_year = equivalentYearForDST(year) - 1900;
243 // We do not allow strftime to generate dates with 2-digits years,
244 // both to avoid ambiguity, and a crash in strncpy, for years that
246 char* formatString = strdup(nl_langinfo(formats[format]));
247 char* yPos = strchr(formatString, 'y');
253 const int bufsize = 128;
254 char timebuffer[bufsize];
257 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
260 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
264 return jsEmptyString(exec);
266 // Copy original into the buffer
267 if (yearNeedsOffset && format != LocaleTime) {
268 static const int yearLen = 5; // FIXME will be a problem in the year 10,000
269 char yearString[yearLen];
271 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
272 char* yearLocation = strstr(timebuffer, yearString);
273 snprintf(yearString, yearLen, "%d", year);
275 strncpy(yearLocation, yearString, yearLen - 1);
278 // Convert multi-byte result to UNICODE.
279 // If __STDC_ISO_10646__ is defined, wide character represents
280 // UTF-16 (or UTF-32) code point. In most modern Unix like system
281 // (e.g. Linux with glibc 2.2 and above) the macro is defined,
282 // and wide character represents UTF-32 code point.
283 // Here we static_cast potential UTF-32 to UTF-16, it should be
284 // safe because date and (or) time related characters in different languages
285 // should be in UNICODE BMP. If mbstowcs fails, we just fall
286 // back on using multi-byte result as-is.
287 #ifdef __STDC_ISO_10646__
288 UChar buffer[bufsize];
289 wchar_t tempbuffer[bufsize];
290 size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
291 if (length != static_cast<size_t>(-1)) {
292 for (size_t i = 0; i < length; ++i)
293 buffer[i] = static_cast<UChar>(tempbuffer[i]);
294 return jsNontrivialString(exec, UString(buffer, length));
298 return jsNontrivialString(exec, timebuffer);
301 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
303 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
304 if (!gregorianDateTime)
305 return jsNontrivialString(exec, "Invalid Date");
306 return formatLocaleDate(exec, *gregorianDateTime, format);
309 #endif // !PLATFORM(MAC) && !PLATFORM(IOS)
311 // Converts a list of arguments sent to a Date member function into milliseconds, updating
312 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
314 // Format of member function: f([hour,] [min,] [sec,] [ms])
315 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
317 double milliseconds = 0;
320 int numArgs = exec->argumentCount();
322 // JS allows extra trailing arguments -- ignore them
323 if (numArgs > maxArgs)
327 if (maxArgs >= 4 && idx < numArgs) {
329 double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
330 ok = isfinite(hours);
331 milliseconds += hours * msPerHour;
335 if (maxArgs >= 3 && idx < numArgs && ok) {
337 double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
338 ok = isfinite(minutes);
339 milliseconds += minutes * msPerMinute;
343 if (maxArgs >= 2 && idx < numArgs && ok) {
345 double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
346 ok = isfinite(seconds);
347 milliseconds += seconds * msPerSecond;
355 double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
356 ok = isfinite(millis);
357 milliseconds += millis;
365 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
366 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
368 // Format of member function: f([years,] [months,] [days])
369 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
373 int numArgs = exec->argumentCount();
375 // JS allows extra trailing arguments -- ignore them
376 if (numArgs > maxArgs)
380 if (maxArgs >= 3 && idx < numArgs) {
381 double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
382 ok = isfinite(years);
383 t->year = toInt32(years - 1900);
386 if (maxArgs >= 2 && idx < numArgs && ok) {
387 double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
388 ok = isfinite(months);
389 t->month = toInt32(months);
392 if (idx < numArgs && ok) {
393 double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
396 *ms += days * msPerDay;
402 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
404 /* Source for DatePrototype.lut.h
406 toString dateProtoFuncToString DontEnum|Function 0
407 toISOString dateProtoFuncToISOString DontEnum|Function 0
408 toUTCString dateProtoFuncToUTCString DontEnum|Function 0
409 toDateString dateProtoFuncToDateString DontEnum|Function 0
410 toTimeString dateProtoFuncToTimeString DontEnum|Function 0
411 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
412 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
413 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
414 valueOf dateProtoFuncGetTime DontEnum|Function 0
415 getTime dateProtoFuncGetTime DontEnum|Function 0
416 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
417 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
418 toGMTString dateProtoFuncToGMTString DontEnum|Function 0
419 getMonth dateProtoFuncGetMonth DontEnum|Function 0
420 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
421 getDate dateProtoFuncGetDate DontEnum|Function 0
422 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
423 getDay dateProtoFuncGetDay DontEnum|Function 0
424 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
425 getHours dateProtoFuncGetHours DontEnum|Function 0
426 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
427 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
428 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
429 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
430 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
431 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
432 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
433 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
434 setTime dateProtoFuncSetTime DontEnum|Function 1
435 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
436 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
437 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
438 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
439 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
440 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
441 setHours dateProtoFuncSetHours DontEnum|Function 4
442 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
443 setDate dateProtoFuncSetDate DontEnum|Function 1
444 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
445 setMonth dateProtoFuncSetMonth DontEnum|Function 2
446 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
447 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
448 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
449 setYear dateProtoFuncSetYear DontEnum|Function 1
450 getYear dateProtoFuncGetYear DontEnum|Function 0
451 toJSON dateProtoFuncToJSON DontEnum|Function 1
457 DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
458 : DateInstance(exec, structure)
462 void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
464 Base::finishCreation(exec->globalData());
465 ASSERT(inherits(&s_info));
467 // The constructor will be added later, after DateConstructor has been built.
470 bool DatePrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
472 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(cell), propertyName, slot);
475 bool DatePrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
477 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, descriptor);
482 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
484 JSValue thisValue = exec->hostThisValue();
485 if (!thisValue.inherits(&DateInstance::s_info))
486 return throwVMTypeError(exec);
488 DateInstance* thisDateObj = asDateInstance(thisValue);
490 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
491 if (!gregorianDateTime)
492 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
493 DateConversionBuffer date;
494 DateConversionBuffer time;
495 formatDate(*gregorianDateTime, date);
496 formatTime(*gregorianDateTime, time);
497 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
500 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
502 JSValue thisValue = exec->hostThisValue();
503 if (!thisValue.inherits(&DateInstance::s_info))
504 return throwVMTypeError(exec);
506 DateInstance* thisDateObj = asDateInstance(thisValue);
508 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
509 if (!gregorianDateTime)
510 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
511 DateConversionBuffer date;
512 DateConversionBuffer time;
513 formatDateUTCVariant(*gregorianDateTime, date);
514 formatTimeUTC(*gregorianDateTime, time);
515 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
518 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
520 JSValue thisValue = exec->hostThisValue();
521 if (!thisValue.inherits(&DateInstance::s_info))
522 return throwVMTypeError(exec);
524 DateInstance* thisDateObj = asDateInstance(thisValue);
525 if (!isfinite(thisDateObj->internalNumber()))
526 return throwVMError(exec, createRangeError(exec, "Invalid Date"));
528 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
529 if (!gregorianDateTime)
530 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
531 // 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)
532 // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
534 // 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).
535 int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
538 if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900)
539 snprintf(buffer, sizeof(buffer) - 1, "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, ms);
541 snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, ms);
542 buffer[sizeof(buffer) - 1] = 0;
543 return JSValue::encode(jsNontrivialString(exec, buffer));
546 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
548 JSValue thisValue = exec->hostThisValue();
549 if (!thisValue.inherits(&DateInstance::s_info))
550 return throwVMTypeError(exec);
552 DateInstance* thisDateObj = asDateInstance(thisValue);
554 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
555 if (!gregorianDateTime)
556 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
557 DateConversionBuffer date;
558 formatDate(*gregorianDateTime, date);
559 return JSValue::encode(jsNontrivialString(exec, date));
562 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
564 JSValue thisValue = exec->hostThisValue();
565 if (!thisValue.inherits(&DateInstance::s_info))
566 return throwVMTypeError(exec);
568 DateInstance* thisDateObj = asDateInstance(thisValue);
570 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
571 if (!gregorianDateTime)
572 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
573 DateConversionBuffer time;
574 formatTime(*gregorianDateTime, time);
575 return JSValue::encode(jsNontrivialString(exec, time));
578 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
580 JSValue thisValue = exec->hostThisValue();
581 if (!thisValue.inherits(&DateInstance::s_info))
582 return throwVMTypeError(exec);
584 DateInstance* thisDateObj = asDateInstance(thisValue);
585 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
588 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
590 JSValue thisValue = exec->hostThisValue();
591 if (!thisValue.inherits(&DateInstance::s_info))
592 return throwVMTypeError(exec);
594 DateInstance* thisDateObj = asDateInstance(thisValue);
595 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
598 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
600 JSValue thisValue = exec->hostThisValue();
601 if (!thisValue.inherits(&DateInstance::s_info))
602 return throwVMTypeError(exec);
604 DateInstance* thisDateObj = asDateInstance(thisValue);
605 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
608 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
610 JSValue thisValue = exec->hostThisValue();
611 if (!thisValue.inherits(&DateInstance::s_info))
612 return throwVMTypeError(exec);
614 return JSValue::encode(asDateInstance(thisValue)->internalValue());
617 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
619 JSValue thisValue = exec->hostThisValue();
620 if (!thisValue.inherits(&DateInstance::s_info))
621 return throwVMTypeError(exec);
623 DateInstance* thisDateObj = asDateInstance(thisValue);
625 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
626 if (!gregorianDateTime)
627 return JSValue::encode(jsNaN());
628 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
631 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
633 JSValue thisValue = exec->hostThisValue();
634 if (!thisValue.inherits(&DateInstance::s_info))
635 return throwVMTypeError(exec);
637 DateInstance* thisDateObj = asDateInstance(thisValue);
639 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
640 if (!gregorianDateTime)
641 return JSValue::encode(jsNaN());
642 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
645 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
647 JSValue thisValue = exec->hostThisValue();
648 if (!thisValue.inherits(&DateInstance::s_info))
649 return throwVMTypeError(exec);
651 DateInstance* thisDateObj = asDateInstance(thisValue);
653 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
654 if (!gregorianDateTime)
655 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
656 DateConversionBuffer date;
657 DateConversionBuffer time;
658 formatDateUTCVariant(*gregorianDateTime, date);
659 formatTimeUTC(*gregorianDateTime, time);
660 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
663 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
665 JSValue thisValue = exec->hostThisValue();
666 if (!thisValue.inherits(&DateInstance::s_info))
667 return throwVMTypeError(exec);
669 DateInstance* thisDateObj = asDateInstance(thisValue);
671 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
672 if (!gregorianDateTime)
673 return JSValue::encode(jsNaN());
674 return JSValue::encode(jsNumber(gregorianDateTime->month));
677 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
679 JSValue thisValue = exec->hostThisValue();
680 if (!thisValue.inherits(&DateInstance::s_info))
681 return throwVMTypeError(exec);
683 DateInstance* thisDateObj = asDateInstance(thisValue);
685 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
686 if (!gregorianDateTime)
687 return JSValue::encode(jsNaN());
688 return JSValue::encode(jsNumber(gregorianDateTime->month));
691 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
693 JSValue thisValue = exec->hostThisValue();
694 if (!thisValue.inherits(&DateInstance::s_info))
695 return throwVMTypeError(exec);
697 DateInstance* thisDateObj = asDateInstance(thisValue);
699 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
700 if (!gregorianDateTime)
701 return JSValue::encode(jsNaN());
702 return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
705 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
707 JSValue thisValue = exec->hostThisValue();
708 if (!thisValue.inherits(&DateInstance::s_info))
709 return throwVMTypeError(exec);
711 DateInstance* thisDateObj = asDateInstance(thisValue);
713 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
714 if (!gregorianDateTime)
715 return JSValue::encode(jsNaN());
716 return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
719 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
721 JSValue thisValue = exec->hostThisValue();
722 if (!thisValue.inherits(&DateInstance::s_info))
723 return throwVMTypeError(exec);
725 DateInstance* thisDateObj = asDateInstance(thisValue);
727 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
728 if (!gregorianDateTime)
729 return JSValue::encode(jsNaN());
730 return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
733 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
735 JSValue thisValue = exec->hostThisValue();
736 if (!thisValue.inherits(&DateInstance::s_info))
737 return throwVMTypeError(exec);
739 DateInstance* thisDateObj = asDateInstance(thisValue);
741 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
742 if (!gregorianDateTime)
743 return JSValue::encode(jsNaN());
744 return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
747 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
749 JSValue thisValue = exec->hostThisValue();
750 if (!thisValue.inherits(&DateInstance::s_info))
751 return throwVMTypeError(exec);
753 DateInstance* thisDateObj = asDateInstance(thisValue);
755 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
756 if (!gregorianDateTime)
757 return JSValue::encode(jsNaN());
758 return JSValue::encode(jsNumber(gregorianDateTime->hour));
761 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
763 JSValue thisValue = exec->hostThisValue();
764 if (!thisValue.inherits(&DateInstance::s_info))
765 return throwVMTypeError(exec);
767 DateInstance* thisDateObj = asDateInstance(thisValue);
769 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
770 if (!gregorianDateTime)
771 return JSValue::encode(jsNaN());
772 return JSValue::encode(jsNumber(gregorianDateTime->hour));
775 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
777 JSValue thisValue = exec->hostThisValue();
778 if (!thisValue.inherits(&DateInstance::s_info))
779 return throwVMTypeError(exec);
781 DateInstance* thisDateObj = asDateInstance(thisValue);
783 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
784 if (!gregorianDateTime)
785 return JSValue::encode(jsNaN());
786 return JSValue::encode(jsNumber(gregorianDateTime->minute));
789 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
791 JSValue thisValue = exec->hostThisValue();
792 if (!thisValue.inherits(&DateInstance::s_info))
793 return throwVMTypeError(exec);
795 DateInstance* thisDateObj = asDateInstance(thisValue);
797 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
798 if (!gregorianDateTime)
799 return JSValue::encode(jsNaN());
800 return JSValue::encode(jsNumber(gregorianDateTime->minute));
803 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
805 JSValue thisValue = exec->hostThisValue();
806 if (!thisValue.inherits(&DateInstance::s_info))
807 return throwVMTypeError(exec);
809 DateInstance* thisDateObj = asDateInstance(thisValue);
811 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
812 if (!gregorianDateTime)
813 return JSValue::encode(jsNaN());
814 return JSValue::encode(jsNumber(gregorianDateTime->second));
817 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
819 JSValue thisValue = exec->hostThisValue();
820 if (!thisValue.inherits(&DateInstance::s_info))
821 return throwVMTypeError(exec);
823 DateInstance* thisDateObj = asDateInstance(thisValue);
825 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
826 if (!gregorianDateTime)
827 return JSValue::encode(jsNaN());
828 return JSValue::encode(jsNumber(gregorianDateTime->second));
831 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
833 JSValue thisValue = exec->hostThisValue();
834 if (!thisValue.inherits(&DateInstance::s_info))
835 return throwVMTypeError(exec);
837 DateInstance* thisDateObj = asDateInstance(thisValue);
838 double milli = thisDateObj->internalNumber();
840 return JSValue::encode(jsNaN());
842 double secs = floor(milli / msPerSecond);
843 double ms = milli - secs * msPerSecond;
844 return JSValue::encode(jsNumber(ms));
847 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
849 JSValue thisValue = exec->hostThisValue();
850 if (!thisValue.inherits(&DateInstance::s_info))
851 return throwVMTypeError(exec);
853 DateInstance* thisDateObj = asDateInstance(thisValue);
854 double milli = thisDateObj->internalNumber();
856 return JSValue::encode(jsNaN());
858 double secs = floor(milli / msPerSecond);
859 double ms = milli - secs * msPerSecond;
860 return JSValue::encode(jsNumber(ms));
863 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
865 JSValue thisValue = exec->hostThisValue();
866 if (!thisValue.inherits(&DateInstance::s_info))
867 return throwVMTypeError(exec);
869 DateInstance* thisDateObj = asDateInstance(thisValue);
871 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
872 if (!gregorianDateTime)
873 return JSValue::encode(jsNaN());
874 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
877 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
879 JSValue thisValue = exec->hostThisValue();
880 if (!thisValue.inherits(&DateInstance::s_info))
881 return throwVMTypeError(exec);
883 DateInstance* thisDateObj = asDateInstance(thisValue);
885 double milli = timeClip(exec->argument(0).toNumber(exec));
886 JSValue result = jsNumber(milli);
887 thisDateObj->setInternalValue(exec->globalData(), result);
888 return JSValue::encode(result);
891 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
893 JSValue thisValue = exec->hostThisValue();
894 if (!thisValue.inherits(&DateInstance::s_info))
895 return throwVMTypeError(exec);
897 DateInstance* thisDateObj = asDateInstance(thisValue);
898 double milli = thisDateObj->internalNumber();
900 if (!exec->argumentCount() || isnan(milli)) {
901 JSValue result = jsNaN();
902 thisDateObj->setInternalValue(exec->globalData(), result);
903 return JSValue::encode(result);
906 double secs = floor(milli / msPerSecond);
907 double ms = milli - secs * msPerSecond;
909 const GregorianDateTime* other = inputIsUTC
910 ? thisDateObj->gregorianDateTimeUTC(exec)
911 : thisDateObj->gregorianDateTime(exec);
913 return JSValue::encode(jsNaN());
915 GregorianDateTime gregorianDateTime;
916 gregorianDateTime.copyFrom(*other);
917 if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
918 JSValue result = jsNaN();
919 thisDateObj->setInternalValue(exec->globalData(), result);
920 return JSValue::encode(result);
923 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
924 thisDateObj->setInternalValue(exec->globalData(), result);
925 return JSValue::encode(result);
928 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
930 JSValue thisValue = exec->hostThisValue();
931 if (!thisValue.inherits(&DateInstance::s_info))
932 return throwVMTypeError(exec);
934 DateInstance* thisDateObj = asDateInstance(thisValue);
935 if (!exec->argumentCount()) {
936 JSValue result = jsNaN();
937 thisDateObj->setInternalValue(exec->globalData(), result);
938 return JSValue::encode(result);
941 double milli = thisDateObj->internalNumber();
944 GregorianDateTime gregorianDateTime;
945 if (numArgsToUse == 3 && isnan(milli))
946 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
948 ms = milli - floor(milli / msPerSecond) * msPerSecond;
949 const GregorianDateTime* other = inputIsUTC
950 ? thisDateObj->gregorianDateTimeUTC(exec)
951 : thisDateObj->gregorianDateTime(exec);
953 return JSValue::encode(jsNaN());
954 gregorianDateTime.copyFrom(*other);
957 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
958 JSValue result = jsNaN();
959 thisDateObj->setInternalValue(exec->globalData(), result);
960 return JSValue::encode(result);
963 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
964 thisDateObj->setInternalValue(exec->globalData(), result);
965 return JSValue::encode(result);
968 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
970 const bool inputIsUTC = false;
971 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
974 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
976 const bool inputIsUTC = true;
977 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
980 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
982 const bool inputIsUTC = false;
983 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
986 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
988 const bool inputIsUTC = true;
989 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
992 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
994 const bool inputIsUTC = false;
995 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
998 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
1000 const bool inputIsUTC = true;
1001 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
1004 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
1006 const bool inputIsUTC = false;
1007 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
1010 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
1012 const bool inputIsUTC = true;
1013 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
1016 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
1018 const bool inputIsUTC = false;
1019 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1022 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
1024 const bool inputIsUTC = true;
1025 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1028 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1030 const bool inputIsUTC = false;
1031 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1034 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1036 const bool inputIsUTC = true;
1037 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1040 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1042 const bool inputIsUTC = false;
1043 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1046 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1048 const bool inputIsUTC = true;
1049 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1052 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1054 JSValue thisValue = exec->hostThisValue();
1055 if (!thisValue.inherits(&DateInstance::s_info))
1056 return throwVMTypeError(exec);
1058 DateInstance* thisDateObj = asDateInstance(thisValue);
1059 if (!exec->argumentCount()) {
1060 JSValue result = jsNaN();
1061 thisDateObj->setInternalValue(exec->globalData(), result);
1062 return JSValue::encode(result);
1065 double milli = thisDateObj->internalNumber();
1068 GregorianDateTime gregorianDateTime;
1070 // Based on ECMA 262 B.2.5 (setYear)
1071 // the time must be reset to +0 if it is NaN.
1072 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1074 double secs = floor(milli / msPerSecond);
1075 ms = milli - secs * msPerSecond;
1076 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1077 gregorianDateTime.copyFrom(*other);
1080 double year = exec->argument(0).toIntegerPreserveNaN(exec);
1081 if (!isfinite(year)) {
1082 JSValue result = jsNaN();
1083 thisDateObj->setInternalValue(exec->globalData(), result);
1084 return JSValue::encode(result);
1087 gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
1088 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1089 thisDateObj->setInternalValue(exec->globalData(), result);
1090 return JSValue::encode(result);
1093 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1095 JSValue thisValue = exec->hostThisValue();
1096 if (!thisValue.inherits(&DateInstance::s_info))
1097 return throwVMTypeError(exec);
1099 DateInstance* thisDateObj = asDateInstance(thisValue);
1101 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1102 if (!gregorianDateTime)
1103 return JSValue::encode(jsNaN());
1105 // NOTE: IE returns the full year even in getYear.
1106 return JSValue::encode(jsNumber(gregorianDateTime->year));
1109 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1111 JSValue thisValue = exec->hostThisValue();
1112 JSObject* object = thisValue.toThisObject(exec);
1113 if (exec->hadException())
1114 return JSValue::encode(jsNull());
1116 JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
1117 if (exec->hadException())
1118 return JSValue::encode(jsNull());
1121 CallType callType = getCallData(toISOValue, callData);
1122 if (callType == CallTypeNone)
1123 return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
1125 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1126 if (exec->hadException())
1127 return JSValue::encode(jsNull());
1128 if (result.isObject())
1129 return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
1130 return JSValue::encode(result);