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"
31 #include "JSStringBuilder.h"
33 #include "ObjectPrototype.h"
35 #if !PLATFORM(MAC) && HAVE(LANGINFO_H)
44 #include <wtf/Assertions.h>
45 #include <wtf/DateMath.h>
46 #include <wtf/MathExtras.h>
47 #include <wtf/StringExtras.h>
48 #include <wtf/UnusedParam.h>
51 #include <sys/param.h>
59 #include <sys/timeb.h>
63 #include <CoreFoundation/CoreFoundation.h>
66 #if OS(WINCE) && !PLATFORM(QT)
67 extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
74 ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
76 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
77 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
78 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
79 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
80 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
81 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
82 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
83 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
84 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
85 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
86 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
87 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
88 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
89 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
90 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
91 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
92 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
93 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
94 static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
95 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
96 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
97 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
98 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
99 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
100 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
101 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
102 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
103 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
104 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
105 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
106 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
107 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
108 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
109 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
110 static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
111 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
112 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
113 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
114 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
115 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
116 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
117 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
118 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
119 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
120 static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
124 #include "DatePrototype.lut.h"
128 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
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 PLATFORM(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)
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)) || OS(SYMBIAN)
204 // strftime() does not support '#' on WinCE or Symbian
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)
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::info = {"Date", &DateInstance::info, 0, ExecState::dateTable};
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, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure)
433 : DateInstance(exec, structure)
435 // The constructor will be added later, after DateConstructor has been built.
436 putAnonymousValue(0, globalObject);
439 bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
441 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot);
445 bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
447 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
452 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
454 JSValue thisValue = exec->hostThisValue();
455 if (!thisValue.inherits(&DateInstance::info))
456 return throwVMTypeError(exec);
458 DateInstance* thisDateObj = asDateInstance(thisValue);
460 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
461 if (!gregorianDateTime)
462 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
463 DateConversionBuffer date;
464 DateConversionBuffer time;
465 formatDate(*gregorianDateTime, date);
466 formatTime(*gregorianDateTime, time);
467 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
470 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
472 JSValue thisValue = exec->hostThisValue();
473 if (!thisValue.inherits(&DateInstance::info))
474 return throwVMTypeError(exec);
476 DateInstance* thisDateObj = asDateInstance(thisValue);
478 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
479 if (!gregorianDateTime)
480 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
481 DateConversionBuffer date;
482 DateConversionBuffer time;
483 formatDateUTCVariant(*gregorianDateTime, date);
484 formatTimeUTC(*gregorianDateTime, time);
485 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
488 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
490 JSValue thisValue = exec->hostThisValue();
491 if (!thisValue.inherits(&DateInstance::info))
492 return throwVMTypeError(exec);
494 DateInstance* thisDateObj = asDateInstance(thisValue);
496 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
497 if (!gregorianDateTime)
498 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
499 // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
500 // 6 for formatting and one for null termination = 27. We add one extra character to allow us to force null termination.
502 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)));
503 buffer[sizeof(buffer) - 1] = 0;
504 return JSValue::encode(jsNontrivialString(exec, buffer));
507 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
509 JSValue thisValue = exec->hostThisValue();
510 if (!thisValue.inherits(&DateInstance::info))
511 return throwVMTypeError(exec);
513 DateInstance* thisDateObj = asDateInstance(thisValue);
515 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
516 if (!gregorianDateTime)
517 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
518 DateConversionBuffer date;
519 formatDate(*gregorianDateTime, date);
520 return JSValue::encode(jsNontrivialString(exec, date));
523 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
525 JSValue thisValue = exec->hostThisValue();
526 if (!thisValue.inherits(&DateInstance::info))
527 return throwVMTypeError(exec);
529 DateInstance* thisDateObj = asDateInstance(thisValue);
531 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
532 if (!gregorianDateTime)
533 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
534 DateConversionBuffer time;
535 formatTime(*gregorianDateTime, time);
536 return JSValue::encode(jsNontrivialString(exec, time));
539 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
541 JSValue thisValue = exec->hostThisValue();
542 if (!thisValue.inherits(&DateInstance::info))
543 return throwVMTypeError(exec);
545 DateInstance* thisDateObj = asDateInstance(thisValue);
546 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
549 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
551 JSValue thisValue = exec->hostThisValue();
552 if (!thisValue.inherits(&DateInstance::info))
553 return throwVMTypeError(exec);
555 DateInstance* thisDateObj = asDateInstance(thisValue);
556 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
559 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
561 JSValue thisValue = exec->hostThisValue();
562 if (!thisValue.inherits(&DateInstance::info))
563 return throwVMTypeError(exec);
565 DateInstance* thisDateObj = asDateInstance(thisValue);
566 return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
569 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
571 JSValue thisValue = exec->hostThisValue();
572 if (!thisValue.inherits(&DateInstance::info))
573 return throwVMTypeError(exec);
575 return JSValue::encode(asDateInstance(thisValue)->internalValue());
578 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
580 JSValue thisValue = exec->hostThisValue();
581 if (!thisValue.inherits(&DateInstance::info))
582 return throwVMTypeError(exec);
584 DateInstance* thisDateObj = asDateInstance(thisValue);
586 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
587 if (!gregorianDateTime)
588 return JSValue::encode(jsNaN());
589 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
592 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
594 JSValue thisValue = exec->hostThisValue();
595 if (!thisValue.inherits(&DateInstance::info))
596 return throwVMTypeError(exec);
598 DateInstance* thisDateObj = asDateInstance(thisValue);
600 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
601 if (!gregorianDateTime)
602 return JSValue::encode(jsNaN());
603 return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
606 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
608 JSValue thisValue = exec->hostThisValue();
609 if (!thisValue.inherits(&DateInstance::info))
610 return throwVMTypeError(exec);
612 DateInstance* thisDateObj = asDateInstance(thisValue);
614 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
615 if (!gregorianDateTime)
616 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
617 DateConversionBuffer date;
618 DateConversionBuffer time;
619 formatDateUTCVariant(*gregorianDateTime, date);
620 formatTimeUTC(*gregorianDateTime, time);
621 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
624 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
626 JSValue thisValue = exec->hostThisValue();
627 if (!thisValue.inherits(&DateInstance::info))
628 return throwVMTypeError(exec);
630 DateInstance* thisDateObj = asDateInstance(thisValue);
632 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
633 if (!gregorianDateTime)
634 return JSValue::encode(jsNaN());
635 return JSValue::encode(jsNumber(gregorianDateTime->month));
638 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
640 JSValue thisValue = exec->hostThisValue();
641 if (!thisValue.inherits(&DateInstance::info))
642 return throwVMTypeError(exec);
644 DateInstance* thisDateObj = asDateInstance(thisValue);
646 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
647 if (!gregorianDateTime)
648 return JSValue::encode(jsNaN());
649 return JSValue::encode(jsNumber(gregorianDateTime->month));
652 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
654 JSValue thisValue = exec->hostThisValue();
655 if (!thisValue.inherits(&DateInstance::info))
656 return throwVMTypeError(exec);
658 DateInstance* thisDateObj = asDateInstance(thisValue);
660 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
661 if (!gregorianDateTime)
662 return JSValue::encode(jsNaN());
663 return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
666 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
668 JSValue thisValue = exec->hostThisValue();
669 if (!thisValue.inherits(&DateInstance::info))
670 return throwVMTypeError(exec);
672 DateInstance* thisDateObj = asDateInstance(thisValue);
674 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
675 if (!gregorianDateTime)
676 return JSValue::encode(jsNaN());
677 return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
680 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
682 JSValue thisValue = exec->hostThisValue();
683 if (!thisValue.inherits(&DateInstance::info))
684 return throwVMTypeError(exec);
686 DateInstance* thisDateObj = asDateInstance(thisValue);
688 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
689 if (!gregorianDateTime)
690 return JSValue::encode(jsNaN());
691 return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
694 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
696 JSValue thisValue = exec->hostThisValue();
697 if (!thisValue.inherits(&DateInstance::info))
698 return throwVMTypeError(exec);
700 DateInstance* thisDateObj = asDateInstance(thisValue);
702 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
703 if (!gregorianDateTime)
704 return JSValue::encode(jsNaN());
705 return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
708 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
710 JSValue thisValue = exec->hostThisValue();
711 if (!thisValue.inherits(&DateInstance::info))
712 return throwVMTypeError(exec);
714 DateInstance* thisDateObj = asDateInstance(thisValue);
716 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
717 if (!gregorianDateTime)
718 return JSValue::encode(jsNaN());
719 return JSValue::encode(jsNumber(gregorianDateTime->hour));
722 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
724 JSValue thisValue = exec->hostThisValue();
725 if (!thisValue.inherits(&DateInstance::info))
726 return throwVMTypeError(exec);
728 DateInstance* thisDateObj = asDateInstance(thisValue);
730 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
731 if (!gregorianDateTime)
732 return JSValue::encode(jsNaN());
733 return JSValue::encode(jsNumber(gregorianDateTime->hour));
736 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
738 JSValue thisValue = exec->hostThisValue();
739 if (!thisValue.inherits(&DateInstance::info))
740 return throwVMTypeError(exec);
742 DateInstance* thisDateObj = asDateInstance(thisValue);
744 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
745 if (!gregorianDateTime)
746 return JSValue::encode(jsNaN());
747 return JSValue::encode(jsNumber(gregorianDateTime->minute));
750 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
752 JSValue thisValue = exec->hostThisValue();
753 if (!thisValue.inherits(&DateInstance::info))
754 return throwVMTypeError(exec);
756 DateInstance* thisDateObj = asDateInstance(thisValue);
758 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
759 if (!gregorianDateTime)
760 return JSValue::encode(jsNaN());
761 return JSValue::encode(jsNumber(gregorianDateTime->minute));
764 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
766 JSValue thisValue = exec->hostThisValue();
767 if (!thisValue.inherits(&DateInstance::info))
768 return throwVMTypeError(exec);
770 DateInstance* thisDateObj = asDateInstance(thisValue);
772 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
773 if (!gregorianDateTime)
774 return JSValue::encode(jsNaN());
775 return JSValue::encode(jsNumber(gregorianDateTime->second));
778 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
780 JSValue thisValue = exec->hostThisValue();
781 if (!thisValue.inherits(&DateInstance::info))
782 return throwVMTypeError(exec);
784 DateInstance* thisDateObj = asDateInstance(thisValue);
786 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
787 if (!gregorianDateTime)
788 return JSValue::encode(jsNaN());
789 return JSValue::encode(jsNumber(gregorianDateTime->second));
792 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
794 JSValue thisValue = exec->hostThisValue();
795 if (!thisValue.inherits(&DateInstance::info))
796 return throwVMTypeError(exec);
798 DateInstance* thisDateObj = asDateInstance(thisValue);
799 double milli = thisDateObj->internalNumber();
801 return JSValue::encode(jsNaN());
803 double secs = floor(milli / msPerSecond);
804 double ms = milli - secs * msPerSecond;
805 return JSValue::encode(jsNumber(ms));
808 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
810 JSValue thisValue = exec->hostThisValue();
811 if (!thisValue.inherits(&DateInstance::info))
812 return throwVMTypeError(exec);
814 DateInstance* thisDateObj = asDateInstance(thisValue);
815 double milli = thisDateObj->internalNumber();
817 return JSValue::encode(jsNaN());
819 double secs = floor(milli / msPerSecond);
820 double ms = milli - secs * msPerSecond;
821 return JSValue::encode(jsNumber(ms));
824 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
826 JSValue thisValue = exec->hostThisValue();
827 if (!thisValue.inherits(&DateInstance::info))
828 return throwVMTypeError(exec);
830 DateInstance* thisDateObj = asDateInstance(thisValue);
832 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
833 if (!gregorianDateTime)
834 return JSValue::encode(jsNaN());
835 return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
838 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
840 JSValue thisValue = exec->hostThisValue();
841 if (!thisValue.inherits(&DateInstance::info))
842 return throwVMTypeError(exec);
844 DateInstance* thisDateObj = asDateInstance(thisValue);
846 double milli = timeClip(exec->argument(0).toNumber(exec));
847 JSValue result = jsNumber(milli);
848 thisDateObj->setInternalValue(exec->globalData(), result);
849 return JSValue::encode(result);
852 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
854 JSValue thisValue = exec->hostThisValue();
855 if (!thisValue.inherits(&DateInstance::info))
856 return throwVMTypeError(exec);
858 DateInstance* thisDateObj = asDateInstance(thisValue);
859 double milli = thisDateObj->internalNumber();
861 if (!exec->argumentCount() || isnan(milli)) {
862 JSValue result = jsNaN();
863 thisDateObj->setInternalValue(exec->globalData(), result);
864 return JSValue::encode(result);
867 double secs = floor(milli / msPerSecond);
868 double ms = milli - secs * msPerSecond;
870 const GregorianDateTime* other = inputIsUTC
871 ? thisDateObj->gregorianDateTimeUTC(exec)
872 : thisDateObj->gregorianDateTime(exec);
874 return JSValue::encode(jsNaN());
876 GregorianDateTime gregorianDateTime;
877 gregorianDateTime.copyFrom(*other);
878 if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
879 JSValue result = jsNaN();
880 thisDateObj->setInternalValue(exec->globalData(), result);
881 return JSValue::encode(result);
884 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
885 thisDateObj->setInternalValue(exec->globalData(), result);
886 return JSValue::encode(result);
889 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
891 JSValue thisValue = exec->hostThisValue();
892 if (!thisValue.inherits(&DateInstance::info))
893 return throwVMTypeError(exec);
895 DateInstance* thisDateObj = asDateInstance(thisValue);
896 if (!exec->argumentCount()) {
897 JSValue result = jsNaN();
898 thisDateObj->setInternalValue(exec->globalData(), result);
899 return JSValue::encode(result);
902 double milli = thisDateObj->internalNumber();
905 GregorianDateTime gregorianDateTime;
906 if (numArgsToUse == 3 && isnan(milli))
907 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
909 ms = milli - floor(milli / msPerSecond) * msPerSecond;
910 const GregorianDateTime* other = inputIsUTC
911 ? thisDateObj->gregorianDateTimeUTC(exec)
912 : thisDateObj->gregorianDateTime(exec);
914 return JSValue::encode(jsNaN());
915 gregorianDateTime.copyFrom(*other);
918 if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
919 JSValue result = jsNaN();
920 thisDateObj->setInternalValue(exec->globalData(), result);
921 return JSValue::encode(result);
924 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
925 thisDateObj->setInternalValue(exec->globalData(), result);
926 return JSValue::encode(result);
929 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
931 const bool inputIsUTC = false;
932 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
935 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
937 const bool inputIsUTC = true;
938 return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
941 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
943 const bool inputIsUTC = false;
944 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
947 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
949 const bool inputIsUTC = true;
950 return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
953 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
955 const bool inputIsUTC = false;
956 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
959 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
961 const bool inputIsUTC = true;
962 return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
965 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
967 const bool inputIsUTC = false;
968 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
971 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
973 const bool inputIsUTC = true;
974 return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
977 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
979 const bool inputIsUTC = false;
980 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
983 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
985 const bool inputIsUTC = true;
986 return setNewValueFromDateArgs(exec, 1, inputIsUTC);
989 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
991 const bool inputIsUTC = false;
992 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
995 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
997 const bool inputIsUTC = true;
998 return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1001 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1003 const bool inputIsUTC = false;
1004 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1007 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1009 const bool inputIsUTC = true;
1010 return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1013 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1015 JSValue thisValue = exec->hostThisValue();
1016 if (!thisValue.inherits(&DateInstance::info))
1017 return throwVMTypeError(exec);
1019 DateInstance* thisDateObj = asDateInstance(thisValue);
1020 if (!exec->argumentCount()) {
1021 JSValue result = jsNaN();
1022 thisDateObj->setInternalValue(exec->globalData(), result);
1023 return JSValue::encode(result);
1026 double milli = thisDateObj->internalNumber();
1029 GregorianDateTime gregorianDateTime;
1031 // Based on ECMA 262 B.2.5 (setYear)
1032 // the time must be reset to +0 if it is NaN.
1033 msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1035 double secs = floor(milli / msPerSecond);
1036 ms = milli - secs * msPerSecond;
1037 if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1038 gregorianDateTime.copyFrom(*other);
1041 double year = exec->argument(0).toIntegerPreserveNaN(exec);
1042 if (!isfinite(year)) {
1043 JSValue result = jsNaN();
1044 thisDateObj->setInternalValue(exec->globalData(), result);
1045 return JSValue::encode(result);
1048 gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
1049 JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1050 thisDateObj->setInternalValue(exec->globalData(), result);
1051 return JSValue::encode(result);
1054 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1056 JSValue thisValue = exec->hostThisValue();
1057 if (!thisValue.inherits(&DateInstance::info))
1058 return throwVMTypeError(exec);
1060 DateInstance* thisDateObj = asDateInstance(thisValue);
1062 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1063 if (!gregorianDateTime)
1064 return JSValue::encode(jsNaN());
1066 // NOTE: IE returns the full year even in getYear.
1067 return JSValue::encode(jsNumber(gregorianDateTime->year));
1070 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1072 JSValue thisValue = exec->hostThisValue();
1073 JSObject* object = thisValue.toThisObject(exec);
1074 if (exec->hadException())
1075 return JSValue::encode(jsNull());
1077 JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
1078 if (exec->hadException())
1079 return JSValue::encode(jsNull());
1082 CallType callType = getCallData(toISOValue, callData);
1083 if (callType == CallTypeNone)
1084 return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
1086 JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1087 if (exec->hadException())
1088 return JSValue::encode(jsNull());
1089 if (result.isObject())
1090 return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
1091 return JSValue::encode(result);