1/*
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.
6 *
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.
11 *
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.
16 *
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
20 *  USA
21 *
22 */
23
24#include "config.h"
25#include "DatePrototype.h"
26
27#include "DateConversion.h"
28#include "DateInstance.h"
29#include "Error.h"
30#include "JSDateMath.h"
31#include "JSGlobalObject.h"
32#include "JSString.h"
33#include "Lookup.h"
34#include "ObjectPrototype.h"
35#include "JSCInlines.h"
36#include <limits.h>
37#include <locale.h>
38#include <math.h>
39#include <stdlib.h>
40#include <time.h>
41#include <wtf/Assertions.h>
42#include <wtf/MathExtras.h>
43#include <wtf/StringExtras.h>
44
45#if HAVE(LANGINFO_H)
46#include <langinfo.h>
47#endif
48
49#if HAVE(SYS_PARAM_H)
50#include <sys/param.h>
51#endif
52
53#if HAVE(SYS_TIME_H)
54#include <sys/time.h>
55#endif
56
57#if HAVE(SYS_TIMEB_H)
58#include <sys/timeb.h>
59#endif
60
61#if !(OS(DARWIN) && USE(CF))
62#include <unicode/udat.h>
63#endif
64
65#if USE(CF)
66#include <CoreFoundation/CoreFoundation.h>
67#endif
68
69using namespace WTF;
70
71namespace JSC {
72
73static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
74static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
75static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
76static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
77static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
78static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
79static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
80static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
81static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
82static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
83static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
84static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
85static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
86static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
87static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
88static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
89static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
90static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
91static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
92static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
93static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
94static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
95static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
96static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
97static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
98static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
99static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
100static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
101static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
102static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
103static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
104static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
105static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
106static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
107static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
108static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
109static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
110static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
111static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
112static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
113static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
114static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
115static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
116static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
117static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
118
119}
120
121#include "DatePrototype.lut.h"
122
123namespace JSC {
124
125enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
126
127#if OS(DARWIN) && USE(CF)
128
129// FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)?
130// Instead we should consider using this whenever USE(CF) is true.
131
132static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
133{
134    if (string == "short")
135        return kCFDateFormatterShortStyle;
136    if (string == "medium")
137        return kCFDateFormatterMediumStyle;
138    if (string == "long")
139        return kCFDateFormatterLongStyle;
140    if (string == "full")
141        return kCFDateFormatterFullStyle;
142    return defaultStyle;
143}
144
145static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
146{
147    CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
148    CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
149
150    bool useCustomFormat = false;
151    String customFormatString;
152
153    String arg0String = exec->argument(0).toString(exec)->value(exec);
154    if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
155        useCustomFormat = true;
156        customFormatString = exec->argument(1).toString(exec)->value(exec);
157    } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
158        dateStyle = styleFromArgString(arg0String, dateStyle);
159        timeStyle = styleFromArgString(exec->argument(1).toString(exec)->value(exec), timeStyle);
160    } else if (format != LocaleTime && !exec->argument(0).isUndefined())
161        dateStyle = styleFromArgString(arg0String, dateStyle);
162    else if (format != LocaleDate && !exec->argument(0).isUndefined())
163        timeStyle = styleFromArgString(arg0String, timeStyle);
164
165    CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
166
167    auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
168    if (useCustomFormat)
169        CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
170    return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
171}
172
173#elif !UCONFIG_NO_FORMATTING
174
175static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
176{
177    UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
178    UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
179
180    UErrorCode status = U_ZERO_ERROR;
181    UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
182    if (!df)
183        return jsEmptyString(exec);
184
185    UChar buffer[128];
186    int32_t length;
187    length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
188    udat_close(df);
189    if (status != U_ZERO_ERROR)
190        return jsEmptyString(exec);
191
192    return jsNontrivialString(exec, String(buffer, length));
193}
194
195#else
196
197static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
198{
199#if OS(WINDOWS)
200    SYSTEMTIME systemTime;
201    memset(&systemTime, 0, sizeof(systemTime));
202    systemTime.wYear = gdt.year();
203    systemTime.wMonth = gdt.month() + 1;
204    systemTime.wDay = gdt.monthDay();
205    systemTime.wDayOfWeek = gdt.weekDay();
206    systemTime.wHour = gdt.hour();
207    systemTime.wMinute = gdt.minute();
208    systemTime.wSecond = gdt.second();
209
210    Vector<UChar, 128> buffer;
211    size_t length = 0;
212
213    if (format == LocaleDate) {
214        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
215        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
216    } else if (format == LocaleTime) {
217        buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
218        length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
219    } else if (format == LocaleDateAndTime) {
220        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
221        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
222        if (length) {
223            buffer[length - 1] = ' ';
224            length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
225        }
226    } else
227        RELEASE_ASSERT_NOT_REACHED();
228
229    //  Remove terminating null character.
230    if (length)
231        length--;
232
233    return jsNontrivialString(exec, String(buffer.data(), length));
234
235#else // OS(WINDOWS)
236
237#if HAVE(LANGINFO_H)
238    static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
239#else
240    static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
241#endif
242
243    // Offset year if needed
244    struct tm localTM = gdt;
245    int year = gdt.year();
246    bool yearNeedsOffset = year < 1900 || year > 2038;
247    if (yearNeedsOffset)
248        localTM.tm_year = equivalentYearForDST(year) - 1900;
249
250#if HAVE(LANGINFO_H)
251    // We do not allow strftime to generate dates with 2-digits years,
252    // both to avoid ambiguity, and a crash in strncpy, for years that
253    // need offset.
254    char* formatString = strdup(nl_langinfo(formats[format]));
255    char* yPos = strchr(formatString, 'y');
256    if (yPos)
257        *yPos = 'Y';
258#endif
259
260    // Do the formatting
261    const int bufsize = 128;
262    char timebuffer[bufsize];
263
264#if HAVE(LANGINFO_H)
265    size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
266    free(formatString);
267#else
268    size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
269#endif
270
271    if (ret == 0)
272        return jsEmptyString(exec);
273
274    // Copy original into the buffer
275    if (yearNeedsOffset && format != LocaleTime) {
276        static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
277        char yearString[yearLen];
278
279        snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
280        char* yearLocation = strstr(timebuffer, yearString);
281        snprintf(yearString, yearLen, "%d", year);
282
283        strncpy(yearLocation, yearString, yearLen - 1);
284    }
285
286    // Convert multi-byte result to UNICODE.
287    // If __STDC_ISO_10646__ is defined, wide character represents
288    // UTF-16 (or UTF-32) code point. In most modern Unix like system
289    // (e.g. Linux with glibc 2.2 and above) the macro is defined,
290    // and wide character represents UTF-32 code point.
291    // Here we static_cast potential UTF-32 to UTF-16, it should be
292    // safe because date and (or) time related characters in different languages
293    // should be in UNICODE BMP. If mbstowcs fails, we just fall
294    // back on using multi-byte result as-is.
295#ifdef __STDC_ISO_10646__
296    UChar buffer[bufsize];
297    wchar_t tempbuffer[bufsize];
298    size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
299    if (length != static_cast<size_t>(-1)) {
300        for (size_t i = 0; i < length; ++i)
301            buffer[i] = static_cast<UChar>(tempbuffer[i]);
302        return jsNontrivialString(exec, String(buffer, length));
303    }
304#endif
305
306    return jsNontrivialString(exec, timebuffer);
307#endif // OS(WINDOWS)
308}
309
310static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
311{
312    const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
313    if (!gregorianDateTime)
314        return jsNontrivialString(exec, ASCIILiteral("Invalid Date"));
315    return formatLocaleDate(exec, *gregorianDateTime, format);
316}
317
318#endif // OS(DARWIN) && USE(CF)
319
320static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
321{
322    JSValue thisValue = exec->thisValue();
323    if (!thisValue.inherits(DateInstance::info()))
324        return throwVMTypeError(exec);
325
326    DateInstance* thisDateObj = asDateInstance(thisValue);
327
328    const GregorianDateTime* gregorianDateTime = asUTCVariant
329        ? thisDateObj->gregorianDateTimeUTC(exec)
330        : thisDateObj->gregorianDateTime(exec);
331    if (!gregorianDateTime)
332        return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
333
334    return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
335}
336
337// Converts a list of arguments sent to a Date member function into milliseconds, updating
338// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
339//
340// Format of member function: f([hour,] [min,] [sec,] [ms])
341static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
342{
343    double milliseconds = 0;
344    bool ok = true;
345    int idx = 0;
346    int numArgs = exec->argumentCount();
347
348    // JS allows extra trailing arguments -- ignore them
349    if (numArgs > maxArgs)
350        numArgs = maxArgs;
351
352    // hours
353    if (maxArgs >= 4 && idx < numArgs) {
354        t->setHour(0);
355        double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
356        ok = std::isfinite(hours);
357        milliseconds += hours * msPerHour;
358    }
359
360    // minutes
361    if (maxArgs >= 3 && idx < numArgs && ok) {
362        t->setMinute(0);
363        double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
364        ok = std::isfinite(minutes);
365        milliseconds += minutes * msPerMinute;
366    }
367
368    // seconds
369    if (maxArgs >= 2 && idx < numArgs && ok) {
370        t->setSecond(0);
371        double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
372        ok = std::isfinite(seconds);
373        milliseconds += seconds * msPerSecond;
374    }
375
376    if (!ok)
377        return false;
378
379    // milliseconds
380    if (idx < numArgs) {
381        double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
382        ok = std::isfinite(millis);
383        milliseconds += millis;
384    } else
385        milliseconds += *ms;
386
387    *ms = milliseconds;
388    return ok;
389}
390
391// Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
392// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
393//
394// Format of member function: f([years,] [months,] [days])
395static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
396{
397    int idx = 0;
398    bool ok = true;
399    int numArgs = exec->argumentCount();
400
401    // JS allows extra trailing arguments -- ignore them
402    if (numArgs > maxArgs)
403        numArgs = maxArgs;
404
405    // years
406    if (maxArgs >= 3 && idx < numArgs) {
407        double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
408        ok = std::isfinite(years);
409        t->setYear(toInt32(years));
410    }
411    // months
412    if (maxArgs >= 2 && idx < numArgs && ok) {
413        double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
414        ok = std::isfinite(months);
415        t->setMonth(toInt32(months));
416    }
417    // days
418    if (idx < numArgs && ok) {
419        double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
420        ok = std::isfinite(days);
421        t->setMonthDay(0);
422        *ms += days * msPerDay;
423    }
424
425    return ok;
426}
427
428const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
429
430/* Source for DatePrototype.lut.h
431@begin dateTable
432  toString              dateProtoFuncToString                DontEnum|Function       0
433  toISOString           dateProtoFuncToISOString             DontEnum|Function       0
434  toUTCString           dateProtoFuncToUTCString             DontEnum|Function       0
435  toDateString          dateProtoFuncToDateString            DontEnum|Function       0
436  toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
437  toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
438  toLocaleDateString    dateProtoFuncToLocaleDateString      DontEnum|Function       0
439  toLocaleTimeString    dateProtoFuncToLocaleTimeString      DontEnum|Function       0
440  valueOf               dateProtoFuncGetTime                 DontEnum|Function       0
441  getTime               dateProtoFuncGetTime                 DontEnum|Function       0
442  getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
443  getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
444  toGMTString           dateProtoFuncToGMTString             DontEnum|Function       0
445  getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
446  getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
447  getDate               dateProtoFuncGetDate                 DontEnum|Function       0
448  getUTCDate            dateProtoFuncGetUTCDate              DontEnum|Function       0
449  getDay                dateProtoFuncGetDay                  DontEnum|Function       0
450  getUTCDay             dateProtoFuncGetUTCDay               DontEnum|Function       0
451  getHours              dateProtoFuncGetHours                DontEnum|Function       0
452  getUTCHours           dateProtoFuncGetUTCHours             DontEnum|Function       0
453  getMinutes            dateProtoFuncGetMinutes              DontEnum|Function       0
454  getUTCMinutes         dateProtoFuncGetUTCMinutes           DontEnum|Function       0
455  getSeconds            dateProtoFuncGetSeconds              DontEnum|Function       0
456  getUTCSeconds         dateProtoFuncGetUTCSeconds           DontEnum|Function       0
457  getMilliseconds       dateProtoFuncGetMilliSeconds         DontEnum|Function       0
458  getUTCMilliseconds    dateProtoFuncGetUTCMilliseconds      DontEnum|Function       0
459  getTimezoneOffset     dateProtoFuncGetTimezoneOffset       DontEnum|Function       0
460  setTime               dateProtoFuncSetTime                 DontEnum|Function       1
461  setMilliseconds       dateProtoFuncSetMilliSeconds         DontEnum|Function       1
462  setUTCMilliseconds    dateProtoFuncSetUTCMilliseconds      DontEnum|Function       1
463  setSeconds            dateProtoFuncSetSeconds              DontEnum|Function       2
464  setUTCSeconds         dateProtoFuncSetUTCSeconds           DontEnum|Function       2
465  setMinutes            dateProtoFuncSetMinutes              DontEnum|Function       3
466  setUTCMinutes         dateProtoFuncSetUTCMinutes           DontEnum|Function       3
467  setHours              dateProtoFuncSetHours                DontEnum|Function       4
468  setUTCHours           dateProtoFuncSetUTCHours             DontEnum|Function       4
469  setDate               dateProtoFuncSetDate                 DontEnum|Function       1
470  setUTCDate            dateProtoFuncSetUTCDate              DontEnum|Function       1
471  setMonth              dateProtoFuncSetMonth                DontEnum|Function       2
472  setUTCMonth           dateProtoFuncSetUTCMonth             DontEnum|Function       2
473  setFullYear           dateProtoFuncSetFullYear             DontEnum|Function       3
474  setUTCFullYear        dateProtoFuncSetUTCFullYear          DontEnum|Function       3
475  setYear               dateProtoFuncSetYear                 DontEnum|Function       1
476  getYear               dateProtoFuncGetYear                 DontEnum|Function       0
477  toJSON                dateProtoFuncToJSON                  DontEnum|Function       1
478@end
479*/
480
481// ECMA 15.9.4
482
483DatePrototype::DatePrototype(VM& vm, Structure* structure)
484    : DateInstance(vm, structure)
485{
486}
487
488void DatePrototype::finishCreation(VM& vm, JSGlobalObject*)
489{
490    Base::finishCreation(vm);
491    ASSERT(inherits(info()));
492
493    // The constructor will be added later, after DateConstructor has been built.
494}
495
496bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
497{
498    return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec->vm()), jsCast<DatePrototype*>(object), propertyName, slot);
499}
500
501// Functions
502
503EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
504{
505    const bool asUTCVariant = false;
506    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
507}
508
509EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
510{
511    const bool asUTCVariant = true;
512    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
513}
514
515EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
516{
517    JSValue thisValue = exec->thisValue();
518    if (!thisValue.inherits(DateInstance::info()))
519        return throwVMTypeError(exec);
520
521    DateInstance* thisDateObj = asDateInstance(thisValue);
522    if (!std::isfinite(thisDateObj->internalNumber()))
523        return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));
524
525    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
526    if (!gregorianDateTime)
527        return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
528    // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
529    // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
530    char buffer[28];
531    // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
532    int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
533    if (ms < 0)
534        ms += msPerSecond;
535
536    int charactersWritten;
537    if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
538        charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
539    else
540        charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
541
542    ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
543    if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
544        return JSValue::encode(jsEmptyString(exec));
545
546    return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
547}
548
549EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
550{
551    const bool asUTCVariant = false;
552    return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
553}
554
555EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
556{
557    const bool asUTCVariant = false;
558    return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
559}
560
561EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
562{
563    JSValue thisValue = exec->thisValue();
564    if (!thisValue.inherits(DateInstance::info()))
565        return throwVMTypeError(exec);
566
567    DateInstance* thisDateObj = asDateInstance(thisValue);
568    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
569}
570
571EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
572{
573    JSValue thisValue = exec->thisValue();
574    if (!thisValue.inherits(DateInstance::info()))
575        return throwVMTypeError(exec);
576
577    DateInstance* thisDateObj = asDateInstance(thisValue);
578    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
579}
580
581EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
582{
583    JSValue thisValue = exec->thisValue();
584    if (!thisValue.inherits(DateInstance::info()))
585        return throwVMTypeError(exec);
586
587    DateInstance* thisDateObj = asDateInstance(thisValue);
588    return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
589}
590
591EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
592{
593    JSValue thisValue = exec->thisValue();
594    if (!thisValue.inherits(DateInstance::info()))
595        return throwVMTypeError(exec);
596
597    return JSValue::encode(asDateInstance(thisValue)->internalValue());
598}
599
600EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
601{
602    JSValue thisValue = exec->thisValue();
603    if (!thisValue.inherits(DateInstance::info()))
604        return throwVMTypeError(exec);
605
606    DateInstance* thisDateObj = asDateInstance(thisValue);
607
608    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
609    if (!gregorianDateTime)
610        return JSValue::encode(jsNaN());
611    return JSValue::encode(jsNumber(gregorianDateTime->year()));
612}
613
614EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
615{
616    JSValue thisValue = exec->thisValue();
617    if (!thisValue.inherits(DateInstance::info()))
618        return throwVMTypeError(exec);
619
620    DateInstance* thisDateObj = asDateInstance(thisValue);
621
622    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
623    if (!gregorianDateTime)
624        return JSValue::encode(jsNaN());
625    return JSValue::encode(jsNumber(gregorianDateTime->year()));
626}
627
628EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
629{
630    const bool asUTCVariant = true;
631    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
632}
633
634EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
635{
636    JSValue thisValue = exec->thisValue();
637    if (!thisValue.inherits(DateInstance::info()))
638        return throwVMTypeError(exec);
639
640    DateInstance* thisDateObj = asDateInstance(thisValue);
641
642    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
643    if (!gregorianDateTime)
644        return JSValue::encode(jsNaN());
645    return JSValue::encode(jsNumber(gregorianDateTime->month()));
646}
647
648EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
649{
650    JSValue thisValue = exec->thisValue();
651    if (!thisValue.inherits(DateInstance::info()))
652        return throwVMTypeError(exec);
653
654    DateInstance* thisDateObj = asDateInstance(thisValue);
655
656    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
657    if (!gregorianDateTime)
658        return JSValue::encode(jsNaN());
659    return JSValue::encode(jsNumber(gregorianDateTime->month()));
660}
661
662EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
663{
664    JSValue thisValue = exec->thisValue();
665    if (!thisValue.inherits(DateInstance::info()))
666        return throwVMTypeError(exec);
667
668    DateInstance* thisDateObj = asDateInstance(thisValue);
669
670    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
671    if (!gregorianDateTime)
672        return JSValue::encode(jsNaN());
673    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
674}
675
676EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
677{
678    JSValue thisValue = exec->thisValue();
679    if (!thisValue.inherits(DateInstance::info()))
680        return throwVMTypeError(exec);
681
682    DateInstance* thisDateObj = asDateInstance(thisValue);
683
684    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
685    if (!gregorianDateTime)
686        return JSValue::encode(jsNaN());
687    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
688}
689
690EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
691{
692    JSValue thisValue = exec->thisValue();
693    if (!thisValue.inherits(DateInstance::info()))
694        return throwVMTypeError(exec);
695
696    DateInstance* thisDateObj = asDateInstance(thisValue);
697
698    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
699    if (!gregorianDateTime)
700        return JSValue::encode(jsNaN());
701    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
702}
703
704EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
705{
706    JSValue thisValue = exec->thisValue();
707    if (!thisValue.inherits(DateInstance::info()))
708        return throwVMTypeError(exec);
709
710    DateInstance* thisDateObj = asDateInstance(thisValue);
711
712    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
713    if (!gregorianDateTime)
714        return JSValue::encode(jsNaN());
715    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
716}
717
718EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
719{
720    JSValue thisValue = exec->thisValue();
721    if (!thisValue.inherits(DateInstance::info()))
722        return throwVMTypeError(exec);
723
724    DateInstance* thisDateObj = asDateInstance(thisValue);
725
726    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
727    if (!gregorianDateTime)
728        return JSValue::encode(jsNaN());
729    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
730}
731
732EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
733{
734    JSValue thisValue = exec->thisValue();
735    if (!thisValue.inherits(DateInstance::info()))
736        return throwVMTypeError(exec);
737
738    DateInstance* thisDateObj = asDateInstance(thisValue);
739
740    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
741    if (!gregorianDateTime)
742        return JSValue::encode(jsNaN());
743    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
744}
745
746EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
747{
748    JSValue thisValue = exec->thisValue();
749    if (!thisValue.inherits(DateInstance::info()))
750        return throwVMTypeError(exec);
751
752    DateInstance* thisDateObj = asDateInstance(thisValue);
753
754    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
755    if (!gregorianDateTime)
756        return JSValue::encode(jsNaN());
757    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
758}
759
760EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
761{
762    JSValue thisValue = exec->thisValue();
763    if (!thisValue.inherits(DateInstance::info()))
764        return throwVMTypeError(exec);
765
766    DateInstance* thisDateObj = asDateInstance(thisValue);
767
768    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
769    if (!gregorianDateTime)
770        return JSValue::encode(jsNaN());
771    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
772}
773
774EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
775{
776    JSValue thisValue = exec->thisValue();
777    if (!thisValue.inherits(DateInstance::info()))
778        return throwVMTypeError(exec);
779
780    DateInstance* thisDateObj = asDateInstance(thisValue);
781
782    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
783    if (!gregorianDateTime)
784        return JSValue::encode(jsNaN());
785    return JSValue::encode(jsNumber(gregorianDateTime->second()));
786}
787
788EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
789{
790    JSValue thisValue = exec->thisValue();
791    if (!thisValue.inherits(DateInstance::info()))
792        return throwVMTypeError(exec);
793
794    DateInstance* thisDateObj = asDateInstance(thisValue);
795
796    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
797    if (!gregorianDateTime)
798        return JSValue::encode(jsNaN());
799    return JSValue::encode(jsNumber(gregorianDateTime->second()));
800}
801
802EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
803{
804    JSValue thisValue = exec->thisValue();
805    if (!thisValue.inherits(DateInstance::info()))
806        return throwVMTypeError(exec);
807
808    DateInstance* thisDateObj = asDateInstance(thisValue);
809    double milli = thisDateObj->internalNumber();
810    if (std::isnan(milli))
811        return JSValue::encode(jsNaN());
812
813    double secs = floor(milli / msPerSecond);
814    double ms = milli - secs * msPerSecond;
815    return JSValue::encode(jsNumber(ms));
816}
817
818EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
819{
820    JSValue thisValue = exec->thisValue();
821    if (!thisValue.inherits(DateInstance::info()))
822        return throwVMTypeError(exec);
823
824    DateInstance* thisDateObj = asDateInstance(thisValue);
825    double milli = thisDateObj->internalNumber();
826    if (std::isnan(milli))
827        return JSValue::encode(jsNaN());
828
829    double secs = floor(milli / msPerSecond);
830    double ms = milli - secs * msPerSecond;
831    return JSValue::encode(jsNumber(ms));
832}
833
834EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
835{
836    JSValue thisValue = exec->thisValue();
837    if (!thisValue.inherits(DateInstance::info()))
838        return throwVMTypeError(exec);
839
840    DateInstance* thisDateObj = asDateInstance(thisValue);
841
842    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
843    if (!gregorianDateTime)
844        return JSValue::encode(jsNaN());
845    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
846}
847
848EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
849{
850    JSValue thisValue = exec->thisValue();
851    if (!thisValue.inherits(DateInstance::info()))
852        return throwVMTypeError(exec);
853
854    DateInstance* thisDateObj = asDateInstance(thisValue);
855
856    double milli = timeClip(exec->argument(0).toNumber(exec));
857    JSValue result = jsNumber(milli);
858    thisDateObj->setInternalValue(exec->vm(), result);
859    return JSValue::encode(result);
860}
861
862static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
863{
864    JSValue thisValue = exec->thisValue();
865    if (!thisValue.inherits(DateInstance::info()))
866        return throwVMTypeError(exec);
867
868    DateInstance* thisDateObj = asDateInstance(thisValue);
869    double milli = thisDateObj->internalNumber();
870    VM& vm = exec->vm();
871
872    if (!exec->argumentCount() || std::isnan(milli)) {
873        JSValue result = jsNaN();
874        thisDateObj->setInternalValue(vm, result);
875        return JSValue::encode(result);
876    }
877
878    double secs = floor(milli / msPerSecond);
879    double ms = milli - secs * msPerSecond;
880
881    const GregorianDateTime* other = inputIsUTC
882        ? thisDateObj->gregorianDateTimeUTC(exec)
883        : thisDateObj->gregorianDateTime(exec);
884    if (!other)
885        return JSValue::encode(jsNaN());
886
887    GregorianDateTime gregorianDateTime;
888    gregorianDateTime.copyFrom(*other);
889    if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
890        JSValue result = jsNaN();
891        thisDateObj->setInternalValue(vm, result);
892        return JSValue::encode(result);
893    }
894
895    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
896    thisDateObj->setInternalValue(vm, result);
897    return JSValue::encode(result);
898}
899
900static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
901{
902    JSValue thisValue = exec->thisValue();
903    if (!thisValue.inherits(DateInstance::info()))
904        return throwVMTypeError(exec);
905
906    DateInstance* thisDateObj = asDateInstance(thisValue);
907    if (!exec->argumentCount()) {
908        JSValue result = jsNaN();
909        thisDateObj->setInternalValue(exec->vm(), result);
910        return JSValue::encode(result);
911    }
912
913    VM& vm = exec->vm();
914    double milli = thisDateObj->internalNumber();
915    double ms = 0;
916
917    GregorianDateTime gregorianDateTime;
918    if (numArgsToUse == 3 && std::isnan(milli))
919        msToGregorianDateTime(vm, 0, true, gregorianDateTime);
920    else {
921        ms = milli - floor(milli / msPerSecond) * msPerSecond;
922        const GregorianDateTime* other = inputIsUTC
923            ? thisDateObj->gregorianDateTimeUTC(exec)
924            : thisDateObj->gregorianDateTime(exec);
925        if (!other)
926            return JSValue::encode(jsNaN());
927        gregorianDateTime.copyFrom(*other);
928    }
929
930    if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
931        JSValue result = jsNaN();
932        thisDateObj->setInternalValue(vm, result);
933        return JSValue::encode(result);
934    }
935
936    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
937    thisDateObj->setInternalValue(vm, result);
938    return JSValue::encode(result);
939}
940
941EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
942{
943    const bool inputIsUTC = false;
944    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
945}
946
947EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
948{
949    const bool inputIsUTC = true;
950    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
951}
952
953EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
954{
955    const bool inputIsUTC = false;
956    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
957}
958
959EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
960{
961    const bool inputIsUTC = true;
962    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
963}
964
965EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
966{
967    const bool inputIsUTC = false;
968    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
969}
970
971EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
972{
973    const bool inputIsUTC = true;
974    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
975}
976
977EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
978{
979    const bool inputIsUTC = false;
980    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
981}
982
983EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
984{
985    const bool inputIsUTC = true;
986    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
987}
988
989EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
990{
991    const bool inputIsUTC = false;
992    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
993}
994
995EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
996{
997    const bool inputIsUTC = true;
998    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
999}
1000
1001EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
1002{
1003    const bool inputIsUTC = false;
1004    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1005}
1006
1007EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
1008{
1009    const bool inputIsUTC = true;
1010    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1011}
1012
1013EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1014{
1015    const bool inputIsUTC = false;
1016    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1017}
1018
1019EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1020{
1021    const bool inputIsUTC = true;
1022    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1023}
1024
1025EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1026{
1027    JSValue thisValue = exec->thisValue();
1028    if (!thisValue.inherits(DateInstance::info()))
1029        return throwVMTypeError(exec);
1030
1031    VM& vm = exec->vm();
1032    DateInstance* thisDateObj = asDateInstance(thisValue);
1033    if (!exec->argumentCount()) {
1034        JSValue result = jsNaN();
1035        thisDateObj->setInternalValue(vm, result);
1036        return JSValue::encode(result);
1037    }
1038
1039    double milli = thisDateObj->internalNumber();
1040    double ms = 0;
1041
1042    GregorianDateTime gregorianDateTime;
1043    if (std::isnan(milli))
1044        // Based on ECMA 262 B.2.5 (setYear)
1045        // the time must be reset to +0 if it is NaN.
1046        msToGregorianDateTime(vm, 0, true, gregorianDateTime);
1047    else {
1048        double secs = floor(milli / msPerSecond);
1049        ms = milli - secs * msPerSecond;
1050        if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1051            gregorianDateTime.copyFrom(*other);
1052    }
1053
1054    double year = exec->argument(0).toIntegerPreserveNaN(exec);
1055    if (!std::isfinite(year)) {
1056        JSValue result = jsNaN();
1057        thisDateObj->setInternalValue(vm, result);
1058        return JSValue::encode(result);
1059    }
1060
1061    gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
1062    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, false));
1063    thisDateObj->setInternalValue(vm, result);
1064    return JSValue::encode(result);
1065}
1066
1067EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1068{
1069    JSValue thisValue = exec->thisValue();
1070    if (!thisValue.inherits(DateInstance::info()))
1071        return throwVMTypeError(exec);
1072
1073    DateInstance* thisDateObj = asDateInstance(thisValue);
1074
1075    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1076    if (!gregorianDateTime)
1077        return JSValue::encode(jsNaN());
1078
1079    // NOTE: IE returns the full year even in getYear.
1080    return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
1081}
1082
1083EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1084{
1085    JSValue thisValue = exec->thisValue();
1086    JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
1087    if (exec->hadException())
1088        return JSValue::encode(jsNull());
1089
1090    JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
1091    if (exec->hadException())
1092        return JSValue::encode(jsNull());
1093
1094    CallData callData;
1095    CallType callType = getCallData(toISOValue, callData);
1096    if (callType == CallTypeNone)
1097        return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function")));
1098
1099    JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1100    if (exec->hadException())
1101        return JSValue::encode(jsNull());
1102    if (result.isObject())
1103        return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value")));
1104    return JSValue::encode(result);
1105}
1106
1107} // namespace JSC
1108