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