1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/builtins/builtins-utils-inl.h"
6#include "src/builtins/builtins.h"
7#include "src/codegen/code-factory.h"
8#include "src/date/date.h"
9#include "src/date/dateparser-inl.h"
10#include "src/logging/counters.h"
11#include "src/numbers/conversions.h"
12#include "src/objects/objects-inl.h"
13#ifdef V8_INTL_SUPPORT
14#include "src/objects/intl-objects.h"
15#include "src/objects/js-date-time-format.h"
16#endif
17#include "src/strings/string-stream.h"
18
19namespace v8 {
20namespace internal {
21
22// -----------------------------------------------------------------------------
23// ES6 section 20.3 Date Objects
24
25namespace {
26
27// ES6 section 20.3.1.16 Date Time String Format
28double ParseDateTimeString(Isolate* isolate, Handle<String> str) {
29  str = String::Flatten(isolate, str);
30  double out[DateParser::OUTPUT_SIZE];
31  DisallowGarbageCollection no_gc;
32  String::FlatContent str_content = str->GetFlatContent(no_gc);
33  bool result;
34  if (str_content.IsOneByte()) {
35    result = DateParser::Parse(isolate, str_content.ToOneByteVector(), out);
36  } else {
37    result = DateParser::Parse(isolate, str_content.ToUC16Vector(), out);
38  }
39  if (!result) return std::numeric_limits<double>::quiet_NaN();
40  double const day = MakeDay(out[DateParser::YEAR], out[DateParser::MONTH],
41                             out[DateParser::DAY]);
42  double const time =
43      MakeTime(out[DateParser::HOUR], out[DateParser::MINUTE],
44               out[DateParser::SECOND], out[DateParser::MILLISECOND]);
45  double date = MakeDate(day, time);
46  if (std::isnan(out[DateParser::UTC_OFFSET])) {
47    if (date >= -DateCache::kMaxTimeBeforeUTCInMs &&
48        date <= DateCache::kMaxTimeBeforeUTCInMs) {
49      date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
50    } else {
51      return std::numeric_limits<double>::quiet_NaN();
52    }
53  } else {
54    date -= out[DateParser::UTC_OFFSET] * 1000.0;
55  }
56  return DateCache::TimeClip(date);
57}
58
59Object SetLocalDateValue(Isolate* isolate, Handle<JSDate> date,
60                         double time_val) {
61  if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
62      time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
63    time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
64  } else {
65    time_val = std::numeric_limits<double>::quiet_NaN();
66  }
67  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
68}
69
70}  // namespace
71
72// ES #sec-date-constructor
73BUILTIN(DateConstructor) {
74  HandleScope scope(isolate);
75  if (args.new_target()->IsUndefined(isolate)) {
76    double const time_val = JSDate::CurrentTimeValue(isolate);
77    DateBuffer buffer = ToDateString(time_val, isolate->date_cache(),
78                                     ToDateStringMode::kLocalDateAndTime);
79    RETURN_RESULT_OR_FAILURE(
80        isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer)));
81  }
82  // [Construct]
83  int const argc = args.length() - 1;
84  Handle<JSFunction> target = args.target();
85  Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
86  double time_val;
87  if (argc == 0) {
88    time_val = JSDate::CurrentTimeValue(isolate);
89  } else if (argc == 1) {
90    Handle<Object> value = args.at(1);
91    if (value->IsJSDate()) {
92      time_val = Handle<JSDate>::cast(value)->value().Number();
93    } else {
94      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
95                                         Object::ToPrimitive(isolate, value));
96      if (value->IsString()) {
97        time_val = ParseDateTimeString(isolate, Handle<String>::cast(value));
98      } else {
99        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
100                                           Object::ToNumber(isolate, value));
101        time_val = value->Number();
102      }
103    }
104  } else {
105    Handle<Object> year_object;
106    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
107                                       Object::ToNumber(isolate, args.at(1)));
108    Handle<Object> month_object;
109    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
110                                       Object::ToNumber(isolate, args.at(2)));
111    double year = year_object->Number();
112    double month = month_object->Number();
113    double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
114    if (argc >= 3) {
115      Handle<Object> date_object;
116      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object,
117                                         Object::ToNumber(isolate, args.at(3)));
118      date = date_object->Number();
119      if (argc >= 4) {
120        Handle<Object> hours_object;
121        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
122            isolate, hours_object, Object::ToNumber(isolate, args.at(4)));
123        hours = hours_object->Number();
124        if (argc >= 5) {
125          Handle<Object> minutes_object;
126          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
127              isolate, minutes_object, Object::ToNumber(isolate, args.at(5)));
128          minutes = minutes_object->Number();
129          if (argc >= 6) {
130            Handle<Object> seconds_object;
131            ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
132                isolate, seconds_object, Object::ToNumber(isolate, args.at(6)));
133            seconds = seconds_object->Number();
134            if (argc >= 7) {
135              Handle<Object> ms_object;
136              ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
137                  isolate, ms_object, Object::ToNumber(isolate, args.at(7)));
138              ms = ms_object->Number();
139            }
140          }
141        }
142      }
143    }
144    if (!std::isnan(year)) {
145      double const y = DoubleToInteger(year);
146      if (0.0 <= y && y <= 99) year = 1900 + y;
147    }
148    double const day = MakeDay(year, month, date);
149    double const time = MakeTime(hours, minutes, seconds, ms);
150    time_val = MakeDate(day, time);
151    if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
152        time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
153      time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
154    } else {
155      time_val = std::numeric_limits<double>::quiet_NaN();
156    }
157  }
158  RETURN_RESULT_OR_FAILURE(isolate, JSDate::New(target, new_target, time_val));
159}
160
161// ES6 section 20.3.3.1 Date.now ( )
162BUILTIN(DateNow) {
163  HandleScope scope(isolate);
164  return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
165}
166
167// ES6 section 20.3.3.2 Date.parse ( string )
168BUILTIN(DateParse) {
169  HandleScope scope(isolate);
170  Handle<String> string;
171  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
172      isolate, string,
173      Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
174  return *isolate->factory()->NewNumber(ParseDateTimeString(isolate, string));
175}
176
177// ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms)
178BUILTIN(DateUTC) {
179  HandleScope scope(isolate);
180  int const argc = args.length() - 1;
181  double year = std::numeric_limits<double>::quiet_NaN();
182  double month = 0.0, date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0,
183         ms = 0.0;
184  if (argc >= 1) {
185    Handle<Object> year_object;
186    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
187                                       Object::ToNumber(isolate, args.at(1)));
188    year = year_object->Number();
189    if (argc >= 2) {
190      Handle<Object> month_object;
191      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
192                                         Object::ToNumber(isolate, args.at(2)));
193      month = month_object->Number();
194      if (argc >= 3) {
195        Handle<Object> date_object;
196        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
197            isolate, date_object, Object::ToNumber(isolate, args.at(3)));
198        date = date_object->Number();
199        if (argc >= 4) {
200          Handle<Object> hours_object;
201          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
202              isolate, hours_object, Object::ToNumber(isolate, args.at(4)));
203          hours = hours_object->Number();
204          if (argc >= 5) {
205            Handle<Object> minutes_object;
206            ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
207                isolate, minutes_object, Object::ToNumber(isolate, args.at(5)));
208            minutes = minutes_object->Number();
209            if (argc >= 6) {
210              Handle<Object> seconds_object;
211              ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
212                  isolate, seconds_object,
213                  Object::ToNumber(isolate, args.at(6)));
214              seconds = seconds_object->Number();
215              if (argc >= 7) {
216                Handle<Object> ms_object;
217                ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
218                    isolate, ms_object, Object::ToNumber(isolate, args.at(7)));
219                ms = ms_object->Number();
220              }
221            }
222          }
223        }
224      }
225    }
226  }
227  if (!std::isnan(year)) {
228    double const y = DoubleToInteger(year);
229    if (0.0 <= y && y <= 99) year = 1900 + y;
230  }
231  double const day = MakeDay(year, month, date);
232  double const time = MakeTime(hours, minutes, seconds, ms);
233  return *isolate->factory()->NewNumber(
234      DateCache::TimeClip(MakeDate(day, time)));
235}
236
237// ES6 section 20.3.4.20 Date.prototype.setDate ( date )
238BUILTIN(DatePrototypeSetDate) {
239  HandleScope scope(isolate);
240  CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate");
241  Handle<Object> value = args.atOrUndefined(isolate, 1);
242  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
243                                     Object::ToNumber(isolate, value));
244  double time_val = date->value().Number();
245  if (!std::isnan(time_val)) {
246    int64_t const time_ms = static_cast<int64_t>(time_val);
247    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
248    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
249    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
250    int year, month, day;
251    isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
252    time_val = MakeDate(MakeDay(year, month, value->Number()), time_within_day);
253  }
254  return SetLocalDateValue(isolate, date, time_val);
255}
256
257// ES6 section 20.3.4.21 Date.prototype.setFullYear (year, month, date)
258BUILTIN(DatePrototypeSetFullYear) {
259  HandleScope scope(isolate);
260  CHECK_RECEIVER(JSDate, date, "Date.prototype.setFullYear");
261  int const argc = args.length() - 1;
262  Handle<Object> year = args.atOrUndefined(isolate, 1);
263  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year,
264                                     Object::ToNumber(isolate, year));
265  double year_double = year->Number(), month_double = 0.0, day_double = 1.0;
266  int time_within_day = 0;
267  if (!std::isnan(date->value().Number())) {
268    int64_t const time_ms = static_cast<int64_t>(date->value().Number());
269    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
270    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
271    time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
272    int year_int, month_int, day_int;
273    isolate->date_cache()->YearMonthDayFromDays(days, &year_int, &month_int,
274                                                &day_int);
275    month_double = month_int;
276    day_double = day_int;
277  }
278  if (argc >= 2) {
279    Handle<Object> month = args.at(2);
280    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
281                                       Object::ToNumber(isolate, month));
282    month_double = month->Number();
283    if (argc >= 3) {
284      Handle<Object> day = args.at(3);
285      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, day,
286                                         Object::ToNumber(isolate, day));
287      day_double = day->Number();
288    }
289  }
290  double time_val =
291      MakeDate(MakeDay(year_double, month_double, day_double), time_within_day);
292  return SetLocalDateValue(isolate, date, time_val);
293}
294
295// ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms)
296BUILTIN(DatePrototypeSetHours) {
297  HandleScope scope(isolate);
298  CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours");
299  int const argc = args.length() - 1;
300  Handle<Object> hour = args.atOrUndefined(isolate, 1);
301  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour,
302                                     Object::ToNumber(isolate, hour));
303  double h = hour->Number();
304  double time_val = date->value().Number();
305  if (!std::isnan(time_val)) {
306    int64_t const time_ms = static_cast<int64_t>(time_val);
307    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
308    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
309    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
310    double m = (time_within_day / (60 * 1000)) % 60;
311    double s = (time_within_day / 1000) % 60;
312    double milli = time_within_day % 1000;
313    if (argc >= 2) {
314      Handle<Object> min = args.at(2);
315      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
316                                         Object::ToNumber(isolate, min));
317      m = min->Number();
318      if (argc >= 3) {
319        Handle<Object> sec = args.at(3);
320        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
321                                           Object::ToNumber(isolate, sec));
322        s = sec->Number();
323        if (argc >= 4) {
324          Handle<Object> ms = args.at(4);
325          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
326                                             Object::ToNumber(isolate, ms));
327          milli = ms->Number();
328        }
329      }
330    }
331    time_val = MakeDate(day, MakeTime(h, m, s, milli));
332  }
333  return SetLocalDateValue(isolate, date, time_val);
334}
335
336// ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms)
337BUILTIN(DatePrototypeSetMilliseconds) {
338  HandleScope scope(isolate);
339  CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds");
340  Handle<Object> ms = args.atOrUndefined(isolate, 1);
341  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
342                                     Object::ToNumber(isolate, ms));
343  double time_val = date->value().Number();
344  if (!std::isnan(time_val)) {
345    int64_t const time_ms = static_cast<int64_t>(time_val);
346    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
347    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
348    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
349    int h = time_within_day / (60 * 60 * 1000);
350    int m = (time_within_day / (60 * 1000)) % 60;
351    int s = (time_within_day / 1000) % 60;
352    time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
353  }
354  return SetLocalDateValue(isolate, date, time_val);
355}
356
357// ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms )
358BUILTIN(DatePrototypeSetMinutes) {
359  HandleScope scope(isolate);
360  CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes");
361  int const argc = args.length() - 1;
362  Handle<Object> min = args.atOrUndefined(isolate, 1);
363  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
364                                     Object::ToNumber(isolate, min));
365  double time_val = date->value().Number();
366  if (!std::isnan(time_val)) {
367    int64_t const time_ms = static_cast<int64_t>(time_val);
368    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
369    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
370    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
371    int h = time_within_day / (60 * 60 * 1000);
372    double m = min->Number();
373    double s = (time_within_day / 1000) % 60;
374    double milli = time_within_day % 1000;
375    if (argc >= 2) {
376      Handle<Object> sec = args.at(2);
377      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
378                                         Object::ToNumber(isolate, sec));
379      s = sec->Number();
380      if (argc >= 3) {
381        Handle<Object> ms = args.at(3);
382        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
383                                           Object::ToNumber(isolate, ms));
384        milli = ms->Number();
385      }
386    }
387    time_val = MakeDate(day, MakeTime(h, m, s, milli));
388  }
389  return SetLocalDateValue(isolate, date, time_val);
390}
391
392// ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date )
393BUILTIN(DatePrototypeSetMonth) {
394  HandleScope scope(isolate);
395  CHECK_RECEIVER(JSDate, this_date, "Date.prototype.setMonth");
396  int const argc = args.length() - 1;
397  Handle<Object> month = args.atOrUndefined(isolate, 1);
398  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
399                                     Object::ToNumber(isolate, month));
400  double time_val = this_date->value().Number();
401  if (!std::isnan(time_val)) {
402    int64_t const time_ms = static_cast<int64_t>(time_val);
403    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
404    int days = isolate->date_cache()->DaysFromTime(local_time_ms);
405    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
406    int year, unused, day;
407    isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
408    double m = month->Number();
409    double dt = day;
410    if (argc >= 2) {
411      Handle<Object> date = args.at(2);
412      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
413                                         Object::ToNumber(isolate, date));
414      dt = date->Number();
415    }
416    time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
417  }
418  return SetLocalDateValue(isolate, this_date, time_val);
419}
420
421// ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms )
422BUILTIN(DatePrototypeSetSeconds) {
423  HandleScope scope(isolate);
424  CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds");
425  int const argc = args.length() - 1;
426  Handle<Object> sec = args.atOrUndefined(isolate, 1);
427  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
428                                     Object::ToNumber(isolate, sec));
429  double time_val = date->value().Number();
430  if (!std::isnan(time_val)) {
431    int64_t const time_ms = static_cast<int64_t>(time_val);
432    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
433    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
434    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
435    int h = time_within_day / (60 * 60 * 1000);
436    double m = (time_within_day / (60 * 1000)) % 60;
437    double s = sec->Number();
438    double milli = time_within_day % 1000;
439    if (argc >= 2) {
440      Handle<Object> ms = args.at(2);
441      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
442                                         Object::ToNumber(isolate, ms));
443      milli = ms->Number();
444    }
445    time_val = MakeDate(day, MakeTime(h, m, s, milli));
446  }
447  return SetLocalDateValue(isolate, date, time_val);
448}
449
450// ES6 section 20.3.4.27 Date.prototype.setTime ( time )
451BUILTIN(DatePrototypeSetTime) {
452  HandleScope scope(isolate);
453  CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime");
454  Handle<Object> value = args.atOrUndefined(isolate, 1);
455  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
456                                     Object::ToNumber(isolate, value));
457  return *JSDate::SetValue(date, DateCache::TimeClip(value->Number()));
458}
459
460// ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date )
461BUILTIN(DatePrototypeSetUTCDate) {
462  HandleScope scope(isolate);
463  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate");
464  Handle<Object> value = args.atOrUndefined(isolate, 1);
465  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
466                                     Object::ToNumber(isolate, value));
467  if (std::isnan(date->value().Number())) return date->value();
468  int64_t const time_ms = static_cast<int64_t>(date->value().Number());
469  int const days = isolate->date_cache()->DaysFromTime(time_ms);
470  int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
471  int year, month, day;
472  isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
473  double const time_val =
474      MakeDate(MakeDay(year, month, value->Number()), time_within_day);
475  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
476}
477
478// ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date)
479BUILTIN(DatePrototypeSetUTCFullYear) {
480  HandleScope scope(isolate);
481  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear");
482  int const argc = args.length() - 1;
483  Handle<Object> year = args.atOrUndefined(isolate, 1);
484  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year,
485                                     Object::ToNumber(isolate, year));
486  double year_double = year->Number(), month_double = 0.0, day_double = 1.0;
487  int time_within_day = 0;
488  if (!std::isnan(date->value().Number())) {
489    int64_t const time_ms = static_cast<int64_t>(date->value().Number());
490    int const days = isolate->date_cache()->DaysFromTime(time_ms);
491    time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
492    int year_int, month_int, day_int;
493    isolate->date_cache()->YearMonthDayFromDays(days, &year_int, &month_int,
494                                                &day_int);
495    month_double = month_int;
496    day_double = day_int;
497  }
498  if (argc >= 2) {
499    Handle<Object> month = args.at(2);
500    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
501                                       Object::ToNumber(isolate, month));
502    month_double = month->Number();
503    if (argc >= 3) {
504      Handle<Object> day = args.at(3);
505      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, day,
506                                         Object::ToNumber(isolate, day));
507      day_double = day->Number();
508    }
509  }
510  double const time_val =
511      MakeDate(MakeDay(year_double, month_double, day_double), time_within_day);
512  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
513}
514
515// ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms)
516BUILTIN(DatePrototypeSetUTCHours) {
517  HandleScope scope(isolate);
518  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours");
519  int const argc = args.length() - 1;
520  Handle<Object> hour = args.atOrUndefined(isolate, 1);
521  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour,
522                                     Object::ToNumber(isolate, hour));
523  double h = hour->Number();
524  double time_val = date->value().Number();
525  if (!std::isnan(time_val)) {
526    int64_t const time_ms = static_cast<int64_t>(time_val);
527    int day = isolate->date_cache()->DaysFromTime(time_ms);
528    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
529    double m = (time_within_day / (60 * 1000)) % 60;
530    double s = (time_within_day / 1000) % 60;
531    double milli = time_within_day % 1000;
532    if (argc >= 2) {
533      Handle<Object> min = args.at(2);
534      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
535                                         Object::ToNumber(isolate, min));
536      m = min->Number();
537      if (argc >= 3) {
538        Handle<Object> sec = args.at(3);
539        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
540                                           Object::ToNumber(isolate, sec));
541        s = sec->Number();
542        if (argc >= 4) {
543          Handle<Object> ms = args.at(4);
544          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
545                                             Object::ToNumber(isolate, ms));
546          milli = ms->Number();
547        }
548      }
549    }
550    time_val = MakeDate(day, MakeTime(h, m, s, milli));
551  }
552  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
553}
554
555// ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms)
556BUILTIN(DatePrototypeSetUTCMilliseconds) {
557  HandleScope scope(isolate);
558  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds");
559  Handle<Object> ms = args.atOrUndefined(isolate, 1);
560  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
561                                     Object::ToNumber(isolate, ms));
562  double time_val = date->value().Number();
563  if (!std::isnan(time_val)) {
564    int64_t const time_ms = static_cast<int64_t>(time_val);
565    int day = isolate->date_cache()->DaysFromTime(time_ms);
566    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
567    int h = time_within_day / (60 * 60 * 1000);
568    int m = (time_within_day / (60 * 1000)) % 60;
569    int s = (time_within_day / 1000) % 60;
570    time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
571  }
572  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
573}
574
575// ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms )
576BUILTIN(DatePrototypeSetUTCMinutes) {
577  HandleScope scope(isolate);
578  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes");
579  int const argc = args.length() - 1;
580  Handle<Object> min = args.atOrUndefined(isolate, 1);
581  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
582                                     Object::ToNumber(isolate, min));
583  double time_val = date->value().Number();
584  if (!std::isnan(time_val)) {
585    int64_t const time_ms = static_cast<int64_t>(time_val);
586    int day = isolate->date_cache()->DaysFromTime(time_ms);
587    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
588    int h = time_within_day / (60 * 60 * 1000);
589    double m = min->Number();
590    double s = (time_within_day / 1000) % 60;
591    double milli = time_within_day % 1000;
592    if (argc >= 2) {
593      Handle<Object> sec = args.at(2);
594      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
595                                         Object::ToNumber(isolate, sec));
596      s = sec->Number();
597      if (argc >= 3) {
598        Handle<Object> ms = args.at(3);
599        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
600                                           Object::ToNumber(isolate, ms));
601        milli = ms->Number();
602      }
603    }
604    time_val = MakeDate(day, MakeTime(h, m, s, milli));
605  }
606  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
607}
608
609// ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date )
610BUILTIN(DatePrototypeSetUTCMonth) {
611  HandleScope scope(isolate);
612  CHECK_RECEIVER(JSDate, this_date, "Date.prototype.setUTCMonth");
613  int const argc = args.length() - 1;
614  Handle<Object> month = args.atOrUndefined(isolate, 1);
615  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
616                                     Object::ToNumber(isolate, month));
617  double time_val = this_date->value().Number();
618  if (!std::isnan(time_val)) {
619    int64_t const time_ms = static_cast<int64_t>(time_val);
620    int days = isolate->date_cache()->DaysFromTime(time_ms);
621    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
622    int year, unused, day;
623    isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
624    double m = month->Number();
625    double dt = day;
626    if (argc >= 2) {
627      Handle<Object> date = args.at(2);
628      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
629                                         Object::ToNumber(isolate, date));
630      dt = date->Number();
631    }
632    time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
633  }
634  return *JSDate::SetValue(this_date, DateCache::TimeClip(time_val));
635}
636
637// ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms )
638BUILTIN(DatePrototypeSetUTCSeconds) {
639  HandleScope scope(isolate);
640  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds");
641  int const argc = args.length() - 1;
642  Handle<Object> sec = args.atOrUndefined(isolate, 1);
643  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
644                                     Object::ToNumber(isolate, sec));
645  double time_val = date->value().Number();
646  if (!std::isnan(time_val)) {
647    int64_t const time_ms = static_cast<int64_t>(time_val);
648    int day = isolate->date_cache()->DaysFromTime(time_ms);
649    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
650    int h = time_within_day / (60 * 60 * 1000);
651    double m = (time_within_day / (60 * 1000)) % 60;
652    double s = sec->Number();
653    double milli = time_within_day % 1000;
654    if (argc >= 2) {
655      Handle<Object> ms = args.at(2);
656      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
657                                         Object::ToNumber(isolate, ms));
658      milli = ms->Number();
659    }
660    time_val = MakeDate(day, MakeTime(h, m, s, milli));
661  }
662  return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
663}
664
665// ES6 section 20.3.4.35 Date.prototype.toDateString ( )
666BUILTIN(DatePrototypeToDateString) {
667  HandleScope scope(isolate);
668  CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString");
669  DateBuffer buffer =
670      ToDateString(date->value().Number(), isolate->date_cache(),
671                   ToDateStringMode::kLocalDate);
672  RETURN_RESULT_OR_FAILURE(
673      isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer)));
674}
675
676// ES6 section 20.3.4.36 Date.prototype.toISOString ( )
677BUILTIN(DatePrototypeToISOString) {
678  HandleScope scope(isolate);
679  CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString");
680  double const time_val = date->value().Number();
681  if (std::isnan(time_val)) {
682    THROW_NEW_ERROR_RETURN_FAILURE(
683        isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
684  }
685  int64_t const time_ms = static_cast<int64_t>(time_val);
686  int year, month, day, weekday, hour, min, sec, ms;
687  isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
688                                       &hour, &min, &sec, &ms);
689  char buffer[128];
690  if (year >= 0 && year <= 9999) {
691    SNPrintF(base::ArrayVector(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
692             year, month + 1, day, hour, min, sec, ms);
693  } else if (year < 0) {
694    SNPrintF(base::ArrayVector(buffer), "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ",
695             -year, month + 1, day, hour, min, sec, ms);
696  } else {
697    SNPrintF(base::ArrayVector(buffer), "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ",
698             year, month + 1, day, hour, min, sec, ms);
699  }
700  return *isolate->factory()->NewStringFromAsciiChecked(buffer);
701}
702
703// ES6 section 20.3.4.41 Date.prototype.toString ( )
704BUILTIN(DatePrototypeToString) {
705  HandleScope scope(isolate);
706  CHECK_RECEIVER(JSDate, date, "Date.prototype.toString");
707  DateBuffer buffer =
708      ToDateString(date->value().Number(), isolate->date_cache(),
709                   ToDateStringMode::kLocalDateAndTime);
710  RETURN_RESULT_OR_FAILURE(
711      isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer)));
712}
713
714// ES6 section 20.3.4.42 Date.prototype.toTimeString ( )
715BUILTIN(DatePrototypeToTimeString) {
716  HandleScope scope(isolate);
717  CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString");
718  DateBuffer buffer =
719      ToDateString(date->value().Number(), isolate->date_cache(),
720                   ToDateStringMode::kLocalTime);
721  RETURN_RESULT_OR_FAILURE(
722      isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer)));
723}
724
725#ifdef V8_INTL_SUPPORT
726// ecma402 #sup-date.prototype.tolocaledatestring
727BUILTIN(DatePrototypeToLocaleDateString) {
728  HandleScope scope(isolate);
729
730  isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateToLocaleDateString);
731
732  const char* method_name = "Date.prototype.toLocaleDateString";
733  CHECK_RECEIVER(JSDate, date, method_name);
734
735  RETURN_RESULT_OR_FAILURE(
736      isolate, JSDateTimeFormat::ToLocaleDateTime(
737                   isolate,
738                   date,                                     // date
739                   args.atOrUndefined(isolate, 1),           // locales
740                   args.atOrUndefined(isolate, 2),           // options
741                   JSDateTimeFormat::RequiredOption::kDate,  // required
742                   JSDateTimeFormat::DefaultsOption::kDate,  // defaults
743                   method_name));                            // method_name
744}
745
746// ecma402 #sup-date.prototype.tolocalestring
747BUILTIN(DatePrototypeToLocaleString) {
748  HandleScope scope(isolate);
749
750  isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateToLocaleString);
751
752  const char* method_name = "Date.prototype.toLocaleString";
753  CHECK_RECEIVER(JSDate, date, method_name);
754
755  RETURN_RESULT_OR_FAILURE(
756      isolate, JSDateTimeFormat::ToLocaleDateTime(
757                   isolate,
758                   date,                                    // date
759                   args.atOrUndefined(isolate, 1),          // locales
760                   args.atOrUndefined(isolate, 2),          // options
761                   JSDateTimeFormat::RequiredOption::kAny,  // required
762                   JSDateTimeFormat::DefaultsOption::kAll,  // defaults
763                   method_name));                           // method_name
764}
765
766// ecma402 #sup-date.prototype.tolocaletimestring
767BUILTIN(DatePrototypeToLocaleTimeString) {
768  HandleScope scope(isolate);
769
770  isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateToLocaleTimeString);
771
772  const char* method_name = "Date.prototype.toLocaleTimeString";
773  CHECK_RECEIVER(JSDate, date, method_name);
774
775  RETURN_RESULT_OR_FAILURE(
776      isolate, JSDateTimeFormat::ToLocaleDateTime(
777                   isolate,
778                   date,                                     // date
779                   args.atOrUndefined(isolate, 1),           // locales
780                   args.atOrUndefined(isolate, 2),           // options
781                   JSDateTimeFormat::RequiredOption::kTime,  // required
782                   JSDateTimeFormat::DefaultsOption::kTime,  // defaults
783                   method_name));                            // method_name
784}
785#endif  // V8_INTL_SUPPORT
786
787// ES6 section 20.3.4.43 Date.prototype.toUTCString ( )
788BUILTIN(DatePrototypeToUTCString) {
789  HandleScope scope(isolate);
790  CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString");
791  DateBuffer buffer =
792      ToDateString(date->value().Number(), isolate->date_cache(),
793                   ToDateStringMode::kUTCDateAndTime);
794  RETURN_RESULT_OR_FAILURE(
795      isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer)));
796}
797
798// ES6 section B.2.4.1 Date.prototype.getYear ( )
799BUILTIN(DatePrototypeGetYear) {
800  HandleScope scope(isolate);
801  CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear");
802  double time_val = date->value().Number();
803  if (std::isnan(time_val)) return date->value();
804  int64_t time_ms = static_cast<int64_t>(time_val);
805  int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
806  int days = isolate->date_cache()->DaysFromTime(local_time_ms);
807  int year, month, day;
808  isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
809  return Smi::FromInt(year - 1900);
810}
811
812// ES6 section B.2.4.2 Date.prototype.setYear ( year )
813BUILTIN(DatePrototypeSetYear) {
814  HandleScope scope(isolate);
815  CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear");
816  Handle<Object> year = args.atOrUndefined(isolate, 1);
817  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year,
818                                     Object::ToNumber(isolate, year));
819  double month_double = 0.0, day_double = 1.0, year_double = year->Number();
820  if (!std::isnan(year_double)) {
821    double year_int = DoubleToInteger(year_double);
822    if (0.0 <= year_int && year_int <= 99.0) {
823      year_double = 1900.0 + year_int;
824    }
825  }
826  int time_within_day = 0;
827  if (!std::isnan(date->value().Number())) {
828    int64_t const time_ms = static_cast<int64_t>(date->value().Number());
829    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
830    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
831    time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
832    int year_int, month_int, day_int;
833    isolate->date_cache()->YearMonthDayFromDays(days, &year_int, &month_int,
834                                                &day_int);
835    month_double = month_int;
836    day_double = day_int;
837  }
838  double time_val =
839      MakeDate(MakeDay(year_double, month_double, day_double), time_within_day);
840  return SetLocalDateValue(isolate, date, time_val);
841}
842
843// ES6 section 20.3.4.37 Date.prototype.toJSON ( key )
844BUILTIN(DatePrototypeToJson) {
845  HandleScope scope(isolate);
846  Handle<Object> receiver = args.atOrUndefined(isolate, 0);
847  Handle<JSReceiver> receiver_obj;
848  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_obj,
849                                     Object::ToObject(isolate, receiver));
850  Handle<Object> primitive;
851  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
852      isolate, primitive,
853      Object::ToPrimitive(isolate, receiver_obj, ToPrimitiveHint::kNumber));
854  if (primitive->IsNumber() && !std::isfinite(primitive->Number())) {
855    return ReadOnlyRoots(isolate).null_value();
856  } else {
857    Handle<String> name =
858        isolate->factory()->NewStringFromAsciiChecked("toISOString");
859    Handle<Object> function;
860    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
861        isolate, function, Object::GetProperty(isolate, receiver_obj, name));
862    if (!function->IsCallable()) {
863      THROW_NEW_ERROR_RETURN_FAILURE(
864          isolate, NewTypeError(MessageTemplate::kCalledNonCallable, name));
865    }
866    RETURN_RESULT_OR_FAILURE(
867        isolate, Execution::Call(isolate, function, receiver_obj, 0, nullptr));
868  }
869}
870
871}  // namespace internal
872}  // namespace v8
873