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 "JSGlobalObject.h"
32 #include "JSStringBuilder.h"
34 #include "ObjectPrototype.h"
36 #if !PLATFORM(MAC) && HAVE(LANGINFO_H)
45 #include <wtf/Assertions.h>
46 #include <wtf/DateMath.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>
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*);
125 #include "DatePrototype.lut.h"
129 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
133 // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
134 // Instead we should consider using this whenever USE(CF) is true.
136 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
138 if (string == "short")
139 return kCFDateFormatterShortStyle;
140 if (string == "medium")
141 return kCFDateFormatterMediumStyle;
142 if (string == "long")
143 return kCFDateFormatterLongStyle;
144 if (string == "full")
145 return kCFDateFormatterFullStyle;
149 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
151 CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
152 CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
154 bool useCustomFormat = false;
155 UString customFormatString;
157 UString arg0String = exec->argument(0).toString(exec);
158 if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
159 useCustomFormat = true;
160 customFormatString = exec->argument(1).toString(exec);
161 } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
162 dateStyle = styleFromArgString(arg0String, dateStyle);
163 timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle);
164 } else if (format != LocaleTime && !exec->argument(0).isUndefined())
165 dateStyle = styleFromArgString(arg0String, dateStyle);
166 else if (format != LocaleDate && !exec->argument(0).isUndefined())
167 timeStyle = styleFromArgString(arg0String, timeStyle);
169 CFLocaleRef locale = CFLocaleCopyCurrent();
170 CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
173 if (useCustomFormat) {
174 CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
175 CFDateFormatterSetFormat(formatter, customFormatCFString);
176 CFRelease(customFormatCFString);
179 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
181 CFRelease(formatter);
183 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
184 // That's not great error handling, but it just won't happen so it doesn't matter.
186 const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
187 size_t length = CFStringGetLength(string);
188 ASSERT(length <= bufferLength);
189 if (length > bufferLength)
190 length = bufferLength;
191 CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
195 return jsNontrivialString(exec, UString(buffer, length));
198 #else // !PLATFORM(MAC)
200 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
203 static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
204 #elif (OS(WINCE) && !PLATFORM(QT)) || OS(SYMBIAN)
205 // strftime() does not support '#' on WinCE or Symbian
206 static const char* const formatStrings[] = { "%c", "%x", "%X" };
208 static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
211 // Offset year if needed
212 struct tm localTM = gdt;
213 int year = gdt.year + 1900;
214 bool yearNeedsOffset = year < 1900 || year > 2038;
216 localTM.tm_year = equivalentYearForDST(year) - 1900;
219 // We do not allow strftime to generate dates with 2-digits years,
220 // both to avoid ambiguity, and a crash in strncpy, for years that
222 char* formatString = strdup(nl_langinfo(formats[format]));
223 char* yPos = strchr(formatString, 'y');
229 const int bufsize = 128;
230 char timebuffer[bufsize];
233 size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
236 size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
240 return jsEmptyString(exec);
242 // Copy original into the buffer
243 if (yearNeedsOffset && format != LocaleTime) {
244 static const int yearLen = 5; // FIXME will be a problem in the year 10,000
245 char yearString[yearLen];
247 snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
248 char* yearLocation = strstr(timebuffer, yearString);
249 snprintf(yearString, yearLen, "%d", year);
251 strncpy(yearLocation, yearString, yearLen - 1);
254 // Convert multi-byte result to UNICODE.
255 // If __STDC_ISO_10646__ is defined, wide character represents
256 // UTF-16 (or UTF-32) code point. In most modern Unix like system
257 // (e.g. Linux with glibc 2.2 and above) the macro is defined,
258 // and wide character represents UTF-32 code point.
259 // Here we static_cast potential UTF-32 to UTF-16, it should be
260 // safe because date and (or) time related characters in different languages
261 // should be in UNICODE BMP. If mbstowcs fails, we just fall
262 // back on using multi-byte result as-is.
263 #ifdef __STDC_ISO_10646__
264 UChar buffer[bufsize];
265 wchar_t tempbuffer[bufsize];
266 size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
267 if (length != static_cast<size_t>(-1)) {
268 for (size_t i = 0; i < length; ++i)
269 buffer[i] = static_cast<UChar>(tempbuffer[i]);
270 return jsNontrivialString(exec, UString(buffer, length));
274 return jsNontrivialString(exec, timebuffer);
277 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
279 const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
280 if (!gregorianDateTime)
281 return jsNontrivialString(exec, "Invalid Date");
282 return formatLocaleDate(exec, *gregorianDateTime, format);
285 #endif // !PLATFORM(MAC)
287 // Converts a list of arguments sent to a Date member function into milliseconds, updating
288 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
290 // Format of member function: f([hour,] [min,] [sec,] [ms])
291 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
293 double milliseconds = 0;
296 int numArgs = exec->argumentCount();
298 // JS allows extra trailing arguments -- ignore them
299 if (numArgs > maxArgs)
303 if (maxArgs >= 4 && idx < numArgs) {
305 double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
306 ok = isfinite(hours);
307 milliseconds += hours * msPerHour;
311 if (maxArgs >= 3 && idx < numArgs && ok) {
313 double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
314 ok = isfinite(minutes);
315 milliseconds += minutes * msPerMinute;
319 if (maxArgs >= 2 && idx < numArgs && ok) {
321 double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
322 ok = isfinite(seconds);
323 milliseconds += seconds * msPerSecond;
331 double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
332 ok = isfinite(millis);
333 milliseconds += millis;
341 // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
342 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
344 // Format of member function: f([years,] [months,] [days])
345 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
349 int numArgs = exec->argumentCount();
351 // JS allows extra trailing arguments -- ignore them
352 if (numArgs > maxArgs)
356 if (maxArgs >= 3 && idx < numArgs) {
357 double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
358 ok = isfinite(years);
359 t->year = toInt32(years - 1900);
362 if (maxArgs >= 2 && idx < numArgs && ok) {
363 double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
364 ok = isfinite(months);
365 t->month = toInt32(months);
368 if (idx < numArgs && ok) {
369 double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
372 *ms += days * msPerDay;
378 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable};
380 /* Source for DatePrototype.lut.h
382 toString dateProtoFuncToString DontEnum|Function 0
383 toISOString dateProtoFuncToISOString DontEnum|Function 0
384 toUTCString dateProtoFuncToUTCString DontEnum|Function 0
385 toDateString dateProtoFuncToDateString DontEnum|Function 0
386 toTimeString dateProtoFuncToTimeString DontEnum|Function 0
387 toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
388 toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
389 toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
390 valueOf dateProtoFuncGetTime DontEnum|Function 0
391 getTime dateProtoFuncGetTime DontEnum|Function 0
392 getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
393 getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
394 toGMTString dateProtoFuncToGMTString DontEnum|Function 0
395 getMonth dateProtoFuncGetMonth DontEnum|Function 0
396 getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
397 getDate dateProtoFuncGetDate DontEnum|Function 0
398 getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
399 getDay dateProtoFuncGetDay DontEnum|Function 0
400 getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
401 getHours dateProtoFuncGetHours DontEnum|Function 0
402 getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
403 getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
404 getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
405 getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
406 getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
407 getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
408 getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
409 getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
410 setTime dateProtoFuncSetTime DontEnum|Function 1
411 setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
412 setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
413 setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
414 setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
415 setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
416 setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
417 setHours dateProtoFuncSetHours DontEnum|Function 4
418 setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
419 setDate dateProtoFuncSetDate DontEnum|Function 1
420 setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
421 setMonth dateProtoFuncSetMonth DontEnum|Function 2
422 setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
423 setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
424 setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
425 setYear dateProtoFuncSetYear DontEnum|Function 1
426 getYear dateProtoFuncGetYear DontEnum|Function 0
427 toJSON dateProtoFuncToJSON DontEnum|Function 1
433 DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
434 : DateInstance(exec, structure)
438 void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
440 Base::finishCreation(exec->globalData());
441 ASSERT(inherits(&s_info));
443 // The constructor will be added later, after DateConstructor has been built.
446 bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
448 return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot);
452 bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
454 return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
459 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
461 JSValue thisValue = exec->hostThisValue();
462 if (!thisValue.inherits(&DateInstance::s_info))
463 return throwVMTypeError(exec);
465 DateInstance* thisDateObj = asDateInstance(thisValue);
467 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
468 if (!gregorianDateTime)
469 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
470 DateConversionBuffer date;
471 DateConversionBuffer time;
472 formatDate(*gregorianDateTime, date);
473 formatTime(*gregorianDateTime, time);
474 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
477 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
479 JSValue thisValue = exec->hostThisValue();
480 if (!thisValue.inherits(&DateInstance::s_info))
481 return throwVMTypeError(exec);
483 DateInstance* thisDateObj = asDateInstance(thisValue);
485 const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
486 if (!gregorianDateTime)
487 return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
488 DateConversionBuffer date;
489 DateConversionBuffer time;
490 formatDateUTCVariant(*gregorianDateTime, date);
491 formatTimeUTC(*gregorianDateTime, time);
492 return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
495 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
497 JSValue thisValue = exec->hostThisValue();
498 if (!thisValue.inherits(&DateInstance::s_info))
499 return throwVMTypeError(exec);
501 DateInstance* thisDateObj = asDateInstance(thisValue);
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);