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