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)
64 #include <CoreFoundation/CoreFoundation.h>
67 #if OS(WINCE) && !PLATFORM(QT)
68 extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
75 ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
77 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
78 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
79 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
80 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
81 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
82 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
83 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
84 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
85 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
86 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
87 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
88 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
89 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
90 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
91 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
92 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
93 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
94 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
95 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
96 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
97 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
98 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
99 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
100 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
101 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
102 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
103 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
104 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
105 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
106 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
107 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
108 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
109 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
110 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
111 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
112 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
113 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
114 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
115 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
116 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
117 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
118 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
119 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
120 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
121 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
124 #include "DatePrototype.lut.h"
128 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
130 #if PLATFORM(MAC) || PLATFORM(IOS)
132 // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
133 // Instead we should consider using this whenever USE(CF) is true.
135 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
137 if (string == "short")
138 return kCFDateFormatterShortStyle;
139 if (string == "medium")
140 return kCFDateFormatterMediumStyle;
141 if (string == "long")
142 return kCFDateFormatterLongStyle;
143 if (string == "full")
144 return kCFDateFormatterFullStyle;
148 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
150 CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
151 CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
153 bool useCustomFormat = false;
154 UString customFormatString;
156 UString arg0String = exec->argument(0).toString(exec);
157 if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
158 useCustomFormat = true;
159 customFormatString = exec->argument(1).toString(exec);
160 } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
161 dateStyle = styleFromArgString(arg0String, dateStyle);
162 timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle);
163 } else if (format != LocaleTime && !exec->argument(0).isUndefined())
164 dateStyle = styleFromArgString(arg0String, dateStyle);
165 else if (format != LocaleDate && !exec->argument(0).isUndefined())
166 timeStyle = styleFromArgString(arg0String, timeStyle);
168 CFLocaleRef locale = CFLocaleCopyCurrent();
169 CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
172 if (useCustomFormat) {
173 CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
174 CFDateFormatterSetFormat(formatter, customFormatCFString);
175 CFRelease(customFormatCFString);
178 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
180 CFRelease(formatter);
182 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
183 // That's not great error handling, but it just won't happen so it doesn't matter.
185 const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
186 size_t length = CFStringGetLength(string);
187 ASSERT(length <= bufferLength);
188 if (length > bufferLength)
189 length = bufferLength;
190 CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
194 return jsNontrivialString(exec, UString(buffer, length));
197 #else // !PLATFORM(MAC) && !PLATFORM(IOS)
199 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
202 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
203 #elif (OS(WINCE) && !PLATFORM(QT))
204 // strftime() does not support '#' on WinCE
205 static const char* const formatStrings[] = { "%c", "%x", "%X" };
207 static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
210 // Offset year if needed
211 struct tm localTM = gdt;
212 int year = gdt.year + 1900;
213 bool yearNeedsOffset = year < 1900 || year > 2038;
215 localTM.tm_year = equivalentYearForDST(year) - 1900;
218 // We do not allow strftime to generate dates with 2-digits years,
219 // both to avoid ambiguity, and a crash in strncpy, for years that
221 char* formatString = strdup(nl_langinfo(formats[format]));
222 char* yPos = strchr(formatString, 'y');
228 const int bufsize = 128;
229 char timebuffer[bufsize];
232 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
235 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
239 return jsEmptyString(exec);
241 // Copy original into the buffer
242 if (yearNeedsOffset && format != LocaleTime) {
243 static const int yearLen = 5; // FIXME will be a problem in the year 10,000
244 char yearString[yearLen];
246 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
247 char* yearLocation = strstr(timebuffer, yearString);
248 snprintf(yearString, yearLen, "%d", year);
250 strncpy(yearLocation, yearString, yearLen - 1);
253 // Convert multi-byte result to UNICODE.
254 // If __STDC_ISO_10646__ is defined, wide character represents
255 // UTF-16 (or UTF-32) code point. In most modern Unix like system
256 // (e.g. Linux with glibc 2.2 and above) the macro is defined,
257 // and wide character represents UTF-32 code point.
258 // Here we static_cast potential UTF-32 to UTF-16, it should be
259 // safe because date and (or) time related characters in different languages
260 // should be in UNICODE BMP. If mbstowcs fails, we just fall
261 // back on using multi-byte result as-is.
262 #ifdef __STDC_ISO_10646__
263 UChar buffer[bufsize];
264 wchar_t tempbuffer[bufsize];
265 size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
266 if (length != static_cast<size_t>(-1)) {
267 for (size_t i = 0; i < length; ++i)
268 buffer[i] = static_cast<UChar>(tempbuffer[i]);
269 return jsNontrivialString(exec, UString(buffer, length));
273 return jsNontrivialString(exec, timebuffer);
276 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
278 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
279 if (!gregorianDateTime)
280 return jsNontrivialString(exec, "Invalid Date");
281 return formatLocaleDate(exec, *gregorianDateTime, format);
284 #endif // !PLATFORM(MAC) && !PLATFORM(IOS)
286 // Converts a list of arguments sent to a Date member function into milliseconds, updating
287 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
289 // Format of member function: f([hour,] [min,] [sec,] [ms])
290 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
292 double milliseconds = 0;
295 int numArgs = exec->argumentCount();
297 // JS allows extra trailing arguments -- ignore them
298 if (numArgs > maxArgs)
302 if (maxArgs >= 4 && idx < numArgs) {
304 double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
305 ok = isfinite(hours);
306 milliseconds += hours * msPerHour;
310 if (maxArgs >= 3 && idx < numArgs && ok) {
312 double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
313 ok = isfinite(minutes);
314 milliseconds += minutes * msPerMinute;
318 if (maxArgs >= 2 && idx < numArgs && ok) {
320 double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
321 ok = isfinite(seconds);
322 milliseconds += seconds * msPerSecond;
330 double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
331 ok = isfinite(millis);
332 milliseconds += millis;
340 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
341 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
343 // Format of member function: f([years,] [months,] [days])
344 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
348 int numArgs = exec->argumentCount();
350 // JS allows extra trailing arguments -- ignore them
351 if (numArgs > maxArgs)
355 if (maxArgs >= 3 && idx < numArgs) {
356 double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
357 ok = isfinite(years);
358 t->year = toInt32(years - 1900);
361 if (maxArgs >= 2 && idx < numArgs && ok) {
362 double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
363 ok = isfinite(months);
364 t->month = toInt32(months);
367 if (idx < numArgs && ok) {
368 double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
371 *ms += days * msPerDay;
377 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
379 /* Source for DatePrototype.lut.h
381 toString dateProtoFuncToString DontEnum|Function 0
382 toISOString dateProtoFuncToISOString DontEnum|Function 0
383 toUTCString dateProtoFuncToUTCString DontEnum|Function 0
384 toDateString dateProtoFuncToDateString DontEnum|Function 0
385 toTimeString dateProtoFuncToTimeString DontEnum|Function 0
386 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
387 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
388 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
389 valueOf dateProtoFuncGetTime DontEnum|Function 0
390 getTime dateProtoFuncGetTime DontEnum|Function 0
391 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
392 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
393 toGMTString dateProtoFuncToGMTString DontEnum|Function 0
394 getMonth dateProtoFuncGetMonth DontEnum|Function 0
395 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
396 getDate dateProtoFuncGetDate DontEnum|Function 0
397 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
398 getDay dateProtoFuncGetDay DontEnum|Function 0
399 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
400 getHours dateProtoFuncGetHours DontEnum|Function 0
401 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
402 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
403 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
404 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
405 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
406 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
407 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
408 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
409 setTime dateProtoFuncSetTime DontEnum|Function 1
410 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
411 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
412 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
413 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
414 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
415 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
416 setHours dateProtoFuncSetHours DontEnum|Function 4
417 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
418 setDate dateProtoFuncSetDate DontEnum|Function 1
419 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
420 setMonth dateProtoFuncSetMonth DontEnum|Function 2
421 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
422 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
423 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
424 setYear dateProtoFuncSetYear DontEnum|Function 1
425 getYear dateProtoFuncGetYear DontEnum|Function 0
426 toJSON dateProtoFuncToJSON DontEnum|Function 1
432 DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
433 : DateInstance(exec, structure)
437 void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
439 Base::finishCreation(exec->globalData());
440 ASSERT(inherits(&s_info));
442 // The constructor will be added later, after DateConstructor has been built.
445 bool DatePrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
447 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(cell), propertyName, slot);
450 bool DatePrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
452 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, descriptor);
457 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
459 JSValue thisValue = exec->hostThisValue();
460 if (!thisValue.inherits(&DateInstance::s_info))
461 return throwVMTypeError(exec);
463 DateInstance* thisDateObj = asDateInstance(thisValue);
465 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
466 if (!gregorianDateTime)
467 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
468 DateConversionBuffer date;
469 DateConversionBuffer time;
470 formatDate(*gregorianDateTime, date);
471 formatTime(*gregorianDateTime, time);
472 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
475 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
477 JSValue thisValue = exec->hostThisValue();
478 if (!thisValue.inherits(&DateInstance::s_info))
479 return throwVMTypeError(exec);
481 DateInstance* thisDateObj = asDateInstance(thisValue);
483 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
484 if (!gregorianDateTime)
485 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
486 DateConversionBuffer date;
487 DateConversionBuffer time;
488 formatDateUTCVariant(*gregorianDateTime, date);
489 formatTimeUTC(*gregorianDateTime, time);
490 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
493 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
495 JSValue thisValue = exec->hostThisValue();
496 if (!thisValue.inherits(&DateInstance::s_info))
497 return throwVMTypeError(exec);
499 DateInstance* thisDateObj = asDateInstance(thisValue);
500 if (!isfinite(thisDateObj->internalNumber()))
501 return throwVMError(exec, createRangeError(exec, "Invalid Date"));
503 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
504 if (!gregorianDateTime)
505 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
506 // 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)
507 // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
509 // 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).
510 if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900)
511 snprintf(buffer, sizeof(buffer) - 1, "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000)));
513 snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000)));
514 buffer[sizeof(buffer) - 1] = 0;
515 return JSValue::encode(jsNontrivialString(exec, buffer));
518 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
520 JSValue thisValue = exec->hostThisValue();
521 if (!thisValue.inherits(&DateInstance::s_info))
522 return throwVMTypeError(exec);
524 DateInstance* thisDateObj = asDateInstance(thisValue);
526 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
527 if (!gregorianDateTime)
528 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
529 DateConversionBuffer date;
530 formatDate(*gregorianDateTime, date);
531 return JSValue::encode(jsNontrivialString(exec, date));
534 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
536 JSValue thisValue = exec->hostThisValue();
537 if (!thisValue.inherits(&DateInstance::s_info))
538 return throwVMTypeError(exec);
540 DateInstance* thisDateObj = asDateInstance(thisValue);
542 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
543 if (!gregorianDateTime)
544 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
545 DateConversionBuffer time;
546 formatTime(*gregorianDateTime, time);
547 return JSValue::encode(jsNontrivialString(exec, time));
550 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
552 JSValue thisValue = exec->hostThisValue();
553 if (!thisValue.inherits(&DateInstance::s_info))
554 return throwVMTypeError(exec);
556 DateInstance* thisDateObj = asDateInstance(thisValue);
557 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
560 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
562 JSValue thisValue = exec->hostThisValue();
563 if (!thisValue.inherits(&DateInstance::s_info))
564 return throwVMTypeError(exec);
566 DateInstance* thisDateObj = asDateInstance(thisValue);
567 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
570 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
572 JSValue thisValue = exec->hostThisValue();
573 if (!thisValue.inherits(&DateInstance::s_info))
574 return throwVMTypeError(exec);
576 DateInstance* thisDateObj = asDateInstance(thisValue);
577 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
580 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
582 JSValue thisValue = exec->hostThisValue();
583 if (!thisValue.inherits(&DateInstance::s_info))
584 return throwVMTypeError(exec);
586 return JSValue::encode(asDateInstance(thisValue)->internalValue());
589 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
591 JSValue thisValue = exec->hostThisValue();
592 if (!thisValue.inherits(&DateInstance::s_info))
593 return throwVMTypeError(exec);
595 DateInstance* thisDateObj = asDateInstance(thisValue);
597 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
598 if (!gregorianDateTime)
599 return JSValue::encode(jsNaN());
600 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
603 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
605 JSValue thisValue = exec->hostThisValue();
606 if (!thisValue.inherits(&DateInstance::s_info))
607 return throwVMTypeError(exec);
609 DateInstance* thisDateObj = asDateInstance(thisValue);
611 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
612 if (!gregorianDateTime)
613 return JSValue::encode(jsNaN());
614 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
617 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(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->gregorianDateTimeUTC(exec);
626 if (!gregorianDateTime)
627 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
628 DateConversionBuffer date;
629 DateConversionBuffer time;
630 formatDateUTCVariant(*gregorianDateTime, date);
631 formatTimeUTC(*gregorianDateTime, time);
632 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
635 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
637 JSValue thisValue = exec->hostThisValue();
638 if (!thisValue.inherits(&DateInstance::s_info))
639 return throwVMTypeError(exec);
641 DateInstance* thisDateObj = asDateInstance(thisValue);
643 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
644 if (!gregorianDateTime)
645 return JSValue::encode(jsNaN());
646 return JSValue::encode(jsNumber(gregorianDateTime->month));
649 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
651 JSValue thisValue = exec->hostThisValue();
652 if (!thisValue.inherits(&DateInstance::s_info))
653 return throwVMTypeError(exec);
655 DateInstance* thisDateObj = asDateInstance(thisValue);
657 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
658 if (!gregorianDateTime)
659 return JSValue::encode(jsNaN());
660 return JSValue::encode(jsNumber(gregorianDateTime->month));
663 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(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->monthDay));
677 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(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->monthDay));
691 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(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->weekDay));
705 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(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->weekDay));
719 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(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->hour));
733 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(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->hour));
747 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(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->minute));
761 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(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->minute));
775 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(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->second));
789 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(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->second));
803 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
805 JSValue thisValue = exec->hostThisValue();
806 if (!thisValue.inherits(&DateInstance::s_info))
807 return throwVMTypeError(exec);
809 DateInstance* thisDateObj = asDateInstance(thisValue);
810 double milli = thisDateObj->internalNumber();
812 return JSValue::encode(jsNaN());
814 double secs = floor(milli / msPerSecond);
815 double ms = milli - secs * msPerSecond;
816 return JSValue::encode(jsNumber(ms));
819 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
821 JSValue thisValue = exec->hostThisValue();
822 if (!thisValue.inherits(&DateInstance::s_info))
823 return throwVMTypeError(exec);
825 DateInstance* thisDateObj = asDateInstance(thisValue);
826 double milli = thisDateObj->internalNumber();
828 return JSValue::encode(jsNaN());
830 double secs = floor(milli / msPerSecond);
831 double ms = milli - secs * msPerSecond;
832 return JSValue::encode(jsNumber(ms));
835 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
837 JSValue thisValue = exec->hostThisValue();
838 if (!thisValue.inherits(&DateInstance::s_info))
839 return throwVMTypeError(exec);
841 DateInstance* thisDateObj = asDateInstance(thisValue);
843 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
844 if (!gregorianDateTime)
845 return JSValue::encode(jsNaN());
846 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
849 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
851 JSValue thisValue = exec->hostThisValue();
852 if (!thisValue.inherits(&DateInstance::s_info))
853 return throwVMTypeError(exec);
855 DateInstance* thisDateObj = asDateInstance(thisValue);
857 double milli = timeClip(exec->argument(0).toNumber(exec));
858 JSValue result = jsNumber(milli);
859 thisDateObj->setInternalValue(exec->globalData(), result);
860 return JSValue::encode(result);
863 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
865 JSValue thisValue = exec->hostThisValue();
866 if (!thisValue.inherits(&DateInstance::s_info))
867 return throwVMTypeError(exec);
869 DateInstance* thisDateObj = asDateInstance(thisValue);
870 double milli = thisDateObj->internalNumber();
872 if (!exec->argumentCount() || isnan(milli)) {
873 JSValue result = jsNaN();
874 thisDateObj->setInternalValue(exec->globalData(), result);
875 return JSValue::encode(result);
878 double secs = floor(milli / msPerSecond);
879 double ms = milli - secs * msPerSecond;
881 const GregorianDateTime* other = inputIsUTC
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(exec->globalData(), result);
892 return JSValue::encode(result);
895 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
896 thisDateObj->setInternalValue(exec->globalData(), result);
897 return JSValue::encode(result);
900 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
902 JSValue thisValue = exec->hostThisValue();
903 if (!thisValue.inherits(&DateInstance::s_info))
904 return throwVMTypeError(exec);
906 DateInstance* thisDateObj = asDateInstance(thisValue);
907 if (!exec->argumentCount()) {
908 JSValue result = jsNaN();
909 thisDateObj->setInternalValue(exec->globalData(), result);
910 return JSValue::encode(result);
913 double milli = thisDateObj->internalNumber();
916 GregorianDateTime gregorianDateTime;
917 if (numArgsToUse == 3 && isnan(milli))
918 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
920 ms = milli - floor(milli / msPerSecond) * msPerSecond;
921 const GregorianDateTime* other = inputIsUTC
922 ? thisDateObj->gregorianDateTimeUTC(exec)
923 : thisDateObj->gregorianDateTime(exec);
925 return JSValue::encode(jsNaN());
926 gregorianDateTime.copyFrom(*other);
929 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
930 JSValue result = jsNaN();
931 thisDateObj->setInternalValue(exec->globalData(), result);
932 return JSValue::encode(result);
935 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
936 thisDateObj->setInternalValue(exec->globalData(), result);
937 return JSValue::encode(result);
940 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
942 const bool inputIsUTC = false;
943 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
946 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
948 const bool inputIsUTC = true;
949 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
952 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
954 const bool inputIsUTC = false;
955 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
958 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
960 const bool inputIsUTC = true;
961 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
964 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
966 const bool inputIsUTC = false;
967 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
970 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
972 const bool inputIsUTC = true;
973 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
976 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
978 const bool inputIsUTC = false;
979 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
982 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
984 const bool inputIsUTC = true;
985 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
988 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
990 const bool inputIsUTC = false;
991 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
994 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
996 const bool inputIsUTC = true;
997 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
1000 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1002 const bool inputIsUTC = false;
1003 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1006 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1008 const bool inputIsUTC = true;
1009 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1012 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1014 const bool inputIsUTC = false;
1015 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1018 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1020 const bool inputIsUTC = true;
1021 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1024 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1026 JSValue thisValue = exec->hostThisValue();
1027 if (!thisValue.inherits(&DateInstance::s_info))
1028 return throwVMTypeError(exec);
1030 DateInstance* thisDateObj = asDateInstance(thisValue);
1031 if (!exec->argumentCount()) {
1032 JSValue result = jsNaN();
1033 thisDateObj->setInternalValue(exec->globalData(), result);
1034 return JSValue::encode(result);
1037 double milli = thisDateObj->internalNumber();
1040 GregorianDateTime gregorianDateTime;
1042 // Based on ECMA 262 B.2.5 (setYear)
1043 // the time must be reset to +0 if it is NaN.
1044 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1046 double secs = floor(milli / msPerSecond);
1047 ms = milli - secs * msPerSecond;
1048 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1049 gregorianDateTime.copyFrom(*other);
1052 double year = exec->argument(0).toIntegerPreserveNaN(exec);
1053 if (!isfinite(year)) {
1054 JSValue result = jsNaN();
1055 thisDateObj->setInternalValue(exec->globalData(), result);
1056 return JSValue::encode(result);
1059 gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
1060 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1061 thisDateObj->setInternalValue(exec->globalData(), result);
1062 return JSValue::encode(result);
1065 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1067 JSValue thisValue = exec->hostThisValue();
1068 if (!thisValue.inherits(&DateInstance::s_info))
1069 return throwVMTypeError(exec);
1071 DateInstance* thisDateObj = asDateInstance(thisValue);
1073 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1074 if (!gregorianDateTime)
1075 return JSValue::encode(jsNaN());
1077 // NOTE: IE returns the full year even in getYear.
1078 return JSValue::encode(jsNumber(gregorianDateTime->year));
1081 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1083 JSValue thisValue = exec->hostThisValue();
1084 JSObject* object = thisValue.toThisObject(exec);
1085 if (exec->hadException())
1086 return JSValue::encode(jsNull());
1088 JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
1089 if (exec->hadException())
1090 return JSValue::encode(jsNull());
1093 CallType callType = getCallData(toISOValue, callData);
1094 if (callType == CallTypeNone)
1095 return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
1097 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1098 if (exec->hadException())
1099 return JSValue::encode(jsNull());
1100 if (result.isObject())
1101 return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
1102 return JSValue::encode(result);