• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "JSString.h"
31 #include "JSStringBuilder.h"
32 #include "Lookup.h"
33 #include "ObjectPrototype.h"
34 
35 #if !PLATFORM(MAC) && HAVE(LANGINFO_H)
36 #include <langinfo.h>
37 #endif
38 
39 #include <limits.h>
40 #include <locale.h>
41 #include <math.h>
42 #include <stdlib.h>
43 #include <time.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>
49 
50 #if HAVE(SYS_PARAM_H)
51 #include <sys/param.h>
52 #endif
53 
54 #if HAVE(SYS_TIME_H)
55 #include <sys/time.h>
56 #endif
57 
58 #if HAVE(SYS_TIMEB_H)
59 #include <sys/timeb.h>
60 #endif
61 
62 #if PLATFORM(MAC)
63 #include <CoreFoundation/CoreFoundation.h>
64 #endif
65 
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
68 #endif
69 
70 using namespace WTF;
71 
72 namespace JSC {
73 
74 ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
75 
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*);
121 
122 }
123 
124 #include "DatePrototype.lut.h"
125 
126 namespace JSC {
127 
128 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
129 
130 #if PLATFORM(MAC)
131 
132 // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
133 // Instead we should consider using this whenever USE(CF) is true.
134 
styleFromArgString(const UString & string,CFDateFormatterStyle defaultStyle)135 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
136 {
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;
145     return defaultStyle;
146 }
147 
formatLocaleDate(ExecState * exec,DateInstance *,double timeInMilliseconds,LocaleDateTimeFormat format)148 static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
149 {
150     CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
151     CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
152 
153     bool useCustomFormat = false;
154     UString customFormatString;
155 
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);
167 
168     CFLocaleRef locale = CFLocaleCopyCurrent();
169     CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
170     CFRelease(locale);
171 
172     if (useCustomFormat) {
173         CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
174         CFDateFormatterSetFormat(formatter, customFormatCFString);
175         CFRelease(customFormatCFString);
176     }
177 
178     CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
179 
180     CFRelease(formatter);
181 
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.
184     UChar buffer[200];
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);
191 
192     CFRelease(string);
193 
194     return jsNontrivialString(exec, UString(buffer, length));
195 }
196 
197 #else // !PLATFORM(MAC)
198 
formatLocaleDate(ExecState * exec,const GregorianDateTime & gdt,LocaleDateTimeFormat format)199 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
200 {
201 #if HAVE(LANGINFO_H)
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" };
206 #else
207     static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
208 #endif
209 
210     // Offset year if needed
211     struct tm localTM = gdt;
212     int year = gdt.year + 1900;
213     bool yearNeedsOffset = year < 1900 || year > 2038;
214     if (yearNeedsOffset)
215         localTM.tm_year = equivalentYearForDST(year) - 1900;
216 
217 #if HAVE(LANGINFO_H)
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
220     // need offset.
221     char* formatString = strdup(nl_langinfo(formats[format]));
222     char* yPos = strchr(formatString, 'y');
223     if (yPos)
224         *yPos = 'Y';
225 #endif
226 
227     // Do the formatting
228     const int bufsize = 128;
229     char timebuffer[bufsize];
230 
231 #if HAVE(LANGINFO_H)
232     size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
233     free(formatString);
234 #else
235     size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
236 #endif
237 
238     if (ret == 0)
239         return jsEmptyString(exec);
240 
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];
245 
246         snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
247         char* yearLocation = strstr(timebuffer, yearString);
248         snprintf(yearString, yearLen, "%d", year);
249 
250         strncpy(yearLocation, yearString, yearLen - 1);
251     }
252 
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));
270     }
271 #endif
272 
273     return jsNontrivialString(exec, timebuffer);
274 }
275 
formatLocaleDate(ExecState * exec,DateInstance * dateObject,double,LocaleDateTimeFormat format)276 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
277 {
278     const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
279     if (!gregorianDateTime)
280         return jsNontrivialString(exec, "Invalid Date");
281     return formatLocaleDate(exec, *gregorianDateTime, format);
282 }
283 
284 #endif // !PLATFORM(MAC)
285 
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.
288 //
289 // Format of member function: f([hour,] [min,] [sec,] [ms])
fillStructuresUsingTimeArgs(ExecState * exec,int maxArgs,double * ms,GregorianDateTime * t)290 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
291 {
292     double milliseconds = 0;
293     bool ok = true;
294     int idx = 0;
295     int numArgs = exec->argumentCount();
296 
297     // JS allows extra trailing arguments -- ignore them
298     if (numArgs > maxArgs)
299         numArgs = maxArgs;
300 
301     // hours
302     if (maxArgs >= 4 && idx < numArgs) {
303         t->hour = 0;
304         double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
305         ok = isfinite(hours);
306         milliseconds += hours * msPerHour;
307     }
308 
309     // minutes
310     if (maxArgs >= 3 && idx < numArgs && ok) {
311         t->minute = 0;
312         double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
313         ok = isfinite(minutes);
314         milliseconds += minutes * msPerMinute;
315     }
316 
317     // seconds
318     if (maxArgs >= 2 && idx < numArgs && ok) {
319         t->second = 0;
320         double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
321         ok = isfinite(seconds);
322         milliseconds += seconds * msPerSecond;
323     }
324 
325     if (!ok)
326         return false;
327 
328     // milliseconds
329     if (idx < numArgs) {
330         double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
331         ok = isfinite(millis);
332         milliseconds += millis;
333     } else
334         milliseconds += *ms;
335 
336     *ms = milliseconds;
337     return ok;
338 }
339 
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.
342 //
343 // Format of member function: f([years,] [months,] [days])
fillStructuresUsingDateArgs(ExecState * exec,int maxArgs,double * ms,GregorianDateTime * t)344 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
345 {
346     int idx = 0;
347     bool ok = true;
348     int numArgs = exec->argumentCount();
349 
350     // JS allows extra trailing arguments -- ignore them
351     if (numArgs > maxArgs)
352         numArgs = maxArgs;
353 
354     // years
355     if (maxArgs >= 3 && idx < numArgs) {
356         double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
357         ok = isfinite(years);
358         t->year = toInt32(years - 1900);
359     }
360     // months
361     if (maxArgs >= 2 && idx < numArgs && ok) {
362         double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
363         ok = isfinite(months);
364         t->month = toInt32(months);
365     }
366     // days
367     if (idx < numArgs && ok) {
368         double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
369         ok = isfinite(days);
370         t->monthDay = 0;
371         *ms += days * msPerDay;
372     }
373 
374     return ok;
375 }
376 
377 const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable};
378 
379 /* Source for DatePrototype.lut.h
380 @begin dateTable
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
427 @end
428 */
429 
430 // ECMA 15.9.4
431 
DatePrototype(ExecState * exec,JSGlobalObject * globalObject,Structure * structure)432 DatePrototype::DatePrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
433     : DateInstance(exec, structure)
434 {
435     ASSERT(inherits(&s_info));
436 
437     // The constructor will be added later, after DateConstructor has been built.
438     putAnonymousValue(exec->globalData(), 0, globalObject);
439 }
440 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)441 bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
442 {
443     return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot);
444 }
445 
446 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)447 bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
448 {
449     return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
450 }
451 
452 // Functions
453 
dateProtoFuncToString(ExecState * exec)454 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
455 {
456     JSValue thisValue = exec->hostThisValue();
457     if (!thisValue.inherits(&DateInstance::s_info))
458         return throwVMTypeError(exec);
459 
460     DateInstance* thisDateObj = asDateInstance(thisValue);
461 
462     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
463     if (!gregorianDateTime)
464         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
465     DateConversionBuffer date;
466     DateConversionBuffer time;
467     formatDate(*gregorianDateTime, date);
468     formatTime(*gregorianDateTime, time);
469     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
470 }
471 
dateProtoFuncToUTCString(ExecState * exec)472 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
473 {
474     JSValue thisValue = exec->hostThisValue();
475     if (!thisValue.inherits(&DateInstance::s_info))
476         return throwVMTypeError(exec);
477 
478     DateInstance* thisDateObj = asDateInstance(thisValue);
479 
480     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
481     if (!gregorianDateTime)
482         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
483     DateConversionBuffer date;
484     DateConversionBuffer time;
485     formatDateUTCVariant(*gregorianDateTime, date);
486     formatTimeUTC(*gregorianDateTime, time);
487     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
488 }
489 
dateProtoFuncToISOString(ExecState * exec)490 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
491 {
492     JSValue thisValue = exec->hostThisValue();
493     if (!thisValue.inherits(&DateInstance::s_info))
494         return throwVMTypeError(exec);
495 
496     DateInstance* thisDateObj = asDateInstance(thisValue);
497 
498     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
499     if (!gregorianDateTime)
500         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
501     // 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)
502     // 6 for formatting and one for null termination = 27.  We add one extra character to allow us to force null termination.
503     char buffer[28];
504     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)));
505     buffer[sizeof(buffer) - 1] = 0;
506     return JSValue::encode(jsNontrivialString(exec, buffer));
507 }
508 
dateProtoFuncToDateString(ExecState * exec)509 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
510 {
511     JSValue thisValue = exec->hostThisValue();
512     if (!thisValue.inherits(&DateInstance::s_info))
513         return throwVMTypeError(exec);
514 
515     DateInstance* thisDateObj = asDateInstance(thisValue);
516 
517     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
518     if (!gregorianDateTime)
519         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
520     DateConversionBuffer date;
521     formatDate(*gregorianDateTime, date);
522     return JSValue::encode(jsNontrivialString(exec, date));
523 }
524 
dateProtoFuncToTimeString(ExecState * exec)525 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
526 {
527     JSValue thisValue = exec->hostThisValue();
528     if (!thisValue.inherits(&DateInstance::s_info))
529         return throwVMTypeError(exec);
530 
531     DateInstance* thisDateObj = asDateInstance(thisValue);
532 
533     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
534     if (!gregorianDateTime)
535         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
536     DateConversionBuffer time;
537     formatTime(*gregorianDateTime, time);
538     return JSValue::encode(jsNontrivialString(exec, time));
539 }
540 
dateProtoFuncToLocaleString(ExecState * exec)541 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
542 {
543     JSValue thisValue = exec->hostThisValue();
544     if (!thisValue.inherits(&DateInstance::s_info))
545         return throwVMTypeError(exec);
546 
547     DateInstance* thisDateObj = asDateInstance(thisValue);
548     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
549 }
550 
dateProtoFuncToLocaleDateString(ExecState * exec)551 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
552 {
553     JSValue thisValue = exec->hostThisValue();
554     if (!thisValue.inherits(&DateInstance::s_info))
555         return throwVMTypeError(exec);
556 
557     DateInstance* thisDateObj = asDateInstance(thisValue);
558     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
559 }
560 
dateProtoFuncToLocaleTimeString(ExecState * exec)561 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
562 {
563     JSValue thisValue = exec->hostThisValue();
564     if (!thisValue.inherits(&DateInstance::s_info))
565         return throwVMTypeError(exec);
566 
567     DateInstance* thisDateObj = asDateInstance(thisValue);
568     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
569 }
570 
dateProtoFuncGetTime(ExecState * exec)571 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
572 {
573     JSValue thisValue = exec->hostThisValue();
574     if (!thisValue.inherits(&DateInstance::s_info))
575         return throwVMTypeError(exec);
576 
577     return JSValue::encode(asDateInstance(thisValue)->internalValue());
578 }
579 
dateProtoFuncGetFullYear(ExecState * exec)580 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
581 {
582     JSValue thisValue = exec->hostThisValue();
583     if (!thisValue.inherits(&DateInstance::s_info))
584         return throwVMTypeError(exec);
585 
586     DateInstance* thisDateObj = asDateInstance(thisValue);
587 
588     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
589     if (!gregorianDateTime)
590         return JSValue::encode(jsNaN());
591     return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
592 }
593 
dateProtoFuncGetUTCFullYear(ExecState * exec)594 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
595 {
596     JSValue thisValue = exec->hostThisValue();
597     if (!thisValue.inherits(&DateInstance::s_info))
598         return throwVMTypeError(exec);
599 
600     DateInstance* thisDateObj = asDateInstance(thisValue);
601 
602     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
603     if (!gregorianDateTime)
604         return JSValue::encode(jsNaN());
605     return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
606 }
607 
dateProtoFuncToGMTString(ExecState * exec)608 EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
609 {
610     JSValue thisValue = exec->hostThisValue();
611     if (!thisValue.inherits(&DateInstance::s_info))
612         return throwVMTypeError(exec);
613 
614     DateInstance* thisDateObj = asDateInstance(thisValue);
615 
616     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
617     if (!gregorianDateTime)
618         return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
619     DateConversionBuffer date;
620     DateConversionBuffer time;
621     formatDateUTCVariant(*gregorianDateTime, date);
622     formatTimeUTC(*gregorianDateTime, time);
623     return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
624 }
625 
dateProtoFuncGetMonth(ExecState * exec)626 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
627 {
628     JSValue thisValue = exec->hostThisValue();
629     if (!thisValue.inherits(&DateInstance::s_info))
630         return throwVMTypeError(exec);
631 
632     DateInstance* thisDateObj = asDateInstance(thisValue);
633 
634     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
635     if (!gregorianDateTime)
636         return JSValue::encode(jsNaN());
637     return JSValue::encode(jsNumber(gregorianDateTime->month));
638 }
639 
dateProtoFuncGetUTCMonth(ExecState * exec)640 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
641 {
642     JSValue thisValue = exec->hostThisValue();
643     if (!thisValue.inherits(&DateInstance::s_info))
644         return throwVMTypeError(exec);
645 
646     DateInstance* thisDateObj = asDateInstance(thisValue);
647 
648     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
649     if (!gregorianDateTime)
650         return JSValue::encode(jsNaN());
651     return JSValue::encode(jsNumber(gregorianDateTime->month));
652 }
653 
dateProtoFuncGetDate(ExecState * exec)654 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
655 {
656     JSValue thisValue = exec->hostThisValue();
657     if (!thisValue.inherits(&DateInstance::s_info))
658         return throwVMTypeError(exec);
659 
660     DateInstance* thisDateObj = asDateInstance(thisValue);
661 
662     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
663     if (!gregorianDateTime)
664         return JSValue::encode(jsNaN());
665     return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
666 }
667 
dateProtoFuncGetUTCDate(ExecState * exec)668 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
669 {
670     JSValue thisValue = exec->hostThisValue();
671     if (!thisValue.inherits(&DateInstance::s_info))
672         return throwVMTypeError(exec);
673 
674     DateInstance* thisDateObj = asDateInstance(thisValue);
675 
676     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
677     if (!gregorianDateTime)
678         return JSValue::encode(jsNaN());
679     return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
680 }
681 
dateProtoFuncGetDay(ExecState * exec)682 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
683 {
684     JSValue thisValue = exec->hostThisValue();
685     if (!thisValue.inherits(&DateInstance::s_info))
686         return throwVMTypeError(exec);
687 
688     DateInstance* thisDateObj = asDateInstance(thisValue);
689 
690     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
691     if (!gregorianDateTime)
692         return JSValue::encode(jsNaN());
693     return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
694 }
695 
dateProtoFuncGetUTCDay(ExecState * exec)696 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
697 {
698     JSValue thisValue = exec->hostThisValue();
699     if (!thisValue.inherits(&DateInstance::s_info))
700         return throwVMTypeError(exec);
701 
702     DateInstance* thisDateObj = asDateInstance(thisValue);
703 
704     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
705     if (!gregorianDateTime)
706         return JSValue::encode(jsNaN());
707     return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
708 }
709 
dateProtoFuncGetHours(ExecState * exec)710 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
711 {
712     JSValue thisValue = exec->hostThisValue();
713     if (!thisValue.inherits(&DateInstance::s_info))
714         return throwVMTypeError(exec);
715 
716     DateInstance* thisDateObj = asDateInstance(thisValue);
717 
718     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
719     if (!gregorianDateTime)
720         return JSValue::encode(jsNaN());
721     return JSValue::encode(jsNumber(gregorianDateTime->hour));
722 }
723 
dateProtoFuncGetUTCHours(ExecState * exec)724 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
725 {
726     JSValue thisValue = exec->hostThisValue();
727     if (!thisValue.inherits(&DateInstance::s_info))
728         return throwVMTypeError(exec);
729 
730     DateInstance* thisDateObj = asDateInstance(thisValue);
731 
732     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
733     if (!gregorianDateTime)
734         return JSValue::encode(jsNaN());
735     return JSValue::encode(jsNumber(gregorianDateTime->hour));
736 }
737 
dateProtoFuncGetMinutes(ExecState * exec)738 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
739 {
740     JSValue thisValue = exec->hostThisValue();
741     if (!thisValue.inherits(&DateInstance::s_info))
742         return throwVMTypeError(exec);
743 
744     DateInstance* thisDateObj = asDateInstance(thisValue);
745 
746     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
747     if (!gregorianDateTime)
748         return JSValue::encode(jsNaN());
749     return JSValue::encode(jsNumber(gregorianDateTime->minute));
750 }
751 
dateProtoFuncGetUTCMinutes(ExecState * exec)752 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
753 {
754     JSValue thisValue = exec->hostThisValue();
755     if (!thisValue.inherits(&DateInstance::s_info))
756         return throwVMTypeError(exec);
757 
758     DateInstance* thisDateObj = asDateInstance(thisValue);
759 
760     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
761     if (!gregorianDateTime)
762         return JSValue::encode(jsNaN());
763     return JSValue::encode(jsNumber(gregorianDateTime->minute));
764 }
765 
dateProtoFuncGetSeconds(ExecState * exec)766 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
767 {
768     JSValue thisValue = exec->hostThisValue();
769     if (!thisValue.inherits(&DateInstance::s_info))
770         return throwVMTypeError(exec);
771 
772     DateInstance* thisDateObj = asDateInstance(thisValue);
773 
774     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
775     if (!gregorianDateTime)
776         return JSValue::encode(jsNaN());
777     return JSValue::encode(jsNumber(gregorianDateTime->second));
778 }
779 
dateProtoFuncGetUTCSeconds(ExecState * exec)780 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
781 {
782     JSValue thisValue = exec->hostThisValue();
783     if (!thisValue.inherits(&DateInstance::s_info))
784         return throwVMTypeError(exec);
785 
786     DateInstance* thisDateObj = asDateInstance(thisValue);
787 
788     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
789     if (!gregorianDateTime)
790         return JSValue::encode(jsNaN());
791     return JSValue::encode(jsNumber(gregorianDateTime->second));
792 }
793 
dateProtoFuncGetMilliSeconds(ExecState * exec)794 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
795 {
796     JSValue thisValue = exec->hostThisValue();
797     if (!thisValue.inherits(&DateInstance::s_info))
798         return throwVMTypeError(exec);
799 
800     DateInstance* thisDateObj = asDateInstance(thisValue);
801     double milli = thisDateObj->internalNumber();
802     if (isnan(milli))
803         return JSValue::encode(jsNaN());
804 
805     double secs = floor(milli / msPerSecond);
806     double ms = milli - secs * msPerSecond;
807     return JSValue::encode(jsNumber(ms));
808 }
809 
dateProtoFuncGetUTCMilliseconds(ExecState * exec)810 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
811 {
812     JSValue thisValue = exec->hostThisValue();
813     if (!thisValue.inherits(&DateInstance::s_info))
814         return throwVMTypeError(exec);
815 
816     DateInstance* thisDateObj = asDateInstance(thisValue);
817     double milli = thisDateObj->internalNumber();
818     if (isnan(milli))
819         return JSValue::encode(jsNaN());
820 
821     double secs = floor(milli / msPerSecond);
822     double ms = milli - secs * msPerSecond;
823     return JSValue::encode(jsNumber(ms));
824 }
825 
dateProtoFuncGetTimezoneOffset(ExecState * exec)826 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
827 {
828     JSValue thisValue = exec->hostThisValue();
829     if (!thisValue.inherits(&DateInstance::s_info))
830         return throwVMTypeError(exec);
831 
832     DateInstance* thisDateObj = asDateInstance(thisValue);
833 
834     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
835     if (!gregorianDateTime)
836         return JSValue::encode(jsNaN());
837     return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
838 }
839 
dateProtoFuncSetTime(ExecState * exec)840 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
841 {
842     JSValue thisValue = exec->hostThisValue();
843     if (!thisValue.inherits(&DateInstance::s_info))
844         return throwVMTypeError(exec);
845 
846     DateInstance* thisDateObj = asDateInstance(thisValue);
847 
848     double milli = timeClip(exec->argument(0).toNumber(exec));
849     JSValue result = jsNumber(milli);
850     thisDateObj->setInternalValue(exec->globalData(), result);
851     return JSValue::encode(result);
852 }
853 
setNewValueFromTimeArgs(ExecState * exec,int numArgsToUse,bool inputIsUTC)854 static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
855 {
856     JSValue thisValue = exec->hostThisValue();
857     if (!thisValue.inherits(&DateInstance::s_info))
858         return throwVMTypeError(exec);
859 
860     DateInstance* thisDateObj = asDateInstance(thisValue);
861     double milli = thisDateObj->internalNumber();
862 
863     if (!exec->argumentCount() || isnan(milli)) {
864         JSValue result = jsNaN();
865         thisDateObj->setInternalValue(exec->globalData(), result);
866         return JSValue::encode(result);
867     }
868 
869     double secs = floor(milli / msPerSecond);
870     double ms = milli - secs * msPerSecond;
871 
872     const GregorianDateTime* other = inputIsUTC
873         ? thisDateObj->gregorianDateTimeUTC(exec)
874         : thisDateObj->gregorianDateTime(exec);
875     if (!other)
876         return JSValue::encode(jsNaN());
877 
878     GregorianDateTime gregorianDateTime;
879     gregorianDateTime.copyFrom(*other);
880     if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
881         JSValue result = jsNaN();
882         thisDateObj->setInternalValue(exec->globalData(), result);
883         return JSValue::encode(result);
884     }
885 
886     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
887     thisDateObj->setInternalValue(exec->globalData(), result);
888     return JSValue::encode(result);
889 }
890 
setNewValueFromDateArgs(ExecState * exec,int numArgsToUse,bool inputIsUTC)891 static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
892 {
893     JSValue thisValue = exec->hostThisValue();
894     if (!thisValue.inherits(&DateInstance::s_info))
895         return throwVMTypeError(exec);
896 
897     DateInstance* thisDateObj = asDateInstance(thisValue);
898     if (!exec->argumentCount()) {
899         JSValue result = jsNaN();
900         thisDateObj->setInternalValue(exec->globalData(), result);
901         return JSValue::encode(result);
902     }
903 
904     double milli = thisDateObj->internalNumber();
905     double ms = 0;
906 
907     GregorianDateTime gregorianDateTime;
908     if (numArgsToUse == 3 && isnan(milli))
909         msToGregorianDateTime(exec, 0, true, gregorianDateTime);
910     else {
911         ms = milli - floor(milli / msPerSecond) * msPerSecond;
912         const GregorianDateTime* other = inputIsUTC
913             ? thisDateObj->gregorianDateTimeUTC(exec)
914             : thisDateObj->gregorianDateTime(exec);
915         if (!other)
916             return JSValue::encode(jsNaN());
917         gregorianDateTime.copyFrom(*other);
918     }
919 
920     if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
921         JSValue result = jsNaN();
922         thisDateObj->setInternalValue(exec->globalData(), result);
923         return JSValue::encode(result);
924     }
925 
926     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
927     thisDateObj->setInternalValue(exec->globalData(), result);
928     return JSValue::encode(result);
929 }
930 
dateProtoFuncSetMilliSeconds(ExecState * exec)931 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
932 {
933     const bool inputIsUTC = false;
934     return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
935 }
936 
dateProtoFuncSetUTCMilliseconds(ExecState * exec)937 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
938 {
939     const bool inputIsUTC = true;
940     return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
941 }
942 
dateProtoFuncSetSeconds(ExecState * exec)943 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
944 {
945     const bool inputIsUTC = false;
946     return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
947 }
948 
dateProtoFuncSetUTCSeconds(ExecState * exec)949 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
950 {
951     const bool inputIsUTC = true;
952     return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
953 }
954 
dateProtoFuncSetMinutes(ExecState * exec)955 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
956 {
957     const bool inputIsUTC = false;
958     return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
959 }
960 
dateProtoFuncSetUTCMinutes(ExecState * exec)961 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
962 {
963     const bool inputIsUTC = true;
964     return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
965 }
966 
dateProtoFuncSetHours(ExecState * exec)967 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
968 {
969     const bool inputIsUTC = false;
970     return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
971 }
972 
dateProtoFuncSetUTCHours(ExecState * exec)973 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
974 {
975     const bool inputIsUTC = true;
976     return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
977 }
978 
dateProtoFuncSetDate(ExecState * exec)979 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
980 {
981     const bool inputIsUTC = false;
982     return setNewValueFromDateArgs(exec, 1, inputIsUTC);
983 }
984 
dateProtoFuncSetUTCDate(ExecState * exec)985 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
986 {
987     const bool inputIsUTC = true;
988     return setNewValueFromDateArgs(exec, 1, inputIsUTC);
989 }
990 
dateProtoFuncSetMonth(ExecState * exec)991 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
992 {
993     const bool inputIsUTC = false;
994     return setNewValueFromDateArgs(exec, 2, inputIsUTC);
995 }
996 
dateProtoFuncSetUTCMonth(ExecState * exec)997 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
998 {
999     const bool inputIsUTC = true;
1000     return setNewValueFromDateArgs(exec, 2, inputIsUTC);
1001 }
1002 
dateProtoFuncSetFullYear(ExecState * exec)1003 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
1004 {
1005     const bool inputIsUTC = false;
1006     return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1007 }
1008 
dateProtoFuncSetUTCFullYear(ExecState * exec)1009 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
1010 {
1011     const bool inputIsUTC = true;
1012     return setNewValueFromDateArgs(exec, 3, inputIsUTC);
1013 }
1014 
dateProtoFuncSetYear(ExecState * exec)1015 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
1016 {
1017     JSValue thisValue = exec->hostThisValue();
1018     if (!thisValue.inherits(&DateInstance::s_info))
1019         return throwVMTypeError(exec);
1020 
1021     DateInstance* thisDateObj = asDateInstance(thisValue);
1022     if (!exec->argumentCount()) {
1023         JSValue result = jsNaN();
1024         thisDateObj->setInternalValue(exec->globalData(), result);
1025         return JSValue::encode(result);
1026     }
1027 
1028     double milli = thisDateObj->internalNumber();
1029     double ms = 0;
1030 
1031     GregorianDateTime gregorianDateTime;
1032     if (isnan(milli))
1033         // Based on ECMA 262 B.2.5 (setYear)
1034         // the time must be reset to +0 if it is NaN.
1035         msToGregorianDateTime(exec, 0, true, gregorianDateTime);
1036     else {
1037         double secs = floor(milli / msPerSecond);
1038         ms = milli - secs * msPerSecond;
1039         if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
1040             gregorianDateTime.copyFrom(*other);
1041     }
1042 
1043     double year = exec->argument(0).toIntegerPreserveNaN(exec);
1044     if (!isfinite(year)) {
1045         JSValue result = jsNaN();
1046         thisDateObj->setInternalValue(exec->globalData(), result);
1047         return JSValue::encode(result);
1048     }
1049 
1050     gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
1051     JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
1052     thisDateObj->setInternalValue(exec->globalData(), result);
1053     return JSValue::encode(result);
1054 }
1055 
dateProtoFuncGetYear(ExecState * exec)1056 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
1057 {
1058     JSValue thisValue = exec->hostThisValue();
1059     if (!thisValue.inherits(&DateInstance::s_info))
1060         return throwVMTypeError(exec);
1061 
1062     DateInstance* thisDateObj = asDateInstance(thisValue);
1063 
1064     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
1065     if (!gregorianDateTime)
1066         return JSValue::encode(jsNaN());
1067 
1068     // NOTE: IE returns the full year even in getYear.
1069     return JSValue::encode(jsNumber(gregorianDateTime->year));
1070 }
1071 
dateProtoFuncToJSON(ExecState * exec)1072 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
1073 {
1074     JSValue thisValue = exec->hostThisValue();
1075     JSObject* object = thisValue.toThisObject(exec);
1076     if (exec->hadException())
1077         return JSValue::encode(jsNull());
1078 
1079     JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
1080     if (exec->hadException())
1081         return JSValue::encode(jsNull());
1082 
1083     CallData callData;
1084     CallType callType = getCallData(toISOValue, callData);
1085     if (callType == CallTypeNone)
1086         return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
1087 
1088     JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
1089     if (exec->hadException())
1090         return JSValue::encode(jsNull());
1091     if (result.isObject())
1092         return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
1093     return JSValue::encode(result);
1094 }
1095 
1096 } // namespace JSC
1097