1// Copyright 2021 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/objects/js-temporal-objects.h"
6
7#include <set>
8
9#include "src/common/globals.h"
10#include "src/date/date.h"
11#include "src/execution/isolate.h"
12#include "src/heap/factory.h"
13#include "src/numbers/conversions-inl.h"
14#ifdef V8_INTL_SUPPORT
15#include "src/objects/intl-objects.h"
16#include "src/objects/js-date-time-format.h"
17#endif  // V8_INTL_SUPPORT
18#include "src/objects/js-objects-inl.h"
19#include "src/objects/js-objects.h"
20#include "src/objects/js-temporal-objects-inl.h"
21#ifdef V8_INTL_SUPPORT
22#include "src/objects/managed-inl.h"
23#endif  // V8_INTL_SUPPORT
24#include "src/objects/objects-inl.h"
25#include "src/objects/option-utils.h"
26#include "src/objects/property-descriptor.h"
27#include "src/strings/string-builder-inl.h"
28#include "src/temporal/temporal-parser.h"
29#ifdef V8_INTL_SUPPORT
30#include "unicode/calendar.h"
31#include "unicode/unistr.h"
32#endif  // V8_INTL_SUPPORT
33
34namespace v8 {
35namespace internal {
36
37namespace {
38
39enum class Unit {
40  kNotPresent,
41  kAuto,
42  kYear,
43  kMonth,
44  kWeek,
45  kDay,
46  kHour,
47  kMinute,
48  kSecond,
49  kMillisecond,
50  kMicrosecond,
51  kNanosecond
52};
53
54/**
55 * This header declare the Abstract Operations defined in the
56 * Temporal spec with the enum and struct for them.
57 */
58
59// Struct
60struct DateTimeRecordCommon {
61  int32_t year;
62  int32_t month;
63  int32_t day;
64  int32_t hour;
65  int32_t minute;
66  int32_t second;
67  int32_t millisecond;
68  int32_t microsecond;
69  int32_t nanosecond;
70};
71
72struct DateRecord {
73  int32_t year;
74  int32_t month;
75  int32_t day;
76  Handle<String> calendar;
77};
78
79struct InstantRecord : public DateTimeRecordCommon {
80  Handle<String> offset_string;
81};
82
83struct DateTimeRecord : public DateTimeRecordCommon {
84  Handle<String> calendar;
85};
86
87struct DurationRecord {
88  int64_t years;
89  int64_t months;
90  int64_t weeks;
91  int64_t days;
92  int64_t hours;
93  int64_t minutes;
94  int64_t seconds;
95  int64_t milliseconds;
96  int64_t microseconds;
97  int64_t nanoseconds;
98};
99
100struct TimeRecord {
101  int32_t hour;
102  int32_t minute;
103  int32_t second;
104  int32_t millisecond;
105  int32_t microsecond;
106  int32_t nanosecond;
107  Handle<String> calendar;
108};
109
110struct TimeZoneRecord {
111  bool z;
112  Handle<String> offset_string;
113  Handle<String> name;
114};
115
116// Options
117
118V8_WARN_UNUSED_RESULT Handle<String> UnitToString(Isolate* isolate, Unit unit);
119
120// #sec-temporal-totemporaldisambiguation
121enum class Disambiguation { kCompatible, kEarlier, kLater, kReject };
122
123// #sec-temporal-totemporaloverflow
124enum class ShowOverflow { kConstrain, kReject };
125
126// ISO8601 String Parsing
127
128// #sec-temporal-parsetemporalcalendarstring
129V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalCalendarString(
130    Isolate* isolate, Handle<String> iso_string);
131
132// #sec-temporal-parsetemporaldatestring
133V8_WARN_UNUSED_RESULT Maybe<DateRecord> ParseTemporalDateString(
134    Isolate* isolate, Handle<String> iso_string);
135
136// #sec-temporal-parsetemporaltimestring
137Maybe<TimeRecord> ParseTemporalTimeString(Isolate* isolate,
138                                          Handle<String> iso_string);
139
140// #sec-temporal-parsetemporaltimezone
141V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalTimeZone(
142    Isolate* isolate, Handle<String> string);
143
144// #sec-temporal-parsetemporaltimezonestring
145V8_WARN_UNUSED_RESULT Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(
146    Isolate* isolate, Handle<String> iso_string);
147
148// #sec-temporal-parsetimezoneoffsetstring
149V8_WARN_UNUSED_RESULT Maybe<int64_t> ParseTimeZoneOffsetString(
150    Isolate* isolate, Handle<String> offset_string,
151    bool throwIfNotSatisfy = true);
152
153// #sec-temporal-parsetemporalinstant
154V8_WARN_UNUSED_RESULT MaybeHandle<BigInt> ParseTemporalInstant(
155    Isolate* isolate, Handle<String> iso_string);
156
157void BalanceISODate(Isolate* isolate, int32_t* year, int32_t* month,
158                    int32_t* day);
159
160// Math and Misc
161
162V8_WARN_UNUSED_RESULT MaybeHandle<BigInt> AddInstant(
163    Isolate* isolate, Handle<BigInt> epoch_nanoseconds, int64_t hours,
164    int64_t minutes, int64_t seconds, int64_t milliseconds,
165    int64_t microseconds, int64_t nanoseconds);
166
167// #sec-temporal-balanceduration
168V8_WARN_UNUSED_RESULT Maybe<bool> BalanceDuration(
169    Isolate* isolate, int64_t* days, int64_t* hours, int64_t* minutes,
170    int64_t* seconds, int64_t* milliseconds, int64_t* microseconds,
171    int64_t* nanoseconds, Unit largest_unit, Handle<Object> relative_to,
172    const char* method_name);
173
174V8_WARN_UNUSED_RESULT Maybe<DurationRecord> DifferenceISODateTime(
175    Isolate* isolate, int32_t y1, int32_t mon1, int32_t d1, int32_t h1,
176    int32_t min1, int32_t s1, int32_t ms1, int32_t mus1, int32_t ns1,
177    int32_t y2, int32_t mon2, int32_t d2, int32_t h2, int32_t min2, int32_t s2,
178    int32_t ms2, int32_t mus2, int32_t ns2, Handle<JSReceiver> calendar,
179    Unit largest_unit, Handle<Object> relative_to, const char* method_name);
180
181// #sec-temporal-adddatetime
182V8_WARN_UNUSED_RESULT Maybe<DateTimeRecordCommon> AddDateTime(
183    Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour,
184    int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond,
185    int32_t nanosecond, Handle<JSReceiver> calendar, const DurationRecord& dur,
186    Handle<Object> options);
187
188// #sec-temporal-addzoneddatetime
189V8_WARN_UNUSED_RESULT MaybeHandle<BigInt> AddZonedDateTime(
190    Isolate* isolate, Handle<BigInt> eopch_nanoseconds,
191    Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar,
192    const DurationRecord& duration, const char* method_name);
193
194V8_WARN_UNUSED_RESULT MaybeHandle<BigInt> AddZonedDateTime(
195    Isolate* isolate, Handle<BigInt> eopch_nanoseconds,
196    Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar,
197    const DurationRecord& duration, Handle<JSReceiver> options,
198    const char* method_name);
199
200// #sec-temporal-isvalidepochnanoseconds
201bool IsValidEpochNanoseconds(Isolate* isolate,
202                             Handle<BigInt> epoch_nanoseconds);
203
204// #sec-temporal-isvalidduration
205bool IsValidDuration(Isolate* isolate, const DurationRecord& dur);
206
207// #sec-temporal-nanosecondstodays
208V8_WARN_UNUSED_RESULT Maybe<bool> NanosecondsToDays(
209    Isolate* isolate, Handle<BigInt> nanoseconds,
210    Handle<Object> relative_to_obj, int64_t* result_days,
211    int64_t* result_nanoseconds, int64_t* result_day_length,
212    const char* method_name);
213
214V8_WARN_UNUSED_RESULT Maybe<bool> NanosecondsToDays(
215    Isolate* isolate, int64_t nanoseconds, Handle<Object> relative_to_obj,
216    int64_t* result_days, int64_t* resultj_nanoseconds,
217    int64_t* result_day_length, const char* method_name);
218
219// #sec-temporal-interpretisodatetimeoffset
220enum class OffsetBehaviour { kOption, kExact, kWall };
221
222V8_WARN_UNUSED_RESULT
223MaybeHandle<BigInt> GetEpochFromISOParts(Isolate* isolate, int32_t year,
224                                         int32_t month, int32_t day,
225                                         int32_t hour, int32_t minute,
226                                         int32_t second, int32_t millisecond,
227                                         int32_t microsecond,
228                                         int32_t nanosecond);
229
230int32_t DurationSign(Isolate* isolaet, const DurationRecord& dur);
231
232// #sec-temporal-isodaysinmonth
233int32_t ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month);
234
235// #sec-temporal-isodaysinyear
236int32_t ISODaysInYear(Isolate* isolate, int32_t year);
237
238bool IsValidTime(Isolate* isolate, int32_t hour, int32_t minute, int32_t second,
239                 int32_t millisecond, int32_t microsecond, int32_t nanosecond);
240
241// #sec-temporal-isvalidisodate
242bool IsValidISODate(Isolate* isolate, int32_t year, int32_t month, int32_t day);
243
244// #sec-temporal-compareisodate
245int32_t CompareISODate(Isolate* isolate, int32_t y1, int32_t m1, int32_t d1,
246                       int32_t y2, int32_t m2, int32_t d2);
247
248// #sec-temporal-balanceisoyearmonth
249void BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month);
250
251// #sec-temporal-balancetime
252V8_WARN_UNUSED_RESULT DateTimeRecordCommon
253BalanceTime(Isolate* isolate, int64_t hour, int64_t minute, int64_t second,
254            int64_t millisecond, int64_t microsecond, int64_t nanosecond);
255
256// #sec-temporal-differencetime
257V8_WARN_UNUSED_RESULT DurationRecord
258DifferenceTime(Isolate* isolate, int32_t h1, int32_t min1, int32_t s1,
259               int32_t ms1, int32_t mus1, int32_t ns1, int32_t h2, int32_t min2,
260               int32_t s2, int32_t ms2, int32_t mus2, int32_t ns2);
261
262// #sec-temporal-addtime
263V8_WARN_UNUSED_RESULT DateTimeRecordCommon
264AddTime(Isolate* isolate, int64_t hour, int64_t minute, int64_t second,
265        int64_t millisecond, int64_t microsecond, int64_t nanosecond,
266        int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds,
267        int64_t microseconds, int64_t nanoseconds);
268
269// #sec-temporal-totaldurationnanoseconds
270int64_t TotalDurationNanoseconds(Isolate* isolate, int64_t days, int64_t hours,
271                                 int64_t minutes, int64_t seconds,
272                                 int64_t milliseconds, int64_t microseconds,
273                                 int64_t nanoseconds, int64_t offset_shift);
274
275// #sec-temporal-totemporaltimerecord
276Maybe<TimeRecord> ToTemporalTimeRecord(Isolate* isolate,
277                                       Handle<JSReceiver> temporal_time_like,
278                                       const char* method_name);
279// Calendar Operations
280
281// #sec-temporal-calendardateadd
282V8_WARN_UNUSED_RESULT MaybeHandle<JSTemporalPlainDate> CalendarDateAdd(
283    Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> date,
284    Handle<Object> durations, Handle<Object> options, Handle<Object> date_add);
285
286// #sec-temporal-calendardateuntil
287V8_WARN_UNUSED_RESULT MaybeHandle<JSTemporalDuration> CalendarDateUntil(
288    Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> one,
289    Handle<Object> two, Handle<Object> options, Handle<Object> date_until);
290
291// #sec-temporal-calendarfields
292MaybeHandle<FixedArray> CalendarFields(Isolate* isolate,
293                                       Handle<JSReceiver> calendar,
294                                       Handle<FixedArray> field_names);
295
296// #sec-temporal-getoffsetnanosecondsfor
297V8_WARN_UNUSED_RESULT Maybe<int64_t> GetOffsetNanosecondsFor(
298    Isolate* isolate, Handle<JSReceiver> time_zone, Handle<Object> instant,
299    const char* method_name);
300
301// #sec-temporal-totemporalcalendarwithisodefault
302MaybeHandle<JSReceiver> ToTemporalCalendarWithISODefault(
303    Isolate* isolate, Handle<Object> temporal_calendar_like,
304    const char* method_name);
305
306// #sec-temporal-isbuiltincalendar
307bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id);
308
309// Internal Helper Function
310int32_t CalendarIndex(Isolate* isolate, Handle<String> id);
311
312// #sec-isvalidtimezonename
313bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone);
314
315// #sec-canonicalizetimezonename
316V8_WARN_UNUSED_RESULT MaybeHandle<String> CanonicalizeTimeZoneName(
317    Isolate* isolate, Handle<String> identifier);
318
319// #sec-temporal-tointegerthrowoninfinity
320MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
321                                             Handle<Object> argument);
322
323// #sec-temporal-topositiveinteger
324MaybeHandle<Object> ToPositiveInteger(Isolate* isolate,
325                                      Handle<Object> argument);
326
327inline int64_t floor_divide(int64_t a, int64_t b) {
328  return (((a) / (b)) + ((((a) < 0) && (((a) % (b)) != 0)) ? -1 : 0));
329}
330inline int64_t modulo(int64_t a, int64_t b) {
331  return ((((a) % (b)) + (b)) % (b));
332}
333
334#define STRINGIFY(x) #x
335#define TOSTRING(x) STRINGIFY(x)
336#define AT __FILE__ ":" TOSTRING(__LINE__)
337
338#ifdef DEBUG
339#define TEMPORAL_DEBUG_INFO AT
340#define TEMPORAL_ENTER_FUNC()
341// #define TEMPORAL_ENTER_FUNC()  do { PrintF("Start: %s\n", __func__); } while
342// (false)
343#else
344// #define TEMPORAL_DEBUG_INFO ""
345#define TEMPORAL_DEBUG_INFO AT
346#define TEMPORAL_ENTER_FUNC()
347// #define TEMPORAL_ENTER_FUNC()  do { PrintF("Start: %s\n", __func__); } while
348// (false)
349#endif  // DEBUG
350
351#define NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR()        \
352  NewTypeError(                                     \
353      MessageTemplate::kInvalidArgumentForTemporal, \
354      isolate->factory()->NewStringFromStaticChars(TEMPORAL_DEBUG_INFO))
355
356#define NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR()        \
357  NewRangeError(                                     \
358      MessageTemplate::kInvalidTimeValueForTemporal, \
359      isolate->factory()->NewStringFromStaticChars(TEMPORAL_DEBUG_INFO))
360
361// #sec-defaulttimezone
362MaybeHandle<String> DefaultTimeZone(Isolate* isolate) {
363  TEMPORAL_ENTER_FUNC();
364  // For now, always return "UTC"
365  // TODO(ftang) implement behavior specified in  #sup-defaulttimezone
366  return isolate->factory()->UTC_string();
367}
368
369// #sec-temporal-isodatetimewithinlimits
370bool ISODateTimeWithinLimits(Isolate* isolate, int32_t year, int32_t month,
371                             int32_t day, int32_t hour, int32_t minute,
372                             int32_t second, int32_t millisecond,
373                             int32_t microsecond, int32_t nanosecond) {
374  TEMPORAL_ENTER_FUNC();
375  /**
376   * Note: It is really overkill to decide within the limit by following the
377   * specified algorithm literally, which require the conversion to BigInt.
378   * Take a short cut and use pre-calculated year/month/day boundary instead.
379   *
380   * Math:
381   * (-8.64 x 10^21- 8.64 x 10^16,  8.64 x 10^21 + 8.64 x 10^16) ns
382   * = (-8.64 x 9999 x 10^16,  8.64 x 9999 x 10^16) ns
383   * = (-8.64 x 9999 x 10^10,  8.64 x 9999 x 10^10) millisecond
384   * = (-8.64 x 9999 x 10^7,  8.64 x 9999 x 10^7) second
385   * = (-86400 x 9999 x 10^3,  86400 x 9999 x 10^3) second
386   * = (-9999 x 10^3,  9999 x 10^3) days => Because 60*60*24 = 86400
387   * 9999000 days is about 27376 years, 4 months and 7 days.
388   * Therefore 9999000 days before Jan 1 1970 is around Auguest 23, -25407 and
389   * 9999000 days after Jan 1 1970 is around April 9, 29346.
390   */
391  if (year > -25407 && year < 29346) return true;
392  if (year < -25407 || year > 29346) return false;
393  if (year == -25407) {
394    if (month > 8) return true;
395    if (month < 8) return false;
396    return (day > 23);
397  } else {
398    DCHECK_EQ(year, 29346);
399    if (month > 4) return false;
400    if (month < 4) return true;
401    return (day > 23);
402  }
403  // 1. Assert: year, month, day, hour, minute, second, millisecond,
404  // microsecond, and nanosecond are integers.
405  // 2. Let ns be ! GetEpochFromISOParts(year, month, day, hour, minute,
406  // second, millisecond, microsecond, nanosecond).
407  // 3. If ns ≤ -8.64 × 10^21 - 8.64 × 10^16, then
408  // 4. If ns ≥ 8.64 × 10^21 + 8.64 × 10^16, then
409  // 5. Return true.
410}
411
412// #sec-temporal-isoyearmonthwithinlimits
413bool ISOYearMonthWithinLimits(int32_t year, int32_t month) {
414  TEMPORAL_ENTER_FUNC();
415  // 1. Assert: year and month are integers.
416  // 2. If year < −271821 or year > 275760, then
417  // a. Return false.
418  if (year < -271821 || year > 275760) return false;
419  // 3. If year is −271821 and month < 4, then
420  // a. Return false.
421  if (year == -271821 && month < 4) return false;
422  // 4. If year is 275760 and month > 9, then
423  // a. Return false.
424  if (year == 275760 && month > 9) return false;
425  // 5. Return true.
426  return true;
427}
428
429#define ORDINARY_CREATE_FROM_CONSTRUCTOR(obj, target, new_target, T)       \
430  Handle<JSReceiver> new_target_receiver =                                 \
431      Handle<JSReceiver>::cast(new_target);                                \
432  Handle<Map> map;                                                         \
433  ASSIGN_RETURN_ON_EXCEPTION(                                              \
434      isolate, map,                                                        \
435      JSFunction::GetDerivedMap(isolate, target, new_target_receiver), T); \
436  Handle<T> object =                                                       \
437      Handle<T>::cast(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
438
439#define THROW_INVALID_RANGE(T) \
440  THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), T);
441
442#define CONSTRUCTOR(name)                                                    \
443  Handle<JSFunction>(                                                        \
444      JSFunction::cast(                                                      \
445          isolate->context().native_context().temporal_##name##_function()), \
446      isolate)
447
448// #sec-temporal-systemutcepochnanoseconds
449MaybeHandle<BigInt> SystemUTCEpochNanoseconds(Isolate* isolate) {
450  TEMPORAL_ENTER_FUNC();
451  // 1. Let ns be the approximate current UTC date and time, in nanoseconds
452  // since the epoch.
453  double ms = V8::GetCurrentPlatform()->CurrentClockTimeMillis();
454  // 2. Set ns to the result of clamping ns between −8.64 × 10^21 and 8.64 ×
455  // 10^21.
456
457  // 3. Return ℤ(ns).
458  double ns = ms * 1000000.0;
459  ns = std::floor(std::max(-8.64e21, std::min(ns, 8.64e21)));
460  return BigInt::FromNumber(isolate, isolate->factory()->NewNumber(ns));
461}
462
463// #sec-temporal-createtemporalcalendar
464MaybeHandle<JSTemporalCalendar> CreateTemporalCalendar(
465    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
466    Handle<String> identifier) {
467  TEMPORAL_ENTER_FUNC();
468  // 1. Assert: ! IsBuiltinCalendar(identifier) is true.
469  // 2. If newTarget is not provided, set newTarget to %Temporal.Calendar%.
470  // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget,
471  // "%Temporal.Calendar.prototype%", « [[InitializedTemporalCalendar]],
472  // [[Identifier]] »).
473  int32_t index = CalendarIndex(isolate, identifier);
474
475  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
476                                   JSTemporalCalendar)
477
478  object->set_flags(0);
479  // 4. Set object.[[Identifier]] to identifier.
480  object->set_calendar_index(index);
481  // 5. Return object.
482  return object;
483}
484
485MaybeHandle<JSTemporalCalendar> CreateTemporalCalendar(
486    Isolate* isolate, Handle<String> identifier) {
487  TEMPORAL_ENTER_FUNC();
488  return CreateTemporalCalendar(isolate, CONSTRUCTOR(calendar),
489                                CONSTRUCTOR(calendar), identifier);
490}
491
492// #sec-temporal-createtemporaldate
493MaybeHandle<JSTemporalPlainDate> CreateTemporalDate(
494    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
495    int32_t iso_year, int32_t iso_month, int32_t iso_day,
496    Handle<JSReceiver> calendar) {
497  TEMPORAL_ENTER_FUNC();
498  // 1. Assert: isoYear is an integer.
499  // 2. Assert: isoMonth is an integer.
500  // 3. Assert: isoDay is an integer.
501  // 4. Assert: Type(calendar) is Object.
502  // 5. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a
503  // RangeError exception.
504  if (!IsValidISODate(isolate, iso_year, iso_month, iso_day)) {
505    THROW_INVALID_RANGE(JSTemporalPlainDate);
506  }
507  // 6. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0,
508  // 0) is false, throw a RangeError exception.
509  if (!ISODateTimeWithinLimits(isolate, iso_year, iso_month, iso_day, 12, 0, 0,
510                               0, 0, 0)) {
511    THROW_INVALID_RANGE(JSTemporalPlainDate);
512  }
513  // 7. If newTarget is not present, set it to %Temporal.PlainDate%.
514
515  // 8. Let object be ? OrdinaryCreateFromConstructor(newTarget,
516  // "%Temporal.PlainDate.prototype%", « [[InitializedTemporalDate]],
517  // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
518  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
519                                   JSTemporalPlainDate)
520  object->set_year_month_day(0);
521  // 9. Set object.[[ISOYear]] to isoYear.
522  object->set_iso_year(iso_year);
523  // 10. Set object.[[ISOMonth]] to isoMonth.
524  object->set_iso_month(iso_month);
525  // 11. Set object.[[ISODay]] to isoDay.
526  object->set_iso_day(iso_day);
527  // 12. Set object.[[Calendar]] to calendar.
528  object->set_calendar(*calendar);
529  // 13. Return object.
530  return object;
531}
532
533MaybeHandle<JSTemporalPlainDate> CreateTemporalDate(
534    Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day,
535    Handle<JSReceiver> calendar) {
536  TEMPORAL_ENTER_FUNC();
537  return CreateTemporalDate(isolate, CONSTRUCTOR(plain_date),
538                            CONSTRUCTOR(plain_date), iso_year, iso_month,
539                            iso_day, calendar);
540}
541
542// #sec-temporal-createtemporaldatetime
543MaybeHandle<JSTemporalPlainDateTime> CreateTemporalDateTime(
544    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
545    int32_t iso_year, int32_t iso_month, int32_t iso_day, int32_t hour,
546    int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond,
547    int32_t nanosecond, Handle<JSReceiver> calendar) {
548  TEMPORAL_ENTER_FUNC();
549  // 1. Assert: isoYear, isoMonth, isoDay, hour, minute, second, millisecond,
550  // microsecond, and nanosecond are integers.
551  // 2. Assert: Type(calendar) is Object.
552  // 3. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a
553  // RangeError exception.
554  if (!IsValidISODate(isolate, iso_year, iso_month, iso_day)) {
555    THROW_INVALID_RANGE(JSTemporalPlainDateTime);
556  }
557  // 4. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
558  // nanosecond) is false, throw a RangeError exception.
559  if (!IsValidTime(isolate, hour, minute, second, millisecond, microsecond,
560                   nanosecond)) {
561    THROW_INVALID_RANGE(JSTemporalPlainDateTime);
562  }
563  // 5. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute,
564  // second, millisecond, microsecond, nanosecond) is false, then
565  if (!ISODateTimeWithinLimits(isolate, iso_year, iso_month, iso_day, hour,
566                               minute, second, millisecond, microsecond,
567                               nanosecond)) {
568    // a. Throw a RangeError exception.
569    THROW_INVALID_RANGE(JSTemporalPlainDateTime);
570  }
571  // 6. If newTarget is not present, set it to %Temporal.PlainDateTime%.
572  // 7. Let object be ? OrdinaryCreateFromConstructor(newTarget,
573  // "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]],
574  // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]],
575  // [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]],
576  // [[Calendar]] »).
577  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
578                                   JSTemporalPlainDateTime)
579
580  object->set_year_month_day(0);
581  object->set_hour_minute_second(0);
582  object->set_second_parts(0);
583  // 8. Set object.[[ISOYear]] to isoYear.
584  object->set_iso_year(iso_year);
585  // 9. Set object.[[ISOMonth]] to isoMonth.
586  object->set_iso_month(iso_month);
587  // 10. Set object.[[ISODay]] to isoDay.
588  object->set_iso_day(iso_day);
589  // 11. Set object.[[ISOHour]] to hour.
590  object->set_iso_hour(hour);
591  // 12. Set object.[[ISOMinute]] to minute.
592  object->set_iso_minute(minute);
593  // 13. Set object.[[ISOSecond]] to second.
594  object->set_iso_second(second);
595  // 14. Set object.[[ISOMillisecond]] to millisecond.
596  object->set_iso_millisecond(millisecond);
597  // 15. Set object.[[ISOMicrosecond]] to microsecond.
598  object->set_iso_microsecond(microsecond);
599  // 16. Set object.[[ISONanosecond]] to nanosecond.
600  object->set_iso_nanosecond(nanosecond);
601  // 17. Set object.[[Calendar]] to calendar.
602  object->set_calendar(*calendar);
603  // 18. Return object.
604  return object;
605}
606
607MaybeHandle<JSTemporalPlainDateTime> CreateTemporalDateTimeDefaultTarget(
608    Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day,
609    int32_t hour, int32_t minute, int32_t second, int32_t millisecond,
610    int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar) {
611  TEMPORAL_ENTER_FUNC();
612  return CreateTemporalDateTime(isolate, CONSTRUCTOR(plain_date_time),
613                                CONSTRUCTOR(plain_date_time), iso_year,
614                                iso_month, iso_day, hour, minute, second,
615                                millisecond, microsecond, nanosecond, calendar);
616}
617
618}  // namespace
619
620namespace temporal {
621
622MaybeHandle<JSTemporalPlainDateTime> CreateTemporalDateTime(
623    Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day,
624    int32_t hour, int32_t minute, int32_t second, int32_t millisecond,
625    int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar) {
626  return CreateTemporalDateTimeDefaultTarget(
627      isolate, iso_year, iso_month, iso_day, hour, minute, second, millisecond,
628      microsecond, nanosecond, calendar);
629}
630
631}  // namespace temporal
632
633namespace {
634// #sec-temporal-createtemporaltime
635MaybeHandle<JSTemporalPlainTime> CreateTemporalTime(
636    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
637    int32_t hour, int32_t minute, int32_t second, int32_t millisecond,
638    int32_t microsecond, int32_t nanosecond) {
639  TEMPORAL_ENTER_FUNC();
640  // 2. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
641  // nanosecond) is false, throw a RangeError exception.
642  if (!IsValidTime(isolate, hour, minute, second, millisecond, microsecond,
643                   nanosecond)) {
644    THROW_INVALID_RANGE(JSTemporalPlainTime);
645  }
646
647  // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget,
648  // "%Temporal.PlainTime.prototype%", « [[InitializedTemporalTime]],
649  // [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]],
650  // [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] »).
651  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
652                                   JSTemporalPlainTime)
653  Handle<JSTemporalCalendar> calendar;
654  ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar,
655                             temporal::GetISO8601Calendar(isolate),
656                             JSTemporalPlainTime);
657  object->set_hour_minute_second(0);
658  object->set_second_parts(0);
659  // 5. Set object.[[ISOHour]] to hour.
660  object->set_iso_hour(hour);
661  // 6. Set object.[[ISOMinute]] to minute.
662  object->set_iso_minute(minute);
663  // 7. Set object.[[ISOSecond]] to second.
664  object->set_iso_second(second);
665  // 8. Set object.[[ISOMillisecond]] to millisecond.
666  object->set_iso_millisecond(millisecond);
667  // 9. Set object.[[ISOMicrosecond]] to microsecond.
668  object->set_iso_microsecond(microsecond);
669  // 10. Set object.[[ISONanosecond]] to nanosecond.
670  object->set_iso_nanosecond(nanosecond);
671  // 11. Set object.[[Calendar]] to ? GetISO8601Calendar().
672  object->set_calendar(*calendar);
673
674  // 12. Return object.
675  return object;
676}
677
678MaybeHandle<JSTemporalPlainTime> CreateTemporalTime(
679    Isolate* isolate, int32_t hour, int32_t minute, int32_t second,
680    int32_t millisecond, int32_t microsecond, int32_t nanosecond) {
681  TEMPORAL_ENTER_FUNC();
682  return CreateTemporalTime(isolate, CONSTRUCTOR(plain_time),
683                            CONSTRUCTOR(plain_time), hour, minute, second,
684                            millisecond, microsecond, nanosecond);
685}
686
687// #sec-temporal-createtemporalmonthday
688MaybeHandle<JSTemporalPlainMonthDay> CreateTemporalMonthDay(
689    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
690    int32_t iso_month, int32_t iso_day, Handle<JSReceiver> calendar,
691    int32_t reference_iso_year) {
692  TEMPORAL_ENTER_FUNC();
693  // 1. Assert: isoMonth, isoDay, and referenceISOYear are integers.
694  // 2. Assert: Type(calendar) is Object.
695  // 3. If ! IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw
696  // a RangeError exception.
697  if (!IsValidISODate(isolate, reference_iso_year, iso_month, iso_day)) {
698    THROW_INVALID_RANGE(JSTemporalPlainMonthDay);
699  }
700  // 4. If newTarget is not present, set it to %Temporal.PlainMonthDay%.
701  // 5. Let object be ? OrdinaryCreateFromConstructor(newTarget,
702  // "%Temporal.PlainMonthDay.prototype%", « [[InitializedTemporalMonthDay]],
703  // [[ISOMonth]], [[ISODay]], [[ISOYear]], [[Calendar]] »).
704  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
705                                   JSTemporalPlainMonthDay)
706  object->set_year_month_day(0);
707  // 6. Set object.[[ISOMonth]] to isoMonth.
708  object->set_iso_month(iso_month);
709  // 7. Set object.[[ISODay]] to isoDay.
710  object->set_iso_day(iso_day);
711  // 8. Set object.[[Calendar]] to calendar.
712  object->set_calendar(*calendar);
713  // 9. Set object.[[ISOYear]] to referenceISOYear.
714  object->set_iso_year(reference_iso_year);
715  // 10. Return object.
716  return object;
717}
718
719// #sec-temporal-createtemporalyearmonth
720MaybeHandle<JSTemporalPlainYearMonth> CreateTemporalYearMonth(
721    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
722    int32_t iso_year, int32_t iso_month, Handle<JSReceiver> calendar,
723    int32_t reference_iso_day) {
724  TEMPORAL_ENTER_FUNC();
725  // 1. Assert: isoYear, isoMonth, and referenceISODay are integers.
726  // 2. Assert: Type(calendar) is Object.
727  // 3. If ! IsValidISODate(isoYear, isoMonth, referenceISODay) is false, throw
728  // a RangeError exception.
729  if (!IsValidISODate(isolate, iso_year, iso_month, reference_iso_day)) {
730    THROW_INVALID_RANGE(JSTemporalPlainYearMonth);
731  }
732  // 4. If ! ISOYearMonthWithinLimits(isoYear, isoMonth) is false, throw a
733  // RangeError exception.
734  if (!ISOYearMonthWithinLimits(iso_year, iso_month)) {
735    THROW_INVALID_RANGE(JSTemporalPlainYearMonth);
736  }
737  // 5. If newTarget is not present, set it to %Temporal.PlainYearMonth%.
738  // 6. Let object be ? OrdinaryCreateFromConstructor(newTarget,
739  // "%Temporal.PlainYearMonth.prototype%", « [[InitializedTemporalYearMonth]],
740  // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
741  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
742                                   JSTemporalPlainYearMonth)
743  object->set_year_month_day(0);
744  // 7. Set object.[[ISOYear]] to isoYear.
745  object->set_iso_year(iso_year);
746  // 8. Set object.[[ISOMonth]] to isoMonth.
747  object->set_iso_month(iso_month);
748  // 9. Set object.[[Calendar]] to calendar.
749  object->set_calendar(*calendar);
750  // 10. Set object.[[ISODay]] to referenceISODay.
751  object->set_iso_day(reference_iso_day);
752  // 11. Return object.
753  return object;
754}
755
756// #sec-temporal-createtemporalzoneddatetime
757MaybeHandle<JSTemporalZonedDateTime> CreateTemporalZonedDateTime(
758    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
759    Handle<BigInt> epoch_nanoseconds, Handle<JSReceiver> time_zone,
760    Handle<JSReceiver> calendar) {
761  TEMPORAL_ENTER_FUNC();
762  // 1. Assert: Type(epochNanoseconds) is BigInt.
763  // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
764  DCHECK(IsValidEpochNanoseconds(isolate, epoch_nanoseconds));
765  // 3. Assert: Type(timeZone) is Object.
766  // 4. Assert: Type(calendar) is Object.
767  // 5. If newTarget is not present, set it to %Temporal.ZonedDateTime%.
768  // 6. Let object be ? OrdinaryCreateFromConstructor(newTarget,
769  // "%Temporal.ZonedDateTime.prototype%", «
770  // [[InitializedTemporalZonedDateTime]], [[Nanoseconds]], [[TimeZone]],
771  // [[Calendar]] »).
772  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
773                                   JSTemporalZonedDateTime)
774  // 7. Set object.[[Nanoseconds]] to epochNanoseconds.
775  object->set_nanoseconds(*epoch_nanoseconds);
776  // 8. Set object.[[TimeZone]] to timeZone.
777  object->set_time_zone(*time_zone);
778  // 9. Set object.[[Calendar]] to calendar.
779  object->set_calendar(*calendar);
780  // 10. Return object.
781  return object;
782}
783MaybeHandle<JSTemporalZonedDateTime> CreateTemporalZonedDateTime(
784    Isolate* isolate, Handle<BigInt> epoch_nanoseconds,
785    Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar) {
786  TEMPORAL_ENTER_FUNC();
787  return CreateTemporalZonedDateTime(isolate, CONSTRUCTOR(zoned_date_time),
788                                     CONSTRUCTOR(zoned_date_time),
789                                     epoch_nanoseconds, time_zone, calendar);
790}
791
792// #sec-temporal-createtemporalduration
793MaybeHandle<JSTemporalDuration> CreateTemporalDuration(
794    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
795    int64_t years, int64_t months, int64_t weeks, int64_t days, int64_t hours,
796    int64_t minutes, int64_t seconds, int64_t milliseconds,
797    int64_t microseconds, int64_t nanoseconds) {
798  TEMPORAL_ENTER_FUNC();
799  Factory* factory = isolate->factory();
800  // 1. If ! IsValidDuration(years, months, weeks, days, hours, minutes,
801  // seconds, milliseconds, microseconds, nanoseconds) is false, throw a
802  // RangeError exception.
803  if (!IsValidDuration(isolate,
804                       {years, months, weeks, days, hours, minutes, seconds,
805                        milliseconds, microseconds, nanoseconds})) {
806    THROW_INVALID_RANGE(JSTemporalDuration);
807  }
808
809  // 2. If newTarget is not present, set it to %Temporal.Duration%.
810  // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget,
811  // "%Temporal.Duration.prototype%", « [[InitializedTemporalDuration]],
812  // [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]],
813  // [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
814  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
815                                   JSTemporalDuration)
816#define SET_FROM_INT64(obj, p)                            \
817  do {                                                    \
818    Handle<Object> item = factory->NewNumberFromInt64(p); \
819    object->set_##p(*item);                               \
820  } while (false)
821  // 4. Set object.[[Years]] to years.
822  SET_FROM_INT64(object, years);
823  // 5. Set object.[[Months]] to months.
824  SET_FROM_INT64(object, months);
825  // 6. Set object.[[Weeks]] to weeks.
826  SET_FROM_INT64(object, weeks);
827  // 7. Set object.[[Days]] to days.
828  SET_FROM_INT64(object, days);
829  // 8. Set object.[[Hours]] to hours.
830  SET_FROM_INT64(object, hours);
831  // 9. Set object.[[Minutes]] to minutes.
832  SET_FROM_INT64(object, minutes);
833  // 10. Set object.[[Seconds]] to seconds.
834  SET_FROM_INT64(object, seconds);
835  // 11. Set object.[[Milliseconds]] to milliseconds.
836  SET_FROM_INT64(object, milliseconds);
837  // 12. Set object.[[Microseconds]] to microseconds.
838  SET_FROM_INT64(object, microseconds);
839  // 13. Set object.[[Nanoseconds]] to nanoseconds.
840  SET_FROM_INT64(object, nanoseconds);
841#undef SET_FROM_INT64
842  // 14. Return object.
843  return object;
844}
845
846MaybeHandle<JSTemporalDuration> CreateTemporalDuration(
847    Isolate* isolate, int64_t years, int64_t months, int64_t weeks,
848    int64_t days, int64_t hours, int64_t minutes, int64_t seconds,
849    int64_t milliseconds, int64_t microseconds, int64_t nanoseconds) {
850  TEMPORAL_ENTER_FUNC();
851  return CreateTemporalDuration(isolate, CONSTRUCTOR(duration),
852                                CONSTRUCTOR(duration), years, months, weeks,
853                                days, hours, minutes, seconds, milliseconds,
854                                microseconds, nanoseconds);
855}
856
857}  // namespace
858
859namespace temporal {
860
861// #sec-temporal-createtemporalinstant
862MaybeHandle<JSTemporalInstant> CreateTemporalInstant(
863    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
864    Handle<BigInt> epoch_nanoseconds) {
865  TEMPORAL_ENTER_FUNC();
866  // 1. Assert: Type(epochNanoseconds) is BigInt.
867  // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
868  DCHECK(IsValidEpochNanoseconds(isolate, epoch_nanoseconds));
869
870  // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget,
871  // "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]],
872  // [[Nanoseconds]] »).
873  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
874                                   JSTemporalInstant)
875  // 5. Set object.[[Nanoseconds]] to ns.
876  object->set_nanoseconds(*epoch_nanoseconds);
877  return object;
878}
879
880MaybeHandle<JSTemporalInstant> CreateTemporalInstant(
881    Isolate* isolate, Handle<BigInt> epoch_nanoseconds) {
882  TEMPORAL_ENTER_FUNC();
883  return CreateTemporalInstant(isolate, CONSTRUCTOR(instant),
884                               CONSTRUCTOR(instant), epoch_nanoseconds);
885}
886
887}  // namespace temporal
888
889namespace {
890
891MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZoneFromIndex(
892    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
893    int32_t index) {
894  TEMPORAL_ENTER_FUNC();
895  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
896                                   JSTemporalTimeZone)
897  object->set_flags(0);
898  object->set_details(0);
899
900  object->set_is_offset(false);
901  object->set_offset_milliseconds_or_time_zone_index(index);
902  return object;
903}
904
905MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(
906    Isolate* isolate, Handle<JSFunction> target,
907    Handle<HeapObject> new_target) {
908  TEMPORAL_ENTER_FUNC();
909  return CreateTemporalTimeZoneFromIndex(isolate, target, new_target, 0);
910}
911
912bool IsUTC(Isolate* isolate, Handle<String> time_zone);
913
914// #sec-temporal-createtemporaltimezone
915MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZone(
916    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
917    Handle<String> identifier) {
918  TEMPORAL_ENTER_FUNC();
919  // 1. If newTarget is not present, set it to %Temporal.TimeZone%.
920  // 2. Let object be ? OrdinaryCreateFromConstructor(newTarget,
921  // "%Temporal.TimeZone.prototype%", « [[InitializedTemporalTimeZone]],
922  // [[Identifier]], [[OffsetNanoseconds]] »).
923  // 3. Set object.[[Identifier]] to identifier.
924  if (IsUTC(isolate, identifier)) {
925    return CreateTemporalTimeZoneUTC(isolate, target, new_target);
926  }
927#ifdef V8_INTL_SUPPORT
928  int32_t time_zone_index;
929  Maybe<bool> maybe_time_zone_index =
930      Intl::GetTimeZoneIndex(isolate, identifier, &time_zone_index);
931  MAYBE_RETURN(maybe_time_zone_index, Handle<JSTemporalTimeZone>());
932  if (maybe_time_zone_index.FromJust()) {
933    return CreateTemporalTimeZoneFromIndex(isolate, target, new_target,
934                                           time_zone_index);
935  }
936#endif  // V8_INTL_SUPPORT
937
938  // 4. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset
939  // (see 13.33), then a. Set object.[[OffsetNanoseconds]] to !
940  // ParseTimeZoneOffsetString(identifier).
941  // 5. Else,
942  // a. Assert: ! CanonicalizeTimeZoneName(identifier) is identifier.
943  // b. Set object.[[OffsetNanoseconds]] to undefined.
944  // 6. Return object.
945  Maybe<int64_t> maybe_offset_nanoseconds =
946      ParseTimeZoneOffsetString(isolate, identifier, false);
947  MAYBE_RETURN(maybe_offset_nanoseconds, Handle<JSTemporalTimeZone>());
948  int64_t offset_nanoseconds = maybe_offset_nanoseconds.FromJust();
949
950  ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target,
951                                   JSTemporalTimeZone)
952  object->set_flags(0);
953  object->set_details(0);
954
955  object->set_is_offset(true);
956  object->set_offset_nanoseconds(offset_nanoseconds);
957  return object;
958}
959
960MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZoneDefaultTarget(
961    Isolate* isolate, Handle<String> identifier) {
962  TEMPORAL_ENTER_FUNC();
963  return CreateTemporalTimeZone(isolate, CONSTRUCTOR(time_zone),
964                                CONSTRUCTOR(time_zone), identifier);
965}
966
967}  // namespace
968
969namespace temporal {
970MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZone(
971    Isolate* isolate, Handle<String> identifier) {
972  return CreateTemporalTimeZoneDefaultTarget(isolate, identifier);
973}
974}  // namespace temporal
975
976namespace {
977
978// #sec-temporal-systeminstant
979MaybeHandle<JSTemporalInstant> SystemInstant(Isolate* isolate) {
980  TEMPORAL_ENTER_FUNC();
981  // 1. Let ns be ! SystemUTCEpochNanoseconds().
982  Handle<BigInt> ns;
983  ASSIGN_RETURN_ON_EXCEPTION(isolate, ns, SystemUTCEpochNanoseconds(isolate),
984                             JSTemporalInstant);
985  // 2. Return ? CreateTemporalInstant(ns).
986  return temporal::CreateTemporalInstant(isolate, ns);
987}
988
989// #sec-temporal-systemtimezone
990MaybeHandle<JSTemporalTimeZone> SystemTimeZone(Isolate* isolate) {
991  TEMPORAL_ENTER_FUNC();
992  Handle<String> default_time_zone;
993  ASSIGN_RETURN_ON_EXCEPTION(isolate, default_time_zone,
994                             DefaultTimeZone(isolate), JSTemporalTimeZone);
995  return temporal::CreateTemporalTimeZone(isolate, default_time_zone);
996}
997
998Maybe<DateTimeRecordCommon> GetISOPartsFromEpoch(
999    Isolate* isolate, Handle<BigInt> epoch_nanoseconds) {
1000  TEMPORAL_ENTER_FUNC();
1001  DateTimeRecordCommon result;
1002  // 1. Let remainderNs be epochNanoseconds modulo 10^6.
1003  Handle<BigInt> million = BigInt::FromInt64(isolate, 1000000);
1004  Handle<BigInt> remainder_ns;
1005  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1006      isolate, remainder_ns,
1007      BigInt::Remainder(isolate, epoch_nanoseconds, million),
1008      Nothing<DateTimeRecordCommon>());
1009  // Need to do some remainder magic to negative remainder.
1010  if (remainder_ns->IsNegative()) {
1011    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1012        isolate, remainder_ns, BigInt::Add(isolate, remainder_ns, million),
1013        Nothing<DateTimeRecordCommon>());
1014  }
1015
1016  // 2. Let epochMilliseconds be (epochNanoseconds − remainderNs) / 10^6.
1017  Handle<BigInt> bigint;
1018  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1019      isolate, bigint,
1020      BigInt::Subtract(isolate, epoch_nanoseconds, remainder_ns),
1021      Nothing<DateTimeRecordCommon>());
1022  ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, bigint,
1023                                   BigInt::Divide(isolate, bigint, million),
1024                                   Nothing<DateTimeRecordCommon>());
1025  int64_t epoch_milliseconds = bigint->AsInt64();
1026  int year = 0;
1027  int month = 0;
1028  int day = 0;
1029  int wday = 0;
1030  int hour = 0;
1031  int min = 0;
1032  int sec = 0;
1033  int ms = 0;
1034  isolate->date_cache()->BreakDownTime(epoch_milliseconds, &year, &month, &day,
1035                                       &wday, &hour, &min, &sec, &ms);
1036
1037  // 3. Let year be ! YearFromTime(epochMilliseconds).
1038  result.year = year;
1039  // 4. Let month be ! MonthFromTime(epochMilliseconds) + 1.
1040  result.month = month + 1;
1041  DCHECK_GE(result.month, 1);
1042  DCHECK_LE(result.month, 12);
1043  // 5. Let day be ! DateFromTime(epochMilliseconds).
1044  result.day = day;
1045  DCHECK_GE(result.day, 1);
1046  DCHECK_LE(result.day, 31);
1047  // 6. Let hour be ! HourFromTime(epochMilliseconds).
1048  result.hour = hour;
1049  DCHECK_GE(result.hour, 0);
1050  DCHECK_LE(result.hour, 23);
1051  // 7. Let minute be ! MinFromTime(epochMilliseconds).
1052  result.minute = min;
1053  DCHECK_GE(result.minute, 0);
1054  DCHECK_LE(result.minute, 59);
1055  // 8. Let second be ! SecFromTime(epochMilliseconds).
1056  result.second = sec;
1057  DCHECK_GE(result.second, 0);
1058  DCHECK_LE(result.second, 59);
1059  // 9. Let millisecond be ! msFromTime(epochMilliseconds).
1060  result.millisecond = ms;
1061  DCHECK_GE(result.millisecond, 0);
1062  DCHECK_LE(result.millisecond, 999);
1063  // 10. Let microsecond be floor(remainderNs / 1000) modulo 1000.
1064  int64_t remainder = remainder_ns->AsInt64();
1065  result.microsecond = (remainder / 1000) % 1000;
1066  DCHECK_GE(result.microsecond, 0);
1067  DCHECK_LE(result.microsecond, 999);
1068  // 11. Let nanosecond be remainderNs modulo 1000.
1069  result.nanosecond = remainder % 1000;
1070  DCHECK_GE(result.nanosecond, 0);
1071  DCHECK_LE(result.nanosecond, 999);
1072  return Just(result);
1073}
1074
1075// #sec-temporal-balanceisodatetime
1076DateTimeRecordCommon BalanceISODateTime(Isolate* isolate, int32_t year,
1077                                        int32_t month, int32_t day,
1078                                        int32_t hour, int32_t minute,
1079                                        int32_t second, int32_t millisecond,
1080                                        int32_t microsecond,
1081                                        int64_t nanosecond) {
1082  TEMPORAL_ENTER_FUNC();
1083  // 1. Assert: year, month, day, hour, minute, second, millisecond,
1084  // microsecond, and nanosecond are integers.
1085  // 2. Let balancedTime be ! BalanceTime(hour, minute, second, millisecond,
1086  // microsecond, nanosecond).
1087  DateTimeRecordCommon balanced_time = BalanceTime(
1088      isolate, hour, minute, second, millisecond, microsecond, nanosecond);
1089  // 3. Let balancedDate be ! BalanceISODate(year, month, day +
1090  // balancedTime.[[Days]]).
1091  day += balanced_time.day;
1092  BalanceISODate(isolate, &year, &month, &day);
1093  // 4. Return the Record { [[Year]]: balancedDate.[[Year]], [[Month]]:
1094  // balancedDate.[[Month]], [[Day]]: balancedDate.[[Day]], [[Hour]]:
1095  // balancedTime.[[Hour]], [[Minute]]: balancedTime.[[Minute]], [[Second]]:
1096  // balancedTime.[[Second]], [[Millisecond]]: balancedTime.[[Millisecond]],
1097  // [[Microsecond]]: balancedTime.[[Microsecond]], [[Nanosecond]]:
1098  // balancedTime.[[Nanosecond]] }.
1099  return {year,
1100          month,
1101          day,
1102          balanced_time.hour,
1103          balanced_time.minute,
1104          balanced_time.second,
1105          balanced_time.millisecond,
1106          balanced_time.microsecond,
1107          balanced_time.nanosecond};
1108}
1109
1110}  // namespace
1111
1112namespace temporal {
1113MaybeHandle<JSTemporalPlainDateTime> BuiltinTimeZoneGetPlainDateTimeFor(
1114    Isolate* isolate, Handle<JSReceiver> time_zone,
1115    Handle<JSTemporalInstant> instant, Handle<JSReceiver> calendar,
1116    const char* method_name) {
1117  TEMPORAL_ENTER_FUNC();
1118  // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
1119  Maybe<int64_t> maybe_offset_nanoseconds =
1120      GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name);
1121  MAYBE_RETURN(maybe_offset_nanoseconds, Handle<JSTemporalPlainDateTime>());
1122  // 2. Let result be ! GetISOPartsFromEpoch(instant.[[Nanoseconds]]).
1123  Maybe<DateTimeRecordCommon> maybe_result = GetISOPartsFromEpoch(
1124      isolate, Handle<BigInt>(instant->nanoseconds(), isolate));
1125  MAYBE_RETURN(maybe_result, Handle<JSTemporalPlainDateTime>());
1126  int64_t offset_nanoseconds = maybe_offset_nanoseconds.FromJust();
1127
1128  // 3. Set result to ! BalanceISODateTime(result.[[Year]], result.[[Month]],
1129  // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
1130  // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]] +
1131  // offsetNanoseconds).
1132  DateTimeRecordCommon result = maybe_result.FromJust();
1133  result = BalanceISODateTime(isolate, result.year, result.month, result.day,
1134                              result.hour, result.minute, result.second,
1135                              result.millisecond, result.microsecond,
1136                              offset_nanoseconds + result.nanosecond);
1137  // 4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
1138  // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
1139  // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
1140  // calendar).
1141  return temporal::CreateTemporalDateTime(
1142      isolate, result.year, result.month, result.day, result.hour,
1143      result.minute, result.second, result.millisecond, result.microsecond,
1144      result.nanosecond, calendar);
1145}
1146
1147}  // namespace temporal
1148
1149namespace {
1150// #sec-temporal-getpossibleinstantsfor
1151MaybeHandle<FixedArray> GetPossibleInstantsFor(Isolate* isolate,
1152                                               Handle<JSReceiver> time_zone,
1153                                               Handle<Object> date_time) {
1154  TEMPORAL_ENTER_FUNC();
1155  // 1. Let possibleInstants be ? Invoke(timeZone, "getPossibleInstantsFor", «
1156  // dateTime »).
1157  Handle<Object> function;
1158  ASSIGN_RETURN_ON_EXCEPTION(
1159      isolate, function,
1160      Object::GetProperty(isolate, time_zone,
1161                          isolate->factory()->getPossibleInstantsFor_string()),
1162      FixedArray);
1163  if (!function->IsCallable()) {
1164    THROW_NEW_ERROR(
1165        isolate,
1166        NewTypeError(MessageTemplate::kCalledNonCallable,
1167                     isolate->factory()->getPossibleInstantsFor_string()),
1168        FixedArray);
1169  }
1170  Handle<Object> possible_instants;
1171  {
1172    Handle<Object> argv[] = {date_time};
1173    ASSIGN_RETURN_ON_EXCEPTION(
1174        isolate, possible_instants,
1175        Execution::Call(isolate, function, time_zone, arraysize(argv), argv),
1176        FixedArray);
1177  }
1178
1179  // Step 4-6 of GetPossibleInstantsFor is implemented inside
1180  // temporal_instant_fixed_array_from_iterable.
1181  {
1182    Handle<Object> argv[] = {possible_instants};
1183    ASSIGN_RETURN_ON_EXCEPTION(
1184        isolate, possible_instants,
1185        Execution::CallBuiltin(
1186            isolate, isolate->temporal_instant_fixed_array_from_iterable(),
1187            possible_instants, arraysize(argv), argv),
1188        FixedArray);
1189  }
1190  DCHECK(possible_instants->IsFixedArray());
1191  // 7. Return list.
1192  return Handle<FixedArray>::cast(possible_instants);
1193}
1194
1195// #sec-temporal-disambiguatepossibleinstants
1196MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
1197    Isolate* isolate, Handle<FixedArray> possible_instants,
1198    Handle<JSReceiver> time_zone, Handle<Object> date_time_obj,
1199    Disambiguation disambiguation, const char* method_name) {
1200  TEMPORAL_ENTER_FUNC();
1201  // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot.
1202  DCHECK(date_time_obj->IsJSTemporalPlainDateTime());
1203  Handle<JSTemporalPlainDateTime> date_time =
1204      Handle<JSTemporalPlainDateTime>::cast(date_time_obj);
1205
1206  // 2. Let n be possibleInstants's length.
1207  int32_t n = possible_instants->length();
1208
1209  // 3. If n = 1, then
1210  if (n == 1) {
1211    // a. Return possibleInstants[0].
1212    Handle<Object> ret_obj = FixedArray::get(*possible_instants, 0, isolate);
1213    DCHECK(ret_obj->IsJSTemporalInstant());
1214    return Handle<JSTemporalInstant>::cast(ret_obj);
1215  }
1216  // 4. If n ≠ 0, then
1217  if (n != 0) {
1218    // a. If disambiguation is "earlier" or "compatible", then
1219    if (disambiguation == Disambiguation::kEarlier ||
1220        disambiguation == Disambiguation::kCompatible) {
1221      // i. Return possibleInstants[0].
1222      Handle<Object> ret_obj = FixedArray::get(*possible_instants, 0, isolate);
1223      DCHECK(ret_obj->IsJSTemporalInstant());
1224      return Handle<JSTemporalInstant>::cast(ret_obj);
1225    }
1226    // b. If disambiguation is "later", then
1227    if (disambiguation == Disambiguation::kLater) {
1228      // i. Return possibleInstants[n − 1].
1229      Handle<Object> ret_obj =
1230          FixedArray::get(*possible_instants, n - 1, isolate);
1231      DCHECK(ret_obj->IsJSTemporalInstant());
1232      return Handle<JSTemporalInstant>::cast(ret_obj);
1233    }
1234    // c. Assert: disambiguation is "reject".
1235    DCHECK_EQ(disambiguation, Disambiguation::kReject);
1236    // d. Throw a RangeError exception.
1237    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
1238                    JSTemporalInstant);
1239  }
1240  // 5. Assert: n = 0.
1241  DCHECK_EQ(n, 0);
1242  // 6. If disambiguation is "reject", then
1243  if (disambiguation == Disambiguation::kReject) {
1244    // a. Throw a RangeError exception.
1245    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
1246                    JSTemporalInstant);
1247  }
1248  // 7. Let epochNanoseconds be ! GetEpochFromISOParts(dateTime.[[ISOYear]],
1249  // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
1250  // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
1251  // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
1252  // dateTime.[[ISONanosecond]]).
1253  Handle<BigInt> epoch_nanoseconds;
1254  ASSIGN_RETURN_ON_EXCEPTION(
1255      isolate, epoch_nanoseconds,
1256      GetEpochFromISOParts(
1257          isolate, date_time->iso_year(), date_time->iso_month(),
1258          date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
1259          date_time->iso_second(), date_time->iso_millisecond(),
1260          date_time->iso_microsecond(), date_time->iso_nanosecond()),
1261      JSTemporalInstant);
1262
1263  // 8. Let dayBefore be ! CreateTemporalInstant(epochNanoseconds − 8.64 ×
1264  // 10^13).
1265  Handle<BigInt> one_day_in_ns = BigInt::FromUint64(isolate, 86400000000000ULL);
1266  Handle<BigInt> day_before_ns;
1267  ASSIGN_RETURN_ON_EXCEPTION(
1268      isolate, day_before_ns,
1269      BigInt::Subtract(isolate, epoch_nanoseconds, one_day_in_ns),
1270      JSTemporalInstant);
1271  Handle<JSTemporalInstant> day_before;
1272  ASSIGN_RETURN_ON_EXCEPTION(
1273      isolate, day_before,
1274      temporal::CreateTemporalInstant(isolate, day_before_ns),
1275      JSTemporalInstant);
1276  // 9. Let dayAfter be ! CreateTemporalInstant(epochNanoseconds + 8.64 ×
1277  // 10^13).
1278  Handle<BigInt> day_after_ns;
1279  ASSIGN_RETURN_ON_EXCEPTION(
1280      isolate, day_after_ns,
1281      BigInt::Add(isolate, epoch_nanoseconds, one_day_in_ns),
1282      JSTemporalInstant);
1283  Handle<JSTemporalInstant> day_after;
1284  ASSIGN_RETURN_ON_EXCEPTION(
1285      isolate, day_after,
1286      temporal::CreateTemporalInstant(isolate, day_after_ns),
1287      JSTemporalInstant);
1288  // 10. Let offsetBefore be ? GetOffsetNanosecondsFor(timeZone, dayBefore).
1289  Maybe<int64_t> maybe_offset_before =
1290      GetOffsetNanosecondsFor(isolate, time_zone, day_before, method_name);
1291  MAYBE_RETURN(maybe_offset_before, Handle<JSTemporalInstant>());
1292  // 11. Let offsetAfter be ? GetOffsetNanosecondsFor(timeZone, dayAfter).
1293  Maybe<int64_t> maybe_offset_after =
1294      GetOffsetNanosecondsFor(isolate, time_zone, day_after, method_name);
1295  MAYBE_RETURN(maybe_offset_after, Handle<JSTemporalInstant>());
1296
1297  // 12. Let nanoseconds be offsetAfter − offsetBefore.
1298  int64_t nanoseconds =
1299      maybe_offset_after.FromJust() - maybe_offset_before.FromJust();
1300
1301  // 13. If disambiguation is "earlier", then
1302  if (disambiguation == Disambiguation::kEarlier) {
1303    // a. Let earlier be ? AddDateTime(dateTime.[[ISOYear]],
1304    // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
1305    // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
1306    // dateTime.[[ISOMillisecond]],
1307    // dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]],
1308    // dateTime.[[Calendar]], 0, 0, 0, 0, 0, 0, 0, 0, 0, −nanoseconds,
1309    // undefined).
1310    Maybe<DateTimeRecordCommon> maybe_earlier = AddDateTime(
1311        isolate, date_time->iso_year(), date_time->iso_month(),
1312        date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
1313        date_time->iso_second(), date_time->iso_millisecond(),
1314        date_time->iso_microsecond(), date_time->iso_nanosecond(),
1315        handle(date_time->calendar(), isolate),
1316        {0, 0, 0, 0, 0, 0, 0, 0, 0, -nanoseconds},
1317        isolate->factory()->undefined_value());
1318    MAYBE_RETURN(maybe_earlier, Handle<JSTemporalInstant>());
1319    DateTimeRecordCommon earlier = maybe_earlier.FromJust();
1320
1321    // See https://github.com/tc39/proposal-temporal/issues/1816
1322    // b. Let earlierDateTime be ? CreateTemporalDateTime(earlier.[[Year]],
1323    // earlier.[[Month]], earlier.[[Day]], earlier.[[Hour]], earlier.[[Minute]],
1324    // earlier.[[Second]], earlier.[[Millisecond]], earlier.[[Microsecond]],
1325    // earlier.[[Nanosecond]], dateTime.[[Calendar]]).
1326    Handle<JSTemporalPlainDateTime> earlier_date_time;
1327    ASSIGN_RETURN_ON_EXCEPTION(
1328        isolate, earlier_date_time,
1329        temporal::CreateTemporalDateTime(
1330            isolate, earlier.year, earlier.month, earlier.day, earlier.hour,
1331            earlier.minute, earlier.second, earlier.millisecond,
1332            earlier.microsecond, earlier.nanosecond,
1333            handle(date_time->calendar(), isolate)),
1334        JSTemporalInstant);
1335
1336    // c. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
1337    // earlierDateTime).
1338    ASSIGN_RETURN_ON_EXCEPTION(
1339        isolate, possible_instants,
1340        GetPossibleInstantsFor(isolate, time_zone, earlier_date_time),
1341        JSTemporalInstant);
1342
1343    // d. If possibleInstants is empty, throw a RangeError exception.
1344    if (possible_instants->length() == 0) {
1345      THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
1346                      JSTemporalInstant);
1347    }
1348    // e. Return possibleInstants[0].
1349    Handle<Object> ret_obj = FixedArray::get(*possible_instants, 0, isolate);
1350    DCHECK(ret_obj->IsJSTemporalInstant());
1351    return Handle<JSTemporalInstant>::cast(ret_obj);
1352  }
1353  // 14. Assert: disambiguation is "compatible" or "later".
1354  DCHECK(disambiguation == Disambiguation::kCompatible ||
1355         disambiguation == Disambiguation::kLater);
1356  // 15. Let later be ? AddDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
1357  // dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]],
1358  // dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]],
1359  // dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]],
1360  // dateTime.[[Calendar]], 0, 0, 0, 0, 0, 0, 0, 0, 0, nanoseconds, undefined).
1361  Maybe<DateTimeRecordCommon> maybe_later = AddDateTime(
1362      isolate, date_time->iso_year(), date_time->iso_month(),
1363      date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
1364      date_time->iso_second(), date_time->iso_millisecond(),
1365      date_time->iso_microsecond(), date_time->iso_nanosecond(),
1366      handle(date_time->calendar(), isolate),
1367      {0, 0, 0, 0, 0, 0, 0, 0, 0, nanoseconds},
1368      isolate->factory()->undefined_value());
1369  MAYBE_RETURN(maybe_later, Handle<JSTemporalInstant>());
1370  DateTimeRecordCommon later = maybe_later.FromJust();
1371
1372  // See https://github.com/tc39/proposal-temporal/issues/1816
1373  // 16. Let laterDateTime be ? CreateTemporalDateTime(later.[[Year]],
1374  // later.[[Month]], later.[[Day]], later.[[Hour]], later.[[Minute]],
1375  // later.[[Second]], later.[[Millisecond]], later.[[Microsecond]],
1376  // later.[[Nanosecond]], dateTime.[[Calendar]]).
1377
1378  Handle<JSTemporalPlainDateTime> later_date_time;
1379  ASSIGN_RETURN_ON_EXCEPTION(
1380      isolate, later_date_time,
1381      temporal::CreateTemporalDateTime(
1382          isolate, later.year, later.month, later.day, later.hour, later.minute,
1383          later.second, later.millisecond, later.microsecond, later.nanosecond,
1384          handle(date_time->calendar(), isolate)),
1385      JSTemporalInstant);
1386  // 17. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
1387  // laterDateTime).
1388  ASSIGN_RETURN_ON_EXCEPTION(
1389      isolate, possible_instants,
1390      GetPossibleInstantsFor(isolate, time_zone, later_date_time),
1391      JSTemporalInstant);
1392  // 18. Set n to possibleInstants's length.
1393  n = possible_instants->length();
1394  // 19. If n = 0, throw a RangeError exception.
1395  if (n == 0) {
1396    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
1397                    JSTemporalInstant);
1398  }
1399  // 20. Return possibleInstants[n − 1].
1400  Handle<Object> ret_obj = FixedArray::get(*possible_instants, n - 1, isolate);
1401  DCHECK(ret_obj->IsJSTemporalInstant());
1402  return Handle<JSTemporalInstant>::cast(ret_obj);
1403}
1404
1405// #sec-temporal-gettemporalcalendarwithisodefault
1406MaybeHandle<JSReceiver> GetTemporalCalendarWithISODefault(
1407    Isolate* isolate, Handle<JSReceiver> item, const char* method_name) {
1408  TEMPORAL_ENTER_FUNC();
1409
1410  Factory* factory = isolate->factory();
1411  // 1. If item has an [[InitializedTemporalDate]],
1412  // [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
1413  // [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
1414  // [[InitializedTemporalZonedDateTime]] internal slot, then a. Return
1415  // item.[[Calendar]].
1416  if (item->IsJSTemporalPlainDate()) {
1417    return handle(Handle<JSTemporalPlainDate>::cast(item)->calendar(), isolate);
1418  }
1419  if (item->IsJSTemporalPlainDateTime()) {
1420    return handle(Handle<JSTemporalPlainDateTime>::cast(item)->calendar(),
1421                  isolate);
1422  }
1423  if (item->IsJSTemporalPlainMonthDay()) {
1424    return handle(Handle<JSTemporalPlainMonthDay>::cast(item)->calendar(),
1425                  isolate);
1426  }
1427  if (item->IsJSTemporalPlainTime()) {
1428    return handle(Handle<JSTemporalPlainTime>::cast(item)->calendar(), isolate);
1429  }
1430  if (item->IsJSTemporalPlainYearMonth()) {
1431    return handle(Handle<JSTemporalPlainYearMonth>::cast(item)->calendar(),
1432                  isolate);
1433  }
1434  if (item->IsJSTemporalZonedDateTime()) {
1435    return handle(Handle<JSTemporalZonedDateTime>::cast(item)->calendar(),
1436                  isolate);
1437  }
1438
1439  // 2. Let calendar be ? Get(item, "calendar").
1440  Handle<Object> calendar;
1441  ASSIGN_RETURN_ON_EXCEPTION(
1442      isolate, calendar,
1443      JSReceiver::GetProperty(isolate, item, factory->calendar_string()),
1444      JSReceiver);
1445  // 3. Return ? ToTemporalCalendarWithISODefault(calendar).
1446  return ToTemporalCalendarWithISODefault(isolate, calendar, method_name);
1447}
1448
1449enum class RequiredFields { kNone, kTimeZone, kTimeZoneAndOffset, kDay };
1450
1451// The common part of PrepareTemporalFields and PreparePartialTemporalFields
1452// #sec-temporal-preparetemporalfields
1453// #sec-temporal-preparepartialtemporalfields
1454V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> PrepareTemporalFieldsOrPartial(
1455    Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names,
1456    RequiredFields required, bool partial) {
1457  TEMPORAL_ENTER_FUNC();
1458
1459  Factory* factory = isolate->factory();
1460  // 1. Assert: Type(fields) is Object.
1461  // 2. Let result be ! OrdinaryObjectCreate(%Object.prototype%).
1462  Handle<JSObject> result =
1463      isolate->factory()->NewJSObject(isolate->object_function());
1464  // 3. For each value property of fieldNames, do
1465  int length = field_names->length();
1466  bool any = false;
1467  for (int i = 0; i < length; i++) {
1468    Handle<Object> property_obj = Handle<Object>(field_names->get(i), isolate);
1469    Handle<String> property = Handle<String>::cast(property_obj);
1470    // a. Let value be ? Get(fields, property).
1471    Handle<Object> value;
1472    ASSIGN_RETURN_ON_EXCEPTION(
1473        isolate, value, JSReceiver::GetProperty(isolate, fields, property),
1474        JSObject);
1475
1476    // b. If value is undefined, then
1477    if (value->IsUndefined()) {
1478      // This part is only for PrepareTemporalFields
1479      // Skip for the case of PreparePartialTemporalFields.
1480      if (partial) continue;
1481
1482      // i. If requiredFields contains property, then
1483      if ((required == RequiredFields::kDay &&
1484           String::Equals(isolate, property, factory->day_string())) ||
1485          ((required == RequiredFields::kTimeZone ||
1486            required == RequiredFields::kTimeZoneAndOffset) &&
1487           String::Equals(isolate, property, factory->timeZone_string())) ||
1488          (required == RequiredFields::kTimeZoneAndOffset &&
1489           String::Equals(isolate, property, factory->offset_string()))) {
1490        // 1. Throw a TypeError exception.
1491        THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
1492                        JSObject);
1493      }
1494      // ii. Else,
1495      // 1. If property is in the Property column of Table 13, then
1496      // a. Set value to the corresponding Default value of the same row.
1497      if (String::Equals(isolate, property, factory->hour_string()) ||
1498          String::Equals(isolate, property, factory->minute_string()) ||
1499          String::Equals(isolate, property, factory->second_string()) ||
1500          String::Equals(isolate, property, factory->millisecond_string()) ||
1501          String::Equals(isolate, property, factory->microsecond_string()) ||
1502          String::Equals(isolate, property, factory->nanosecond_string())) {
1503        value = Handle<Object>(Smi::zero(), isolate);
1504      }
1505    } else {
1506      // For both PrepareTemporalFields and PreparePartialTemporalFields
1507      any = partial;
1508      // c. Else,
1509      // i. If property is in the Property column of Table 13 and there is a
1510      // Conversion value in the same row, then
1511      // 1. Let Conversion represent the abstract operation named by the
1512      // Conversion value of the same row.
1513      // 2. Set value to ? Conversion(value).
1514      if (String::Equals(isolate, property, factory->month_string()) ||
1515          String::Equals(isolate, property, factory->day_string())) {
1516        ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
1517                                   ToPositiveInteger(isolate, value), JSObject);
1518      } else if (String::Equals(isolate, property, factory->year_string()) ||
1519                 String::Equals(isolate, property, factory->hour_string()) ||
1520                 String::Equals(isolate, property, factory->minute_string()) ||
1521                 String::Equals(isolate, property, factory->second_string()) ||
1522                 String::Equals(isolate, property,
1523                                factory->millisecond_string()) ||
1524                 String::Equals(isolate, property,
1525                                factory->microsecond_string()) ||
1526                 String::Equals(isolate, property,
1527                                factory->nanosecond_string()) ||
1528                 String::Equals(isolate, property, factory->eraYear_string())) {
1529        ASSIGN_RETURN_ON_EXCEPTION(
1530            isolate, value, ToIntegerThrowOnInfinity(isolate, value), JSObject);
1531      } else if (String::Equals(isolate, property,
1532                                factory->monthCode_string()) ||
1533                 String::Equals(isolate, property, factory->offset_string()) ||
1534                 String::Equals(isolate, property, factory->era_string())) {
1535        ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
1536                                   Object::ToString(isolate, value), JSObject);
1537      }
1538    }
1539
1540    // d. Perform ! CreateDataPropertyOrThrow(result, property, value).
1541    CHECK(JSReceiver::CreateDataProperty(isolate, result, property, value,
1542                                         Just(kThrowOnError))
1543              .FromJust());
1544  }
1545
1546  // Only for PreparePartialTemporalFields
1547  if (partial) {
1548    // 5. If any is false, then
1549    if (!any) {
1550      // a. Throw a TypeError exception.
1551      THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(), JSObject);
1552    }
1553  }
1554  // 4. Return result.
1555  return result;
1556}
1557
1558// #sec-temporal-preparetemporalfields
1559V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> PrepareTemporalFields(
1560    Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names,
1561    RequiredFields required) {
1562  TEMPORAL_ENTER_FUNC();
1563
1564  return PrepareTemporalFieldsOrPartial(isolate, fields, field_names, required,
1565                                        false);
1566}
1567
1568// Template for DateFromFields, YearMonthFromFields, and MonthDayFromFields
1569template <typename T>
1570MaybeHandle<T> FromFields(Isolate* isolate, Handle<JSReceiver> calendar,
1571                          Handle<JSReceiver> fields, Handle<Object> options,
1572                          Handle<String> property, InstanceType type) {
1573  Handle<Object> function;
1574  ASSIGN_RETURN_ON_EXCEPTION(
1575      isolate, function, Object::GetProperty(isolate, calendar, property), T);
1576  if (!function->IsCallable()) {
1577    THROW_NEW_ERROR(isolate,
1578                    NewTypeError(MessageTemplate::kCalledNonCallable, property),
1579                    T);
1580  }
1581  Handle<Object> argv[] = {fields, options};
1582  Handle<Object> result;
1583  ASSIGN_RETURN_ON_EXCEPTION(
1584      isolate, result, Execution::Call(isolate, function, calendar, 2, argv),
1585      T);
1586  if ((!result->IsHeapObject()) ||
1587      HeapObject::cast(*result).map().instance_type() != type) {
1588    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(), T);
1589  }
1590  return Handle<T>::cast(result);
1591}
1592
1593// #sec-temporal-datefromfields
1594MaybeHandle<JSTemporalPlainDate> DateFromFields(Isolate* isolate,
1595                                                Handle<JSReceiver> calendar,
1596                                                Handle<JSReceiver> fields,
1597                                                Handle<Object> options) {
1598  return FromFields<JSTemporalPlainDate>(
1599      isolate, calendar, fields, options,
1600      isolate->factory()->dateFromFields_string(), JS_TEMPORAL_PLAIN_DATE_TYPE);
1601}
1602
1603// #sec-temporal-yearmonthfromfields
1604MaybeHandle<JSTemporalPlainYearMonth> YearMonthFromFields(
1605    Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields,
1606    Handle<Object> options) {
1607  return FromFields<JSTemporalPlainYearMonth>(
1608      isolate, calendar, fields, options,
1609      isolate->factory()->yearMonthFromFields_string(),
1610      JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE);
1611}
1612
1613// #sec-temporal-monthdayfromfields
1614MaybeHandle<JSTemporalPlainMonthDay> MonthDayFromFields(
1615    Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields,
1616    Handle<Object> options) {
1617  return FromFields<JSTemporalPlainMonthDay>(
1618      isolate, calendar, fields, options,
1619      isolate->factory()->monthDayFromFields_string(),
1620      JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE);
1621}
1622
1623// #sec-temporal-totemporaloverflow
1624Maybe<ShowOverflow> ToTemporalOverflow(Isolate* isolate,
1625                                       Handle<JSReceiver> options,
1626                                       const char* method_name) {
1627  return GetStringOption<ShowOverflow>(
1628      isolate, options, "overflow", method_name, {"constrain", "reject"},
1629      {ShowOverflow::kConstrain, ShowOverflow::kReject},
1630      ShowOverflow::kConstrain);
1631}
1632
1633// #sec-temporal-builtintimezonegetinstantfor
1634MaybeHandle<JSTemporalInstant> BuiltinTimeZoneGetInstantFor(
1635    Isolate* isolate, Handle<JSReceiver> time_zone,
1636    Handle<JSTemporalPlainDateTime> date_time, Disambiguation disambiguation,
1637    const char* method_name) {
1638  TEMPORAL_ENTER_FUNC();
1639  // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot.
1640  // 2. Let possibleInstants be ? GetPossibleInstantsFor(timeZone, dateTime).
1641  Handle<FixedArray> possible_instants;
1642  ASSIGN_RETURN_ON_EXCEPTION(
1643      isolate, possible_instants,
1644      GetPossibleInstantsFor(isolate, time_zone, date_time), JSTemporalInstant);
1645  // 3. Return ? DisambiguatePossibleInstants(possibleInstants, timeZone,
1646  // dateTime, disambiguation).
1647  return DisambiguatePossibleInstants(isolate, possible_instants, time_zone,
1648                                      date_time, disambiguation, method_name);
1649}
1650
1651// #sec-temporal-totemporalinstant
1652MaybeHandle<JSTemporalInstant> ToTemporalInstant(Isolate* isolate,
1653                                                 Handle<Object> item,
1654                                                 const char* method) {
1655  TEMPORAL_ENTER_FUNC();
1656
1657  // 1. If Type(item) is Object, then
1658  // a. If item has an [[InitializedTemporalInstant]] internal slot, then
1659  if (item->IsJSTemporalInstant()) {
1660    // i. Return item.
1661    return Handle<JSTemporalInstant>::cast(item);
1662  }
1663  // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
1664  if (item->IsJSTemporalZonedDateTime()) {
1665    // i. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
1666    Handle<BigInt> nanoseconds =
1667        handle(JSTemporalZonedDateTime::cast(*item).nanoseconds(), isolate);
1668    return temporal::CreateTemporalInstant(isolate, nanoseconds);
1669  }
1670  // 2. Let string be ? ToString(item).
1671  Handle<String> string;
1672  ASSIGN_RETURN_ON_EXCEPTION(isolate, string, Object::ToString(isolate, item),
1673                             JSTemporalInstant);
1674
1675  // 3. Let epochNanoseconds be ? ParseTemporalInstant(string).
1676  Handle<BigInt> epoch_nanoseconds;
1677  ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_nanoseconds,
1678                             ParseTemporalInstant(isolate, string),
1679                             JSTemporalInstant);
1680
1681  // 4. Return ? CreateTemporalInstant(ℤ(epochNanoseconds)).
1682  return temporal::CreateTemporalInstant(isolate, epoch_nanoseconds);
1683}
1684
1685}  // namespace
1686
1687namespace temporal {
1688
1689// #sec-temporal-totemporalcalendar
1690MaybeHandle<JSReceiver> ToTemporalCalendar(
1691    Isolate* isolate, Handle<Object> temporal_calendar_like,
1692    const char* method_name) {
1693  Factory* factory = isolate->factory();
1694  // 1.If Type(temporalCalendarLike) is Object, then
1695  if (temporal_calendar_like->IsJSReceiver()) {
1696    // a. If temporalCalendarLike has an [[InitializedTemporalDate]],
1697    // [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
1698    // [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
1699    // [[InitializedTemporalZonedDateTime]] internal slot, then i. Return
1700    // temporalCalendarLike.[[Calendar]].
1701
1702#define EXTRACT_CALENDAR(T, obj)                                          \
1703  if (obj->IsJSTemporal##T()) {                                           \
1704    return handle(Handle<JSTemporal##T>::cast(obj)->calendar(), isolate); \
1705  }
1706
1707    EXTRACT_CALENDAR(PlainDate, temporal_calendar_like)
1708    EXTRACT_CALENDAR(PlainDateTime, temporal_calendar_like)
1709    EXTRACT_CALENDAR(PlainMonthDay, temporal_calendar_like)
1710    EXTRACT_CALENDAR(PlainTime, temporal_calendar_like)
1711    EXTRACT_CALENDAR(PlainYearMonth, temporal_calendar_like)
1712    EXTRACT_CALENDAR(ZonedDateTime, temporal_calendar_like)
1713
1714#undef EXTRACT_CALENDAR
1715    Handle<JSReceiver> obj = Handle<JSReceiver>::cast(temporal_calendar_like);
1716
1717    // b. If ? HasProperty(temporalCalendarLike, "calendar") is false, return
1718    // temporalCalendarLike.
1719    Maybe<bool> maybe_has =
1720        JSReceiver::HasProperty(isolate, obj, factory->calendar_string());
1721
1722    MAYBE_RETURN(maybe_has, Handle<JSReceiver>());
1723    if (!maybe_has.FromJust()) {
1724      return obj;
1725    }
1726    // c.  Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
1727    ASSIGN_RETURN_ON_EXCEPTION(
1728        isolate, temporal_calendar_like,
1729        JSReceiver::GetProperty(isolate, obj, factory->calendar_string()),
1730        JSReceiver);
1731    // d. If Type(temporalCalendarLike) is Object
1732    if (temporal_calendar_like->IsJSReceiver()) {
1733      obj = Handle<JSReceiver>::cast(temporal_calendar_like);
1734      // and ? HasProperty(temporalCalendarLike, "calendar") is false,
1735      maybe_has =
1736          JSReceiver::HasProperty(isolate, obj, factory->calendar_string());
1737      MAYBE_RETURN(maybe_has, Handle<JSReceiver>());
1738      if (!maybe_has.FromJust()) {
1739        // return temporalCalendarLike.
1740        return obj;
1741      }
1742    }
1743  }
1744
1745  // 2. Let identifier be ? ToString(temporalCalendarLike).
1746  Handle<String> identifier;
1747  ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
1748                             Object::ToString(isolate, temporal_calendar_like),
1749                             JSReceiver);
1750  // 3. If ! IsBuiltinCalendar(identifier) is false, then
1751  if (!IsBuiltinCalendar(isolate, identifier)) {
1752    // a. Let identifier be ? ParseTemporalCalendarString(identifier).
1753    ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
1754                               ParseTemporalCalendarString(isolate, identifier),
1755                               JSReceiver);
1756  }
1757  // 4. Return ? CreateTemporalCalendar(identifier).
1758  return CreateTemporalCalendar(isolate, identifier);
1759}
1760
1761}  // namespace temporal
1762
1763namespace {
1764// #sec-temporal-totemporalcalendarwithisodefault
1765MaybeHandle<JSReceiver> ToTemporalCalendarWithISODefault(
1766    Isolate* isolate, Handle<Object> temporal_calendar_like,
1767    const char* method_name) {
1768  TEMPORAL_ENTER_FUNC();
1769
1770  // 1. If temporalCalendarLike is undefined, then
1771  if (temporal_calendar_like->IsUndefined()) {
1772    // a. Return ? GetISO8601Calendar().
1773    return temporal::GetISO8601Calendar(isolate);
1774  }
1775  // 2. Return ? ToTemporalCalendar(temporalCalendarLike).
1776  return temporal::ToTemporalCalendar(isolate, temporal_calendar_like,
1777                                      method_name);
1778}
1779
1780// #sec-temporal-totemporaldate
1781MaybeHandle<JSTemporalPlainDate> ToTemporalDate(Isolate* isolate,
1782                                                Handle<Object> item_obj,
1783                                                Handle<JSReceiver> options,
1784                                                const char* method_name) {
1785  TEMPORAL_ENTER_FUNC();
1786
1787  Factory* factory = isolate->factory();
1788  // 2. Assert: Type(options) is Object.
1789  // 3. If Type(item) is Object, then
1790  if (item_obj->IsJSReceiver()) {
1791    Handle<JSReceiver> item = Handle<JSReceiver>::cast(item_obj);
1792    // a. If item has an [[InitializedTemporalDate]] internal slot, then
1793    // i. Return item.
1794    if (item->IsJSTemporalPlainDate()) {
1795      return Handle<JSTemporalPlainDate>::cast(item);
1796    }
1797    // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
1798    // then
1799    if (item->IsJSTemporalZonedDateTime()) {
1800      // i. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
1801      Handle<JSTemporalZonedDateTime> zoned_date_time =
1802          Handle<JSTemporalZonedDateTime>::cast(item);
1803      Handle<JSTemporalInstant> instant;
1804      ASSIGN_RETURN_ON_EXCEPTION(
1805          isolate, instant,
1806          temporal::CreateTemporalInstant(
1807              isolate, Handle<BigInt>(zoned_date_time->nanoseconds(), isolate)),
1808          JSTemporalPlainDate);
1809      // ii. Let plainDateTime be ?
1810      // BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
1811      // instant, item.[[Calendar]]).
1812      Handle<JSTemporalPlainDateTime> plain_date_time;
1813      ASSIGN_RETURN_ON_EXCEPTION(
1814          isolate, plain_date_time,
1815          temporal::BuiltinTimeZoneGetPlainDateTimeFor(
1816              isolate,
1817              Handle<JSReceiver>(zoned_date_time->time_zone(), isolate),
1818              instant, Handle<JSReceiver>(zoned_date_time->calendar(), isolate),
1819              method_name),
1820          JSTemporalPlainDate);
1821      // iii. Return ! CreateTemporalDate(plainDateTime.[[ISOYear]],
1822      // plainDateTime.[[ISOMonth]], plainDateTime.[[ISODay]],
1823      // plainDateTime.[[Calendar]]).
1824      return CreateTemporalDate(
1825          isolate, plain_date_time->iso_year(), plain_date_time->iso_month(),
1826          plain_date_time->iso_day(),
1827          Handle<JSReceiver>(plain_date_time->calendar(), isolate));
1828    }
1829
1830    // c. If item has an [[InitializedTemporalDateTime]] internal slot, then
1831    // i. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
1832    // item.[[ISODay]], item.[[Calendar]]).
1833    if (item->IsJSTemporalPlainDateTime()) {
1834      Handle<JSTemporalPlainDateTime> date_time =
1835          Handle<JSTemporalPlainDateTime>::cast(item);
1836      return CreateTemporalDate(isolate, date_time->iso_year(),
1837                                date_time->iso_month(), date_time->iso_day(),
1838                                handle(date_time->calendar(), isolate));
1839    }
1840
1841    // d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
1842    Handle<JSReceiver> calendar;
1843    ASSIGN_RETURN_ON_EXCEPTION(
1844        isolate, calendar,
1845        GetTemporalCalendarWithISODefault(isolate, item, method_name),
1846        JSTemporalPlainDate);
1847    // e. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
1848    // "monthCode", "year" »).
1849    Handle<FixedArray> field_names = factory->NewFixedArray(4);
1850    field_names->set(0, ReadOnlyRoots(isolate).day_string());
1851    field_names->set(1, ReadOnlyRoots(isolate).month_string());
1852    field_names->set(2, ReadOnlyRoots(isolate).monthCode_string());
1853    field_names->set(3, ReadOnlyRoots(isolate).year_string());
1854    ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
1855                               CalendarFields(isolate, calendar, field_names),
1856                               JSTemporalPlainDate);
1857    // f. Let fields be ? PrepareTemporalFields(item,
1858    // fieldNames, «»).
1859    Handle<JSReceiver> fields;
1860    ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
1861                               PrepareTemporalFields(isolate, item, field_names,
1862                                                     RequiredFields::kNone),
1863                               JSTemporalPlainDate);
1864    // g. Return ? DateFromFields(calendar, fields, options).
1865    return DateFromFields(isolate, calendar, fields, options);
1866  }
1867  // 4. Perform ? ToTemporalOverflow(options).
1868  Maybe<ShowOverflow> maybe_overflow =
1869      ToTemporalOverflow(isolate, options, method_name);
1870  MAYBE_RETURN(maybe_overflow, Handle<JSTemporalPlainDate>());
1871
1872  // 5. Let string be ? ToString(item).
1873  Handle<String> string;
1874  ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
1875                             Object::ToString(isolate, item_obj),
1876                             JSTemporalPlainDate);
1877  // 6. Let result be ? ParseTemporalDateString(string).
1878  Maybe<DateRecord> maybe_result = ParseTemporalDateString(isolate, string);
1879  MAYBE_RETURN(maybe_result, MaybeHandle<JSTemporalPlainDate>());
1880  DateRecord result = maybe_result.FromJust();
1881
1882  // 7. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
1883  // result.[[Day]]) is true.
1884  DCHECK(IsValidISODate(isolate, result.year, result.month, result.day));
1885  // 8. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
1886  Handle<Object> calendar_string;
1887  if (result.calendar->length() == 0) {
1888    calendar_string = factory->undefined_value();
1889  } else {
1890    calendar_string = result.calendar;
1891  }
1892  Handle<JSReceiver> calendar;
1893  ASSIGN_RETURN_ON_EXCEPTION(
1894      isolate, calendar,
1895      ToTemporalCalendarWithISODefault(isolate, calendar_string, method_name),
1896      JSTemporalPlainDate);
1897  // 9. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
1898  // result.[[Day]], calendar).
1899  return CreateTemporalDate(isolate, result.year, result.month, result.day,
1900                            calendar);
1901}
1902
1903}  // namespace
1904
1905namespace temporal {
1906
1907// #sec-temporal-regulatetime
1908Maybe<bool> RegulateTime(Isolate* isolate, TimeRecord* time,
1909                         ShowOverflow overflow) {
1910  TEMPORAL_ENTER_FUNC();
1911
1912  // 1. Assert: hour, minute, second, millisecond, microsecond and nanosecond
1913  // are integers.
1914  // 2. Assert: overflow is either "constrain" or "reject".
1915  switch (overflow) {
1916    case ShowOverflow::kConstrain:
1917      // 3. If overflow is "constrain", then
1918      // a. Return ! ConstrainTime(hour, minute, second, millisecond,
1919      // microsecond, nanosecond).
1920      time->hour = std::max(std::min(time->hour, 23), 0);
1921      time->minute = std::max(std::min(time->minute, 59), 0);
1922      time->second = std::max(std::min(time->second, 59), 0);
1923      time->millisecond = std::max(std::min(time->millisecond, 999), 0);
1924      time->microsecond = std::max(std::min(time->microsecond, 999), 0);
1925      time->nanosecond = std::max(std::min(time->nanosecond, 999), 0);
1926      return Just(true);
1927    case ShowOverflow::kReject:
1928      // 4. If overflow is "reject", then
1929      // a. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
1930      // nanosecond) is false, throw a RangeError exception.
1931      if (!IsValidTime(isolate, time->hour, time->minute, time->second,
1932                       time->millisecond, time->microsecond,
1933                       time->nanosecond)) {
1934        THROW_NEW_ERROR_RETURN_VALUE(
1935            isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Nothing<bool>());
1936      }
1937      // b. Return the new Record { [[Hour]]: hour, [[Minute]]: minute,
1938      // [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]:
1939      // microsecond, [[Nanosecond]]: nanosecond }.
1940      return Just(true);
1941  }
1942}
1943
1944// #sec-temporal-totemporaltime
1945MaybeHandle<JSTemporalPlainTime> ToTemporalTime(Isolate* isolate,
1946                                                Handle<Object> item_obj,
1947                                                ShowOverflow overflow,
1948                                                const char* method_name) {
1949  Factory* factory = isolate->factory();
1950  TimeRecord result;
1951  // 2. Assert: overflow is either "constrain" or "reject".
1952  // 3. If Type(item) is Object, then
1953  if (item_obj->IsJSReceiver()) {
1954    Handle<JSReceiver> item = Handle<JSReceiver>::cast(item_obj);
1955    // a. If item has an [[InitializedTemporalTime]] internal slot, then
1956    // i. Return item.
1957    if (item->IsJSTemporalPlainTime()) {
1958      return Handle<JSTemporalPlainTime>::cast(item);
1959    }
1960    // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
1961    // then
1962    if (item->IsJSTemporalZonedDateTime()) {
1963      // i. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
1964      Handle<JSTemporalZonedDateTime> zoned_date_time =
1965          Handle<JSTemporalZonedDateTime>::cast(item);
1966      Handle<JSTemporalInstant> instant;
1967      ASSIGN_RETURN_ON_EXCEPTION(
1968          isolate, instant,
1969          CreateTemporalInstant(
1970              isolate, Handle<BigInt>(zoned_date_time->nanoseconds(), isolate)),
1971          JSTemporalPlainTime);
1972      // ii. Set plainDateTime to ?
1973      // BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
1974      // instant, item.[[Calendar]]).
1975      Handle<JSTemporalPlainDateTime> plain_date_time;
1976      ASSIGN_RETURN_ON_EXCEPTION(
1977          isolate, plain_date_time,
1978          BuiltinTimeZoneGetPlainDateTimeFor(
1979              isolate,
1980              Handle<JSReceiver>(zoned_date_time->time_zone(), isolate),
1981              instant, Handle<JSReceiver>(zoned_date_time->calendar(), isolate),
1982              method_name),
1983          JSTemporalPlainTime);
1984      // iii. Return !
1985      // CreateTemporalTime(plainDateTime.[[ISOHour]],
1986      // plainDateTime.[[ISOMinute]], plainDateTime.[[ISOSecond]],
1987      // plainDateTime.[[ISOMillisecond]], plainDateTime.[[ISOMicrosecond]],
1988      // plainDateTime.[[ISONanosecond]]).
1989      return CreateTemporalTime(
1990          isolate, plain_date_time->iso_hour(), plain_date_time->iso_minute(),
1991          plain_date_time->iso_second(), plain_date_time->iso_millisecond(),
1992          plain_date_time->iso_microsecond(),
1993          plain_date_time->iso_nanosecond());
1994    }
1995    // c. If item has an [[InitializedTemporalDateTime]] internal slot, then
1996    if (item->IsJSTemporalPlainDateTime()) {
1997      // i. Return ! CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]],
1998      // item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]],
1999      // item.[[ISONanosecond]]).
2000      Handle<JSTemporalPlainDateTime> date_time =
2001          Handle<JSTemporalPlainDateTime>::cast(item);
2002      return CreateTemporalTime(
2003          isolate, date_time->iso_hour(), date_time->iso_minute(),
2004          date_time->iso_second(), date_time->iso_millisecond(),
2005          date_time->iso_microsecond(), date_time->iso_nanosecond());
2006    }
2007    // d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
2008    Handle<JSReceiver> calendar;
2009    ASSIGN_RETURN_ON_EXCEPTION(
2010        isolate, calendar,
2011        GetTemporalCalendarWithISODefault(isolate, item, method_name),
2012        JSTemporalPlainTime);
2013    // e. If ? ToString(calendar) is not "iso8601", then
2014    Handle<String> identifier;
2015    ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
2016                               Object::ToString(isolate, calendar),
2017                               JSTemporalPlainTime);
2018    if (!String::Equals(isolate, factory->iso8601_string(), identifier)) {
2019      // i. Throw a RangeError exception.
2020      THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2021                      JSTemporalPlainTime);
2022    }
2023    // f. Let result be ? ToTemporalTimeRecord(item).
2024    Maybe<TimeRecord> maybe_time_result =
2025        ToTemporalTimeRecord(isolate, item, method_name);
2026    MAYBE_RETURN(maybe_time_result, Handle<JSTemporalPlainTime>());
2027    result = maybe_time_result.FromJust();
2028    // g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]],
2029    // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2030    // result.[[Nanosecond]], overflow).
2031    Maybe<bool> maybe_regulate_time = RegulateTime(isolate, &result, overflow);
2032    MAYBE_RETURN(maybe_regulate_time, Handle<JSTemporalPlainTime>());
2033    DCHECK(maybe_regulate_time.FromJust());
2034  } else {
2035    // 4. Else,
2036    // a. Let string be ? ToString(item).
2037    Handle<String> string;
2038    ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
2039                               Object::ToString(isolate, item_obj),
2040                               JSTemporalPlainTime);
2041    // b. Let result be ? ParseTemporalTimeString(string).
2042    Maybe<TimeRecord> maybe_result = ParseTemporalTimeString(isolate, string);
2043    MAYBE_RETURN(maybe_result, MaybeHandle<JSTemporalPlainTime>());
2044    result = maybe_result.FromJust();
2045    // c. Assert: ! IsValidTime(result.[[Hour]], result.[[Minute]],
2046    // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2047    // result.[[Nanosecond]]) is true.
2048    DCHECK(IsValidTime(isolate, result.hour, result.minute, result.second,
2049                       result.millisecond, result.microsecond,
2050                       result.nanosecond));
2051    // d. If result.[[Calendar]] is not one of undefined or "iso8601", then
2052    if ((result.calendar->length() > 0) /* not undefined */ &&
2053        !String::Equals(isolate, result.calendar,
2054                        isolate->factory()->iso8601_string())) {
2055      // i. Throw a RangeError exception.
2056      THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2057                      JSTemporalPlainTime);
2058    }
2059  }
2060  // 5. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]],
2061  // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2062  // result.[[Nanosecond]]).
2063  return CreateTemporalTime(isolate, result.hour, result.minute, result.second,
2064                            result.millisecond, result.microsecond,
2065                            result.nanosecond);
2066}
2067
2068// #sec-temporal-totemporaltimezone
2069MaybeHandle<JSReceiver> ToTemporalTimeZone(
2070    Isolate* isolate, Handle<Object> temporal_time_zone_like,
2071    const char* method_name) {
2072  TEMPORAL_ENTER_FUNC();
2073
2074  Factory* factory = isolate->factory();
2075  // 1. If Type(temporalTimeZoneLike) is Object, then
2076  if (temporal_time_zone_like->IsJSReceiver()) {
2077    // a. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]]
2078    // internal slot, then
2079    if (temporal_time_zone_like->IsJSTemporalZonedDateTime()) {
2080      // i. Return temporalTimeZoneLike.[[TimeZone]].
2081      Handle<JSTemporalZonedDateTime> zoned_date_time =
2082          Handle<JSTemporalZonedDateTime>::cast(temporal_time_zone_like);
2083      return handle(zoned_date_time->time_zone(), isolate);
2084    }
2085    Handle<JSReceiver> obj = Handle<JSReceiver>::cast(temporal_time_zone_like);
2086    // b. If ? HasProperty(temporalTimeZoneLike, "timeZone") is false,
2087    Maybe<bool> maybe_has =
2088        JSReceiver::HasProperty(isolate, obj, factory->timeZone_string());
2089    MAYBE_RETURN(maybe_has, Handle<JSReceiver>());
2090    if (!maybe_has.FromJust()) {
2091      // return temporalTimeZoneLike.
2092      return obj;
2093    }
2094    // c. Set temporalTimeZoneLike to ?
2095    // Get(temporalTimeZoneLike, "timeZone").
2096    ASSIGN_RETURN_ON_EXCEPTION(
2097        isolate, temporal_time_zone_like,
2098        JSReceiver::GetProperty(isolate, obj, factory->timeZone_string()),
2099        JSReceiver);
2100    // d. If Type(temporalTimeZoneLike)
2101    if (temporal_time_zone_like->IsJSReceiver()) {
2102      // is Object and ? HasProperty(temporalTimeZoneLike, "timeZone") is false,
2103      obj = Handle<JSReceiver>::cast(temporal_time_zone_like);
2104      maybe_has =
2105          JSReceiver::HasProperty(isolate, obj, factory->timeZone_string());
2106      MAYBE_RETURN(maybe_has, Handle<JSReceiver>());
2107      if (!maybe_has.FromJust()) {
2108        // return temporalTimeZoneLike.
2109        return obj;
2110      }
2111    }
2112  }
2113  Handle<String> identifier;
2114  // 2. Let identifier be ? ToString(temporalTimeZoneLike).
2115  ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
2116                             Object::ToString(isolate, temporal_time_zone_like),
2117                             JSReceiver);
2118  // 3. Let result be ? ParseTemporalTimeZone(identifier).
2119  Handle<String> result;
2120  ASSIGN_RETURN_ON_EXCEPTION(
2121      isolate, result, ParseTemporalTimeZone(isolate, identifier), JSReceiver);
2122
2123  // 4. Return ? CreateTemporalTimeZone(result).
2124  return temporal::CreateTemporalTimeZone(isolate, result);
2125}
2126
2127}  // namespace temporal
2128
2129namespace {
2130// #sec-temporal-systemdatetime
2131MaybeHandle<JSTemporalPlainDateTime> SystemDateTime(
2132    Isolate* isolate, Handle<Object> temporal_time_zone_like,
2133    Handle<Object> calendar_like, const char* method_name) {
2134  TEMPORAL_ENTER_FUNC();
2135
2136  Handle<JSReceiver> time_zone;
2137  // 1. 1. If temporalTimeZoneLike is undefined, then
2138  if (temporal_time_zone_like->IsUndefined()) {
2139    // a. Let timeZone be ! SystemTimeZone().
2140    ASSIGN_RETURN_ON_EXCEPTION(isolate, time_zone, SystemTimeZone(isolate),
2141                               JSTemporalPlainDateTime);
2142  } else {
2143    // 2. Else,
2144    // a. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
2145    ASSIGN_RETURN_ON_EXCEPTION(
2146        isolate, time_zone,
2147        temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
2148                                     method_name),
2149        JSTemporalPlainDateTime);
2150  }
2151  Handle<JSReceiver> calendar;
2152  // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
2153  ASSIGN_RETURN_ON_EXCEPTION(
2154      isolate, calendar,
2155      temporal::ToTemporalCalendar(isolate, calendar_like, method_name),
2156      JSTemporalPlainDateTime);
2157  // 4. Let instant be ! SystemInstant().
2158  Handle<JSTemporalInstant> instant;
2159  ASSIGN_RETURN_ON_EXCEPTION(isolate, instant, SystemInstant(isolate),
2160                             JSTemporalPlainDateTime);
2161  // 5. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
2162  // calendar).
2163  return temporal::BuiltinTimeZoneGetPlainDateTimeFor(
2164      isolate, time_zone, instant, calendar, method_name);
2165}
2166
2167MaybeHandle<JSTemporalZonedDateTime> SystemZonedDateTime(
2168    Isolate* isolate, Handle<Object> temporal_time_zone_like,
2169    Handle<Object> calendar_like, const char* method_name) {
2170  TEMPORAL_ENTER_FUNC();
2171
2172  Handle<JSReceiver> time_zone;
2173  // 1. 1. If temporalTimeZoneLike is undefined, then
2174  if (temporal_time_zone_like->IsUndefined()) {
2175    // a. Let timeZone be ! SystemTimeZone().
2176    ASSIGN_RETURN_ON_EXCEPTION(isolate, time_zone, SystemTimeZone(isolate),
2177                               JSTemporalZonedDateTime);
2178  } else {
2179    // 2. Else,
2180    // a. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
2181    ASSIGN_RETURN_ON_EXCEPTION(
2182        isolate, time_zone,
2183        temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
2184                                     method_name),
2185        JSTemporalZonedDateTime);
2186  }
2187  Handle<JSReceiver> calendar;
2188  // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
2189  ASSIGN_RETURN_ON_EXCEPTION(
2190      isolate, calendar,
2191      temporal::ToTemporalCalendar(isolate, calendar_like, method_name),
2192      JSTemporalZonedDateTime);
2193  // 4. Let ns be ! SystemUTCEpochNanoseconds().
2194  Handle<BigInt> ns;
2195  ASSIGN_RETURN_ON_EXCEPTION(isolate, ns, SystemUTCEpochNanoseconds(isolate),
2196                             JSTemporalZonedDateTime);
2197  // Return ? CreateTemporalZonedDateTime(ns, timeZone, calendar).
2198  return CreateTemporalZonedDateTime(isolate, ns, time_zone, calendar);
2199}
2200
2201#define COMPARE_RESULT_TO_SIGN(r)  \
2202  ((r) == ComparisonResult::kEqual \
2203       ? 0                         \
2204       : ((r) == ComparisonResult::kLessThan ? -1 : 1))
2205
2206// #sec-temporal-formattimezoneoffsetstring
2207MaybeHandle<String> FormatTimeZoneOffsetString(Isolate* isolate,
2208                                               int64_t offset_nanoseconds) {
2209  IncrementalStringBuilder builder(isolate);
2210  // 1. Assert: offsetNanoseconds is an integer.
2211  // 2. If offsetNanoseconds ≥ 0, let sign be "+"; otherwise, let sign be "-".
2212  builder.AppendCString((offset_nanoseconds >= 0) ? "+" : "-");
2213  // 3. Let offsetNanoseconds be abs(offsetNanoseconds).
2214  offset_nanoseconds = std::abs(offset_nanoseconds);
2215  // 3. Let nanoseconds be offsetNanoseconds modulo 10^9.
2216  int64_t nanoseconds = offset_nanoseconds % 1000000000;
2217  // 4. Let seconds be floor(offsetNanoseconds / 10^9) modulo 60.
2218  int64_t seconds = (offset_nanoseconds / 1000000000) % 60;
2219  // 5. Let minutes be floor(offsetNanoseconds / (6 × 10^10)) modulo 60.
2220  int64_t minutes = (offset_nanoseconds / 60000000000) % 60;
2221  // 6. Let hours be floor(offsetNanoseconds / (3.6 × 10^12)).
2222  int64_t hours = offset_nanoseconds / 3600000000000;
2223  // 7. Let h be hours, formatted as a two-digit decimal number, padded to the
2224  // left with a zero if necessary.
2225  if (hours < 10) {
2226    builder.AppendCStringLiteral("0");
2227  }
2228  builder.AppendInt(static_cast<int32_t>(hours));
2229  // 8. Let m be minutes, formatted as a two-digit decimal number, padded to the
2230  // left with a zero if necessary.
2231  builder.AppendCString((minutes < 10) ? ":0" : ":");
2232  builder.AppendInt(static_cast<int>(minutes));
2233  // 9. Let s be seconds, formatted as a two-digit decimal number, padded to the
2234  // left with a zero if necessary.
2235  // 10. If nanoseconds ≠ 0, then
2236  if (nanoseconds != 0) {
2237    builder.AppendCString((seconds < 10) ? ":0" : ":");
2238    builder.AppendInt(static_cast<int>(seconds));
2239    builder.AppendCStringLiteral(".");
2240    // a. Let fraction be nanoseconds, formatted as a nine-digit decimal number,
2241    // padded to the left with zeroes if necessary.
2242    // b. Set fraction to the longest possible substring of fraction starting at
2243    // position 0 and not ending with the code unit 0x0030 (DIGIT ZERO).
2244    int64_t divisor = 100000000;
2245    do {
2246      builder.AppendInt(static_cast<int>(nanoseconds / divisor));
2247      nanoseconds %= divisor;
2248      divisor /= 10;
2249    } while (nanoseconds > 0);
2250    // c. Let post be the string-concatenation of the code unit 0x003A (COLON),
2251    // s, the code unit 0x002E (FULL STOP), and fraction.
2252    // 11. Else if seconds ≠ 0, then
2253  } else if (seconds != 0) {
2254    // a. Let post be the string-concatenation of the code unit 0x003A (COLON)
2255    // and s.
2256    builder.AppendCString((seconds < 10) ? ":0" : ":");
2257    builder.AppendInt(static_cast<int>(seconds));
2258  }
2259  // 12. Return the string-concatenation of sign, h, the code unit 0x003A
2260  // (COLON), m, and post.
2261  return builder.Finish();
2262}
2263
2264// #sec-temporal-builtintimezonegetoffsetstringfor
2265MaybeHandle<String> BuiltinTimeZoneGetOffsetStringFor(
2266    Isolate* isolate, Handle<JSReceiver> time_zone,
2267    Handle<JSTemporalInstant> instant, const char* method_name) {
2268  TEMPORAL_ENTER_FUNC();
2269  // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
2270  Maybe<int64_t> maybe_offset_nanoseconds =
2271      GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name);
2272  MAYBE_RETURN(maybe_offset_nanoseconds, Handle<String>());
2273  int64_t offset_nanoseconds = maybe_offset_nanoseconds.FromJust();
2274
2275  // 2. Return ! FormatTimeZoneOffsetString(offsetNanoseconds).
2276  return FormatTimeZoneOffsetString(isolate, offset_nanoseconds);
2277}
2278
2279// #sec-temporal-parseisodatetime
2280Maybe<DateTimeRecord> ParseISODateTime(Isolate* isolate,
2281                                       Handle<String> iso_string,
2282                                       const ParsedISO8601Result& parsed) {
2283  TEMPORAL_ENTER_FUNC();
2284
2285  DateTimeRecord result;
2286  // 5. Set year to ! ToIntegerOrInfinity(year).
2287  result.year = parsed.date_year;
2288  // 6. If month is undefined, then
2289  if (parsed.date_month_is_undefined()) {
2290    // a. Set month to 1.
2291    result.month = 1;
2292    // 7. Else,
2293  } else {
2294    // a. Set month to ! ToIntegerOrInfinity(month).
2295    result.month = parsed.date_month;
2296  }
2297
2298  // 8. If day is undefined, then
2299  if (parsed.date_day_is_undefined()) {
2300    // a. Set day to 1.
2301    result.day = 1;
2302    // 9. Else,
2303  } else {
2304    // a. Set day to ! ToIntegerOrInfinity(day).
2305    result.day = parsed.date_day;
2306  }
2307  // 10. Set hour to ! ToIntegerOrInfinity(hour).
2308  result.hour = parsed.time_hour_is_undefined() ? 0 : parsed.time_hour;
2309  // 11. Set minute to ! ToIntegerOrInfinity(minute).
2310  result.minute = parsed.time_minute_is_undefined() ? 0 : parsed.time_minute;
2311  // 12. Set second to ! ToIntegerOrInfinity(second).
2312  result.second = parsed.time_second_is_undefined() ? 0 : parsed.time_second;
2313  // 13. If second is 60, then
2314  if (result.second == 60) {
2315    // a. Set second to 59.
2316    result.second = 59;
2317  }
2318  // 14. If fraction is not undefined, then
2319  if (!parsed.time_nanosecond_is_undefined()) {
2320    // a. Set fraction to the string-concatenation of the previous value of
2321    // fraction and the string "000000000".
2322    // b. Let millisecond be the String value equal to the substring of fraction
2323    // from 0 to 3. c. Set millisecond to ! ToIntegerOrInfinity(millisecond).
2324    result.millisecond = parsed.time_nanosecond / 1000000;
2325    // d. Let microsecond be the String value equal to the substring of fraction
2326    // from 3 to 6. e. Set microsecond to ! ToIntegerOrInfinity(microsecond).
2327    result.microsecond = (parsed.time_nanosecond / 1000) % 1000;
2328    // f. Let nanosecond be the String value equal to the substring of fraction
2329    // from 6 to 9. g. Set nanosecond to ! ToIntegerOrInfinity(nanosecond).
2330    result.nanosecond = (parsed.time_nanosecond % 1000);
2331    // 15. Else,
2332  } else {
2333    // a. Let millisecond be 0.
2334    result.millisecond = 0;
2335    // b. Let microsecond be 0.
2336    result.microsecond = 0;
2337    // c. Let nanosecond be 0.
2338    result.nanosecond = 0;
2339  }
2340  // 16. If ! IsValidISODate(year, month, day) is false, throw a RangeError
2341  // exception.
2342  if (!IsValidISODate(isolate, result.year, result.month, result.day)) {
2343    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2344                                 Nothing<DateTimeRecord>());
2345  }
2346  // 17. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
2347  // nanosecond) is false, throw a RangeError exception.
2348  if (!IsValidTime(isolate, result.hour, result.minute, result.second,
2349                   result.millisecond, result.microsecond, result.nanosecond)) {
2350    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2351                                 Nothing<DateTimeRecord>());
2352  }
2353  // 18. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day,
2354  // [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]:
2355  // millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond,
2356  // [[Calendar]]: calendar }.
2357  if (parsed.calendar_name_length == 0) {
2358    result.calendar = isolate->factory()->empty_string();
2359  } else {
2360    result.calendar = isolate->factory()->NewSubString(
2361        iso_string, parsed.calendar_name_start,
2362        parsed.calendar_name_start + parsed.calendar_name_length);
2363  }
2364  return Just(result);
2365}
2366
2367// #sec-temporal-parsetemporaldatestring
2368Maybe<DateRecord> ParseTemporalDateString(Isolate* isolate,
2369                                          Handle<String> iso_string) {
2370  TEMPORAL_ENTER_FUNC();
2371  // 1. Assert: Type(isoString) is String.
2372  // 2. If isoString does not satisfy the syntax of a TemporalDateString
2373  // (see 13.33), then
2374  Maybe<ParsedISO8601Result> maybe_parsed =
2375      TemporalParser::ParseTemporalDateString(isolate, iso_string);
2376  if (maybe_parsed.IsNothing()) {
2377    // a. Throw a *RangeError* exception.
2378    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2379                                 Nothing<DateRecord>());
2380  }
2381  MAYBE_RETURN(maybe_parsed, Nothing<DateRecord>());
2382
2383  ParsedISO8601Result parsed = maybe_parsed.FromJust();
2384  // 3. If _isoString_ contains a |UTCDesignator|, then
2385  if (parsed.utc_designator) {
2386    // a. Throw a *RangeError* exception.
2387    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2388                                 Nothing<DateRecord>());
2389  }
2390  // 3. Let result be ? ParseISODateTime(isoString).
2391  Maybe<DateTimeRecord> maybe_result =
2392      ParseISODateTime(isolate, iso_string, parsed);
2393
2394  MAYBE_RETURN(maybe_result, Nothing<DateRecord>());
2395  DateTimeRecord result = maybe_result.FromJust();
2396  // 4. Return the Record { [[Year]]: result.[[Year]], [[Month]]:
2397  // result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]:
2398  // result.[[Calendar]] }.
2399  DateRecord ret = {result.year, result.month, result.day, result.calendar};
2400  return Just(ret);
2401}
2402
2403// #sec-temporal-parsetemporaltimestring
2404Maybe<TimeRecord> ParseTemporalTimeString(Isolate* isolate,
2405                                          Handle<String> iso_string) {
2406  TEMPORAL_ENTER_FUNC();
2407
2408  // 1. Assert: Type(isoString) is String.
2409  // 2. If isoString does not satisfy the syntax of a TemporalTimeString
2410  // (see 13.33), then
2411  Maybe<ParsedISO8601Result> maybe_parsed =
2412      TemporalParser::ParseTemporalTimeString(isolate, iso_string);
2413  ParsedISO8601Result parsed;
2414  if (!maybe_parsed.To(&parsed)) {
2415    // a. Throw a *RangeError* exception.
2416    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2417                                 Nothing<TimeRecord>());
2418  }
2419
2420  // 3. If _isoString_ contains a |UTCDesignator|, then
2421  if (parsed.utc_designator) {
2422    // a. Throw a *RangeError* exception.
2423    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2424                                 Nothing<TimeRecord>());
2425  }
2426
2427  // 3. Let result be ? ParseISODateTime(isoString).
2428  Maybe<DateTimeRecord> maybe_result =
2429      ParseISODateTime(isolate, iso_string, parsed);
2430  MAYBE_RETURN(maybe_result, Nothing<TimeRecord>());
2431  DateTimeRecord result = maybe_result.FromJust();
2432  // 4. Return the Record { [[Hour]]: result.[[Hour]], [[Minute]]:
2433  // result.[[Minute]], [[Second]]: result.[[Second]], [[Millisecond]]:
2434  // result.[[Millisecond]], [[Microsecond]]: result.[[Microsecond]],
2435  // [[Nanosecond]]: result.[[Nanosecond]], [[Calendar]]: result.[[Calendar]] }.
2436  TimeRecord ret = {result.hour,        result.minute,      result.second,
2437                    result.millisecond, result.microsecond, result.nanosecond,
2438                    result.calendar};
2439  return Just(ret);
2440}
2441
2442// #sec-temporal-parsetemporalinstantstring
2443Maybe<InstantRecord> ParseTemporalInstantString(Isolate* isolate,
2444                                                Handle<String> iso_string) {
2445  TEMPORAL_ENTER_FUNC();
2446
2447  // 1. Assert: Type(isoString) is String.
2448  // 2. If isoString does not satisfy the syntax of a TemporalInstantString
2449  // (see 13.33), then
2450  Maybe<ParsedISO8601Result> maybe_parsed =
2451      TemporalParser::ParseTemporalInstantString(isolate, iso_string);
2452  if (maybe_parsed.IsNothing()) {
2453    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2454                                 Nothing<InstantRecord>());
2455  }
2456
2457  // 3. Let result be ! ParseISODateTime(isoString).
2458  Maybe<DateTimeRecord> maybe_result =
2459      ParseISODateTime(isolate, iso_string, maybe_parsed.FromJust());
2460
2461  MAYBE_RETURN(maybe_result, Nothing<InstantRecord>());
2462  DateTimeRecord result = maybe_result.FromJust();
2463
2464  // 4. Let timeZoneResult be ? ParseTemporalTimeZoneString(isoString).
2465  Maybe<TimeZoneRecord> maybe_time_zone_result =
2466      ParseTemporalTimeZoneString(isolate, iso_string);
2467  MAYBE_RETURN(maybe_time_zone_result, Nothing<InstantRecord>());
2468  TimeZoneRecord time_zone_result = maybe_time_zone_result.FromJust();
2469  // 5. Let offsetString be timeZoneResult.[[OffsetString]].
2470  Handle<String> offset_string = time_zone_result.offset_string;
2471  // 6. If timeZoneResult.[[Z]] is true, then
2472  if (time_zone_result.z) {
2473    // a. Set offsetString to "+00:00".
2474    offset_string = isolate->factory()->NewStringFromStaticChars("+00:00");
2475  }
2476  // 7. Assert: offsetString is not undefined.
2477  DCHECK_GT(offset_string->length(), 0);
2478
2479  // 6. Return the new Record { [[Year]]: result.[[Year]],
2480  // [[Month]]: result.[[Month]], [[Day]]: result.[[Day]],
2481  // [[Hour]]: result.[[Hour]], [[Minute]]: result.[[Minute]],
2482  // [[Second]]: result.[[Second]],
2483  // [[Millisecond]]: result.[[Millisecond]],
2484  // [[Microsecond]]: result.[[Microsecond]],
2485  // [[Nanosecond]]: result.[[Nanosecond]],
2486  // [[TimeZoneOffsetString]]: offsetString }.
2487  InstantRecord record;
2488  record.year = result.year;
2489  record.month = result.month;
2490  record.day = result.day;
2491  record.hour = result.hour;
2492  record.minute = result.minute;
2493  record.second = result.second;
2494  record.millisecond = result.millisecond;
2495  record.microsecond = result.microsecond;
2496  record.nanosecond = result.nanosecond;
2497  record.offset_string = offset_string;
2498  return Just(record);
2499}
2500
2501// #sec-temporal-parsetemporalinstant
2502MaybeHandle<BigInt> ParseTemporalInstant(Isolate* isolate,
2503                                         Handle<String> iso_string) {
2504  TEMPORAL_ENTER_FUNC();
2505
2506  Factory* factory = isolate->factory();
2507  // 1. Assert: Type(isoString) is String.
2508  // 2. Let result be ? ParseTemporalInstantString(isoString).
2509  Maybe<InstantRecord> maybe_result =
2510      ParseTemporalInstantString(isolate, iso_string);
2511  MAYBE_RETURN(maybe_result, Handle<BigInt>());
2512  InstantRecord result = maybe_result.FromJust();
2513
2514  // 3. Let offsetString be result.[[TimeZoneOffsetString]].
2515  // 4. Assert: offsetString is not undefined.
2516  DCHECK_NE(result.offset_string->length(), 0);
2517
2518  // 5. Let utc be ? GetEpochFromISOParts(result.[[Year]], result.[[Month]],
2519  // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
2520  // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
2521  Handle<BigInt> utc;
2522  ASSIGN_RETURN_ON_EXCEPTION(
2523      isolate, utc,
2524      GetEpochFromISOParts(isolate, result.year, result.month, result.day,
2525                           result.hour, result.minute, result.second,
2526                           result.millisecond, result.microsecond,
2527                           result.nanosecond),
2528      BigInt);
2529
2530  // 6. If utc < −8.64 × 10^21 or utc > 8.64 × 10^21, then
2531  if ((BigInt::CompareToNumber(utc, factory->NewNumber(-8.64e21)) ==
2532       ComparisonResult::kLessThan) ||
2533      (BigInt::CompareToNumber(utc, factory->NewNumber(8.64e21)) ==
2534       ComparisonResult::kGreaterThan)) {
2535    // a. Throw a RangeError exception.
2536    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), BigInt);
2537  }
2538  // 7. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(offsetString).
2539  Maybe<int64_t> maybe_offset_nanoseconds =
2540      ParseTimeZoneOffsetString(isolate, result.offset_string);
2541  MAYBE_RETURN(maybe_offset_nanoseconds, Handle<BigInt>());
2542  int64_t offset_nanoseconds = maybe_offset_nanoseconds.FromJust();
2543
2544  // 8. Return utc − offsetNanoseconds.
2545  return BigInt::Subtract(isolate, utc,
2546                          BigInt::FromInt64(isolate, offset_nanoseconds));
2547}
2548
2549// #sec-temporal-parsetemporaltimezonestring
2550Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(Isolate* isolate,
2551                                                  Handle<String> iso_string) {
2552  TEMPORAL_ENTER_FUNC();
2553
2554  // 1. Assert: Type(isoString) is String.
2555  // 2. If isoString does not satisfy the syntax of a TemporalTimeZoneString
2556  // (see 13.33), then
2557  Maybe<ParsedISO8601Result> maybe_parsed =
2558      TemporalParser::ParseTemporalTimeZoneString(isolate, iso_string);
2559  MAYBE_RETURN(maybe_parsed, Nothing<TimeZoneRecord>());
2560  if (maybe_parsed.IsNothing()) {
2561    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2562                                 Nothing<TimeZoneRecord>());
2563  }
2564  ParsedISO8601Result parsed = maybe_parsed.FromJust();
2565  // 3. Let z, sign, hours, minutes, seconds, fraction and name be the parts of
2566  // isoString produced respectively by the UTCDesignator,
2567  // TimeZoneUTCOffsetSign, TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute,
2568  // TimeZoneUTCOffsetSecond, TimeZoneUTCOffsetFraction, and TimeZoneIANAName
2569  // productions, or undefined if not present.
2570  // 4. If z is not undefined, then
2571  if (parsed.utc_designator) {
2572    // a. Return the Record { [[Z]]: true, [[OffsetString]]: undefined,
2573    // [[Name]]: name }.
2574    if (parsed.tzi_name_length > 0) {
2575      Handle<String> name = isolate->factory()->NewSubString(
2576          iso_string, parsed.tzi_name_start,
2577          parsed.tzi_name_start + parsed.tzi_name_length);
2578      TimeZoneRecord ret({true, isolate->factory()->empty_string(), name});
2579      return Just(ret);
2580    }
2581    TimeZoneRecord ret({true, isolate->factory()->empty_string(),
2582                        isolate->factory()->empty_string()});
2583    return Just(ret);
2584  }
2585
2586  // 5. If hours is undefined, then
2587  // a. Let offsetString be undefined.
2588  // 6. Else,
2589  Handle<String> offset_string;
2590  bool offset_string_is_defined = false;
2591  if (!parsed.tzuo_hour_is_undefined()) {
2592    // a. Assert: sign is not undefined.
2593    DCHECK(!parsed.tzuo_sign_is_undefined());
2594    // b. Set hours to ! ToIntegerOrInfinity(hours).
2595    int32_t hours = parsed.tzuo_hour;
2596    // c. If sign is the code unit 0x002D (HYPHEN-MINUS) or the code unit 0x2212
2597    // (MINUS SIGN), then i. Set sign to −1. d. Else, i. Set sign to 1.
2598    int32_t sign = parsed.tzuo_sign;
2599    // e. Set minutes to ! ToIntegerOrInfinity(minutes).
2600    int32_t minutes =
2601        parsed.tzuo_minute_is_undefined() ? 0 : parsed.tzuo_minute;
2602    // f. Set seconds to ! ToIntegerOrInfinity(seconds).
2603    int32_t seconds =
2604        parsed.tzuo_second_is_undefined() ? 0 : parsed.tzuo_second;
2605    // g. If fraction is not undefined, then
2606    int32_t nanoseconds;
2607    if (!parsed.tzuo_nanosecond_is_undefined()) {
2608      // i. Set fraction to the string-concatenation of the previous value of
2609      // fraction and the string "000000000".
2610      // ii. Let nanoseconds be the String value equal to the substring of
2611      // fraction from 0 to 9. iii. Set nanoseconds to !
2612      // ToIntegerOrInfinity(nanoseconds).
2613      nanoseconds = parsed.tzuo_nanosecond;
2614      // h. Else,
2615    } else {
2616      // i. Let nanoseconds be 0.
2617      nanoseconds = 0;
2618    }
2619    // i. Let offsetNanoseconds be sign × (((hours × 60 + minutes) × 60 +
2620    // seconds) × 10^9 + nanoseconds).
2621    int64_t offset_nanoseconds =
2622        sign *
2623        (((hours * 60 + minutes) * 60 + seconds) * 1000000000L + nanoseconds);
2624    // j. Let offsetString be ! FormatTimeZoneOffsetString(offsetNanoseconds).
2625    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2626        isolate, offset_string,
2627        FormatTimeZoneOffsetString(isolate, offset_nanoseconds),
2628        Nothing<TimeZoneRecord>());
2629    offset_string_is_defined = true;
2630  }
2631  // 7. If name is not undefined, then
2632  Handle<String> name;
2633  if (parsed.tzi_name_length > 0) {
2634    name = isolate->factory()->NewSubString(
2635        iso_string, parsed.tzi_name_start,
2636        parsed.tzi_name_start + parsed.tzi_name_length);
2637
2638    // a. If ! IsValidTimeZoneName(name) is false, throw a RangeError exception.
2639    if (!IsValidTimeZoneName(isolate, name)) {
2640      THROW_NEW_ERROR_RETURN_VALUE(isolate,
2641                                   NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2642                                   Nothing<TimeZoneRecord>());
2643    }
2644    // b. Set name to ! CanonicalizeTimeZoneName(name).
2645    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, name,
2646                                     CanonicalizeTimeZoneName(isolate, name),
2647                                     Nothing<TimeZoneRecord>());
2648    // 8. Return the Record { [[Z]]: false, [[OffsetString]]: offsetString,
2649    // [[Name]]: name }.
2650    TimeZoneRecord ret({false,
2651                        offset_string_is_defined
2652                            ? offset_string
2653                            : isolate->factory()->empty_string(),
2654                        name});
2655    return Just(ret);
2656  }
2657  // 8. Return the Record { [[Z]]: false, [[OffsetString]]: offsetString,
2658  // [[Name]]: name }.
2659  TimeZoneRecord ret({false,
2660                      offset_string_is_defined
2661                          ? offset_string
2662                          : isolate->factory()->empty_string(),
2663                      isolate->factory()->empty_string()});
2664  return Just(ret);
2665}
2666
2667// #sec-temporal-parsetemporaltimezone
2668MaybeHandle<String> ParseTemporalTimeZone(Isolate* isolate,
2669                                          Handle<String> string) {
2670  TEMPORAL_ENTER_FUNC();
2671
2672  // 2. Let result be ? ParseTemporalTimeZoneString(string).
2673  Maybe<TimeZoneRecord> maybe_result =
2674      ParseTemporalTimeZoneString(isolate, string);
2675  MAYBE_RETURN(maybe_result, Handle<String>());
2676  TimeZoneRecord result = maybe_result.FromJust();
2677
2678  // 3. If result.[[Name]] is not undefined, return result.[[Name]].
2679  if (result.name->length() > 0) {
2680    return result.name;
2681  }
2682
2683  // 4. If result.[[Z]] is true, return "UTC".
2684  if (result.z) {
2685    return isolate->factory()->UTC_string();
2686  }
2687
2688  // 5. Return result.[[OffsetString]].
2689  return result.offset_string;
2690}
2691
2692Maybe<int64_t> ParseTimeZoneOffsetString(Isolate* isolate,
2693                                         Handle<String> iso_string,
2694                                         bool throwIfNotSatisfy) {
2695  TEMPORAL_ENTER_FUNC();
2696
2697  // 1. Assert: Type(offsetString) is String.
2698  // 2. If offsetString does not satisfy the syntax of a
2699  // TimeZoneNumericUTCOffset (see 13.33), then
2700  Maybe<ParsedISO8601Result> maybe_parsed =
2701      TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, iso_string);
2702  MAYBE_RETURN(maybe_parsed, Nothing<int64_t>());
2703  if (throwIfNotSatisfy && maybe_parsed.IsNothing()) {
2704    /* a. Throw a RangeError exception. */
2705    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2706                                 Nothing<int64_t>());
2707  }
2708  ParsedISO8601Result parsed = maybe_parsed.FromJust();
2709  // 3. Let sign, hours, minutes, seconds, and fraction be the parts of
2710  // offsetString produced respectively by the TimeZoneUTCOffsetSign,
2711  // TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute, TimeZoneUTCOffsetSecond,
2712  // and TimeZoneUTCOffsetFraction productions, or undefined if not present.
2713  // 4. If either hours or sign are undefined, throw a RangeError exception.
2714  if (parsed.tzuo_hour_is_undefined() || parsed.tzuo_sign_is_undefined()) {
2715    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
2716                                 Nothing<int64_t>());
2717  }
2718  // 5. If sign is the code unit 0x002D (HYPHEN-MINUS) or 0x2212 (MINUS SIGN),
2719  // then a. Set sign to −1.
2720  // 6. Else,
2721  // a. Set sign to 1.
2722  int64_t sign = parsed.tzuo_sign;
2723
2724  // 7. Set hours to ! ToIntegerOrInfinity(hours).
2725  int64_t hours = parsed.tzuo_hour;
2726  // 8. Set minutes to ! ToIntegerOrInfinity(minutes).
2727  int64_t minutes = parsed.tzuo_minute_is_undefined() ? 0 : parsed.tzuo_minute;
2728  // 9. Set seconds to ! ToIntegerOrInfinity(seconds).
2729  int64_t seconds = parsed.tzuo_second_is_undefined() ? 0 : parsed.tzuo_second;
2730  // 10. If fraction is not undefined, then
2731  int64_t nanoseconds;
2732  if (!parsed.tzuo_nanosecond_is_undefined()) {
2733    // a. Set fraction to the string-concatenation of the previous value of
2734    // fraction and the string "000000000".
2735    // b. Let nanoseconds be the String value equal to the substring of fraction
2736    // consisting of the code units with indices 0 (inclusive) through 9
2737    // (exclusive). c. Set nanoseconds to ! ToIntegerOrInfinity(nanoseconds).
2738    nanoseconds = parsed.tzuo_nanosecond;
2739    // 11. Else,
2740  } else {
2741    // a. Let nanoseconds be 0.
2742    nanoseconds = 0;
2743  }
2744  // 12. Return sign × (((hours × 60 + minutes) × 60 + seconds) × 10^9 +
2745  // nanoseconds).
2746  return Just(sign * (((hours * 60 + minutes) * 60 + seconds) * 1000000000 +
2747                      nanoseconds));
2748}
2749
2750Maybe<bool> IsValidTimeZoneNumericUTCOffsetString(Isolate* isolate,
2751                                                  Handle<String> iso_string) {
2752  TEMPORAL_ENTER_FUNC();
2753
2754  Maybe<ParsedISO8601Result> maybe_parsed =
2755      TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, iso_string);
2756  return Just(maybe_parsed.IsJust());
2757}
2758
2759// #sec-temporal-parsetemporalcalendarstring
2760MaybeHandle<String> ParseTemporalCalendarString(Isolate* isolate,
2761                                                Handle<String> iso_string) {
2762  TEMPORAL_ENTER_FUNC();
2763
2764  // 1. Assert: Type(isoString) is String.
2765  // 2. If isoString does not satisfy the syntax of a TemporalCalendarString
2766  // (see 13.33), then a. Throw a RangeError exception.
2767  Maybe<ParsedISO8601Result> maybe_parsed =
2768      TemporalParser::ParseTemporalCalendarString(isolate, iso_string);
2769  MAYBE_RETURN(maybe_parsed, Handle<String>());
2770  if (maybe_parsed.IsNothing()) {
2771    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), String);
2772  }
2773  ParsedISO8601Result parsed = maybe_parsed.FromJust();
2774  // 3. Let id be the part of isoString produced by the CalendarName production,
2775  // or undefined if not present.
2776  // 4. If id is undefined, then
2777  if (parsed.calendar_name_length == 0) {
2778    // a. Return "iso8601".
2779    return isolate->factory()->iso8601_string();
2780  }
2781  Handle<String> id = isolate->factory()->NewSubString(
2782      iso_string, parsed.calendar_name_start,
2783      parsed.calendar_name_start + parsed.calendar_name_length);
2784  // 5. If ! IsBuiltinCalendar(id) is false, then
2785  if (!IsBuiltinCalendar(isolate, id)) {
2786    // a. Throw a RangeError exception.
2787    THROW_NEW_ERROR(
2788        isolate, NewRangeError(MessageTemplate::kInvalidCalendar, id), String);
2789  }
2790  // 6. Return id.
2791  return id;
2792}
2793
2794// #sec-temporal-calendarfields
2795MaybeHandle<FixedArray> CalendarFields(Isolate* isolate,
2796                                       Handle<JSReceiver> calendar,
2797                                       Handle<FixedArray> field_names) {
2798  // 1. Let fields be ? GetMethod(calendar, "fields").
2799  Handle<Object> fields;
2800  ASSIGN_RETURN_ON_EXCEPTION(
2801      isolate, fields,
2802      Object::GetMethod(calendar, isolate->factory()->fields_string()),
2803      FixedArray);
2804  // 2. Let fieldsArray be ! CreateArrayFromList(fieldNames).
2805  Handle<Object> fields_array =
2806      isolate->factory()->NewJSArrayWithElements(field_names);
2807  // 3. If fields is not undefined, then
2808  if (!fields->IsUndefined()) {
2809    // a. Set fieldsArray to ? Call(fields, calendar, « fieldsArray »).
2810    Handle<Object> argv[] = {fields_array};
2811    ASSIGN_RETURN_ON_EXCEPTION(
2812        isolate, fields_array,
2813        Execution::Call(isolate, fields, calendar, 1, argv), FixedArray);
2814  }
2815  // 4. Return ? IterableToListOfType(fieldsArray, « String »).
2816  Handle<Object> argv[] = {fields_array};
2817  ASSIGN_RETURN_ON_EXCEPTION(
2818      isolate, fields_array,
2819      Execution::CallBuiltin(isolate,
2820                             isolate->string_fixed_array_from_iterable(),
2821                             fields_array, 1, argv),
2822      FixedArray);
2823  DCHECK(fields_array->IsFixedArray());
2824  return Handle<FixedArray>::cast(fields_array);
2825}
2826
2827MaybeHandle<JSTemporalPlainDate> CalendarDateAdd(Isolate* isolate,
2828                                                 Handle<JSReceiver> calendar,
2829                                                 Handle<Object> date,
2830                                                 Handle<Object> duration,
2831                                                 Handle<Object> options) {
2832  return CalendarDateAdd(isolate, calendar, date, duration, options,
2833                         isolate->factory()->undefined_value());
2834}
2835
2836MaybeHandle<JSTemporalPlainDate> CalendarDateAdd(
2837    Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> date,
2838    Handle<Object> duration, Handle<Object> options, Handle<Object> date_add) {
2839  // 1. Assert: Type(calendar) is Object.
2840  // 2. If dateAdd is not present, set dateAdd to ? GetMethod(calendar,
2841  // "dateAdd").
2842  if (date_add->IsUndefined()) {
2843    ASSIGN_RETURN_ON_EXCEPTION(
2844        isolate, date_add,
2845        Object::GetMethod(calendar, isolate->factory()->dateAdd_string()),
2846        JSTemporalPlainDate);
2847  }
2848  // 3. Let addedDate be ? Call(dateAdd, calendar, « date, duration, options »).
2849  Handle<Object> argv[] = {date, duration, options};
2850  Handle<Object> added_date;
2851  ASSIGN_RETURN_ON_EXCEPTION(
2852      isolate, added_date,
2853      Execution::Call(isolate, date_add, calendar, arraysize(argv), argv),
2854      JSTemporalPlainDate);
2855  // 4. Perform ? RequireInternalSlot(addedDate, [[InitializedTemporalDate]]).
2856  if (!added_date->IsJSTemporalPlainDate()) {
2857    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
2858                    JSTemporalPlainDate);
2859  }
2860  // 5. Return addedDate.
2861  return Handle<JSTemporalPlainDate>::cast(added_date);
2862}
2863
2864MaybeHandle<JSTemporalDuration> CalendarDateUntil(Isolate* isolate,
2865                                                  Handle<JSReceiver> calendar,
2866                                                  Handle<Object> one,
2867                                                  Handle<Object> two,
2868                                                  Handle<Object> options) {
2869  return CalendarDateUntil(isolate, calendar, one, two, options,
2870                           isolate->factory()->undefined_value());
2871}
2872
2873MaybeHandle<JSTemporalDuration> CalendarDateUntil(
2874    Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> one,
2875    Handle<Object> two, Handle<Object> options, Handle<Object> date_until) {
2876  // 1. Assert: Type(calendar) is Object.
2877  // 2. If dateUntil is not present, set dateUntil to ? GetMethod(calendar,
2878  // "dateUntil").
2879  if (date_until->IsUndefined()) {
2880    ASSIGN_RETURN_ON_EXCEPTION(
2881        isolate, date_until,
2882        Object::GetMethod(calendar, isolate->factory()->dateUntil_string()),
2883        JSTemporalDuration);
2884  }
2885  // 3. Let duration be ? Call(dateUntil, calendar, « one, two, options »).
2886  Handle<Object> argv[] = {one, two, options};
2887  Handle<Object> duration;
2888  ASSIGN_RETURN_ON_EXCEPTION(
2889      isolate, duration,
2890      Execution::Call(isolate, date_until, calendar, arraysize(argv), argv),
2891      JSTemporalDuration);
2892  // 4. Perform ? RequireInternalSlot(duration,
2893  // [[InitializedTemporalDuration]]).
2894  if (!duration->IsJSTemporalDuration()) {
2895    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
2896                    JSTemporalDuration);
2897  }
2898  // 5. Return duration.
2899  return Handle<JSTemporalDuration>::cast(duration);
2900}
2901
2902// #sec-temporal-defaultmergefields
2903MaybeHandle<JSReceiver> DefaultMergeFields(
2904    Isolate* isolate, Handle<JSReceiver> fields,
2905    Handle<JSReceiver> additional_fields) {
2906  Factory* factory = isolate->factory();
2907  // 1. Let merged be ! OrdinaryObjectCreate(%Object.prototype%).
2908  Handle<JSObject> merged =
2909      isolate->factory()->NewJSObject(isolate->object_function());
2910
2911  // 2. Let originalKeys be ? EnumerableOwnPropertyNames(fields, key).
2912  Handle<FixedArray> original_keys;
2913  ASSIGN_RETURN_ON_EXCEPTION(
2914      isolate, original_keys,
2915      KeyAccumulator::GetKeys(fields, KeyCollectionMode::kOwnOnly,
2916                              ENUMERABLE_STRINGS,
2917                              GetKeysConversion::kConvertToString),
2918      JSReceiver);
2919  // 3. For each element nextKey of originalKeys, do
2920  for (int i = 0; i < original_keys->length(); i++) {
2921    // a. If nextKey is not "month" or "monthCode", then
2922    Handle<Object> next_key = handle(original_keys->get(i), isolate);
2923    DCHECK(next_key->IsString());
2924    Handle<String> next_key_string = Handle<String>::cast(next_key);
2925    if (!(String::Equals(isolate, factory->month_string(), next_key_string) ||
2926          String::Equals(isolate, factory->monthCode_string(),
2927                         next_key_string))) {
2928      // i. Let propValue be ? Get(fields, nextKey).
2929      Handle<Object> prop_value;
2930      ASSIGN_RETURN_ON_EXCEPTION(
2931          isolate, prop_value,
2932          JSReceiver::GetPropertyOrElement(isolate, fields, next_key_string),
2933          JSReceiver);
2934      // ii. If propValue is not undefined, then
2935      if (!prop_value->IsUndefined()) {
2936        // 1. Perform ! CreateDataPropertyOrThrow(merged, nextKey,
2937        // propValue).
2938        CHECK(JSReceiver::CreateDataProperty(isolate, merged, next_key_string,
2939                                             prop_value, Just(kDontThrow))
2940                  .FromJust());
2941      }
2942    }
2943  }
2944  // 4. Let newKeys be ? EnumerableOwnPropertyNames(additionalFields, key).
2945  Handle<FixedArray> new_keys;
2946  ASSIGN_RETURN_ON_EXCEPTION(
2947      isolate, new_keys,
2948      KeyAccumulator::GetKeys(additional_fields, KeyCollectionMode::kOwnOnly,
2949                              ENUMERABLE_STRINGS,
2950                              GetKeysConversion::kConvertToString),
2951      JSReceiver);
2952  bool new_keys_has_month_or_month_code = false;
2953  // 5. For each element nextKey of newKeys, do
2954  for (int i = 0; i < new_keys->length(); i++) {
2955    Handle<Object> next_key = handle(new_keys->get(i), isolate);
2956    DCHECK(next_key->IsString());
2957    Handle<String> next_key_string = Handle<String>::cast(next_key);
2958    // a. Let propValue be ? Get(additionalFields, nextKey).
2959    Handle<Object> prop_value;
2960    ASSIGN_RETURN_ON_EXCEPTION(isolate, prop_value,
2961                               JSReceiver::GetPropertyOrElement(
2962                                   isolate, additional_fields, next_key_string),
2963                               JSReceiver);
2964    // b. If propValue is not undefined, then
2965    if (!prop_value->IsUndefined()) {
2966      // 1. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
2967      Maybe<bool> maybe_created = JSReceiver::CreateDataProperty(
2968          isolate, merged, next_key_string, prop_value, Just(kThrowOnError));
2969      MAYBE_RETURN(maybe_created, Handle<JSReceiver>());
2970    }
2971    new_keys_has_month_or_month_code |=
2972        String::Equals(isolate, factory->month_string(), next_key_string) ||
2973        String::Equals(isolate, factory->monthCode_string(), next_key_string);
2974  }
2975  // 6. If newKeys does not contain either "month" or "monthCode", then
2976  if (!new_keys_has_month_or_month_code) {
2977    // a. Let month be ? Get(fields, "month").
2978    Handle<Object> month;
2979    ASSIGN_RETURN_ON_EXCEPTION(isolate, month,
2980                               JSReceiver::GetPropertyOrElement(
2981                                   isolate, fields, factory->month_string()),
2982                               JSReceiver);
2983    // b. If month is not undefined, then
2984    if (!month->IsUndefined()) {
2985      // i. Perform ! CreateDataPropertyOrThrow(merged, "month", month).
2986      CHECK(JSReceiver::CreateDataProperty(isolate, merged,
2987                                           factory->month_string(), month,
2988                                           Just(kDontThrow))
2989                .FromJust());
2990    }
2991    // c. Let monthCode be ? Get(fields, "monthCode").
2992    Handle<Object> month_code;
2993    ASSIGN_RETURN_ON_EXCEPTION(
2994        isolate, month_code,
2995        JSReceiver::GetPropertyOrElement(isolate, fields,
2996                                         factory->monthCode_string()),
2997        JSReceiver);
2998    // d. If monthCode is not undefined, then
2999    if (!month_code->IsUndefined()) {
3000      // i. Perform ! CreateDataPropertyOrThrow(merged, "monthCode", monthCode).
3001      CHECK(JSReceiver::CreateDataProperty(isolate, merged,
3002                                           factory->monthCode_string(),
3003                                           month_code, Just(kDontThrow))
3004                .FromJust());
3005    }
3006  }
3007  // 7. Return merged.
3008  return merged;
3009}
3010
3011// #sec-temporal-getoffsetnanosecondsfor
3012Maybe<int64_t> GetOffsetNanosecondsFor(Isolate* isolate,
3013                                       Handle<JSReceiver> time_zone_obj,
3014                                       Handle<Object> instant,
3015                                       const char* method_name) {
3016  TEMPORAL_ENTER_FUNC();
3017  // 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone,
3018  // "getOffsetNanosecondsFor").
3019  Handle<Object> get_offset_nanoseconds_for;
3020  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3021      isolate, get_offset_nanoseconds_for,
3022      Object::GetMethod(time_zone_obj,
3023                        isolate->factory()->getOffsetNanosecondsFor_string()),
3024      Nothing<int64_t>());
3025  if (!get_offset_nanoseconds_for->IsCallable()) {
3026    THROW_NEW_ERROR_RETURN_VALUE(
3027        isolate,
3028        NewTypeError(MessageTemplate::kCalledNonCallable,
3029                     isolate->factory()->getOffsetNanosecondsFor_string()),
3030        Nothing<int64_t>());
3031  }
3032  Handle<Object> offset_nanoseconds_obj;
3033  // 3. Let offsetNanoseconds be ? Call(getOffsetNanosecondsFor, timeZone, «
3034  // instant »).
3035  Handle<Object> argv[] = {instant};
3036  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3037      isolate, offset_nanoseconds_obj,
3038      Execution::Call(isolate, get_offset_nanoseconds_for, time_zone_obj, 1,
3039                      argv),
3040      Nothing<int64_t>());
3041
3042  // 4. If Type(offsetNanoseconds) is not Number, throw a TypeError exception.
3043  if (!offset_nanoseconds_obj->IsNumber()) {
3044    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
3045                                 Nothing<int64_t>());
3046  }
3047
3048  // 5. If ! IsIntegralNumber(offsetNanoseconds) is false, throw a RangeError
3049  // exception.
3050  double offset_nanoseconds = offset_nanoseconds_obj->Number();
3051  if ((offset_nanoseconds - std::floor(offset_nanoseconds) != 0)) {
3052    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
3053                                 Nothing<int64_t>());
3054  }
3055
3056  // 6. Set offsetNanoseconds to ℝ(offsetNanoseconds).
3057  int64_t offset_nanoseconds_int = static_cast<int64_t>(offset_nanoseconds);
3058  // 7. If abs(offsetNanoseconds) > 86400 × 10^9, throw a RangeError exception.
3059  if (std::abs(offset_nanoseconds_int) > 86400e9) {
3060    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
3061                                 Nothing<int64_t>());
3062  }
3063  // 8. Return offsetNanoseconds.
3064  return Just(offset_nanoseconds_int);
3065}
3066
3067// #sec-temporal-topositiveinteger
3068MaybeHandle<Object> ToPositiveInteger(Isolate* isolate,
3069                                      Handle<Object> argument) {
3070  TEMPORAL_ENTER_FUNC();
3071
3072  // 1. Let integer be ? ToInteger(argument).
3073  ASSIGN_RETURN_ON_EXCEPTION(
3074      isolate, argument, ToIntegerThrowOnInfinity(isolate, argument), Object);
3075  // 2. If integer ≤ 0, then
3076  if (NumberToInt32(*argument) <= 0) {
3077    // a. Throw a RangeError exception.
3078    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Object);
3079  }
3080  return argument;
3081}
3082
3083}  // namespace
3084
3085namespace temporal {
3086MaybeHandle<Object> InvokeCalendarMethod(Isolate* isolate,
3087                                         Handle<JSReceiver> calendar,
3088                                         Handle<String> name,
3089                                         Handle<JSReceiver> date_like) {
3090  Handle<Object> result;
3091  /* 1. Assert: Type(calendar) is Object. */
3092  DCHECK(calendar->IsObject());
3093  /* 2. Let result be ? Invoke(calendar, #name, « dateLike »). */
3094  Handle<Object> function;
3095  ASSIGN_RETURN_ON_EXCEPTION(
3096      isolate, function, Object::GetProperty(isolate, calendar, name), Object);
3097  if (!function->IsCallable()) {
3098    THROW_NEW_ERROR(isolate,
3099                    NewTypeError(MessageTemplate::kCalledNonCallable, name),
3100                    Object);
3101  }
3102  Handle<Object> argv[] = {date_like};
3103  ASSIGN_RETURN_ON_EXCEPTION(
3104      isolate, result,
3105      Execution::Call(isolate, function, calendar, arraysize(argv), argv),
3106      Object);
3107  return result;
3108}
3109
3110#define CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Name, name, Action)             \
3111  MaybeHandle<Object> Calendar##Name(Isolate* isolate,                         \
3112                                     Handle<JSReceiver> calendar,              \
3113                                     Handle<JSReceiver> date_like) {           \
3114    /* 1. Assert: Type(calendar) is Object.   */                               \
3115    /* 2. Let result be ? Invoke(calendar, property, « dateLike »). */       \
3116    Handle<Object> result;                                                     \
3117    ASSIGN_RETURN_ON_EXCEPTION(                                                \
3118        isolate, result,                                                       \
3119        InvokeCalendarMethod(isolate, calendar,                                \
3120                             isolate->factory()->name##_string(), date_like),  \
3121        Object);                                                               \
3122    /* 3. If result is undefined, throw a RangeError exception. */             \
3123    if (result->IsUndefined()) {                                               \
3124      THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Object); \
3125    }                                                                          \
3126    /* 4. Return ? Action(result). */                                          \
3127    ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Action(isolate, result),       \
3128                               Object);                                        \
3129    return Handle<Smi>(Smi::FromInt(result->Number()), isolate);               \
3130  }
3131
3132// #sec-temporal-calendaryear
3133CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Year, year, ToIntegerThrowOnInfinity)
3134// #sec-temporal-calendarmonth
3135CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Month, month, ToPositiveInteger)
3136// #sec-temporal-calendarday
3137CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Day, day, ToPositiveInteger)
3138// #sec-temporal-calendarmonthcode
3139MaybeHandle<Object> CalendarMonthCode(Isolate* isolate,
3140                                      Handle<JSReceiver> calendar,
3141                                      Handle<JSReceiver> date_like) {
3142  // 1. Assert: Type(calendar) is Object.
3143  // 2. Let result be ? Invoke(calendar, monthCode , « dateLike »).
3144  Handle<Object> result;
3145  ASSIGN_RETURN_ON_EXCEPTION(
3146      isolate, result,
3147      InvokeCalendarMethod(isolate, calendar,
3148                           isolate->factory()->monthCode_string(), date_like),
3149      Object);
3150  /* 3. If result is undefined, throw a RangeError exception. */
3151  if (result->IsUndefined()) {
3152    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Object);
3153  }
3154  // 4. Return ? ToString(result).
3155  return Object::ToString(isolate, result);
3156}
3157
3158#ifdef V8_INTL_SUPPORT
3159// #sec-temporal-calendarerayear
3160MaybeHandle<Object> CalendarEraYear(Isolate* isolate,
3161                                    Handle<JSReceiver> calendar,
3162                                    Handle<JSReceiver> date_like) {
3163  // 1. Assert: Type(calendar) is Object.
3164  // 2. Let result be ? Invoke(calendar, eraYear , « dateLike »).
3165  Handle<Object> result;
3166  ASSIGN_RETURN_ON_EXCEPTION(
3167      isolate, result,
3168      InvokeCalendarMethod(isolate, calendar,
3169                           isolate->factory()->eraYear_string(), date_like),
3170      Object);
3171  // 3. If result is not undefined, set result to ? ToIntegerOrInfinity(result).
3172  if (!result->IsUndefined()) {
3173    ASSIGN_RETURN_ON_EXCEPTION(
3174        isolate, result, ToIntegerThrowOnInfinity(isolate, result), Object);
3175  }
3176  // 4. Return result.
3177  return result;
3178}
3179
3180// #sec-temporal-calendarera
3181MaybeHandle<Object> CalendarEra(Isolate* isolate, Handle<JSReceiver> calendar,
3182                                Handle<JSReceiver> date_like) {
3183  // 1. Assert: Type(calendar) is Object.
3184  // 2. Let result be ? Invoke(calendar, era , « dateLike »).
3185  Handle<Object> result;
3186  ASSIGN_RETURN_ON_EXCEPTION(
3187      isolate, result,
3188      InvokeCalendarMethod(isolate, calendar, isolate->factory()->era_string(),
3189                           date_like),
3190      Object);
3191  // 3. If result is not undefined, set result to ? ToString(result).
3192  if (!result->IsUndefined()) {
3193    ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
3194                               Object::ToString(isolate, result), Object);
3195  }
3196  // 4. Return result.
3197  return result;
3198}
3199
3200#endif  //  V8_INTL_SUPPORT
3201
3202// #sec-temporal-getiso8601calendar
3203MaybeHandle<JSTemporalCalendar> GetISO8601Calendar(Isolate* isolate) {
3204  return CreateTemporalCalendar(isolate, isolate->factory()->iso8601_string());
3205}
3206
3207}  // namespace temporal
3208
3209namespace {
3210
3211bool IsUTC(Isolate* isolate, Handle<String> time_zone) {
3212  // 1. Assert: Type(timeZone) is String.
3213  // 2. Let tzText be ! StringToCodePoints(timeZone).
3214  // 3. Let tzUpperText be the result of toUppercase(tzText), according to the
3215  // Unicode Default Case Conversion algorithm.
3216  // 4. Let tzUpper be ! CodePointsToString(tzUpperText).
3217  // 5. If tzUpper and "UTC" are the same sequence of code points, return true.
3218  // 6. Return false.
3219  if (time_zone->length() != 3) return false;
3220  time_zone = String::Flatten(isolate, time_zone);
3221  DisallowGarbageCollection no_gc;
3222  const String::FlatContent& flat = time_zone->GetFlatContent(no_gc);
3223  return (flat.Get(0) == u'U' || flat.Get(0) == u'u') &&
3224         (flat.Get(1) == u'T' || flat.Get(1) == u't') &&
3225         (flat.Get(2) == u'C' || flat.Get(2) == u'c');
3226}
3227
3228#ifdef V8_INTL_SUPPORT
3229class CalendarMap final {
3230 public:
3231  CalendarMap() {
3232    icu::Locale locale("und");
3233    UErrorCode status = U_ZERO_ERROR;
3234    std::unique_ptr<icu::StringEnumeration> enumeration(
3235        icu::Calendar::getKeywordValuesForLocale("ca", locale, false, status));
3236    calendar_ids.push_back("iso8601");
3237    calendar_id_indices.insert({"iso8601", 0});
3238    int32_t i = 1;
3239    for (const char* item = enumeration->next(nullptr, status);
3240         U_SUCCESS(status) && item != nullptr;
3241         item = enumeration->next(nullptr, status)) {
3242      if (strcmp(item, "iso8601") != 0) {
3243        const char* type = uloc_toUnicodeLocaleType("ca", item);
3244        calendar_ids.push_back(type);
3245        calendar_id_indices.insert({type, i++});
3246      }
3247    }
3248  }
3249  bool Contains(const std::string& id) const {
3250    return calendar_id_indices.find(id) != calendar_id_indices.end();
3251  }
3252
3253  std::string Id(int32_t index) const {
3254    DCHECK_LT(index, calendar_ids.size());
3255    return calendar_ids[index];
3256  }
3257
3258  int32_t Index(const char* id) const {
3259    return calendar_id_indices.find(id)->second;
3260  }
3261
3262 private:
3263  std::map<std::string, int32_t> calendar_id_indices;
3264  std::vector<std::string> calendar_ids;
3265};
3266
3267DEFINE_LAZY_LEAKY_OBJECT_GETTER(CalendarMap, GetCalendarMap)
3268
3269// #sec-temporal-isbuiltincalendar
3270bool IsBuiltinCalendar(Isolate* isolate, const std::string& id) {
3271  return GetCalendarMap()->Contains(id);
3272}
3273
3274bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id) {
3275  return IsBuiltinCalendar(isolate, id->ToCString().get());
3276}
3277
3278Handle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
3279  return isolate->factory()->NewStringFromAsciiChecked(
3280      GetCalendarMap()->Id(index).c_str());
3281}
3282
3283int32_t CalendarIndex(Isolate* isolate, Handle<String> id) {
3284  return GetCalendarMap()->Index(id->ToCString().get());
3285}
3286
3287bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone) {
3288  return Intl::IsValidTimeZoneName(isolate, time_zone);
3289}
3290
3291MaybeHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
3292                                             Handle<String> identifier) {
3293  return Intl::CanonicalizeTimeZoneName(isolate, identifier);
3294}
3295
3296#else   // V8_INTL_SUPPORT
3297Handle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
3298  DCHECK_EQ(index, 0);
3299  return isolate->factory()->iso8601_string();
3300}
3301
3302// #sec-temporal-isbuiltincalendar
3303bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id) {
3304  // 1. If id is not "iso8601", return false.
3305  // 2. Return true
3306  return isolate->factory()->iso8601_string()->Equals(*id);
3307}
3308
3309int32_t CalendarIndex(Isolate* isolate, Handle<String> id) { return 0; }
3310// #sec-isvalidtimezonename
3311bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone) {
3312  return IsUTC(isolate, time_zone);
3313}
3314// #sec-canonicalizetimezonename
3315MaybeHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
3316                                             Handle<String> identifier) {
3317  return isolate->factory()->UTC_string();
3318}
3319#endif  // V8_INTL_SUPPORT
3320
3321// #sec-temporal-totemporaltimerecord
3322Maybe<TimeRecord> ToTemporalTimeRecord(Isolate* isolate,
3323                                       Handle<JSReceiver> temporal_time_like,
3324                                       const char* method_name) {
3325  TEMPORAL_ENTER_FUNC();
3326
3327  TimeRecord result;
3328  Factory* factory = isolate->factory();
3329  // 1. Assert: Type(temporalTimeLike) is Object.
3330  // 2. Let result be the new Record { [[Hour]]: undefined, [[Minute]]:
3331  // undefined, [[Second]]: undefined, [[Millisecond]]: undefined,
3332  // [[Microsecond]]: undefined, [[Nanosecond]]: undefined }.
3333  // See https://github.com/tc39/proposal-temporal/pull/1862
3334  // 3. Let _any_ be *false*.
3335  bool any = false;
3336  // 4. For each row of Table 3, except the header row, in table order, do
3337  std::array<std::pair<Handle<String>, int32_t*>, 6> table3 = {
3338      {{factory->hour_string(), &result.hour},
3339       {factory->microsecond_string(), &result.microsecond},
3340       {factory->millisecond_string(), &result.millisecond},
3341       {factory->minute_string(), &result.minute},
3342       {factory->nanosecond_string(), &result.nanosecond},
3343       {factory->second_string(), &result.second}}};
3344  for (const auto& row : table3) {
3345    Handle<Object> value;
3346    // a. Let property be the Property value of the current row.
3347    // b. Let value be ? Get(temporalTimeLike, property).
3348    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3349        isolate, value,
3350        Object::GetPropertyOrElement(isolate, temporal_time_like, row.first),
3351        Nothing<TimeRecord>());
3352    // c. If value is not undefined, then
3353    if (!value->IsUndefined()) {
3354      // i. Set _any_ to *true*.
3355      any = true;
3356    }
3357    // d. Set value to ? ToIntegerThrowOnOInfinity(value).
3358    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value,
3359                                     ToIntegerThrowOnInfinity(isolate, value),
3360                                     Nothing<TimeRecord>());
3361    // e. Set result's internal slot whose name is the Internal Slot value of
3362    // the current row to value.
3363    *(row.second) = value->Number();
3364  }
3365
3366  // 5. If _any_ is *false*, then
3367  if (!any) {
3368    // a. Throw a *TypeError* exception.
3369    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
3370                                 Nothing<TimeRecord>());
3371  }
3372  // 4. Return result.
3373  return Just(result);
3374}
3375
3376// #sec-temporal-mergelargestunitoption
3377MaybeHandle<JSObject> MergeLargestUnitOption(Isolate* isolate,
3378                                             Handle<JSReceiver> options,
3379                                             Unit largest_unit) {
3380  TEMPORAL_ENTER_FUNC();
3381  // 1. Let merged be ! OrdinaryObjectCreate(%Object.prototype%).
3382  Handle<JSObject> merged =
3383      isolate->factory()->NewJSObject(isolate->object_function());
3384  // 2. Let keys be ? EnumerableOwnPropertyNames(options, key).
3385  // 3. For each element nextKey of keys, do
3386  // a. Let propValue be ? Get(options, nextKey).
3387  // b. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
3388  JSReceiver::SetOrCopyDataProperties(
3389      isolate, merged, options, PropertiesEnumerationMode::kEnumerationOrder,
3390      nullptr, false)
3391      .Check();
3392
3393  // 4. Perform ! CreateDataPropertyOrThrow(merged, "largestUnit", largestUnit).
3394  CHECK(JSReceiver::CreateDataProperty(
3395            isolate, merged, isolate->factory()->largestUnit_string(),
3396            UnitToString(isolate, largest_unit), Just(kThrowOnError))
3397            .FromJust());
3398  // 5. Return merged.
3399  return merged;
3400}
3401
3402// #sec-temporal-tointegerthrowoninfinity
3403MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
3404                                             Handle<Object> argument) {
3405  TEMPORAL_ENTER_FUNC();
3406
3407  // 1. Let integer be ? ToIntegerOrInfinity(argument).
3408  ASSIGN_RETURN_ON_EXCEPTION(isolate, argument,
3409                             Object::ToInteger(isolate, argument), Object);
3410  // 2. If integer is +∞ or -∞, throw a RangeError exception.
3411  if (!std::isfinite(argument->Number())) {
3412    // a. Throw a RangeError exception.
3413    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Object);
3414  }
3415  return argument;
3416}
3417
3418// #sec-temporal-largeroftwotemporalunits
3419Unit LargerOfTwoTemporalUnits(Isolate* isolate, Unit u1, Unit u2) {
3420  // 1. If either u1 or u2 is "year", return "year".
3421  if (u1 == Unit::kYear || u2 == Unit::kYear) return Unit::kYear;
3422  // 2. If either u1 or u2 is "month", return "month".
3423  if (u1 == Unit::kMonth || u2 == Unit::kMonth) return Unit::kMonth;
3424  // 3. If either u1 or u2 is "week", return "week".
3425  if (u1 == Unit::kWeek || u2 == Unit::kWeek) return Unit::kWeek;
3426  // 4. If either u1 or u2 is "day", return "day".
3427  if (u1 == Unit::kDay || u2 == Unit::kDay) return Unit::kDay;
3428  // 5. If either u1 or u2 is "hour", return "hour".
3429  if (u1 == Unit::kHour || u2 == Unit::kHour) return Unit::kHour;
3430  // 6. If either u1 or u2 is "minute", return "minute".
3431  if (u1 == Unit::kMinute || u2 == Unit::kMinute) return Unit::kMinute;
3432  // 7. If either u1 or u2 is "second", return "second".
3433  if (u1 == Unit::kSecond || u2 == Unit::kSecond) return Unit::kSecond;
3434  // 8. If either u1 or u2 is "millisecond", return "millisecond".
3435  if (u1 == Unit::kMillisecond || u2 == Unit::kMillisecond)
3436    return Unit::kMillisecond;
3437  // 9. If either u1 or u2 is "microsecond", return "microsecond".
3438  if (u1 == Unit::kMicrosecond || u2 == Unit::kMicrosecond)
3439    return Unit::kMicrosecond;
3440  // 10. Return "nanosecond".
3441  return Unit::kNanosecond;
3442}
3443
3444Handle<String> UnitToString(Isolate* isolate, Unit unit) {
3445  switch (unit) {
3446    case Unit::kYear:
3447      return ReadOnlyRoots(isolate).year_string_handle();
3448    case Unit::kMonth:
3449      return ReadOnlyRoots(isolate).month_string_handle();
3450    case Unit::kWeek:
3451      return ReadOnlyRoots(isolate).week_string_handle();
3452    case Unit::kDay:
3453      return ReadOnlyRoots(isolate).day_string_handle();
3454    case Unit::kHour:
3455      return ReadOnlyRoots(isolate).hour_string_handle();
3456    case Unit::kMinute:
3457      return ReadOnlyRoots(isolate).minute_string_handle();
3458    case Unit::kSecond:
3459      return ReadOnlyRoots(isolate).second_string_handle();
3460    case Unit::kMillisecond:
3461      return ReadOnlyRoots(isolate).millisecond_string_handle();
3462    case Unit::kMicrosecond:
3463      return ReadOnlyRoots(isolate).microsecond_string_handle();
3464    case Unit::kNanosecond:
3465      return ReadOnlyRoots(isolate).nanosecond_string_handle();
3466    default:
3467      UNREACHABLE();
3468  }
3469}
3470
3471// #sec-temporal-balanceisodate
3472void BalanceISODate(Isolate* isolate, int32_t* year, int32_t* month,
3473                    int32_t* day) {
3474  TEMPORAL_ENTER_FUNC();
3475
3476  // 1. Assert: year, month, and day are integers.
3477  // 2. Let balancedYearMonth be ! BalanceISOYearMonth(year, month).
3478  // 3. Set month to balancedYearMonth.[[Month]].
3479  // 4. Set year to balancedYearMonth.[[Year]].
3480  BalanceISOYearMonth(isolate, year, month);
3481  // 5. NOTE: To deal with negative numbers of days whose absolute value is
3482  // greater than the number of days in a year, the following section subtracts
3483  // years and adds days until the number of days is greater than −366 or −365.
3484  // 6. If month > 2, then
3485  // a. Let testYear be year.
3486  // 7. Else,
3487  // a. Let testYear be year − 1.
3488  int32_t test_year = (*month > 2) ? *year : *year - 1;
3489  // 8. Repeat, while day < −1 × ! ISODaysInYear(testYear),
3490  int32_t iso_days_in_year;
3491  while (*day < -(iso_days_in_year = ISODaysInYear(isolate, test_year))) {
3492    // a. Set day to day + ! ISODaysInYear(testYear).
3493    *day += iso_days_in_year;
3494    // b. Set year to year − 1.
3495    (*year)--;
3496    // c. Set testYear to testYear − 1.
3497    test_year--;
3498  }
3499  // 9. NOTE: To deal with numbers of days greater than the number of days in a
3500  // year, the following section adds years and subtracts days until the number
3501  // of days is less than 366 or 365.
3502  // 10. Let testYear be year + 1.
3503  test_year = (*year) + 1;
3504  // 11. Repeat, while day > ! ISODaysInYear(testYear),
3505  while (*day > (iso_days_in_year = ISODaysInYear(isolate, test_year))) {
3506    // a. Set day to day − ! ISODaysInYear(testYear).
3507    *day -= iso_days_in_year;
3508    // b. Set year to year + 1.
3509    (*year)++;
3510    // c. Set testYear to testYear + 1.
3511    test_year++;
3512  }
3513  // 12. NOTE: To deal with negative numbers of days whose absolute value is
3514  // greater than the number of days in the current month, the following section
3515  // subtracts months and adds days until the number of days is greater than 0.
3516  // 13. Repeat, while day < 1,
3517  while (*day < 1) {
3518    // a. Set balancedYearMonth to ! BalanceISOYearMonth(year, month − 1).
3519    // b. Set year to balancedYearMonth.[[Year]].
3520    // c. Set month to balancedYearMonth.[[Month]].
3521    *month -= 1;
3522    BalanceISOYearMonth(isolate, year, month);
3523    // d. Set day to day + ! ISODaysInMonth(year, month).
3524    *day += ISODaysInMonth(isolate, *year, *month);
3525  }
3526  // 14. NOTE: To deal with numbers of days greater than the number of days in
3527  // the current month, the following section adds months and subtracts days
3528  // until the number of days is less than the number of days in the month.
3529  // 15. Repeat, while day > ! ISODaysInMonth(year, month),
3530  int32_t iso_days_in_month;
3531  while (*day > (iso_days_in_month = ISODaysInMonth(isolate, *year, *month))) {
3532    // a. Set day to day − ! ISODaysInMonth(year, month).
3533    *day -= iso_days_in_month;
3534    // b. Set balancedYearMonth to ! BalanceISOYearMonth(year, month + 1).
3535    // c. Set year to balancedYearMonth.[[Year]].
3536    // d. Set month to balancedYearMonth.[[Month]].
3537    *month += 1;
3538    BalanceISOYearMonth(isolate, year, month);
3539  }
3540  // 16. Return the new Record { [[Year]]: year, [[Month]]: month, [[Day]]: day
3541  // }.
3542  return;
3543}
3544
3545// #sec-temporal-adddatetime
3546Maybe<DateTimeRecordCommon> AddDateTime(
3547    Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour,
3548    int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond,
3549    int32_t nanosecond, Handle<JSReceiver> calendar, const DurationRecord& dur,
3550    Handle<Object> options) {
3551  TEMPORAL_ENTER_FUNC();
3552
3553  // 1. Assert: year, month, day, hour, minute, second, millisecond,
3554  // microsecond, and nanosecond are integers.
3555  // 2. Let timeResult be ! AddTime(hour, minute, second, millisecond,
3556  // microsecond, nanosecond, hours, minutes, seconds, milliseconds,
3557  // microseconds, nanoseconds).
3558  DateTimeRecordCommon time_result =
3559      AddTime(isolate, hour, minute, second, millisecond, microsecond,
3560              nanosecond, dur.hours, dur.minutes, dur.seconds, dur.milliseconds,
3561              dur.microseconds, dur.nanoseconds);
3562
3563  // 3. Let datePart be ? CreateTemporalDate(year, month, day, calendar).
3564  Handle<JSTemporalPlainDate> date_part;
3565  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3566      isolate, date_part,
3567      CreateTemporalDate(isolate, year, month, day, calendar),
3568      Nothing<DateTimeRecordCommon>());
3569  // 4. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days
3570  // + timeResult.[[Days]], 0, 0, 0, 0, 0, 0).
3571  Handle<JSTemporalDuration> date_duration;
3572  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3573      isolate, date_duration,
3574      CreateTemporalDuration(isolate, dur.years, dur.months, dur.weeks,
3575                             dur.days + time_result.day, 0, 0, 0, 0, 0, 0),
3576      Nothing<DateTimeRecordCommon>());
3577  // 5. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration,
3578  // options).
3579  Handle<JSTemporalPlainDate> added_date;
3580  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3581      isolate, added_date,
3582      CalendarDateAdd(isolate, calendar, date_part, date_duration, options),
3583      Nothing<DateTimeRecordCommon>());
3584  // 6. Return the new Record { [[Year]]: addedDate.[[ISOYear]], [[Month]]:
3585  // addedDate.[[ISOMonth]], [[Day]]: addedDate.[[ISODay]], [[Hour]]:
3586  // timeResult.[[Hour]], [[Minute]]: timeResult.[[Minute]], [[Second]]:
3587  // timeResult.[[Second]], [[Millisecond]]: timeResult.[[Millisecond]],
3588  // [[Microsecond]]: timeResult.[[Microsecond]], [[Nanosecond]]:
3589  // timeResult.[[Nanosecond]], }.
3590  time_result.year = added_date->iso_year();
3591  time_result.month = added_date->iso_month();
3592  time_result.day = added_date->iso_day();
3593  return Just(time_result);
3594}
3595
3596Maybe<bool> BalanceDuration(Isolate* isolate, int64_t* days, int64_t* hours,
3597                            int64_t* minutes, int64_t* seconds,
3598                            int64_t* milliseconds, int64_t* microseconds,
3599                            int64_t* nanoseconds, Unit largest_unit,
3600                            const char* method_name) {
3601  TEMPORAL_ENTER_FUNC();
3602
3603  // 1. If relativeTo is not present, set relativeTo to undefined.
3604  return BalanceDuration(isolate, days, hours, minutes, seconds, milliseconds,
3605                         microseconds, nanoseconds, largest_unit,
3606                         isolate->factory()->undefined_value(), method_name);
3607}
3608
3609Maybe<bool> BalanceDuration(Isolate* isolate, int64_t* days, int64_t* hours,
3610                            int64_t* minutes, int64_t* seconds,
3611                            int64_t* milliseconds, int64_t* microseconds,
3612                            int64_t* nanoseconds, Unit largest_unit,
3613                            Handle<Object> relative_to_obj,
3614                            const char* method_name) {
3615  TEMPORAL_ENTER_FUNC();
3616
3617  // 2. If Type(relativeTo) is Object and relativeTo has an
3618  // [[InitializedTemporalZonedDateTime]] internal slot, then
3619  if (relative_to_obj->IsJSTemporalZonedDateTime()) {
3620    Handle<JSTemporalZonedDateTime> relative_to =
3621        Handle<JSTemporalZonedDateTime>::cast(relative_to_obj);
3622    // a. Let endNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]],
3623    // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, hours,
3624    // minutes, seconds, milliseconds, microseconds, nanoseconds).
3625    Handle<BigInt> end_ns;
3626    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3627        isolate, end_ns,
3628        AddZonedDateTime(isolate,
3629                         Handle<BigInt>(relative_to->nanoseconds(), isolate),
3630                         Handle<JSReceiver>(relative_to->time_zone(), isolate),
3631                         Handle<JSReceiver>(relative_to->calendar(), isolate),
3632                         {0, 0, 0, *days, *hours, *minutes, *seconds,
3633                          *milliseconds, *microseconds, *nanoseconds},
3634                         method_name),
3635        Nothing<bool>());
3636    // b. Set nanoseconds to endNs − relativeTo.[[Nanoseconds]].
3637    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3638        isolate, end_ns,
3639        BigInt::Subtract(isolate, end_ns,
3640                         Handle<BigInt>(relative_to->nanoseconds(), isolate)),
3641        Nothing<bool>());
3642    *nanoseconds = end_ns->AsInt64();
3643    // 3. Else,
3644  } else {
3645    // a. Set nanoseconds to ℤ(! TotalDurationNanoseconds(days, hours, minutes,
3646    // seconds, milliseconds, microseconds, nanoseconds, 0)).
3647    *nanoseconds =
3648        TotalDurationNanoseconds(isolate, *days, *hours, *minutes, *seconds,
3649                                 *milliseconds, *microseconds, *nanoseconds, 0);
3650  }
3651  // 4. If largestUnit is one of "year", "month", "week", or "day", then
3652  if (largest_unit == Unit::kYear || largest_unit == Unit::kMonth ||
3653      largest_unit == Unit::kWeek || largest_unit == Unit::kDay) {
3654    int64_t result_day_length;
3655    // a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo).
3656    Maybe<bool> maybe_result =
3657        NanosecondsToDays(isolate, *nanoseconds, relative_to_obj, days,
3658                          nanoseconds, &result_day_length, method_name);
3659    MAYBE_RETURN(maybe_result, Nothing<bool>());
3660    DCHECK(maybe_result.FromJust());
3661    // b. Set days to result.[[Days]].
3662    // c. Set nanoseconds to result.[[Nanoseconds]].
3663    // 5. Else,
3664  } else {
3665    // a. Set days to 0.
3666    *days = 0;
3667  }
3668  // 6. Set hours, minutes, seconds, milliseconds, and microseconds to 0.
3669  *hours = *minutes = *seconds = *milliseconds = *microseconds = 0;
3670  // 7. Set nanoseconds to ℝ(nanoseconds).
3671
3672  // 8. If nanoseconds < 0, let sign be −1; else, let sign be 1.
3673  int32_t sign = (*nanoseconds < 0) ? -1 : 1;
3674  // 9. Set nanoseconds to abs(nanoseconds).
3675  *nanoseconds = std::abs(*nanoseconds);
3676  // 10. If largestUnit is "year", "month", "week", "day", or "hour", then
3677  switch (largest_unit) {
3678    case Unit::kYear:
3679    case Unit::kMonth:
3680    case Unit::kWeek:
3681    case Unit::kDay:
3682    case Unit::kHour:
3683      // a. Set microseconds to floor(nanoseconds / 1000).
3684      *microseconds = floor_divide(*nanoseconds, 1000);
3685      // b. Set nanoseconds to nanoseconds modulo 1000.
3686      *nanoseconds = modulo(*nanoseconds, 1000);
3687      // c. Set milliseconds to floor(microseconds / 1000).
3688      *milliseconds = floor_divide(*microseconds, 1000);
3689      // d. Set microseconds to microseconds modulo 1000.
3690      *microseconds = modulo(*microseconds, 1000);
3691      // e. Set seconds to floor(milliseconds / 1000).
3692      *seconds = floor_divide(*milliseconds, 1000);
3693      // f. Set milliseconds to milliseconds modulo 1000.
3694      *milliseconds = modulo(*milliseconds, 1000);
3695      // g. Set minutes to floor(seconds, 60).
3696      *minutes = floor_divide(*seconds, 60);
3697      // h. Set seconds to seconds modulo 60.
3698      *seconds = modulo(*seconds, 60);
3699      // i. Set hours to floor(minutes / 60).
3700      *hours = floor_divide(*minutes, 60);
3701      // j. Set minutes to minutes modulo 60.
3702      *minutes = modulo(*minutes, 60);
3703      break;
3704    // 11. Else if largestUnit is "minute", then
3705    case Unit::kMinute:
3706      // a. Set microseconds to floor(nanoseconds / 1000).
3707      *microseconds = floor_divide(*nanoseconds, 1000);
3708      // b. Set nanoseconds to nanoseconds modulo 1000.
3709      *nanoseconds = modulo(*nanoseconds, 1000);
3710      // c. Set milliseconds to floor(microseconds / 1000).
3711      *milliseconds = floor_divide(*microseconds, 1000);
3712      // d. Set microseconds to microseconds modulo 1000.
3713      *microseconds = modulo(*microseconds, 1000);
3714      // e. Set seconds to floor(milliseconds / 1000).
3715      *seconds = floor_divide(*milliseconds, 1000);
3716      // f. Set milliseconds to milliseconds modulo 1000.
3717      *milliseconds = modulo(*milliseconds, 1000);
3718      // g. Set minutes to floor(seconds / 60).
3719      *minutes = floor_divide(*seconds, 60);
3720      // h. Set seconds to seconds modulo 60.
3721      *seconds = modulo(*seconds, 60);
3722      break;
3723    // 12. Else if largestUnit is "second", then
3724    case Unit::kSecond:
3725      // a. Set microseconds to floor(nanoseconds / 1000).
3726      *microseconds = floor_divide(*nanoseconds, 1000);
3727      // b. Set nanoseconds to nanoseconds modulo 1000.
3728      *nanoseconds = modulo(*nanoseconds, 1000);
3729      // c. Set milliseconds to floor(microseconds / 1000).
3730      *milliseconds = floor_divide(*microseconds, 1000);
3731      // d. Set microseconds to microseconds modulo 1000.
3732      *microseconds = modulo(*microseconds, 1000);
3733      // e. Set seconds to floor(milliseconds / 1000).
3734      *seconds = floor_divide(*milliseconds, 1000);
3735      // f. Set milliseconds to milliseconds modulo 1000.
3736      *milliseconds = modulo(*milliseconds, 1000);
3737      break;
3738    // 13. Else if largestUnit is "millisecond", then
3739    case Unit::kMillisecond:
3740      // a. Set microseconds to floor(nanoseconds / 1000).
3741      *microseconds = floor_divide(*nanoseconds, 1000);
3742      // b. Set nanoseconds to nanoseconds modulo 1000.
3743      *nanoseconds = modulo(*nanoseconds, 1000);
3744      // c. Set milliseconds to floor(microseconds / 1000).
3745      *milliseconds = floor_divide(*microseconds, 1000);
3746      // d. Set microseconds to microseconds modulo 1000.
3747      *microseconds = modulo(*microseconds, 1000);
3748      break;
3749    // 14. Else if largestUnit is "microsecond", then
3750    case Unit::kMicrosecond:
3751      // a. Set microseconds to floor(nanoseconds / 1000).
3752      *microseconds = floor_divide(*nanoseconds, 1000);
3753      // b. Set nanoseconds to nanoseconds modulo 1000.
3754      *nanoseconds = modulo(*nanoseconds, 1000);
3755      break;
3756    // 15. Else,
3757    default:
3758      // a. Assert: largestUnit is "nanosecond".
3759      DCHECK_EQ(largest_unit, Unit::kNanosecond);
3760      break;
3761  }
3762  // 16. Return the new Record { [[Days]]: �(days), [[Hours]]: �(hours × sign),
3763  // [[Minutes]]: �(minutes × sign), [[Seconds]]: �(seconds × sign),
3764  // [[Milliseconds]]: �(milliseconds × sign), [[Microseconds]]: �(microseconds
3765  // × sign), [[Nanoseconds]]: �(nanoseconds × sign) }.
3766  *hours *= sign;
3767  *minutes *= sign;
3768  *seconds *= sign;
3769  *milliseconds *= sign;
3770  *microseconds *= sign;
3771  *nanoseconds *= sign;
3772  return Just(true);
3773}
3774
3775// #sec-temporal-addinstant
3776MaybeHandle<BigInt> AddZonedDateTime(Isolate* isolate,
3777                                     Handle<BigInt> epoch_nanoseconds,
3778                                     Handle<JSReceiver> time_zone,
3779                                     Handle<JSReceiver> calendar,
3780                                     const DurationRecord& duration,
3781                                     const char* method_name) {
3782  TEMPORAL_ENTER_FUNC();
3783
3784  // 1. If options is not present, set options to ! OrdinaryObjectCreate(null).
3785  Handle<JSReceiver> options = isolate->factory()->NewJSObjectWithNullProto();
3786  return AddZonedDateTime(isolate, epoch_nanoseconds, time_zone, calendar,
3787                          duration, options, method_name);
3788}
3789
3790// #sec-temporal-addzoneddatetime
3791MaybeHandle<BigInt> AddZonedDateTime(Isolate* isolate,
3792                                     Handle<BigInt> epoch_nanoseconds,
3793                                     Handle<JSReceiver> time_zone,
3794                                     Handle<JSReceiver> calendar,
3795                                     const DurationRecord& duration,
3796                                     Handle<JSReceiver> options,
3797                                     const char* method_name) {
3798  TEMPORAL_ENTER_FUNC();
3799
3800  // 2. If all of years, months, weeks, and days are 0, then
3801  if (duration.years == 0 && duration.months == 0 && duration.weeks == 0 &&
3802      duration.days == 0) {
3803    // a. Return ! AddInstant(epochNanoseconds, hours, minutes, seconds,
3804    // milliseconds, microseconds, nanoseconds).
3805    return AddInstant(isolate, epoch_nanoseconds, duration.hours,
3806                      duration.minutes, duration.seconds, duration.milliseconds,
3807                      duration.microseconds, duration.nanoseconds);
3808  }
3809  // 3. Let instant be ! CreateTemporalInstant(epochNanoseconds).
3810  Handle<JSTemporalInstant> instant;
3811  ASSIGN_RETURN_ON_EXCEPTION(
3812      isolate, instant,
3813      temporal::CreateTemporalInstant(isolate, epoch_nanoseconds), BigInt);
3814
3815  // 4. Let temporalDateTime be ?
3816  // BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
3817  Handle<JSTemporalPlainDateTime> temporal_date_time;
3818  ASSIGN_RETURN_ON_EXCEPTION(
3819      isolate, temporal_date_time,
3820      temporal::BuiltinTimeZoneGetPlainDateTimeFor(isolate, time_zone, instant,
3821                                                   calendar, method_name),
3822      BigInt);
3823  // 5. Let datePart be ? CreateTemporalDate(temporalDateTime.[[ISOYear]],
3824  // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], calendar).
3825  Handle<JSTemporalPlainDate> date_part;
3826  ASSIGN_RETURN_ON_EXCEPTION(
3827      isolate, date_part,
3828      CreateTemporalDate(isolate, temporal_date_time->iso_year(),
3829                         temporal_date_time->iso_month(),
3830                         temporal_date_time->iso_day(), calendar),
3831      BigInt);
3832  // 6. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days,
3833  // 0, 0, 0, 0, 0, 0).
3834  Handle<JSTemporalDuration> date_duration;
3835  ASSIGN_RETURN_ON_EXCEPTION(
3836      isolate, date_duration,
3837      CreateTemporalDuration(isolate, duration.years, duration.months,
3838                             duration.weeks, duration.days, 0, 0, 0, 0, 0, 0),
3839      BigInt);
3840  // 7. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration,
3841  // options).
3842  Handle<JSTemporalPlainDate> added_date;
3843  ASSIGN_RETURN_ON_EXCEPTION(
3844      isolate, added_date,
3845      CalendarDateAdd(isolate, calendar, date_part, date_duration, options),
3846      BigInt);
3847  // 8. Let intermediateDateTime be ?
3848  // CreateTemporalDateTime(addedDate.[[ISOYear]], addedDate.[[ISOMonth]],
3849  // addedDate.[[ISODay]], temporalDateTime.[[ISOHour]],
3850  // temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
3851  // temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
3852  // temporalDateTime.[[ISONanosecond]], calendar).
3853  Handle<JSTemporalPlainDateTime> intermediate_date_time;
3854  ASSIGN_RETURN_ON_EXCEPTION(
3855      isolate, intermediate_date_time,
3856      temporal::CreateTemporalDateTime(
3857          isolate, added_date->iso_year(), added_date->iso_month(),
3858          added_date->iso_day(), temporal_date_time->iso_hour(),
3859          temporal_date_time->iso_minute(), temporal_date_time->iso_second(),
3860          temporal_date_time->iso_millisecond(),
3861          temporal_date_time->iso_microsecond(),
3862          temporal_date_time->iso_nanosecond(), calendar),
3863      BigInt);
3864  // 9. Let intermediateInstant be ? BuiltinTimeZoneGetInstantFor(timeZone,
3865  // intermediateDateTime, "compatible").
3866  Handle<JSTemporalInstant> intermediate_instant;
3867  ASSIGN_RETURN_ON_EXCEPTION(
3868      isolate, intermediate_instant,
3869      BuiltinTimeZoneGetInstantFor(isolate, time_zone, intermediate_date_time,
3870                                   Disambiguation::kCompatible, method_name),
3871      BigInt);
3872  // 10. Return ! AddInstant(intermediateInstant.[[Nanoseconds]], hours,
3873  // minutes, seconds, milliseconds, microseconds, nanoseconds).
3874  return AddInstant(
3875      isolate, Handle<BigInt>(intermediate_instant->nanoseconds(), isolate),
3876      duration.hours, duration.minutes, duration.seconds, duration.milliseconds,
3877      duration.microseconds, duration.nanoseconds);
3878}
3879
3880// #sec-temporal-nanosecondstodays
3881Maybe<bool> NanosecondsToDays(Isolate* isolate, int64_t nanoseconds,
3882                              Handle<Object> relative_to_obj,
3883                              int64_t* result_days, int64_t* result_nanoseconds,
3884                              int64_t* result_day_length,
3885                              const char* method_name) {
3886  return NanosecondsToDays(isolate, BigInt::FromInt64(isolate, nanoseconds),
3887                           relative_to_obj, result_days, result_nanoseconds,
3888                           result_day_length, method_name);
3889}
3890
3891Maybe<bool> NanosecondsToDays(Isolate* isolate, Handle<BigInt> nanoseconds,
3892                              Handle<Object> relative_to_obj,
3893                              int64_t* result_days, int64_t* result_nanoseconds,
3894                              int64_t* result_day_length,
3895                              const char* method_name) {
3896  TEMPORAL_ENTER_FUNC();
3897
3898  // 1. Assert: Type(nanoseconds) is BigInt.
3899  // 2. Set nanoseconds to ℝ(nanoseconds).
3900  // 3. Let sign be ! ℝ(Sign(�(nanoseconds))).
3901  ComparisonResult compare_result =
3902      BigInt::CompareToBigInt(nanoseconds, BigInt::FromInt64(isolate, 0));
3903  int64_t sign = COMPARE_RESULT_TO_SIGN(compare_result);
3904  // 4. Let dayLengthNs be 8.64 × 10^13.
3905  Handle<BigInt> day_length_ns = BigInt::FromInt64(isolate, 86400000000000LLU);
3906  // 5. If sign is 0, then
3907  if (sign == 0) {
3908    // a. Return the new Record { [[Days]]: 0, [[Nanoseconds]]: 0,
3909    // [[DayLength]]: dayLengthNs }.
3910    *result_days = 0;
3911    *result_nanoseconds = 0;
3912    *result_day_length = day_length_ns->AsInt64();
3913    return Just(true);
3914  }
3915  // 6. If Type(relativeTo) is not Object or relativeTo does not have an
3916  // [[InitializedTemporalZonedDateTime]] internal slot, then
3917  if (!relative_to_obj->IsJSTemporalZonedDateTime()) {
3918    // Return the Record {
3919    // [[Days]]: the integral part of nanoseconds / dayLengthNs,
3920    // [[Nanoseconds]]: (abs(nanoseconds) modulo dayLengthNs) × sign,
3921    // [[DayLength]]: dayLengthNs }.
3922    Handle<BigInt> days_bigint;
3923    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3924        isolate, days_bigint,
3925        BigInt::Divide(isolate, nanoseconds, day_length_ns), Nothing<bool>());
3926
3927    if (sign < 0) {
3928      nanoseconds = BigInt::UnaryMinus(isolate, nanoseconds);
3929    }
3930
3931    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3932        isolate, nanoseconds,
3933        BigInt::Remainder(isolate, nanoseconds, day_length_ns),
3934        Nothing<bool>());
3935    *result_days = days_bigint->AsInt64();
3936    *result_nanoseconds = nanoseconds->AsInt64() * sign;
3937    *result_day_length = day_length_ns->AsInt64();
3938    return Just(true);
3939  }
3940  Handle<JSTemporalZonedDateTime> relative_to =
3941      Handle<JSTemporalZonedDateTime>::cast(relative_to_obj);
3942  // 7. Let startNs be ℝ(relativeTo.[[Nanoseconds]]).
3943  Handle<BigInt> start_ns = Handle<BigInt>(relative_to->nanoseconds(), isolate);
3944  // 8. Let startInstant be ! CreateTemporalInstant(ℤ(sartNs)).
3945  Handle<JSTemporalInstant> start_instant;
3946  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3947      isolate, start_instant,
3948      temporal::CreateTemporalInstant(
3949          isolate, Handle<BigInt>(relative_to->nanoseconds(), isolate)),
3950      Nothing<bool>());
3951
3952  // 9. Let startDateTime be ?
3953  // BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]],
3954  // startInstant, relativeTo.[[Calendar]]).
3955  Handle<JSReceiver> time_zone =
3956      Handle<JSReceiver>(relative_to->time_zone(), isolate);
3957  Handle<JSReceiver> calendar =
3958      Handle<JSReceiver>(relative_to->calendar(), isolate);
3959  Handle<JSTemporalPlainDateTime> start_date_time;
3960  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3961      isolate, start_date_time,
3962      temporal::BuiltinTimeZoneGetPlainDateTimeFor(
3963          isolate, time_zone, start_instant, calendar, method_name),
3964      Nothing<bool>());
3965
3966  // 10. Let endNs be startNs + nanoseconds.
3967  Handle<BigInt> end_ns;
3968  ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, end_ns,
3969                                   BigInt::Add(isolate, start_ns, nanoseconds),
3970                                   Nothing<bool>());
3971
3972  // 11. Let endInstant be ! CreateTemporalInstant(ℤ(endNs)).
3973  Handle<JSTemporalInstant> end_instant;
3974  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3975      isolate, end_instant, temporal::CreateTemporalInstant(isolate, end_ns),
3976      Nothing<bool>());
3977  // 12. Let endDateTime be ?
3978  // BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]],
3979  // endInstant, relativeTo.[[Calendar]]).
3980  Handle<JSTemporalPlainDateTime> end_date_time;
3981  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3982      isolate, end_date_time,
3983      temporal::BuiltinTimeZoneGetPlainDateTimeFor(
3984          isolate, time_zone, end_instant, calendar, method_name),
3985      Nothing<bool>());
3986
3987  // 13. Let dateDifference be ?
3988  // DifferenceISODateTime(startDateTime.[[ISOYear]],
3989  // startDateTime.[[ISOMonth]], startDateTime.[[ISODay]],
3990  // startDateTime.[[ISOHour]], startDateTime.[[ISOMinute]],
3991  // startDateTime.[[ISOSecond]], startDateTime.[[ISOMillisecond]],
3992  // startDateTime.[[ISOMicrosecond]], startDateTime.[[ISONanosecond]],
3993  // endDateTime.[[ISOYear]], endDateTime.[[ISOMonth]], endDateTime.[[ISODay]],
3994  // endDateTime.[[ISOHour]], endDateTime.[[ISOMinute]],
3995  // endDateTime.[[ISOSecond]], endDateTime.[[ISOMillisecond]],
3996  // endDateTime.[[ISOMicrosecond]], endDateTime.[[ISONanosecond]],
3997  // relativeTo.[[Calendar]], "day").
3998  Maybe<DurationRecord> maybe_date_difference = DifferenceISODateTime(
3999      isolate, start_date_time->iso_year(), start_date_time->iso_month(),
4000      start_date_time->iso_day(), start_date_time->iso_hour(),
4001      start_date_time->iso_minute(), start_date_time->iso_second(),
4002      start_date_time->iso_millisecond(), start_date_time->iso_microsecond(),
4003      start_date_time->iso_nanosecond(), end_date_time->iso_year(),
4004      end_date_time->iso_month(), end_date_time->iso_day(),
4005      end_date_time->iso_hour(), end_date_time->iso_minute(),
4006      end_date_time->iso_second(), end_date_time->iso_millisecond(),
4007      end_date_time->iso_microsecond(), end_date_time->iso_nanosecond(),
4008      calendar, Unit::kDay, relative_to, method_name);
4009  MAYBE_RETURN(maybe_date_difference, Nothing<bool>());
4010
4011  DurationRecord date_difference = maybe_date_difference.FromJust();
4012  // 14. Let days be dateDifference.[[Days]].
4013  int64_t days = date_difference.days;
4014
4015  // 15. Let intermediateNs be ℝ(? AddZonedDateTime(ℤ(startNs),
4016  // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0,
4017  // 0, 0, 0)).
4018  Handle<BigInt> intermediate_ns;
4019  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4020      isolate, intermediate_ns,
4021      AddZonedDateTime(isolate, start_ns, time_zone, calendar,
4022                       {0, 0, 0, days, 0, 0, 0, 0, 0, 0}, method_name),
4023      Nothing<bool>());
4024
4025  // 16. If sign is 1, then
4026  if (sign == 1) {
4027    // a. Repeat, while days > 0 and intermediateNs > endNs,
4028    while (days > 0 && BigInt::CompareToBigInt(intermediate_ns, end_ns) ==
4029                           ComparisonResult::kGreaterThan) {
4030      // i. Set days to days − 1.
4031      days -= 1;
4032      // ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs),
4033      // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0,
4034      // 0, 0, 0, 0)).
4035      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4036          isolate, intermediate_ns,
4037          AddZonedDateTime(isolate, start_ns, time_zone, calendar,
4038                           {0, 0, 0, days, 0, 0, 0, 0, 0, 0}, method_name),
4039          Nothing<bool>());
4040    }
4041  }
4042
4043  // 17. Set nanoseconds to endNs − intermediateNs.
4044  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4045      isolate, nanoseconds, BigInt::Subtract(isolate, end_ns, intermediate_ns),
4046      Nothing<bool>());
4047
4048  // 18. Let done be false.
4049  bool done = false;
4050
4051  // 19. Repeat, while done is false,
4052  while (!done) {
4053    // a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs),
4054    // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0,
4055    // 0, 0, 0)).
4056    Handle<BigInt> one_day_farther_ns;
4057    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4058        isolate, one_day_farther_ns,
4059        AddZonedDateTime(isolate, intermediate_ns, time_zone, calendar,
4060                         {0, 0, 0, sign, 0, 0, 0, 0, 0, 0}, method_name),
4061        Nothing<bool>());
4062
4063    // b. Set dayLengthNs to oneDayFartherNs − intermediateNs.
4064    Handle<BigInt> day_length_ns;
4065    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4066        isolate, day_length_ns,
4067        BigInt::Subtract(isolate, one_day_farther_ns, intermediate_ns),
4068        Nothing<bool>());
4069
4070    // c. If (nanoseconds − dayLengthNs) × sign ≥ 0, then
4071    compare_result = BigInt::CompareToBigInt(nanoseconds, day_length_ns);
4072    if (sign * COMPARE_RESULT_TO_SIGN(compare_result) >= 0) {
4073      // i. Set nanoseconds to nanoseconds − dayLengthNs.
4074      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4075          isolate, nanoseconds,
4076          BigInt::Subtract(isolate, nanoseconds, day_length_ns),
4077          Nothing<bool>());
4078
4079      // ii. Set intermediateNs to oneDayFartherNs.
4080      intermediate_ns = one_day_farther_ns;
4081
4082      // iii. Set days to days + sign.
4083      days += sign;
4084      // d. Else,
4085    } else {
4086      // i. Set done to true.
4087      done = true;
4088    }
4089  }
4090
4091  // 20. Return the new Record { [[Days]]: days, [[Nanoseconds]]: nanoseconds,
4092  // [[DayLength]]: abs(dayLengthNs) }.
4093  *result_days = days;
4094  *result_nanoseconds = nanoseconds->AsInt64();
4095  *result_day_length = std::abs(day_length_ns->AsInt64());
4096  return Just(true);
4097}
4098
4099Maybe<DurationRecord> DifferenceISODateTime(
4100    Isolate* isolate, int32_t y1, int32_t mon1, int32_t d1, int32_t h1,
4101    int32_t min1, int32_t s1, int32_t ms1, int32_t mus1, int32_t ns1,
4102    int32_t y2, int32_t mon2, int32_t d2, int32_t h2, int32_t min2, int32_t s2,
4103    int32_t ms2, int32_t mus2, int32_t ns2, Handle<JSReceiver> calendar,
4104    Unit largest_unit, Handle<Object> options_obj, const char* method_name) {
4105  TEMPORAL_ENTER_FUNC();
4106
4107  Factory* factory = isolate->factory();
4108  DurationRecord result;
4109  // 1. Assert: y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2,
4110  // min2, s2, ms2, mus2, and ns2 are integers.
4111  // 2. If options is not present, set options to ! OrdinaryObjectCreate(null).
4112  Handle<JSReceiver> options;
4113  if (options_obj->IsUndefined()) {
4114    options = factory->NewJSObjectWithNullProto();
4115  } else {
4116    DCHECK(options_obj->IsJSReceiver());
4117    options = Handle<JSReceiver>::cast(options_obj);
4118  }
4119  // 3. Let timeDifference be ! DifferenceTime(h1, min1, s1, ms1, mus1, ns1, h2,
4120  // min2, s2, ms2, mus2, ns2).
4121  DurationRecord time_difference = DifferenceTime(
4122      isolate, h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2);
4123
4124  result.hours = time_difference.hours;
4125  result.minutes = time_difference.minutes;
4126  result.seconds = time_difference.seconds;
4127  result.milliseconds = time_difference.milliseconds;
4128  result.microseconds = time_difference.microseconds;
4129  result.nanoseconds = time_difference.nanoseconds;
4130
4131  // 4. Let timeSign be ! DurationSign(0, 0, 0, timeDifference.[[Days]],
4132  // timeDifference.[[Hours]], timeDifference.[[Minutes]],
4133  // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
4134  // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]]).
4135  int32_t time_sign = DurationSign(isolate, time_difference);
4136  // 5. Let dateSign be ! CompareISODate(y2, mon2, d2, y1, mon1, d1).
4137  int32_t date_sign = CompareISODate(isolate, y2, mon2, d2, y1, mon1, d1);
4138  // 6. Let balanceResult be ! BalanceISODate(y1, mon1, d1 +
4139  // timeDifference.[[Days]]).
4140  int32_t balanced_year = y1;
4141  int32_t balanced_month = mon1;
4142  int32_t balanced_day = d1 + static_cast<int32_t>(time_difference.days);
4143  BalanceISODate(isolate, &balanced_year, &balanced_month, &balanced_day);
4144
4145  // 7. If timeSign is -dateSign, then
4146  if (time_sign == -date_sign) {
4147    // a. Set balanceResult be ! BalanceISODate(balanceResult.[[Year]],
4148    // balanceResult.[[Month]], balanceResult.[[Day]] - timeSign).
4149    balanced_day -= time_sign;
4150    BalanceISODate(isolate, &balanced_year, &balanced_month, &balanced_day);
4151    // b. Set timeDifference to ? BalanceDuration(-timeSign,
4152    // timeDifference.[[Hours]], timeDifference.[[Minutes]],
4153    // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
4154    // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]],
4155    // largestUnit).
4156    result.days = -time_sign;
4157    result.hours = time_difference.hours;
4158    result.minutes = time_difference.minutes;
4159    result.seconds = time_difference.seconds;
4160    result.milliseconds = time_difference.milliseconds;
4161    result.microseconds = time_difference.microseconds;
4162    result.nanoseconds = time_difference.nanoseconds;
4163
4164    Maybe<bool> maybe_time_difference = BalanceDuration(
4165        isolate, &(result.days), &(result.hours), &(result.minutes),
4166        &(result.seconds), &(result.milliseconds), &(result.microseconds),
4167        &(result.nanoseconds), largest_unit, method_name);
4168    MAYBE_RETURN(maybe_time_difference, Nothing<DurationRecord>());
4169    DCHECK(maybe_time_difference.FromJust());
4170  }
4171  // 8. Let date1 be ? CreateTemporalDate(balanceResult.[[Year]],
4172  // balanceResult.[[Month]], balanceResult.[[Day]], calendar).
4173  Handle<JSTemporalPlainDate> date1;
4174  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4175      isolate, date1,
4176      CreateTemporalDate(isolate, balanced_year, balanced_month, balanced_day,
4177                         calendar),
4178      Nothing<DurationRecord>());
4179  // 9. Let date2 be ? CreateTemporalDate(y2, mon2, d2, calendar).
4180  Handle<JSTemporalPlainDate> date2;
4181  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4182      isolate, date2, CreateTemporalDate(isolate, y2, mon2, d2, calendar),
4183      Nothing<DurationRecord>());
4184  // 10. Let dateLargestUnit be ! LargerOfTwoTemporalUnits("day", largestUnit).
4185  Unit date_largest_unit =
4186      LargerOfTwoTemporalUnits(isolate, Unit::kDay, largest_unit);
4187
4188  // 11. Let untilOptions be ? MergeLargestUnitOption(options, dateLargestUnit).
4189  Handle<JSObject> until_options;
4190  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4191      isolate, until_options,
4192      MergeLargestUnitOption(isolate, options, date_largest_unit),
4193      Nothing<DurationRecord>());
4194  // 12. Let dateDifference be ? CalendarDateUntil(calendar, date1, date2,
4195  // untilOptions).
4196  Handle<JSTemporalDuration> date_difference;
4197  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
4198      isolate, date_difference,
4199      CalendarDateUntil(isolate, calendar, date1, date2, until_options),
4200      Nothing<DurationRecord>());
4201  // 13. Let balanceResult be ? BalanceDuration(dateDifference.[[Days]],
4202  // timeDifference.[[Hours]], timeDifference.[[Minutes]],
4203  // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
4204  // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]],
4205  // largestUnit).
4206  result.days = NumberToInt64(date_difference->days());
4207
4208  Maybe<bool> maybe_balance_result = BalanceDuration(
4209      isolate, &(result.days), &(result.hours), &(result.minutes),
4210      &(result.seconds), &(result.milliseconds), &(result.microseconds),
4211      &(result.nanoseconds), largest_unit, method_name);
4212  MAYBE_RETURN(maybe_balance_result, Nothing<DurationRecord>());
4213  DCHECK(maybe_balance_result.FromJust());
4214  // 14. Return the Record { [[Years]]: dateDifference.[[Years]], [[Months]]:
4215  // dateDifference.[[Months]], [[Weeks]]: dateDifference.[[Weeks]], [[Days]]:
4216  // balanceResult.[[Days]], [[Hours]]: balanceResult.[[Hours]], [[Minutes]]:
4217  // balanceResult.[[Minutes]], [[Seconds]]: balanceResult.[[Seconds]],
4218  // [[Milliseconds]]: balanceResult.[[Milliseconds]], [[Microseconds]]:
4219  // balanceResult.[[Microseconds]], [[Nanoseconds]]:
4220  // balanceResult.[[Nanoseconds]] }.
4221  result.years = NumberToInt64(date_difference->years());
4222  result.months = NumberToInt64(date_difference->months());
4223  result.weeks = NumberToInt64(date_difference->weeks());
4224  return Just(result);
4225}
4226
4227// #sec-temporal-addinstant
4228MaybeHandle<BigInt> AddInstant(Isolate* isolate,
4229                               Handle<BigInt> epoch_nanoseconds, int64_t hours,
4230                               int64_t minutes, int64_t seconds,
4231                               int64_t milliseconds, int64_t microseconds,
4232                               int64_t nanoseconds) {
4233  TEMPORAL_ENTER_FUNC();
4234
4235  // 1. Assert: hours, minutes, seconds, milliseconds, microseconds, and
4236  // nanoseconds are integer Number values.
4237  // 2. Let result be epochNanoseconds + ℤ(nanoseconds) +
4238  // ℤ(microseconds) × 1000ℤ + ℤ(milliseconds) × 10^6ℤ + ℤ(seconds) × 10^9ℤ +
4239  // ℤ(minutes) × 60ℤ × 10^9ℤ + ℤ(hours) × 3600ℤ × 10^9ℤ.
4240  Handle<BigInt> result;
4241  ASSIGN_RETURN_ON_EXCEPTION(
4242      isolate, result,
4243      BigInt::Add(isolate, epoch_nanoseconds,
4244                  BigInt::FromInt64(isolate, nanoseconds)),
4245      BigInt);
4246  Handle<BigInt> temp;
4247  ASSIGN_RETURN_ON_EXCEPTION(
4248      isolate, temp,
4249      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, microseconds),
4250                       BigInt::FromInt64(isolate, 1000)),
4251      BigInt);
4252  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4253                             BigInt::Add(isolate, result, temp), BigInt);
4254
4255  ASSIGN_RETURN_ON_EXCEPTION(
4256      isolate, temp,
4257      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, milliseconds),
4258                       BigInt::FromInt64(isolate, 1000000)),
4259      BigInt);
4260  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4261                             BigInt::Add(isolate, result, temp), BigInt);
4262
4263  ASSIGN_RETURN_ON_EXCEPTION(
4264      isolate, temp,
4265      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, seconds),
4266                       BigInt::FromInt64(isolate, 1000000000)),
4267      BigInt);
4268  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4269                             BigInt::Add(isolate, result, temp), BigInt);
4270
4271  ASSIGN_RETURN_ON_EXCEPTION(
4272      isolate, temp,
4273      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, minutes),
4274                       BigInt::FromInt64(isolate, 1000000000)),
4275      BigInt);
4276  ASSIGN_RETURN_ON_EXCEPTION(
4277      isolate, temp,
4278      BigInt::Multiply(isolate, temp, BigInt::FromInt64(isolate, 60)), BigInt);
4279  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4280                             BigInt::Add(isolate, result, temp), BigInt);
4281
4282  ASSIGN_RETURN_ON_EXCEPTION(
4283      isolate, temp,
4284      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, hours),
4285                       BigInt::FromInt64(isolate, 1000000000)),
4286      BigInt);
4287  ASSIGN_RETURN_ON_EXCEPTION(
4288      isolate, temp,
4289      BigInt::Multiply(isolate, temp, BigInt::FromInt64(isolate, 3600)),
4290      BigInt);
4291  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4292                             BigInt::Add(isolate, result, temp), BigInt);
4293
4294  // 3. If ! IsValidEpochNanoseconds(result) is false, throw a RangeError
4295  // exception.
4296  if (!IsValidEpochNanoseconds(isolate, result)) {
4297    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), BigInt);
4298  }
4299  // 4. Return result.
4300  return result;
4301}
4302
4303// #sec-temporal-isvalidepochnanoseconds
4304bool IsValidEpochNanoseconds(Isolate* isolate,
4305                             Handle<BigInt> epoch_nanoseconds) {
4306  TEMPORAL_ENTER_FUNC();
4307
4308  // 1. Assert: Type(epochNanoseconds) is BigInt.
4309  // 2. If epochNanoseconds < −86400ℤ × 10^17ℤ or epochNanoseconds > 86400ℤ ×
4310  // 10^17ℤ, then a. Return false.
4311  // 3. Return true.
4312  int64_t ns = epoch_nanoseconds->AsInt64();
4313  return !(ns < -86400 * 1e17 || ns > 86400 * 1e17);
4314}
4315
4316MaybeHandle<BigInt> GetEpochFromISOParts(Isolate* isolate, int32_t year,
4317                                         int32_t month, int32_t day,
4318                                         int32_t hour, int32_t minute,
4319                                         int32_t second, int32_t millisecond,
4320                                         int32_t microsecond,
4321                                         int32_t nanosecond) {
4322  TEMPORAL_ENTER_FUNC();
4323  // 1. Assert: year, month, day, hour, minute, second, millisecond,
4324  // microsecond, and nanosecond are integers.
4325  // 2. Assert: ! IsValidISODate(year, month, day) is true.
4326  DCHECK(IsValidISODate(isolate, year, month, day));
4327  // 3. Assert: ! IsValidTime(hour, minute, second, millisecond, microsecond,
4328  // nanosecond) is true.
4329  DCHECK(IsValidTime(isolate, hour, minute, second, millisecond, microsecond,
4330                     nanosecond));
4331  // 4. Let date be ! MakeDay(�(year), �(month − 1), �(day)).
4332  double date = MakeDay(year, month - 1, day);
4333  // 5. Let time be ! MakeTime(�(hour), �(minute), �(second), �(millisecond)).
4334  double time = MakeTime(hour, minute, second, millisecond);
4335  // 6. Let ms be ! MakeDate(date, time).
4336  double ms = MakeDate(date, time);
4337  // 7. Assert: ms is finite.
4338  // 8. Return ℝ(ms) × 10^6 + microsecond × 10^3 + nanosecond.
4339  Handle<BigInt> result;
4340  ASSIGN_RETURN_ON_EXCEPTION(
4341      isolate, result,
4342      BigInt::FromNumber(isolate, isolate->factory()->NewNumber(ms)), BigInt);
4343
4344  ASSIGN_RETURN_ON_EXCEPTION(
4345      isolate, result,
4346      BigInt::Multiply(isolate, result, BigInt::FromInt64(isolate, 1000000)),
4347      BigInt);
4348
4349  Handle<BigInt> temp;
4350  ASSIGN_RETURN_ON_EXCEPTION(
4351      isolate, temp,
4352      BigInt::Multiply(isolate, BigInt::FromInt64(isolate, microsecond),
4353                       BigInt::FromInt64(isolate, 1000)),
4354      BigInt);
4355
4356  ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
4357                             BigInt::Add(isolate, result, temp), BigInt);
4358  return BigInt::Add(isolate, result, BigInt::FromInt64(isolate, nanosecond));
4359}
4360
4361// #sec-temporal-durationsign
4362int32_t DurationSign(Isolate* isolaet, const DurationRecord& dur) {
4363  TEMPORAL_ENTER_FUNC();
4364
4365  // 1. For each value v of « years, months, weeks, days, hours, minutes,
4366  // seconds, milliseconds, microseconds, nanoseconds », do a. If v < 0, return
4367  // −1. b. If v > 0, return 1.
4368  // 2. Return 0.
4369  if (dur.years < 0) return -1;
4370  if (dur.years > 0) return 1;
4371  if (dur.months < 0) return -1;
4372  if (dur.months > 0) return 1;
4373  if (dur.weeks < 0) return -1;
4374  if (dur.weeks > 0) return 1;
4375  if (dur.days < 0) return -1;
4376  if (dur.days > 0) return 1;
4377  if (dur.hours < 0) return -1;
4378  if (dur.hours > 0) return 1;
4379  if (dur.minutes < 0) return -1;
4380  if (dur.minutes > 0) return 1;
4381  if (dur.seconds < 0) return -1;
4382  if (dur.seconds > 0) return 1;
4383  if (dur.milliseconds < 0) return -1;
4384  if (dur.milliseconds > 0) return 1;
4385  if (dur.microseconds < 0) return -1;
4386  if (dur.microseconds > 0) return 1;
4387  if (dur.nanoseconds < 0) return -1;
4388  if (dur.nanoseconds > 0) return 1;
4389  return 0;
4390}
4391
4392// #sec-temporal-isvalidduration
4393bool IsValidDuration(Isolate* isolate, const DurationRecord& dur) {
4394  TEMPORAL_ENTER_FUNC();
4395
4396  // 1. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes,
4397  // seconds, milliseconds, microseconds, nanoseconds).
4398  int32_t sign = DurationSign(isolate, dur);
4399  // 2. For each value v of « years, months, weeks, days, hours, minutes,
4400  // seconds, milliseconds, microseconds, nanoseconds », do a. If v is not
4401  // finite, return false. b. If v < 0 and sign > 0, return false. c. If v > 0
4402  // and sign < 0, return false.
4403  // 3. Return true.
4404  return !((sign > 0 && (dur.years < 0 || dur.months < 0 || dur.weeks < 0 ||
4405                         dur.days < 0 || dur.hours < 0 || dur.minutes < 0 ||
4406                         dur.seconds < 0 || dur.milliseconds < 0 ||
4407                         dur.microseconds < 0 || dur.nanoseconds < 0)) ||
4408           (sign < 0 && (dur.years > 0 || dur.months > 0 || dur.weeks > 0 ||
4409                         dur.days > 0 || dur.hours > 0 || dur.minutes > 0 ||
4410                         dur.seconds > 0 || dur.milliseconds > 0 ||
4411                         dur.microseconds > 0 || dur.nanoseconds > 0)));
4412}
4413
4414// #sec-temporal-isisoleapyear
4415bool IsISOLeapYear(Isolate* isolate, int32_t year) {
4416  TEMPORAL_ENTER_FUNC();
4417
4418  // 1. Assert: year is an integer.
4419  // 2. If year modulo 4 ≠ 0, return false.
4420  // 3. If year modulo 400 = 0, return true.
4421  // 4. If year modulo 100 = 0, return false.
4422  // 5. Return true.
4423  return isolate->date_cache()->IsLeap(year);
4424}
4425
4426// #sec-temporal-isodaysinmonth
4427int32_t ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month) {
4428  TEMPORAL_ENTER_FUNC();
4429
4430  // 1. Assert: year is an integer.
4431  // 2. Assert: month is an integer, month ≥ 1, and month ≤ 12.
4432  DCHECK_GE(month, 1);
4433  DCHECK_LE(month, 12);
4434  // 3. If month is 1, 3, 5, 7, 8, 10, or 12, return 31.
4435  if (month % 2 == ((month < 8) ? 1 : 0)) return 31;
4436  // 4. If month is 4, 6, 9, or 11, return 30.
4437  DCHECK(month == 2 || month == 4 || month == 6 || month == 9 || month == 11);
4438  if (month != 2) return 30;
4439  // 5. If ! IsISOLeapYear(year) is true, return 29.
4440  return IsISOLeapYear(isolate, year) ? 29 : 28;
4441  // 6. Return 28.
4442}
4443
4444// #sec-temporal-isodaysinyear
4445int32_t ISODaysInYear(Isolate* isolate, int32_t year) {
4446  TEMPORAL_ENTER_FUNC();
4447
4448  // 1. Assert: year is an integer.
4449  // 2. If ! IsISOLeapYear(year) is true, then
4450  // a. Return 366.
4451  // 3. Return 365.
4452  return IsISOLeapYear(isolate, year) ? 366 : 365;
4453}
4454
4455bool IsValidTime(Isolate* isolate, int32_t hour, int32_t minute, int32_t second,
4456                 int32_t millisecond, int32_t microsecond, int32_t nanosecond) {
4457  TEMPORAL_ENTER_FUNC();
4458
4459  // 2. If hour < 0 or hour > 23, then
4460  // a. Return false.
4461  if (hour < 0 || hour > 23) return false;
4462  // 3. If minute < 0 or minute > 59, then
4463  // a. Return false.
4464  if (minute < 0 || minute > 59) return false;
4465  // 4. If second < 0 or second > 59, then
4466  // a. Return false.
4467  if (second < 0 || second > 59) return false;
4468  // 5. If millisecond < 0 or millisecond > 999, then
4469  // a. Return false.
4470  if (millisecond < 0 || millisecond > 999) return false;
4471  // 6. If microsecond < 0 or microsecond > 999, then
4472  // a. Return false.
4473  if (microsecond < 0 || microsecond > 999) return false;
4474  // 7. If nanosecond < 0 or nanosecond > 999, then
4475  // a. Return false.
4476  if (nanosecond < 0 || nanosecond > 999) return false;
4477  // 8. Return true.
4478  return true;
4479}
4480
4481// #sec-temporal-isvalidisodate
4482bool IsValidISODate(Isolate* isolate, int32_t year, int32_t month,
4483                    int32_t day) {
4484  TEMPORAL_ENTER_FUNC();
4485
4486  // 1. Assert: year, month, and day are integers.
4487  // 2. If month < 1 or month > 12, then
4488  // a. Return false.
4489  if (month < 1 || month > 12) return false;
4490  // 3. Let daysInMonth be ! ISODaysInMonth(year, month).
4491  // 4. If day < 1 or day > daysInMonth, then
4492  // a. Return false.
4493  if (day < 1 || day > ISODaysInMonth(isolate, year, month)) return false;
4494  // 5. Return true.
4495  return true;
4496}
4497
4498// #sec-temporal-compareisodate
4499int32_t CompareISODate(Isolate* isolate, int32_t y1, int32_t m1, int32_t d1,
4500                       int32_t y2, int32_t m2, int32_t d2) {
4501  TEMPORAL_ENTER_FUNC();
4502
4503  // 1. Assert: y1, m1, d1, y2, m2, and d2 are integers.
4504  // 2. If y1 > y2, return 1.
4505  if (y1 > y2) return 1;
4506  // 3. If y1 < y2, return -1.
4507  if (y1 < y2) return -1;
4508  // 4. If m1 > m2, return 1.
4509  if (m1 > m2) return 1;
4510  // 5. If m1 < m2, return -1.
4511  if (m1 < m2) return -1;
4512  // 6. If d1 > d2, return 1.
4513  if (d1 > d2) return 1;
4514  // 7. If d1 < d2, return -1.
4515  if (d1 < d2) return -1;
4516  // 8. Return 0.
4517  return 0;
4518}
4519
4520// #sec-temporal-balanceisoyearmonth
4521void BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month) {
4522  TEMPORAL_ENTER_FUNC();
4523
4524  // 1. Assert: year and month are integers.
4525  // 2. Set year to year + floor((month - 1) / 12).
4526  *year += floor_divide((*month - 1), 12);
4527  // 3. Set month to (month − 1) modulo 12 + 1.
4528  *month = static_cast<int32_t>(modulo(*month - 1, 12)) + 1;
4529
4530  // 4. Return the new Record { [[Year]]: year, [[Month]]: month }.
4531}
4532// #sec-temporal-balancetime
4533DateTimeRecordCommon BalanceTime(Isolate* isolate, int64_t hour, int64_t minute,
4534                                 int64_t second, int64_t millisecond,
4535                                 int64_t microsecond, int64_t nanosecond) {
4536  TEMPORAL_ENTER_FUNC();
4537
4538  // 1. Assert: hour, minute, second, millisecond, microsecond, and nanosecond
4539  // are integers.
4540  // 2. Set microsecond to microsecond + floor(nanosecond / 1000).
4541  microsecond += floor_divide(nanosecond, 1000L);
4542  // 3. Set nanosecond to nanosecond modulo 1000.
4543  nanosecond = modulo(nanosecond, 1000L);
4544  // 4. Set millisecond to millisecond + floor(microsecond / 1000).
4545  millisecond += floor_divide(microsecond, 1000L);
4546  // 5. Set microsecond to microsecond modulo 1000.
4547  microsecond = modulo(microsecond, 1000L);
4548  // 6. Set second to second + floor(millisecond / 1000).
4549  second += floor_divide(millisecond, 1000L);
4550  // 7. Set millisecond to millisecond modulo 1000.
4551  millisecond = modulo(millisecond, 1000L);
4552  // 8. Set minute to minute + floor(second / 60).
4553  minute += floor_divide(second, 60L);
4554  // 9. Set second to second modulo 60.
4555  second = modulo(second, 60L);
4556  // 10. Set hour to hour + floor(minute / 60).
4557  hour += floor_divide(minute, 60L);
4558  // 11. Set minute to minute modulo 60.
4559  minute = modulo(minute, 60L);
4560  // 12. Let days be floor(hour / 24).
4561  int64_t days = floor_divide(hour, 24L);
4562  // 13. Set hour to hour modulo 24.
4563  hour = modulo(hour, 24L);
4564  // 14. Return the new Record { [[Days]]: days, [[Hour]]: hour, [[Minute]]:
4565  // minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]:
4566  // microsecond, [[Nanosecond]]: nanosecond }.
4567  return {0,
4568          0,
4569          static_cast<int32_t>(days),
4570          static_cast<int32_t>(hour),
4571          static_cast<int32_t>(minute),
4572          static_cast<int32_t>(second),
4573          static_cast<int32_t>(millisecond),
4574          static_cast<int32_t>(microsecond),
4575          static_cast<int32_t>(nanosecond)};
4576}
4577
4578// #sec-temporal-differencetime
4579DurationRecord DifferenceTime(Isolate* isolate, int32_t h1, int32_t min1,
4580                              int32_t s1, int32_t ms1, int32_t mus1,
4581                              int32_t ns1, int32_t h2, int32_t min2, int32_t s2,
4582                              int32_t ms2, int32_t mus2, int32_t ns2) {
4583  TEMPORAL_ENTER_FUNC();
4584
4585  // 1. Assert: h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, and ns2
4586  // are integers.
4587  DurationRecord dur;
4588  // 2. Let hours be h2 − h1.
4589  dur.hours = h2 - h1;
4590  // 3. Let minutes be min2 − min1.
4591  dur.minutes = min2 - min1;
4592  // 4. Let seconds be s2 − s1.
4593  dur.seconds = s2 - s1;
4594  // 5. Let milliseconds be ms2 − ms1.
4595  dur.milliseconds = ms2 - ms1;
4596  // 6. Let microseconds be mus2 − mus1.
4597  dur.microseconds = mus2 - mus1;
4598  // 7. Let nanoseconds be ns2 − ns1.
4599  dur.nanoseconds = ns2 - ns1;
4600  // 8. Let sign be ! DurationSign(0, 0, 0, 0, hours, minutes, seconds,
4601  // milliseconds, microseconds, nanoseconds).
4602  double sign = DurationSign(isolate, dur);
4603
4604  // See https://github.com/tc39/proposal-temporal/pull/1885
4605  // 9. Let bt be ! BalanceTime(hours × sign, minutes × sign, seconds × sign,
4606  // milliseconds × sign, microseconds × sign, nanoseconds × sign).
4607  DateTimeRecordCommon bt = BalanceTime(
4608      isolate, dur.hours * sign, dur.minutes * sign, dur.seconds * sign,
4609      dur.milliseconds * sign, dur.microseconds * sign, dur.nanoseconds * sign);
4610
4611  // 10. Return the new Record { [[Days]]: bt.[[Days]] × sign, [[Hours]]:
4612  // bt.[[Hour]] × sign, [[Minutes]]: bt.[[Minute]] × sign, [[Seconds]]:
4613  // bt.[[Second]] × sign, [[Milliseconds]]: bt.[[Millisecond]] × sign,
4614  // [[Microseconds]]: bt.[[Microsecond]] × sign, [[Nanoseconds]]:
4615  // bt.[[Nanosecond]] × sign }.
4616  return {0,
4617          0,
4618          0,
4619          static_cast<int64_t>(bt.day * sign),
4620          static_cast<int64_t>(bt.hour * sign),
4621          static_cast<int64_t>(bt.minute * sign),
4622          static_cast<int64_t>(bt.second * sign),
4623          static_cast<int64_t>(bt.millisecond * sign),
4624          static_cast<int64_t>(bt.microsecond * sign),
4625          static_cast<int64_t>(bt.nanosecond * sign)};
4626}
4627
4628// #sec-temporal-addtime
4629DateTimeRecordCommon AddTime(Isolate* isolate, int64_t hour, int64_t minute,
4630                             int64_t second, int64_t millisecond,
4631                             int64_t microsecond, int64_t nanosecond,
4632                             int64_t hours, int64_t minutes, int64_t seconds,
4633                             int64_t milliseconds, int64_t microseconds,
4634                             int64_t nanoseconds) {
4635  TEMPORAL_ENTER_FUNC();
4636
4637  // 1. Assert: hour, minute, second, millisecond, microsecond, nanosecond,
4638  // hours, minutes, seconds, milliseconds, microseconds, and nanoseconds are
4639  // integers.
4640  // 2. Let hour be hour + hours.
4641  return BalanceTime(isolate, hour + hours,
4642                     // 3. Let minute be minute + minutes.
4643                     minute + minutes,
4644                     // 4. Let second be second + seconds.
4645                     second + seconds,
4646                     // 5. Let millisecond be millisecond + milliseconds.
4647                     millisecond + milliseconds,
4648                     // 6. Let microsecond be microsecond + microseconds.
4649                     microsecond + microseconds,
4650                     // 7. Let nanosecond be nanosecond + nanoseconds.
4651                     nanosecond + nanoseconds);
4652  // 8. Return ! BalanceTime(hour, minute, second, millisecond, microsecond,
4653  // nanosecond).
4654}
4655
4656// #sec-temporal-totaldurationnanoseconds
4657int64_t TotalDurationNanoseconds(Isolate* isolate, int64_t days, int64_t hours,
4658                                 int64_t minutes, int64_t seconds,
4659                                 int64_t milliseconds, int64_t microseconds,
4660                                 int64_t nanoseconds, int64_t offset_shift) {
4661  TEMPORAL_ENTER_FUNC();
4662
4663  // 1. Assert: offsetShift is an integer.
4664  // 2. Set nanoseconds to ℝ(nanoseconds).
4665  // 3. If days ≠ 0, then
4666  if (days != 0) {
4667    // a. Set nanoseconds to nanoseconds − offsetShift.
4668    nanoseconds -= offset_shift;
4669  }
4670
4671  // 4. Set hours to ℝ(hours) + ℝ(days) × 24.
4672  hours += days * 24;
4673
4674  // 5. Set minutes to ℝ(minutes) + hours × 60.
4675  minutes += hours * 60;
4676
4677  // 6. Set seconds to ℝ(seconds) + minutes × 60.
4678  seconds += minutes * 60;
4679
4680  // 7. Set milliseconds to ℝ(milliseconds) + seconds × 1000.
4681  milliseconds += seconds * 1000;
4682
4683  // 8. Set microseconds to ℝ(microseconds) + milliseconds × 1000.
4684  microseconds += milliseconds * 1000;
4685
4686  // 9. Return nanoseconds + microseconds × 1000.
4687  return nanoseconds + microseconds * 1000;
4688}
4689
4690}  // namespace
4691
4692// #sec-temporal.duration
4693MaybeHandle<JSTemporalDuration> JSTemporalDuration::Constructor(
4694    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
4695    Handle<Object> years, Handle<Object> months, Handle<Object> weeks,
4696    Handle<Object> days, Handle<Object> hours, Handle<Object> minutes,
4697    Handle<Object> seconds, Handle<Object> milliseconds,
4698    Handle<Object> microseconds, Handle<Object> nanoseconds) {
4699  const char* method_name = "Temporal.Duration";
4700  // 1. If NewTarget is undefined, then
4701  if (new_target->IsUndefined()) {
4702    // a. Throw a TypeError exception.
4703    THROW_NEW_ERROR(isolate,
4704                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
4705                                 isolate->factory()->NewStringFromAsciiChecked(
4706                                     method_name)),
4707                    JSTemporalDuration);
4708  }
4709  // 2. Let y be ? ToIntegerThrowOnInfinity(years).
4710  Handle<Object> number_years;
4711  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_years,
4712                             ToIntegerThrowOnInfinity(isolate, years),
4713                             JSTemporalDuration);
4714  int64_t y = NumberToInt64(*number_years);
4715
4716  // 3. Let mo be ? ToIntegerThrowOnInfinity(months).
4717  Handle<Object> number_months;
4718  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_months,
4719                             ToIntegerThrowOnInfinity(isolate, months),
4720                             JSTemporalDuration);
4721  int64_t mo = NumberToInt64(*number_months);
4722
4723  // 4. Let w be ? ToIntegerThrowOnInfinity(weeks).
4724  Handle<Object> number_weeks;
4725  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_weeks,
4726                             ToIntegerThrowOnInfinity(isolate, weeks),
4727                             JSTemporalDuration);
4728  int64_t w = NumberToInt64(*number_weeks);
4729
4730  // 5. Let d be ? ToIntegerThrowOnInfinity(days).
4731  Handle<Object> number_days;
4732  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_days,
4733                             ToIntegerThrowOnInfinity(isolate, days),
4734                             JSTemporalDuration);
4735  int64_t d = NumberToInt64(*number_days);
4736
4737  // 6. Let h be ? ToIntegerThrowOnInfinity(hours).
4738  Handle<Object> number_hours;
4739  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_hours,
4740                             ToIntegerThrowOnInfinity(isolate, hours),
4741                             JSTemporalDuration);
4742  int64_t h = NumberToInt64(*number_hours);
4743
4744  // 7. Let m be ? ToIntegerThrowOnInfinity(minutes).
4745  Handle<Object> number_minutes;
4746  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_minutes,
4747                             ToIntegerThrowOnInfinity(isolate, minutes),
4748                             JSTemporalDuration);
4749  int64_t m = NumberToInt64(*number_minutes);
4750
4751  // 8. Let s be ? ToIntegerThrowOnInfinity(seconds).
4752  Handle<Object> number_seconds;
4753  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_seconds,
4754                             ToIntegerThrowOnInfinity(isolate, seconds),
4755                             JSTemporalDuration);
4756  int64_t s = NumberToInt64(*number_seconds);
4757
4758  // 9. Let ms be ? ToIntegerThrowOnInfinity(milliseconds).
4759  Handle<Object> number_milliseconds;
4760  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_milliseconds,
4761                             ToIntegerThrowOnInfinity(isolate, milliseconds),
4762                             JSTemporalDuration);
4763  int64_t ms = NumberToInt64(*number_milliseconds);
4764
4765  // 10. Let mis be ? ToIntegerThrowOnInfinity(microseconds).
4766  Handle<Object> number_microseconds;
4767  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_microseconds,
4768                             ToIntegerThrowOnInfinity(isolate, microseconds),
4769                             JSTemporalDuration);
4770  int64_t mis = NumberToInt64(*number_microseconds);
4771
4772  // 11. Let ns be ? ToIntegerThrowOnInfinity(nanoseconds).
4773  Handle<Object> number_nanoseconds;
4774  ASSIGN_RETURN_ON_EXCEPTION(isolate, number_nanoseconds,
4775                             ToIntegerThrowOnInfinity(isolate, nanoseconds),
4776                             JSTemporalDuration);
4777  int64_t ns = NumberToInt64(*number_nanoseconds);
4778
4779  // 12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns,
4780  // NewTarget).
4781  return CreateTemporalDuration(isolate, target, new_target, y, mo, w, d, h, m,
4782                                s, ms, mis, ns);
4783}
4784
4785// #sec-get-temporal.duration.prototype.sign
4786MaybeHandle<Smi> JSTemporalDuration::Sign(Isolate* isolate,
4787                                          Handle<JSTemporalDuration> duration) {
4788  // 1. Let duration be the this value.
4789  // 2. Perform ? RequireInternalSlot(duration,
4790  // [[InitializedTemporalDuration]]).
4791  // 3. Return ! DurationSign(duration.[[Years]], duration.[[Months]],
4792  // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
4793  // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
4794  // duration.[[Microseconds]], duration.[[Nanoseconds]]).
4795  return Handle<Smi>(
4796      Smi::FromInt(DurationSign(
4797          isolate,
4798          {NumberToInt64(duration->years()), NumberToInt64(duration->months()),
4799           NumberToInt64(duration->weeks()), NumberToInt64(duration->days()),
4800           NumberToInt64(duration->hours()), NumberToInt64(duration->minutes()),
4801           NumberToInt64(duration->seconds()),
4802           NumberToInt64(duration->milliseconds()),
4803           NumberToInt64(duration->microseconds()),
4804           NumberToInt64(duration->nanoseconds())})),
4805      isolate);
4806}
4807
4808// #sec-get-temporal.duration.prototype.blank
4809MaybeHandle<Oddball> JSTemporalDuration::Blank(
4810    Isolate* isolate, Handle<JSTemporalDuration> duration) {
4811  // 1. Let duration be the this value.
4812  // 2. Perform ? RequireInternalSlot(duration,
4813  // [[InitializedTemporalDuration]]).
4814  // 3. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]],
4815  // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
4816  // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
4817  // duration.[[Microseconds]], duration.[[Nanoseconds]]).
4818  // 4. If sign = 0, return true.
4819  // 5. Return false.
4820  int32_t sign = DurationSign(
4821      isolate,
4822      {NumberToInt64(duration->years()), NumberToInt64(duration->months()),
4823       NumberToInt64(duration->weeks()), NumberToInt64(duration->days()),
4824       NumberToInt64(duration->hours()), NumberToInt64(duration->minutes()),
4825       NumberToInt64(duration->seconds()),
4826       NumberToInt64(duration->milliseconds()),
4827       NumberToInt64(duration->microseconds()),
4828       NumberToInt64(duration->nanoseconds())});
4829  return sign == 0 ? isolate->factory()->true_value()
4830                   : isolate->factory()->false_value();
4831}
4832
4833namespace {
4834// #sec-temporal-createnegatedtemporalduration
4835MaybeHandle<JSTemporalDuration> CreateNegatedTemporalDuration(
4836    Isolate* isolate, Handle<JSTemporalDuration> duration) {
4837  TEMPORAL_ENTER_FUNC();
4838  // 1. Assert: Type(duration) is Object.
4839  // 2. Assert: duration has an [[InitializedTemporalDuration]] internal slot.
4840  // 3. Return ! CreateTemporalDuration(−duration.[[Years]],
4841  // −duration.[[Months]], −duration.[[Weeks]], −duration.[[Days]],
4842  // −duration.[[Hours]], −duration.[[Minutes]], −duration.[[Seconds]],
4843  // −duration.[[Milliseconds]], −duration.[[Microseconds]],
4844  // −duration.[[Nanoseconds]]).
4845
4846  return CreateTemporalDuration(
4847      isolate, -NumberToInt64(duration->years()),
4848      -NumberToInt64(duration->months()), -NumberToInt64(duration->weeks()),
4849      -NumberToInt64(duration->days()), -NumberToInt64(duration->hours()),
4850      -NumberToInt64(duration->minutes()), -NumberToInt64(duration->seconds()),
4851      -NumberToInt64(duration->milliseconds()),
4852      -NumberToInt64(duration->microseconds()),
4853      -NumberToInt64(duration->nanoseconds()));
4854}
4855
4856}  // namespace
4857
4858// #sec-temporal.duration.prototype.negated
4859MaybeHandle<JSTemporalDuration> JSTemporalDuration::Negated(
4860    Isolate* isolate, Handle<JSTemporalDuration> duration) {
4861  // Let duration be the this value.
4862  // 2. Perform ? RequireInternalSlot(duration,
4863  // [[InitializedTemporalDuration]]).
4864
4865  // 3. Return ! CreateNegatedTemporalDuration(duration).
4866  return CreateNegatedTemporalDuration(isolate, duration);
4867}
4868
4869// #sec-temporal.duration.prototype.abs
4870MaybeHandle<JSTemporalDuration> JSTemporalDuration::Abs(
4871    Isolate* isolate, Handle<JSTemporalDuration> duration) {
4872  // 1. Let duration be the this value.
4873  // 2. Perform ? RequireInternalSlot(duration,
4874  // [[InitializedTemporalDuration]]).
4875  // 3. Return ? CreateTemporalDuration(abs(duration.[[Years]]),
4876  // abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]),
4877  // abs(duration.[[Hours]]), abs(duration.[[Minutes]]),
4878  // abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]),
4879  // abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])).
4880  return CreateTemporalDuration(
4881      isolate, std::abs(NumberToInt64(duration->years())),
4882      std::abs(NumberToInt64(duration->months())),
4883      std::abs(NumberToInt64(duration->weeks())),
4884      std::abs(NumberToInt64(duration->days())),
4885      std::abs(NumberToInt64(duration->hours())),
4886      std::abs(NumberToInt64(duration->minutes())),
4887      std::abs(NumberToInt64(duration->seconds())),
4888      std::abs(NumberToInt64(duration->milliseconds())),
4889      std::abs(NumberToInt64(duration->microseconds())),
4890      std::abs(NumberToInt64(duration->nanoseconds())));
4891}
4892
4893// #sec-temporal.calendar
4894MaybeHandle<JSTemporalCalendar> JSTemporalCalendar::Constructor(
4895    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
4896    Handle<Object> identifier_obj) {
4897  // 1. If NewTarget is undefined, then
4898  if (new_target->IsUndefined(isolate)) {
4899    // a. Throw a TypeError exception.
4900    THROW_NEW_ERROR(isolate,
4901                    NewTypeError(MessageTemplate::kConstructorNotFunction,
4902                                 isolate->factory()->NewStringFromStaticChars(
4903                                     "Temporal.Calendar")),
4904                    JSTemporalCalendar);
4905  }
4906  // 2. Set identifier to ? ToString(identifier).
4907  Handle<String> identifier;
4908  ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
4909                             Object::ToString(isolate, identifier_obj),
4910                             JSTemporalCalendar);
4911  // 3. If ! IsBuiltinCalendar(id) is false, then
4912  if (!IsBuiltinCalendar(isolate, identifier)) {
4913    // a. Throw a RangeError exception.
4914    THROW_NEW_ERROR(
4915        isolate, NewRangeError(MessageTemplate::kInvalidCalendar, identifier),
4916        JSTemporalCalendar);
4917  }
4918  return CreateTemporalCalendar(isolate, target, new_target, identifier);
4919}
4920
4921namespace {
4922
4923// #sec-temporal-toisodayofyear
4924int32_t ToISODayOfYear(Isolate* isolate, int32_t year, int32_t month,
4925                       int32_t day) {
4926  TEMPORAL_ENTER_FUNC();
4927
4928  // 1. Assert: year is an integer.
4929  // 2. Assert: month is an integer.
4930  // 3. Assert: day is an integer.
4931  // 4. Let date be the date given by year, month, and day.
4932  // 5. Return date's ordinal date in the year according to ISO-8601.
4933  // Note: In ISO 8601, Jan: month=1, Dec: month=12,
4934  // In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
4935  return day + isolate->date_cache()->DaysFromYearMonth(year, month - 1) -
4936         isolate->date_cache()->DaysFromYearMonth(year, 0);
4937}
4938
4939bool IsPlainDatePlainDateTimeOrPlainYearMonth(
4940    Handle<Object> temporal_date_like) {
4941  return temporal_date_like->IsJSTemporalPlainDate() ||
4942         temporal_date_like->IsJSTemporalPlainDateTime() ||
4943         temporal_date_like->IsJSTemporalPlainYearMonth();
4944}
4945
4946// #sec-temporal-toisodayofweek
4947int32_t ToISODayOfWeek(Isolate* isolate, int32_t year, int32_t month,
4948                       int32_t day) {
4949  TEMPORAL_ENTER_FUNC();
4950
4951  // 1. Assert: year is an integer.
4952  // 2. Assert: month is an integer.
4953  // 3. Assert: day is an integer.
4954  // 4. Let date be the date given by year, month, and day.
4955  // 5. Return date's day of the week according to ISO-8601.
4956  // Note: In ISO 8601, Jan: month=1, Dec: month=12.
4957  // In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
4958  // Weekday() expect "the number of days since the epoch" as input and the
4959  // value of day is 1-based so we need to minus 1 to calculate "the number of
4960  // days" because the number of days on the epoch (1970/1/1) should be 0,
4961  // not 1.
4962  int32_t weekday = isolate->date_cache()->Weekday(
4963      isolate->date_cache()->DaysFromYearMonth(year, month - 1) + day - 1);
4964  // Note: In ISO 8601, Sun: weekday=7 Mon: weekday=1
4965  // In DateCache API, Sun: weekday=0 Mon: weekday=1
4966  return weekday == 0 ? 7 : weekday;
4967}
4968
4969// #sec-temporal-regulateisodate
4970Maybe<bool> RegulateISODate(Isolate* isolate, ShowOverflow overflow,
4971                            int32_t year, int32_t* month, int32_t* day) {
4972  TEMPORAL_ENTER_FUNC();
4973
4974  // 1. Assert: year, month, and day are integers.
4975  // 2. Assert: overflow is either "constrain" or "reject".
4976  switch (overflow) {
4977    // 3. If overflow is "reject", then
4978    case ShowOverflow::kReject:
4979      // a. If ! IsValidISODate(year, month, day) is false, throw a RangeError
4980      // exception.
4981      if (!IsValidISODate(isolate, year, *month, *day)) {
4982        THROW_NEW_ERROR_RETURN_VALUE(
4983            isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(), Nothing<bool>());
4984      }
4985      // b. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day
4986      // }.
4987      return Just(true);
4988    // 4. If overflow is "constrain", then
4989    case ShowOverflow::kConstrain:
4990      // a. Set month to ! ConstrainToRange(month, 1, 12).
4991      *month = std::max(std::min(*month, 12), 1);
4992      // b. Set day to ! ConstrainToRange(day, 1, ! ISODaysInMonth(year,
4993      // month)).
4994      *day = std::max(std::min(*day, ISODaysInMonth(isolate, year, *month)), 1);
4995      // c. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day
4996      // }.
4997      return Just(true);
4998  }
4999}
5000
5001// #sec-temporal-resolveisomonth
5002Maybe<int32_t> ResolveISOMonth(Isolate* isolate, Handle<JSReceiver> fields) {
5003  Factory* factory = isolate->factory();
5004  // 1. Let month be ? Get(fields, "month").
5005  Handle<Object> month_obj;
5006  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5007      isolate, month_obj,
5008      Object::GetPropertyOrElement(isolate, fields, factory->month_string()),
5009      Nothing<int32_t>());
5010  // 2. Let monthCode be ? Get(fields, "monthCode").
5011  Handle<Object> month_code_obj;
5012  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5013      isolate, month_code_obj,
5014      Object::GetPropertyOrElement(isolate, fields,
5015                                   factory->monthCode_string()),
5016      Nothing<int32_t>());
5017  // 3. If monthCode is undefined, then
5018  if (month_code_obj->IsUndefined(isolate)) {
5019    // a. If month is undefined, throw a TypeError exception.
5020    if (month_obj->IsUndefined(isolate)) {
5021      THROW_NEW_ERROR_RETURN_VALUE(
5022          isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(), Nothing<int32_t>());
5023    }
5024    // b. Return month.
5025    // Note: In Temporal spec, "month" in fields is always converted by
5026    // ToPositiveInteger inside PrepareTemporalFields before calling
5027    // ResolveISOMonth. Therefore the month_obj is always a positive integer.
5028    DCHECK(month_obj->IsSmi() || month_obj->IsHeapNumber());
5029    return Just(FastD2I(month_obj->Number()));
5030  }
5031  // 4. Assert: Type(monthCode) is String.
5032  DCHECK(month_code_obj->IsString());
5033  Handle<String> month_code;
5034  ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, month_code,
5035                                   Object::ToString(isolate, month_code_obj),
5036                                   Nothing<int32_t>());
5037  // 5. Let monthLength be the length of monthCode.
5038  // 6. If monthLength is not 3, throw a RangeError exception.
5039  if (month_code->length() != 3) {
5040    THROW_NEW_ERROR_RETURN_VALUE(
5041        isolate,
5042        NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
5043                      factory->monthCode_string()),
5044        Nothing<int32_t>());
5045  }
5046  // 7. Let numberPart be the substring of monthCode from 1.
5047  // 8. Set numberPart to ! ToIntegerOrInfinity(numberPart).
5048  // 9. If numberPart < 1 or numberPart > 12, throw a RangeError exception.
5049  uint16_t m0 = month_code->Get(0);
5050  uint16_t m1 = month_code->Get(1);
5051  uint16_t m2 = month_code->Get(2);
5052  if (!((m0 == 'M') && ((m1 == '0' && '1' <= m2 && m2 <= '9') ||
5053                        (m1 == '1' && '0' <= m2 && m2 <= '2')))) {
5054    THROW_NEW_ERROR_RETURN_VALUE(
5055        isolate,
5056        NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
5057                      factory->monthCode_string()),
5058        Nothing<int32_t>());
5059  }
5060  int32_t number_part =
5061      10 * static_cast<int32_t>(m1 - '0') + static_cast<int32_t>(m2 - '0');
5062  // 10. If month is not undefined, and month ≠ numberPart, then
5063  // 11. If ! SameValueNonNumeric(monthCode, ! BuildISOMonthCode(numberPart)) is
5064  // false, then a. Throw a RangeError exception.
5065  // Note: In Temporal spec, "month" in fields is always converted by
5066  // ToPositiveInteger inside PrepareTemporalFields before calling
5067  // ResolveISOMonth. Therefore the month_obj is always a positive integer.
5068  if (!month_obj->IsUndefined() &&
5069      FastD2I(month_obj->Number()) != number_part) {
5070    // a. Throw a RangeError exception.
5071    THROW_NEW_ERROR_RETURN_VALUE(
5072        isolate,
5073        NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
5074                      factory->month_string()),
5075        Nothing<int32_t>());
5076  }
5077
5078  // 12. Return numberPart.
5079  return Just(number_part);
5080}
5081
5082// #sec-temporal-isodatefromfields
5083Maybe<bool> ISODateFromFields(Isolate* isolate, Handle<JSReceiver> fields,
5084                              Handle<JSReceiver> options,
5085                              const char* method_name, int32_t* year,
5086                              int32_t* month, int32_t* day) {
5087  Factory* factory = isolate->factory();
5088
5089  // 1. Assert: Type(fields) is Object.
5090  // 2. Let overflow be ? ToTemporalOverflow(options).
5091  Maybe<ShowOverflow> maybe_overflow =
5092      ToTemporalOverflow(isolate, options, method_name);
5093  MAYBE_RETURN(maybe_overflow, Nothing<bool>());
5094  // 3. Set fields to ? PrepareTemporalFields(fields, « "day", "month",
5095  // "monthCode", "year" », «»).
5096  Handle<FixedArray> field_names = factory->NewFixedArray(4);
5097  field_names->set(0, ReadOnlyRoots(isolate).day_string());
5098  field_names->set(1, ReadOnlyRoots(isolate).month_string());
5099  field_names->set(2, ReadOnlyRoots(isolate).monthCode_string());
5100  field_names->set(3, ReadOnlyRoots(isolate).year_string());
5101  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5102      isolate, fields,
5103      PrepareTemporalFields(isolate, fields, field_names,
5104                            RequiredFields::kNone),
5105      Nothing<bool>());
5106
5107  // 4. Let year be ? Get(fields, "year").
5108  Handle<Object> year_obj;
5109  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5110      isolate, year_obj,
5111      Object::GetPropertyOrElement(isolate, fields, factory->year_string()),
5112      Nothing<bool>());
5113  // 5. If year is undefined, throw a TypeError exception.
5114  if (year_obj->IsUndefined(isolate)) {
5115    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
5116                                 Nothing<bool>());
5117  }
5118  // Note: "year" in fields is always converted by
5119  // ToIntegerThrowOnInfinity inside the PrepareTemporalFields above.
5120  // Therefore the year_obj is always an integer.
5121  DCHECK(year_obj->IsSmi() || year_obj->IsHeapNumber());
5122  *year = FastD2I(year_obj->Number());
5123
5124  // 6. Let month be ? ResolveISOMonth(fields).
5125  Maybe<int32_t> maybe_month = ResolveISOMonth(isolate, fields);
5126  MAYBE_RETURN(maybe_month, Nothing<bool>());
5127  *month = maybe_month.FromJust();
5128
5129  // 7. Let day be ? Get(fields, "day").
5130  Handle<Object> day_obj;
5131  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5132      isolate, day_obj,
5133      Object::GetPropertyOrElement(isolate, fields, factory->day_string()),
5134      Nothing<bool>());
5135  // 8. If day is undefined, throw a TypeError exception.
5136  if (day_obj->IsUndefined(isolate)) {
5137    THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
5138                                 Nothing<bool>());
5139  }
5140  // Note: "day" in fields is always converted by
5141  // ToIntegerThrowOnInfinity inside the PrepareTemporalFields above.
5142  // Therefore the day_obj is always an integer.
5143  DCHECK(day_obj->IsSmi() || day_obj->IsHeapNumber());
5144  *day = FastD2I(day_obj->Number());
5145  // 9. Return ? RegulateISODate(year, month, day, overflow).
5146  return RegulateISODate(isolate, maybe_overflow.FromJust(), *year, month, day);
5147}
5148
5149}  // namespace
5150
5151// #sec-temporal.calendar.prototype.daysinyear
5152MaybeHandle<Smi> JSTemporalCalendar::DaysInYear(
5153    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5154    Handle<Object> temporal_date_like) {
5155  // 1. Let calendar be the this value.
5156  // 2. Perform ? RequireInternalSlot(calendar,
5157  // [[InitializedTemporalCalendar]]).
5158  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5159  // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
5160  // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]] or
5161  // [[InitializedTemporalYearMonth]] internal slot, then
5162  if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
5163    // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
5164    ASSIGN_RETURN_ON_EXCEPTION(
5165        isolate, temporal_date_like,
5166        ToTemporalDate(isolate, temporal_date_like,
5167                       isolate->factory()->NewJSObjectWithNullProto(),
5168                       "Temporal.Calendar.prototype.daysInYear"),
5169        Smi);
5170  }
5171
5172  // a. Let daysInYear be ! ISODaysInYear(temporalDateLike.[[ISOYear]]).
5173  int32_t year;
5174  if (temporal_date_like->IsJSTemporalPlainDate()) {
5175    year = Handle<JSTemporalPlainDate>::cast(temporal_date_like)->iso_year();
5176  } else if (temporal_date_like->IsJSTemporalPlainDateTime()) {
5177    year =
5178        Handle<JSTemporalPlainDateTime>::cast(temporal_date_like)->iso_year();
5179  } else {
5180    DCHECK(temporal_date_like->IsJSTemporalPlainYearMonth());
5181    year =
5182        Handle<JSTemporalPlainYearMonth>::cast(temporal_date_like)->iso_year();
5183  }
5184  int32_t days_in_year = ISODaysInYear(isolate, year);
5185  // 6. Return �(daysInYear).
5186  return handle(Smi::FromInt(days_in_year), isolate);
5187}
5188
5189// #sec-temporal.calendar.prototype.daysinmonth
5190MaybeHandle<Smi> JSTemporalCalendar::DaysInMonth(
5191    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5192    Handle<Object> temporal_date_like) {
5193  // 1 Let calendar be the this value.
5194  // 2. Perform ? RequireInternalSlot(calendar,
5195  // [[InitializedTemporalCalendar]]).
5196  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5197  // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
5198  // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]] or
5199  // [[InitializedTemporalYearMonth]] internal slot, then
5200  if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
5201    // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
5202    ASSIGN_RETURN_ON_EXCEPTION(
5203        isolate, temporal_date_like,
5204        ToTemporalDate(isolate, temporal_date_like,
5205                       isolate->factory()->NewJSObjectWithNullProto(),
5206                       "Temporal.Calendar.prototype.daysInMonth"),
5207        Smi);
5208  }
5209
5210  // 5. Return �(! ISODaysInMonth(temporalDateLike.[[ISOYear]],
5211  // temporalDateLike.[[ISOMonth]])).
5212  int32_t year;
5213  int32_t month;
5214  if (temporal_date_like->IsJSTemporalPlainDate()) {
5215    year = Handle<JSTemporalPlainDate>::cast(temporal_date_like)->iso_year();
5216    month = Handle<JSTemporalPlainDate>::cast(temporal_date_like)->iso_month();
5217  } else if (temporal_date_like->IsJSTemporalPlainDateTime()) {
5218    year =
5219        Handle<JSTemporalPlainDateTime>::cast(temporal_date_like)->iso_year();
5220    month =
5221        Handle<JSTemporalPlainDateTime>::cast(temporal_date_like)->iso_month();
5222  } else {
5223    DCHECK(temporal_date_like->IsJSTemporalPlainYearMonth());
5224    year =
5225        Handle<JSTemporalPlainYearMonth>::cast(temporal_date_like)->iso_year();
5226    month =
5227        Handle<JSTemporalPlainYearMonth>::cast(temporal_date_like)->iso_month();
5228  }
5229  return handle(Smi::FromInt(ISODaysInMonth(isolate, year, month)), isolate);
5230}
5231
5232// #sec-temporal.calendar.prototype.year
5233MaybeHandle<Smi> JSTemporalCalendar::Year(Isolate* isolate,
5234                                          Handle<JSTemporalCalendar> calendar,
5235                                          Handle<Object> temporal_date_like) {
5236  // 1. Let calendar be the this value.
5237  // 2. Perform ? RequireInternalSlot(calendar,
5238  // [[InitializedTemporalCalendar]]).
5239  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5240  // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
5241  // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
5242  // or [[InitializedTemporalYearMonth]]
5243  // internal slot, then
5244  if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
5245    // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
5246    ASSIGN_RETURN_ON_EXCEPTION(
5247        isolate, temporal_date_like,
5248        ToTemporalDate(isolate, temporal_date_like,
5249                       isolate->factory()->NewJSObjectWithNullProto(),
5250                       "Temporal.Calendar.prototype.year"),
5251        Smi);
5252  }
5253
5254  // a. Let year be ! ISOYear(temporalDateLike).
5255  int32_t year;
5256  if (temporal_date_like->IsJSTemporalPlainDate()) {
5257    year = Handle<JSTemporalPlainDate>::cast(temporal_date_like)->iso_year();
5258  } else if (temporal_date_like->IsJSTemporalPlainDateTime()) {
5259    year =
5260        Handle<JSTemporalPlainDateTime>::cast(temporal_date_like)->iso_year();
5261  } else {
5262    DCHECK(temporal_date_like->IsJSTemporalPlainYearMonth());
5263    year =
5264        Handle<JSTemporalPlainYearMonth>::cast(temporal_date_like)->iso_year();
5265  }
5266
5267  // 6. Return �(year).
5268  return handle(Smi::FromInt(year), isolate);
5269}
5270
5271// #sec-temporal.calendar.prototype.dayofyear
5272MaybeHandle<Smi> JSTemporalCalendar::DayOfYear(
5273    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5274    Handle<Object> temporal_date_like) {
5275  // 1. Let calendar be the this value.
5276  // 2. Perform ? RequireInternalSlot(calendar,
5277  // [[InitializedTemporalCalendar]]).
5278  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5279  // 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
5280  Handle<JSTemporalPlainDate> temporal_date;
5281  ASSIGN_RETURN_ON_EXCEPTION(
5282      isolate, temporal_date,
5283      ToTemporalDate(isolate, temporal_date_like,
5284                     isolate->factory()->NewJSObjectWithNullProto(),
5285                     "Temporal.Calendar.prototype.dayOfYear"),
5286      Smi);
5287  // a. Let value be ! ToISODayOfYear(temporalDate.[[ISOYear]],
5288  // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
5289  int32_t value =
5290      ToISODayOfYear(isolate, temporal_date->iso_year(),
5291                     temporal_date->iso_month(), temporal_date->iso_day());
5292  return handle(Smi::FromInt(value), isolate);
5293}
5294
5295// #sec-temporal.calendar.prototype.dayofweek
5296MaybeHandle<Smi> JSTemporalCalendar::DayOfWeek(
5297    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5298    Handle<Object> temporal_date_like) {
5299  // 1. Let calendar be the this value.
5300  // 2. Perform ? RequireInternalSlot(calendar,
5301  // [[InitializedTemporalCalendar]]).
5302  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5303  // 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
5304  Handle<JSTemporalPlainDate> temporal_date;
5305  ASSIGN_RETURN_ON_EXCEPTION(
5306      isolate, temporal_date,
5307      ToTemporalDate(isolate, temporal_date_like,
5308                     isolate->factory()->NewJSObjectWithNullProto(),
5309                     "Temporal.Calendar.prototype.dayOfWeek"),
5310      Smi);
5311  // a. Let value be ! ToISODayOfWeek(temporalDate.[[ISOYear]],
5312  // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
5313  int32_t value =
5314      ToISODayOfWeek(isolate, temporal_date->iso_year(),
5315                     temporal_date->iso_month(), temporal_date->iso_day());
5316  return handle(Smi::FromInt(value), isolate);
5317}
5318
5319// #sec-temporal.calendar.prototype.monthsinyear
5320MaybeHandle<Smi> JSTemporalCalendar::MonthsInYear(
5321    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5322    Handle<Object> temporal_date_like) {
5323  // 1. Let calendar be the this value.
5324  // 2. Perform ? RequireInternalSlot(calendar,
5325  // [[InitializedTemporalCalendar]]).
5326  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5327  // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
5328  // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], or
5329  // [[InitializedTemporalYearMonth]] internal slot, then
5330  if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
5331    // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
5332    ASSIGN_RETURN_ON_EXCEPTION(
5333        isolate, temporal_date_like,
5334        ToTemporalDate(isolate, temporal_date_like,
5335                       isolate->factory()->NewJSObjectWithNullProto(),
5336                       "Temporal.Calendar.prototype.monthsInYear"),
5337        Smi);
5338  }
5339
5340  // a. a. Let monthsInYear be 12.
5341  int32_t months_in_year = 12;
5342  // 6. Return �(monthsInYear).
5343  return handle(Smi::FromInt(months_in_year), isolate);
5344}
5345
5346// #sec-temporal.calendar.prototype.inleapyear
5347MaybeHandle<Oddball> JSTemporalCalendar::InLeapYear(
5348    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5349    Handle<Object> temporal_date_like) {
5350  // 1. Let calendar be the this value.
5351  // 2. Perform ? RequireInternalSlot(calendar,
5352  // [[InitializedTemporalCalendar]]).
5353  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5354  // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
5355  // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], or
5356  // [[InitializedTemporalYearMonth]] internal slot, then
5357  if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
5358    // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
5359    ASSIGN_RETURN_ON_EXCEPTION(
5360        isolate, temporal_date_like,
5361        ToTemporalDate(isolate, temporal_date_like,
5362                       isolate->factory()->NewJSObjectWithNullProto(),
5363                       "Temporal.Calendar.prototype.inLeapYear"),
5364        Oddball);
5365  }
5366
5367  // a. Let inLeapYear be ! IsISOLeapYear(temporalDateLike.[[ISOYear]]).
5368  int32_t year;
5369  if (temporal_date_like->IsJSTemporalPlainDate()) {
5370    year = Handle<JSTemporalPlainDate>::cast(temporal_date_like)->iso_year();
5371  } else if (temporal_date_like->IsJSTemporalPlainDateTime()) {
5372    year =
5373        Handle<JSTemporalPlainDateTime>::cast(temporal_date_like)->iso_year();
5374  } else {
5375    DCHECK(temporal_date_like->IsJSTemporalPlainYearMonth());
5376    year =
5377        Handle<JSTemporalPlainYearMonth>::cast(temporal_date_like)->iso_year();
5378  }
5379  return isolate->factory()->ToBoolean(IsISOLeapYear(isolate, year));
5380}
5381
5382// #sec-temporal.calendar.prototype.daysinweek
5383MaybeHandle<Smi> JSTemporalCalendar::DaysInWeek(
5384    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5385    Handle<Object> temporal_date_like) {
5386  // 1. Let calendar be the this value.
5387  // 2. Perform ? RequireInternalSlot(calendar,
5388  // [[InitializedTemporalCalendar]]).
5389  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5390  // 4. Perform ? ToTemporalDate(temporalDateLike).
5391  Handle<JSTemporalPlainDate> date;
5392  ASSIGN_RETURN_ON_EXCEPTION(
5393      isolate, date,
5394      ToTemporalDate(isolate, temporal_date_like,
5395                     isolate->factory()->NewJSObjectWithNullProto(),
5396                     "Temporal.Calendar.prototype.daysInWeek"),
5397      Smi);
5398  // 5. Return 7�.
5399  return handle(Smi::FromInt(7), isolate);
5400}
5401
5402// #sec-temporal.calendar.prototype.datefromfields
5403MaybeHandle<JSTemporalPlainDate> JSTemporalCalendar::DateFromFields(
5404    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5405    Handle<Object> fields_obj, Handle<Object> options_obj) {
5406  // 1. Let calendar be the this value.
5407  // 2. Perform ? RequireInternalSlot(calendar,
5408  // [[InitializedTemporalCalendar]]).
5409  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5410  // 4. If Type(fields) is not Object, throw a TypeError exception.
5411  const char* method_name = "Temporal.Calendar.prototype.dateFromFields";
5412  if (!fields_obj->IsJSReceiver()) {
5413    THROW_NEW_ERROR(isolate,
5414                    NewTypeError(MessageTemplate::kCalledOnNonObject,
5415                                 isolate->factory()->NewStringFromAsciiChecked(
5416                                     method_name)),
5417                    JSTemporalPlainDate);
5418  }
5419  Handle<JSReceiver> fields = Handle<JSReceiver>::cast(fields_obj);
5420
5421  // 5. Set options to ? GetOptionsObject(options).
5422  Handle<JSReceiver> options;
5423  ASSIGN_RETURN_ON_EXCEPTION(
5424      isolate, options, GetOptionsObject(isolate, options_obj, method_name),
5425      JSTemporalPlainDate);
5426  if (calendar->calendar_index() == 0) {
5427    int32_t year;
5428    int32_t month;
5429    int32_t day;
5430    // 6. Let result be ? ISODateFromFields(fields, options).
5431    Maybe<bool> maybe_result = ISODateFromFields(
5432        isolate, fields, options, method_name, &year, &month, &day);
5433    MAYBE_RETURN(maybe_result, Handle<JSTemporalPlainDate>());
5434    DCHECK(maybe_result.FromJust());
5435    // 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
5436    // result.[[Day]], calendar).
5437    return CreateTemporalDate(isolate, year, month, day, calendar);
5438  }
5439  // TODO(ftang) add intl implementation inside #ifdef V8_INTL_SUPPORT
5440  UNREACHABLE();
5441}
5442
5443// #sec-temporal.calendar.prototype.mergefields
5444MaybeHandle<JSReceiver> JSTemporalCalendar::MergeFields(
5445    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5446    Handle<Object> fields_obj, Handle<Object> additional_fields_obj) {
5447  // 1. Let calendar be the this value.
5448  // 2. Perform ? RequireInternalSlot(calendar,
5449  // [[InitializedTemporalCalendar]]).
5450  // 3. Assert: calendar.[[Identifier]] is "iso8601".
5451  // 4. Set fields to ? ToObject(fields).
5452  Handle<JSReceiver> fields;
5453  ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
5454                             Object::ToObject(isolate, fields_obj), JSReceiver);
5455
5456  // 5. Set additionalFields to ? ToObject(additionalFields).
5457  Handle<JSReceiver> additional_fields;
5458  ASSIGN_RETURN_ON_EXCEPTION(isolate, additional_fields,
5459                             Object::ToObject(isolate, additional_fields_obj),
5460                             JSReceiver);
5461  // 5. If calendar.[[Identifier]] is "iso8601", then
5462  if (calendar->calendar_index() == 0) {
5463    // a. Return ? DefaultMergeFields(fields, additionalFields).
5464    return DefaultMergeFields(isolate, fields, additional_fields);
5465  }
5466#ifdef V8_INTL_SUPPORT
5467  // TODO(ftang) add Intl code.
5468#endif  // V8_INTL_SUPPORT
5469  UNREACHABLE();
5470}
5471
5472// #sec-temporal.calendar.prototype.tostring
5473MaybeHandle<String> JSTemporalCalendar::ToString(
5474    Isolate* isolate, Handle<JSTemporalCalendar> calendar,
5475    const char* method_name) {
5476  return CalendarIdentifier(isolate, calendar->calendar_index());
5477}
5478
5479// #sec-temporal.now.timezone
5480MaybeHandle<JSTemporalTimeZone> JSTemporalTimeZone::Now(Isolate* isolate) {
5481  return SystemTimeZone(isolate);
5482}
5483
5484// #sec-temporal.timezone
5485MaybeHandle<JSTemporalTimeZone> JSTemporalTimeZone::Constructor(
5486    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
5487    Handle<Object> identifier_obj) {
5488  // 1. If NewTarget is undefined, then
5489  if (new_target->IsUndefined(isolate)) {
5490    // a. Throw a TypeError exception.
5491    THROW_NEW_ERROR(isolate,
5492                    NewTypeError(MessageTemplate::kConstructorNotFunction,
5493                                 isolate->factory()->NewStringFromAsciiChecked(
5494                                     "Temporal.TimeZone")),
5495                    JSTemporalTimeZone);
5496  }
5497  // 2. Set identifier to ? ToString(identifier).
5498  Handle<String> identifier;
5499  ASSIGN_RETURN_ON_EXCEPTION(isolate, identifier,
5500                             Object::ToString(isolate, identifier_obj),
5501                             JSTemporalTimeZone);
5502  Handle<String> canonical;
5503  // 3. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset
5504  // (see 13.33), then
5505  Maybe<bool> maybe_valid =
5506      IsValidTimeZoneNumericUTCOffsetString(isolate, identifier);
5507  MAYBE_RETURN(maybe_valid, Handle<JSTemporalTimeZone>());
5508
5509  if (maybe_valid.FromJust()) {
5510    // a. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(identifier).
5511    Maybe<int64_t> maybe_offset_nanoseconds =
5512        ParseTimeZoneOffsetString(isolate, identifier);
5513    MAYBE_RETURN(maybe_offset_nanoseconds, Handle<JSTemporalTimeZone>());
5514    int64_t offset_nanoseconds = maybe_offset_nanoseconds.FromJust();
5515
5516    // b. Let canonical be ! FormatTimeZoneOffsetString(offsetNanoseconds).
5517    ASSIGN_RETURN_ON_EXCEPTION(
5518        isolate, canonical,
5519        FormatTimeZoneOffsetString(isolate, offset_nanoseconds),
5520        JSTemporalTimeZone);
5521  } else {
5522    // 4. Else,
5523    // a. If ! IsValidTimeZoneName(identifier) is false, then
5524    if (!IsValidTimeZoneName(isolate, identifier)) {
5525      // i. Throw a RangeError exception.
5526      THROW_NEW_ERROR(
5527          isolate, NewRangeError(MessageTemplate::kInvalidTimeZone, identifier),
5528          JSTemporalTimeZone);
5529    }
5530    // b. Let canonical be ! CanonicalizeTimeZoneName(identifier).
5531    ASSIGN_RETURN_ON_EXCEPTION(isolate, canonical,
5532                               CanonicalizeTimeZoneName(isolate, identifier),
5533                               JSTemporalTimeZone);
5534  }
5535  // 5. Return ? CreateTemporalTimeZone(canonical, NewTarget).
5536  return CreateTemporalTimeZone(isolate, target, new_target, canonical);
5537}
5538
5539// #sec-temporal.timezone.prototype.tostring
5540MaybeHandle<Object> JSTemporalTimeZone::ToString(
5541    Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
5542    const char* method_name) {
5543  return time_zone->id(isolate);
5544}
5545
5546int32_t JSTemporalTimeZone::time_zone_index() const {
5547  DCHECK(is_offset() == false);
5548  return offset_milliseconds_or_time_zone_index();
5549}
5550
5551int64_t JSTemporalTimeZone::offset_nanoseconds() const {
5552  TEMPORAL_ENTER_FUNC();
5553  DCHECK(is_offset());
5554  return 1000000L * offset_milliseconds() + offset_sub_milliseconds();
5555}
5556
5557void JSTemporalTimeZone::set_offset_nanoseconds(int64_t ns) {
5558  this->set_offset_milliseconds(static_cast<int32_t>(ns / 1000000L));
5559  this->set_offset_sub_milliseconds(static_cast<int32_t>(ns % 1000000L));
5560}
5561
5562MaybeHandle<String> JSTemporalTimeZone::id(Isolate* isolate) const {
5563  if (is_offset()) {
5564    return FormatTimeZoneOffsetString(isolate, offset_nanoseconds());
5565  }
5566#ifdef V8_INTL_SUPPORT
5567  std::string id =
5568      Intl::TimeZoneIdFromIndex(offset_milliseconds_or_time_zone_index());
5569  return isolate->factory()->NewStringFromAsciiChecked(id.c_str());
5570#else   // V8_INTL_SUPPORT
5571  DCHECK_EQ(0, offset_milliseconds_or_time_zone_index());
5572  return isolate->factory()->UTC_string();
5573#endif  // V8_INTL_SUPPORT
5574}
5575
5576MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::Constructor(
5577    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
5578    Handle<Object> iso_year_obj, Handle<Object> iso_month_obj,
5579    Handle<Object> iso_day_obj, Handle<Object> calendar_like) {
5580  const char* method_name = "Temporal.PlainDate";
5581  // 1. If NewTarget is undefined, throw a TypeError exception.
5582  if (new_target->IsUndefined()) {
5583    THROW_NEW_ERROR(isolate,
5584                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
5585                                 isolate->factory()->NewStringFromAsciiChecked(
5586                                     method_name)),
5587                    JSTemporalPlainDate);
5588  }
5589#define TO_INT_THROW_ON_INFTY(name, T)                                        \
5590  int32_t name;                                                               \
5591  {                                                                           \
5592    Handle<Object> number_##name;                                             \
5593    /* x. Let name be ? ToIntegerThrowOnInfinity(name). */                    \
5594    ASSIGN_RETURN_ON_EXCEPTION(isolate, number_##name,                        \
5595                               ToIntegerThrowOnInfinity(isolate, name##_obj), \
5596                               T);                                            \
5597    name = NumberToInt32(*number_##name);                                     \
5598  }
5599
5600  TO_INT_THROW_ON_INFTY(iso_year, JSTemporalPlainDate);
5601  TO_INT_THROW_ON_INFTY(iso_month, JSTemporalPlainDate);
5602  TO_INT_THROW_ON_INFTY(iso_day, JSTemporalPlainDate);
5603
5604  // 8. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
5605  Handle<JSReceiver> calendar;
5606  ASSIGN_RETURN_ON_EXCEPTION(
5607      isolate, calendar,
5608      ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name),
5609      JSTemporalPlainDate);
5610
5611  // 9. Return ? CreateTemporalDate(y, m, d, calendar, NewTarget).
5612  return CreateTemporalDate(isolate, target, new_target, iso_year, iso_month,
5613                            iso_day, calendar);
5614}
5615
5616// #sec-temporal.plaindate.prototype.withcalendar
5617MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::WithCalendar(
5618    Isolate* isolate, Handle<JSTemporalPlainDate> temporal_date,
5619    Handle<Object> calendar_like) {
5620  const char* method_name = "Temporal.PlainDate.prototype.withCalendar";
5621  // 1. Let temporalDate be the this value.
5622  // 2. Perform ? RequireInternalSlot(temporalDate,
5623  // [[InitializedTemporalDate]]).
5624  // 3. Let calendar be ? ToTemporalCalendar(calendar).
5625  Handle<JSReceiver> calendar;
5626  ASSIGN_RETURN_ON_EXCEPTION(
5627      isolate, calendar,
5628      temporal::ToTemporalCalendar(isolate, calendar_like, method_name),
5629      JSTemporalPlainDate);
5630  // 4. Return ? CreateTemporalDate(temporalDate.[[ISOYear]],
5631  // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], calendar).
5632  return CreateTemporalDate(isolate, temporal_date->iso_year(),
5633                            temporal_date->iso_month(),
5634                            temporal_date->iso_day(), calendar);
5635}
5636
5637// #sec-temporal.now.plaindate
5638MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::Now(
5639    Isolate* isolate, Handle<Object> calendar_like,
5640    Handle<Object> temporal_time_zone_like) {
5641  const char* method_name = "Temporal.Now.plainDate";
5642  // 1. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendarLike).
5643  Handle<JSTemporalPlainDateTime> date_time;
5644  ASSIGN_RETURN_ON_EXCEPTION(isolate, date_time,
5645                             SystemDateTime(isolate, temporal_time_zone_like,
5646                                            calendar_like, method_name),
5647                             JSTemporalPlainDate);
5648  // 2. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
5649  // dateTime.[[ISODay]], dateTime.[[Calendar]]).
5650  return CreateTemporalDate(isolate, date_time->iso_year(),
5651                            date_time->iso_month(), date_time->iso_day(),
5652                            Handle<JSReceiver>(date_time->calendar(), isolate));
5653}
5654
5655// #sec-temporal.now.plaindateiso
5656MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::NowISO(
5657    Isolate* isolate, Handle<Object> temporal_time_zone_like) {
5658  const char* method_name = "Temporal.Now.plainDateISO";
5659  // 1. Let calendar be ! GetISO8601Calendar().
5660  Handle<JSReceiver> calendar;
5661  ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar,
5662                             temporal::GetISO8601Calendar(isolate),
5663                             JSTemporalPlainDate);
5664  // 2. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendar).
5665  Handle<JSTemporalPlainDateTime> date_time;
5666  ASSIGN_RETURN_ON_EXCEPTION(
5667      isolate, date_time,
5668      SystemDateTime(isolate, temporal_time_zone_like, calendar, method_name),
5669      JSTemporalPlainDate);
5670  // 3. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
5671  // dateTime.[[ISODay]], dateTime.[[Calendar]]).
5672  return CreateTemporalDate(isolate, date_time->iso_year(),
5673                            date_time->iso_month(), date_time->iso_day(),
5674                            Handle<JSReceiver>(date_time->calendar(), isolate));
5675}
5676
5677// #sec-temporal.plaindate.from
5678MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::From(
5679    Isolate* isolate, Handle<Object> item, Handle<Object> options_obj) {
5680  const char* method_name = "Temporal.PlainDate.from";
5681  // 1. Set options to ? GetOptionsObject(options).
5682  Handle<JSReceiver> options;
5683  ASSIGN_RETURN_ON_EXCEPTION(
5684      isolate, options, GetOptionsObject(isolate, options_obj, method_name),
5685      JSTemporalPlainDate);
5686  // 2. If Type(item) is Object and item has an [[InitializedTemporalDate]]
5687  // internal slot, then
5688  if (item->IsJSTemporalPlainDate()) {
5689    // a. Perform ? ToTemporalOverflow(options).
5690    Maybe<ShowOverflow> maybe_overflow =
5691        ToTemporalOverflow(isolate, options, method_name);
5692    MAYBE_RETURN(maybe_overflow, Handle<JSTemporalPlainDate>());
5693    // b. Return ? CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
5694    // item.[[ISODay]], item.[[Calendar]]).
5695    Handle<JSTemporalPlainDate> date = Handle<JSTemporalPlainDate>::cast(item);
5696    return CreateTemporalDate(isolate, date->iso_year(), date->iso_month(),
5697                              date->iso_day(),
5698                              Handle<JSReceiver>(date->calendar(), isolate));
5699  }
5700  // 3. Return ? ToTemporalDate(item, options).
5701  return ToTemporalDate(isolate, item, options, method_name);
5702}
5703
5704#define DEFINE_INT_FIELD(obj, str, field, item)                \
5705  CHECK(JSReceiver::CreateDataProperty(                        \
5706            isolate, obj, factory->str##_string(),             \
5707            Handle<Smi>(Smi::FromInt(item->field()), isolate), \
5708            Just(kThrowOnError))                               \
5709            .FromJust());
5710
5711// #sec-temporal.plaindate.prototype.getisofields
5712MaybeHandle<JSReceiver> JSTemporalPlainDate::GetISOFields(
5713    Isolate* isolate, Handle<JSTemporalPlainDate> temporal_date) {
5714  Factory* factory = isolate->factory();
5715  // 1. Let temporalDate be the this value.
5716  // 2. Perform ? RequireInternalSlot(temporalDate,
5717  // [[InitializedTemporalDate]]).
5718  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
5719  Handle<JSObject> fields =
5720      isolate->factory()->NewJSObject(isolate->object_function());
5721  // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
5722  // temporalDate.[[Calendar]]).
5723  CHECK(JSReceiver::CreateDataProperty(
5724            isolate, fields, factory->calendar_string(),
5725            Handle<JSReceiver>(temporal_date->calendar(), isolate),
5726            Just(kThrowOnError))
5727            .FromJust());
5728  // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
5729  // �(temporalDate.[[ISODay]])).
5730  // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
5731  // �(temporalDate.[[ISOMonth]])).
5732  // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
5733  // �(temporalDate.[[ISOYear]])).
5734  DEFINE_INT_FIELD(fields, isoDay, iso_day, temporal_date)
5735  DEFINE_INT_FIELD(fields, isoMonth, iso_month, temporal_date)
5736  DEFINE_INT_FIELD(fields, isoYear, iso_year, temporal_date)
5737  // 8. Return fields.
5738  return fields;
5739}
5740
5741// #sec-temporal-createtemporaldatetime
5742MaybeHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Constructor(
5743    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
5744    Handle<Object> iso_year_obj, Handle<Object> iso_month_obj,
5745    Handle<Object> iso_day_obj, Handle<Object> hour_obj,
5746    Handle<Object> minute_obj, Handle<Object> second_obj,
5747    Handle<Object> millisecond_obj, Handle<Object> microsecond_obj,
5748    Handle<Object> nanosecond_obj, Handle<Object> calendar_like) {
5749  const char* method_name = "Temporal.PlainDateTime";
5750  // 1. If NewTarget is undefined, throw a TypeError exception.
5751  if (new_target->IsUndefined()) {
5752    THROW_NEW_ERROR(isolate,
5753                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
5754                                 isolate->factory()->NewStringFromAsciiChecked(
5755                                     method_name)),
5756                    JSTemporalPlainDateTime);
5757  }
5758
5759  TO_INT_THROW_ON_INFTY(iso_year, JSTemporalPlainDateTime);
5760  TO_INT_THROW_ON_INFTY(iso_month, JSTemporalPlainDateTime);
5761  TO_INT_THROW_ON_INFTY(iso_day, JSTemporalPlainDateTime);
5762  TO_INT_THROW_ON_INFTY(hour, JSTemporalPlainDateTime);
5763  TO_INT_THROW_ON_INFTY(minute, JSTemporalPlainDateTime);
5764  TO_INT_THROW_ON_INFTY(second, JSTemporalPlainDateTime);
5765  TO_INT_THROW_ON_INFTY(millisecond, JSTemporalPlainDateTime);
5766  TO_INT_THROW_ON_INFTY(microsecond, JSTemporalPlainDateTime);
5767  TO_INT_THROW_ON_INFTY(nanosecond, JSTemporalPlainDateTime);
5768
5769  // 20. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
5770  Handle<JSReceiver> calendar;
5771  ASSIGN_RETURN_ON_EXCEPTION(
5772      isolate, calendar,
5773      ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name),
5774      JSTemporalPlainDateTime);
5775
5776  // 21. Return ? CreateTemporalDateTime(isoYear, isoMonth, isoDay, hour,
5777  // minute, second, millisecond, microsecond, nanosecond, calendar, NewTarget).
5778  return CreateTemporalDateTime(isolate, target, new_target, iso_year,
5779                                iso_month, iso_day, hour, minute, second,
5780                                millisecond, microsecond, nanosecond, calendar);
5781}
5782
5783// #sec-temporal.plaindatetime.prototype.withcalendar
5784MaybeHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::WithCalendar(
5785    Isolate* isolate, Handle<JSTemporalPlainDateTime> date_time,
5786    Handle<Object> calendar_like) {
5787  const char* method_name = "Temporal.PlainDateTime.prototype.withCalendar";
5788  // 1. Let temporalDateTime be the this value.
5789  // 2. Perform ? RequireInternalSlot(temporalDateTime,
5790  // [[InitializedTemporalDateTime]]).
5791  // 3. Let calendar be ? ToTemporalCalendar(calendar).
5792  Handle<JSReceiver> calendar;
5793  ASSIGN_RETURN_ON_EXCEPTION(
5794      isolate, calendar,
5795      temporal::ToTemporalCalendar(isolate, calendar_like, method_name),
5796      JSTemporalPlainDateTime);
5797  // 4. Return ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
5798  // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]],
5799  // temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]],
5800  // temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]],
5801  // temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]],
5802  // calendar).
5803  return temporal::CreateTemporalDateTime(
5804      isolate, date_time->iso_year(), date_time->iso_month(),
5805      date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
5806      date_time->iso_second(), date_time->iso_millisecond(),
5807      date_time->iso_microsecond(), date_time->iso_nanosecond(), calendar);
5808}
5809
5810// #sec-temporal.now.plaindatetime
5811MaybeHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Now(
5812    Isolate* isolate, Handle<Object> calendar_like,
5813    Handle<Object> temporal_time_zone_like) {
5814  const char* method_name = "Temporal.Now.plainDateTime";
5815  // 1. Return ? SystemDateTime(temporalTimeZoneLike, calendarLike).
5816  return SystemDateTime(isolate, temporal_time_zone_like, calendar_like,
5817                        method_name);
5818}
5819
5820// #sec-temporal.now.plaindatetimeiso
5821MaybeHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::NowISO(
5822    Isolate* isolate, Handle<Object> temporal_time_zone_like) {
5823  const char* method_name = "Temporal.Now.plainDateTimeISO";
5824  // 1. Let calendar be ! GetISO8601Calendar().
5825  Handle<JSReceiver> calendar;
5826  ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar,
5827                             temporal::GetISO8601Calendar(isolate),
5828                             JSTemporalPlainDateTime);
5829  // 2. Return ? SystemDateTime(temporalTimeZoneLike, calendar).
5830  return SystemDateTime(isolate, temporal_time_zone_like, calendar,
5831                        method_name);
5832}
5833
5834// #sec-temporal.plaindatetime.prototype.getisofields
5835MaybeHandle<JSReceiver> JSTemporalPlainDateTime::GetISOFields(
5836    Isolate* isolate, Handle<JSTemporalPlainDateTime> date_time) {
5837  Factory* factory = isolate->factory();
5838  // 1. Let dateTime be the this value.
5839  // 2. Perform ? RequireInternalSlot(temporalDateTime,
5840  // [[InitializedTemporalDateTime]]).
5841  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
5842  Handle<JSObject> fields =
5843      isolate->factory()->NewJSObject(isolate->object_function());
5844  // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
5845  // temporalTime.[[Calendar]]).
5846  CHECK(JSReceiver::CreateDataProperty(
5847            isolate, fields, factory->calendar_string(),
5848            Handle<JSReceiver>(date_time->calendar(), isolate),
5849            Just(kThrowOnError))
5850            .FromJust());
5851  // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
5852  // �(dateTime.[[ISODay]])).
5853  // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
5854  // �(temporalTime.[[ISOHour]])).
5855  // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
5856  // �(temporalTime.[[ISOMicrosecond]])).
5857  // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
5858  // �(temporalTime.[[ISOMillisecond]])).
5859  // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
5860  // �(temporalTime.[[ISOMinute]])).
5861  // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
5862  // �(temporalTime.[[ISOMonth]])).
5863  // 11. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
5864  // �(temporalTime.[[ISONanosecond]])).
5865  // 12. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
5866  // �(temporalTime.[[ISOSecond]])).
5867  // 13. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
5868  // �(temporalTime.[[ISOYear]])).
5869  DEFINE_INT_FIELD(fields, isoDay, iso_day, date_time)
5870  DEFINE_INT_FIELD(fields, isoHour, iso_hour, date_time)
5871  DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, date_time)
5872  DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, date_time)
5873  DEFINE_INT_FIELD(fields, isoMinute, iso_minute, date_time)
5874  DEFINE_INT_FIELD(fields, isoMonth, iso_month, date_time)
5875  DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, date_time)
5876  DEFINE_INT_FIELD(fields, isoSecond, iso_second, date_time)
5877  DEFINE_INT_FIELD(fields, isoYear, iso_year, date_time)
5878  // 14. Return fields.
5879  return fields;
5880}
5881
5882// #sec-temporal.plainmonthday
5883MaybeHandle<JSTemporalPlainMonthDay> JSTemporalPlainMonthDay::Constructor(
5884    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
5885    Handle<Object> iso_month_obj, Handle<Object> iso_day_obj,
5886    Handle<Object> calendar_like, Handle<Object> reference_iso_year_obj) {
5887  const char* method_name = "Temporal.PlainMonthDay";
5888  // 1. If NewTarget is undefined, throw a TypeError exception.
5889  if (new_target->IsUndefined()) {
5890    THROW_NEW_ERROR(isolate,
5891                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
5892                                 isolate->factory()->NewStringFromAsciiChecked(
5893                                     method_name)),
5894                    JSTemporalPlainMonthDay);
5895  }
5896
5897  // 3. Let m be ? ToIntegerThrowOnInfinity(isoMonth).
5898  TO_INT_THROW_ON_INFTY(iso_month, JSTemporalPlainMonthDay);
5899  // 5. Let d be ? ToIntegerThrowOnInfinity(isoDay).
5900  TO_INT_THROW_ON_INFTY(iso_day, JSTemporalPlainMonthDay);
5901  // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
5902  Handle<JSReceiver> calendar;
5903  ASSIGN_RETURN_ON_EXCEPTION(
5904      isolate, calendar,
5905      ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name),
5906      JSTemporalPlainMonthDay);
5907
5908  // 2. If referenceISOYear is undefined, then
5909  // a. Set referenceISOYear to 1972�.
5910  // ...
5911  // 8. Let ref be ? ToIntegerThrowOnInfinity(referenceISOYear).
5912  int32_t ref = 1972;
5913  if (!reference_iso_year_obj->IsUndefined()) {
5914    TO_INT_THROW_ON_INFTY(reference_iso_year, JSTemporalPlainMonthDay);
5915    ref = reference_iso_year;
5916  }
5917
5918  // 10. Return ? CreateTemporalMonthDay(y, m, calendar, ref, NewTarget).
5919  return CreateTemporalMonthDay(isolate, target, new_target, iso_month, iso_day,
5920                                calendar, ref);
5921}
5922
5923// #sec-temporal.plainmonthday.prototype.getisofields
5924MaybeHandle<JSReceiver> JSTemporalPlainMonthDay::GetISOFields(
5925    Isolate* isolate, Handle<JSTemporalPlainMonthDay> month_day) {
5926  Factory* factory = isolate->factory();
5927  // 1. Let monthDay be the this value.
5928  // 2. Perform ? RequireInternalSlot(monthDay,
5929  // [[InitializedTemporalMonthDay]]).
5930  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
5931  Handle<JSObject> fields = factory->NewJSObject(isolate->object_function());
5932  // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
5933  // montyDay.[[Calendar]]).
5934  CHECK(JSReceiver::CreateDataProperty(
5935            isolate, fields, factory->calendar_string(),
5936            Handle<JSReceiver>(month_day->calendar(), isolate),
5937            Just(kThrowOnError))
5938            .FromJust());
5939
5940  // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
5941  // �(montyDay.[[ISODay]])).
5942  // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
5943  // �(montyDay.[[ISOMonth]])).
5944  // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
5945  // �(montyDay.[[ISOYear]])).
5946  DEFINE_INT_FIELD(fields, isoDay, iso_day, month_day)
5947  DEFINE_INT_FIELD(fields, isoMonth, iso_month, month_day)
5948  DEFINE_INT_FIELD(fields, isoYear, iso_year, month_day)
5949  // 8. Return fields.
5950  return fields;
5951}
5952
5953MaybeHandle<JSTemporalPlainYearMonth> JSTemporalPlainYearMonth::Constructor(
5954    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
5955    Handle<Object> iso_year_obj, Handle<Object> iso_month_obj,
5956    Handle<Object> calendar_like, Handle<Object> reference_iso_day_obj) {
5957  const char* method_name = "Temporal.PlainYearMonth";
5958  // 1. If NewTarget is undefined, throw a TypeError exception.
5959  if (new_target->IsUndefined()) {
5960    THROW_NEW_ERROR(isolate,
5961                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
5962                                 isolate->factory()->NewStringFromAsciiChecked(
5963                                     method_name)),
5964                    JSTemporalPlainYearMonth);
5965  }
5966  // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
5967  // 10. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget).
5968
5969  // 3. Let y be ? ToIntegerThrowOnInfinity(isoYear).
5970  TO_INT_THROW_ON_INFTY(iso_year, JSTemporalPlainYearMonth);
5971  // 5. Let m be ? ToIntegerThrowOnInfinity(isoMonth).
5972  TO_INT_THROW_ON_INFTY(iso_month, JSTemporalPlainYearMonth);
5973  // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
5974  Handle<JSReceiver> calendar;
5975  ASSIGN_RETURN_ON_EXCEPTION(
5976      isolate, calendar,
5977      ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name),
5978      JSTemporalPlainYearMonth);
5979
5980  // 2. If referenceISODay is undefined, then
5981  // a. Set referenceISODay to 1�.
5982  // ...
5983  // 8. Let ref be ? ToIntegerThrowOnInfinity(referenceISODay).
5984  int32_t ref = 1;
5985  if (!reference_iso_day_obj->IsUndefined()) {
5986    TO_INT_THROW_ON_INFTY(reference_iso_day, JSTemporalPlainYearMonth);
5987    ref = reference_iso_day;
5988  }
5989
5990  // 10. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget).
5991  return CreateTemporalYearMonth(isolate, target, new_target, iso_year,
5992                                 iso_month, calendar, ref);
5993}
5994
5995// #sec-temporal.plainyearmonth.prototype.getisofields
5996MaybeHandle<JSReceiver> JSTemporalPlainYearMonth::GetISOFields(
5997    Isolate* isolate, Handle<JSTemporalPlainYearMonth> year_month) {
5998  Factory* factory = isolate->factory();
5999  // 1. Let yearMonth be the this value.
6000  // 2. Perform ? RequireInternalSlot(yearMonth,
6001  // [[InitializedTemporalYearMonth]]).
6002  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
6003  Handle<JSObject> fields =
6004      isolate->factory()->NewJSObject(isolate->object_function());
6005  // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
6006  // yearMonth.[[Calendar]]).
6007  CHECK(JSReceiver::CreateDataProperty(
6008            isolate, fields, factory->calendar_string(),
6009            Handle<JSReceiver>(year_month->calendar(), isolate),
6010            Just(kThrowOnError))
6011            .FromJust());
6012  // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
6013  // �(yearMonth.[[ISODay]])).
6014  // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
6015  // �(yearMonth.[[ISOMonth]])).
6016  // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
6017  // �(yearMonth.[[ISOYear]])).
6018  DEFINE_INT_FIELD(fields, isoDay, iso_day, year_month)
6019  DEFINE_INT_FIELD(fields, isoMonth, iso_month, year_month)
6020  DEFINE_INT_FIELD(fields, isoYear, iso_year, year_month)
6021  // 8. Return fields.
6022  return fields;
6023}
6024
6025// #sec-temporal-plaintime-constructor
6026MaybeHandle<JSTemporalPlainTime> JSTemporalPlainTime::Constructor(
6027    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
6028    Handle<Object> hour_obj, Handle<Object> minute_obj,
6029    Handle<Object> second_obj, Handle<Object> millisecond_obj,
6030    Handle<Object> microsecond_obj, Handle<Object> nanosecond_obj) {
6031  const char* method_name = "Temporal.PlainTime";
6032  // 1. If NewTarget is undefined, then
6033  // a. Throw a TypeError exception.
6034  if (new_target->IsUndefined()) {
6035    // a. Throw a TypeError exception.
6036    THROW_NEW_ERROR(isolate,
6037                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
6038                                 isolate->factory()->NewStringFromAsciiChecked(
6039                                     method_name)),
6040                    JSTemporalPlainTime);
6041  }
6042
6043  TO_INT_THROW_ON_INFTY(hour, JSTemporalPlainTime);
6044  TO_INT_THROW_ON_INFTY(minute, JSTemporalPlainTime);
6045  TO_INT_THROW_ON_INFTY(second, JSTemporalPlainTime);
6046  TO_INT_THROW_ON_INFTY(millisecond, JSTemporalPlainTime);
6047  TO_INT_THROW_ON_INFTY(microsecond, JSTemporalPlainTime);
6048  TO_INT_THROW_ON_INFTY(nanosecond, JSTemporalPlainTime);
6049
6050  // 14. Return ? CreateTemporalTime(hour, minute, second, millisecond,
6051  // microsecond, nanosecond, NewTarget).
6052  return CreateTemporalTime(isolate, target, new_target, hour, minute, second,
6053                            millisecond, microsecond, nanosecond);
6054}
6055
6056// #sec-temporal.now.plaintimeiso
6057MaybeHandle<JSTemporalPlainTime> JSTemporalPlainTime::NowISO(
6058    Isolate* isolate, Handle<Object> temporal_time_zone_like) {
6059  const char* method_name = "Temporal.Now.plainTimeISO";
6060  // 1. Let calendar be ! GetISO8601Calendar().
6061  Handle<JSReceiver> calendar;
6062  ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar,
6063                             temporal::GetISO8601Calendar(isolate),
6064                             JSTemporalPlainTime);
6065  // 2. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendar).
6066  Handle<JSTemporalPlainDateTime> date_time;
6067  ASSIGN_RETURN_ON_EXCEPTION(
6068      isolate, date_time,
6069      SystemDateTime(isolate, temporal_time_zone_like, calendar, method_name),
6070      JSTemporalPlainTime);
6071  // 3. Return ! CreateTemporalTime(dateTime.[[ISOHour]],
6072  // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
6073  // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
6074  // dateTime.[[ISONanosecond]]).
6075  return CreateTemporalTime(
6076      isolate, date_time->iso_hour(), date_time->iso_minute(),
6077      date_time->iso_second(), date_time->iso_millisecond(),
6078      date_time->iso_microsecond(), date_time->iso_nanosecond());
6079}
6080
6081// #sec-temporal.plaintime.from
6082MaybeHandle<JSTemporalPlainTime> JSTemporalPlainTime::From(
6083    Isolate* isolate, Handle<Object> item_obj, Handle<Object> options_obj) {
6084  const char* method_name = "Temporal.PlainTime.from";
6085  // 1. Set options to ? GetOptionsObject(options).
6086  Handle<JSReceiver> options;
6087  ASSIGN_RETURN_ON_EXCEPTION(
6088      isolate, options, GetOptionsObject(isolate, options_obj, method_name),
6089      JSTemporalPlainTime);
6090  // 2. Let overflow be ? ToTemporalOverflow(options).
6091  Maybe<ShowOverflow> maybe_overflow =
6092      ToTemporalOverflow(isolate, options, method_name);
6093  MAYBE_RETURN(maybe_overflow, Handle<JSTemporalPlainTime>());
6094  ShowOverflow overflow = maybe_overflow.FromJust();
6095  // 3. If Type(item) is Object and item has an [[InitializedTemporalTime]]
6096  // internal slot, then
6097  if (item_obj->IsJSTemporalPlainTime()) {
6098    // a. Return ? CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]],
6099    // item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]],
6100    // item.[[ISONanosecond]]).
6101    Handle<JSTemporalPlainTime> item =
6102        Handle<JSTemporalPlainTime>::cast(item_obj);
6103    return CreateTemporalTime(isolate, item->iso_hour(), item->iso_minute(),
6104                              item->iso_second(), item->iso_millisecond(),
6105                              item->iso_microsecond(), item->iso_nanosecond());
6106  }
6107  // 4. Return ? ToTemporalTime(item, overflow).
6108  return temporal::ToTemporalTime(isolate, item_obj, overflow, method_name);
6109}
6110
6111// #sec-temporal.plaintime.prototype.getisofields
6112MaybeHandle<JSReceiver> JSTemporalPlainTime::GetISOFields(
6113    Isolate* isolate, Handle<JSTemporalPlainTime> temporal_time) {
6114  Factory* factory = isolate->factory();
6115  // 1. Let temporalTime be the this value.
6116  // 2. Perform ? RequireInternalSlot(temporalTime,
6117  // [[InitializedTemporalTime]]).
6118  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
6119  Handle<JSObject> fields =
6120      isolate->factory()->NewJSObject(isolate->object_function());
6121  // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
6122  // temporalTime.[[Calendar]]).
6123  Handle<JSTemporalCalendar> iso8601_calendar;
6124  ASSIGN_RETURN_ON_EXCEPTION(isolate, iso8601_calendar,
6125                             temporal::GetISO8601Calendar(isolate),
6126                             JSTemporalPlainTime);
6127  CHECK(JSReceiver::CreateDataProperty(isolate, fields,
6128                                       factory->calendar_string(),
6129                                       iso8601_calendar, Just(kThrowOnError))
6130            .FromJust());
6131
6132  // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
6133  // �(temporalTime.[[ISOHour]])).
6134  // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
6135  // �(temporalTime.[[ISOMicrosecond]])).
6136  // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
6137  // �(temporalTime.[[ISOMillisecond]])).
6138  // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
6139  // �(temporalTime.[[ISOMinute]])).
6140  // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
6141  // �(temporalTime.[[ISONanosecond]])).
6142  // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
6143  // �(temporalTime.[[ISOSecond]])).
6144  DEFINE_INT_FIELD(fields, isoHour, iso_hour, temporal_time)
6145  DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, temporal_time)
6146  DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, temporal_time)
6147  DEFINE_INT_FIELD(fields, isoMinute, iso_minute, temporal_time)
6148  DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, temporal_time)
6149  DEFINE_INT_FIELD(fields, isoSecond, iso_second, temporal_time)
6150  // 11. Return fields.
6151  return fields;
6152}
6153
6154// #sec-temporal.zoneddatetime
6155MaybeHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Constructor(
6156    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
6157    Handle<Object> epoch_nanoseconds_obj, Handle<Object> time_zone_like,
6158    Handle<Object> calendar_like) {
6159  const char* method_name = "Temporal.ZonedDateTime";
6160  // 1. If NewTarget is undefined, then
6161  if (new_target->IsUndefined()) {
6162    // a. Throw a TypeError exception.
6163    THROW_NEW_ERROR(isolate,
6164                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
6165                                 isolate->factory()->NewStringFromAsciiChecked(
6166                                     method_name)),
6167                    JSTemporalZonedDateTime);
6168  }
6169  // 2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
6170  Handle<BigInt> epoch_nanoseconds;
6171  ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_nanoseconds,
6172                             BigInt::FromObject(isolate, epoch_nanoseconds_obj),
6173                             JSTemporalZonedDateTime);
6174  // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
6175  // RangeError exception.
6176  if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
6177    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
6178                    JSTemporalZonedDateTime);
6179  }
6180
6181  // 4. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
6182  Handle<JSReceiver> time_zone;
6183  ASSIGN_RETURN_ON_EXCEPTION(
6184      isolate, time_zone,
6185      temporal::ToTemporalTimeZone(isolate, time_zone_like, method_name),
6186      JSTemporalZonedDateTime);
6187
6188  // 5. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
6189  Handle<JSReceiver> calendar;
6190  ASSIGN_RETURN_ON_EXCEPTION(
6191      isolate, calendar,
6192      ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name),
6193      JSTemporalZonedDateTime);
6194
6195  // 6. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
6196  // calendar, NewTarget).
6197  return CreateTemporalZonedDateTime(isolate, target, new_target,
6198                                     epoch_nanoseconds, time_zone, calendar);
6199}
6200
6201// #sec-temporal.zoneddatetime.prototype.withcalendar
6202MaybeHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::WithCalendar(
6203    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time,
6204    Handle<Object> calendar_like) {
6205  TEMPORAL_ENTER_FUNC();
6206  const char* method_name = "Temporal.ZonedDateTime.prototype.withCalendar";
6207  // 1. Let zonedDateTime be the this value.
6208  // 2. Perform ? RequireInternalSlot(zonedDateTime,
6209  // [[InitializedTemporalZonedDateTime]]).
6210  // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
6211  Handle<JSReceiver> calendar;
6212  ASSIGN_RETURN_ON_EXCEPTION(
6213      isolate, calendar,
6214      temporal::ToTemporalCalendar(isolate, calendar_like, method_name),
6215      JSTemporalZonedDateTime);
6216
6217  // 4. Return ? CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]],
6218  // zonedDateTime.[[TimeZone]], calendar).
6219  Handle<BigInt> nanoseconds = handle(zoned_date_time->nanoseconds(), isolate);
6220  Handle<JSReceiver> time_zone = handle(zoned_date_time->time_zone(), isolate);
6221  return CreateTemporalZonedDateTime(isolate, nanoseconds, time_zone, calendar);
6222}
6223
6224// #sec-temporal.zoneddatetime.prototype.withtimezone
6225MaybeHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::WithTimeZone(
6226    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time,
6227    Handle<Object> time_zone_like) {
6228  TEMPORAL_ENTER_FUNC();
6229  const char* method_name = "Temporal.ZonedDateTime.prototype.withTimeZone";
6230  // 1. Let zonedDateTime be the this value.
6231  // 2. Perform ? RequireInternalSlot(zonedDateTime,
6232  // [[InitializedTemporalZonedDateTime]]).
6233  // 3. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
6234  Handle<JSReceiver> time_zone;
6235  ASSIGN_RETURN_ON_EXCEPTION(
6236      isolate, time_zone,
6237      temporal::ToTemporalTimeZone(isolate, time_zone_like, method_name),
6238      JSTemporalZonedDateTime);
6239
6240  // 4. Return ? CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]],
6241  // timeZone, zonedDateTime.[[Calendar]]).
6242  Handle<BigInt> nanoseconds = handle(zoned_date_time->nanoseconds(), isolate);
6243  Handle<JSReceiver> calendar = handle(zoned_date_time->calendar(), isolate);
6244  return CreateTemporalZonedDateTime(isolate, nanoseconds, time_zone, calendar);
6245}
6246
6247// Common code shared by ZonedDateTime.prototype.toPlainYearMonth and
6248// toPlainMonthDay
6249template <typename T,
6250          MaybeHandle<T> (*from_fields_func)(
6251              Isolate*, Handle<JSReceiver>, Handle<JSReceiver>, Handle<Object>)>
6252MaybeHandle<T> ZonedDateTimeToPlainYearMonthOrMonthDay(
6253    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time,
6254    Handle<String> field_name_1, Handle<String> field_name_2,
6255    const char* method_name) {
6256  TEMPORAL_ENTER_FUNC();
6257  Factory* factory = isolate->factory();
6258  // 1. Let zonedDateTime be the this value.
6259  // 2. Perform ? RequireInternalSlot(zonedDateTime,
6260  // [[InitializedTemporalZonedDateTime]]).
6261  // 3. Let timeZone be zonedDateTime.[[TimeZone]].
6262  Handle<JSReceiver> time_zone = handle(zoned_date_time->time_zone(), isolate);
6263  // 4. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
6264  Handle<JSTemporalInstant> instant;
6265  ASSIGN_RETURN_ON_EXCEPTION(
6266      isolate, instant,
6267      temporal::CreateTemporalInstant(
6268          isolate, Handle<BigInt>(zoned_date_time->nanoseconds(), isolate)),
6269      T);
6270  // 5. Let calendar be zonedDateTime.[[Calendar]].
6271  Handle<JSReceiver> calendar = handle(zoned_date_time->calendar(), isolate);
6272  // 6. Let temporalDateTime be ?
6273  // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
6274  Handle<JSTemporalPlainDateTime> temporal_date_time;
6275  ASSIGN_RETURN_ON_EXCEPTION(
6276      isolate, temporal_date_time,
6277      temporal::BuiltinTimeZoneGetPlainDateTimeFor(isolate, time_zone, instant,
6278                                                   calendar, method_name),
6279      T);
6280  // 7. Let fieldNames be ? CalendarFields(calendar, « field_name_1,
6281  // field_name_2 »).
6282  Handle<FixedArray> field_names = factory->NewFixedArray(2);
6283  field_names->set(0, *field_name_1);
6284  field_names->set(1, *field_name_2);
6285  ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
6286                             CalendarFields(isolate, calendar, field_names), T);
6287  // 8. Let fields be ? PrepareTemporalFields(temporalDateTime, fieldNames, «»).
6288  Handle<JSReceiver> fields;
6289  ASSIGN_RETURN_ON_EXCEPTION(
6290      isolate, fields,
6291      PrepareTemporalFields(isolate, temporal_date_time, field_names,
6292                            RequiredFields::kNone),
6293      T);
6294  // 9. Return ? XxxFromFields(calendar, fields).
6295  return from_fields_func(isolate, calendar, fields,
6296                          factory->undefined_value());
6297}
6298
6299// #sec-temporal.zoneddatetime.prototype.toplainyearmonth
6300MaybeHandle<JSTemporalPlainYearMonth> JSTemporalZonedDateTime::ToPlainYearMonth(
6301    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time) {
6302  return ZonedDateTimeToPlainYearMonthOrMonthDay<JSTemporalPlainYearMonth,
6303                                                 YearMonthFromFields>(
6304      isolate, zoned_date_time, isolate->factory()->monthCode_string(),
6305      isolate->factory()->year_string(),
6306      "Temporal.ZonedDateTime.prototype.toPlainYearMonth");
6307}
6308
6309// #sec-temporal.zoneddatetime.prototype.toplainmonthday
6310MaybeHandle<JSTemporalPlainMonthDay> JSTemporalZonedDateTime::ToPlainMonthDay(
6311    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time) {
6312  return ZonedDateTimeToPlainYearMonthOrMonthDay<JSTemporalPlainMonthDay,
6313                                                 MonthDayFromFields>(
6314      isolate, zoned_date_time, isolate->factory()->day_string(),
6315      isolate->factory()->monthCode_string(),
6316      "Temporal.ZonedDateTime.prototype.toPlainMonthDay");
6317}
6318
6319// #sec-temporal.now.zoneddatetime
6320MaybeHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Now(
6321    Isolate* isolate, Handle<Object> calendar_like,
6322    Handle<Object> temporal_time_zone_like) {
6323  const char* method_name = "Temporal.Now.zonedDateTime";
6324  // 1. Return ? SystemZonedDateTime(temporalTimeZoneLike, calendarLike).
6325  return SystemZonedDateTime(isolate, temporal_time_zone_like, calendar_like,
6326                             method_name);
6327}
6328
6329// #sec-temporal.now.zoneddatetimeiso
6330MaybeHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::NowISO(
6331    Isolate* isolate, Handle<Object> temporal_time_zone_like) {
6332  TEMPORAL_ENTER_FUNC();
6333  const char* method_name = "Temporal.Now.zonedDateTimeISO";
6334  // 1. Let calendar be ! GetISO8601Calendar().
6335  Handle<JSReceiver> calendar;
6336  ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar,
6337                             temporal::GetISO8601Calendar(isolate),
6338                             JSTemporalZonedDateTime);
6339  // 2. Return ? SystemZonedDateTime(temporalTimeZoneLike, calendar).
6340  return SystemZonedDateTime(isolate, temporal_time_zone_like, calendar,
6341                             method_name);
6342}
6343
6344// #sec-temporal.zoneddatetime.prototype.getisofields
6345MaybeHandle<JSReceiver> JSTemporalZonedDateTime::GetISOFields(
6346    Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time) {
6347  TEMPORAL_ENTER_FUNC();
6348  const char* method_name = "Temporal.ZonedDateTime.prototype.getISOFields";
6349  Factory* factory = isolate->factory();
6350  // 1. Let zonedDateTime be the this value.
6351  // 2. Perform ? RequireInternalSlot(zonedDateTime,
6352  // [[InitializedTemporalZonedDateTime]]).
6353  // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
6354  Handle<JSObject> fields =
6355      isolate->factory()->NewJSObject(isolate->object_function());
6356  // 4. Let timeZone be zonedDateTime.[[TimeZone]].
6357  Handle<JSReceiver> time_zone =
6358      Handle<JSReceiver>(zoned_date_time->time_zone(), isolate);
6359  // 5. Let instant be ? CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
6360  Handle<JSTemporalInstant> instant;
6361  ASSIGN_RETURN_ON_EXCEPTION(
6362      isolate, instant,
6363      temporal::CreateTemporalInstant(
6364          isolate, Handle<BigInt>(zoned_date_time->nanoseconds(), isolate)),
6365      JSReceiver);
6366
6367  // 6. Let calendar be zonedDateTime.[[Calendar]].
6368  Handle<JSReceiver> calendar =
6369      Handle<JSReceiver>(zoned_date_time->calendar(), isolate);
6370  // 7. Let dateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone,
6371  // instant, calendar).
6372  Handle<JSTemporalPlainDateTime> date_time;
6373  ASSIGN_RETURN_ON_EXCEPTION(
6374      isolate, date_time,
6375      temporal::BuiltinTimeZoneGetPlainDateTimeFor(isolate, time_zone, instant,
6376                                                   calendar, method_name),
6377      JSReceiver);
6378  // 8. Let offset be ? BuiltinTimeZoneGetOffsetStringFor(timeZone, instant).
6379  Handle<String> offset;
6380  ASSIGN_RETURN_ON_EXCEPTION(isolate, offset,
6381                             BuiltinTimeZoneGetOffsetStringFor(
6382                                 isolate, time_zone, instant, method_name),
6383                             JSReceiver);
6384
6385#define DEFINE_STRING_FIELD(obj, str, field)                                  \
6386  CHECK(JSReceiver::CreateDataProperty(isolate, obj, factory->str##_string(), \
6387                                       field, Just(kThrowOnError))            \
6388            .FromJust());
6389
6390  // 9. Perform ! CreateDataPropertyOrThrow(fields, "calendar", calendar).
6391  // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
6392  // �(dateTime.[[ISODay]])).
6393  // 11. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
6394  // �(temporalTime.[[ISOHour]])).
6395  // 12. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
6396  // �(temporalTime.[[ISOMicrosecond]])).
6397  // 13. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
6398  // �(temporalTime.[[ISOMillisecond]])).
6399  // 14. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
6400  // �(temporalTime.[[ISOMinute]])).
6401  // 15. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
6402  // �(temporalTime.[[ISOMonth]])).
6403  // 16. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
6404  // �(temporalTime.[[ISONanosecond]])).
6405  // 17. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
6406  // �(temporalTime.[[ISOSecond]])).
6407  // 18. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
6408  // �(temporalTime.[[ISOYear]])).
6409  // 19. Perform ! CreateDataPropertyOrThrow(fields, "offset", offset).
6410  // 20. Perform ! CreateDataPropertyOrThrow(fields, "timeZone", timeZone).
6411  DEFINE_STRING_FIELD(fields, calendar, calendar)
6412  DEFINE_INT_FIELD(fields, isoDay, iso_day, date_time)
6413  DEFINE_INT_FIELD(fields, isoHour, iso_hour, date_time)
6414  DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, date_time)
6415  DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, date_time)
6416  DEFINE_INT_FIELD(fields, isoMinute, iso_minute, date_time)
6417  DEFINE_INT_FIELD(fields, isoMonth, iso_month, date_time)
6418  DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, date_time)
6419  DEFINE_INT_FIELD(fields, isoSecond, iso_second, date_time)
6420  DEFINE_INT_FIELD(fields, isoYear, iso_year, date_time)
6421  DEFINE_STRING_FIELD(fields, offset, offset)
6422  DEFINE_STRING_FIELD(fields, timeZone, time_zone)
6423  // 21. Return fields.
6424  return fields;
6425}
6426
6427// #sec-temporal.now.instant
6428MaybeHandle<JSTemporalInstant> JSTemporalInstant::Now(Isolate* isolate) {
6429  TEMPORAL_ENTER_FUNC();
6430  return SystemInstant(isolate);
6431}
6432
6433// #sec-temporal.instant
6434MaybeHandle<JSTemporalInstant> JSTemporalInstant::Constructor(
6435    Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target,
6436    Handle<Object> epoch_nanoseconds_obj) {
6437  TEMPORAL_ENTER_FUNC();
6438  const char* method_name = "Temporal.Instant";
6439  // 1. If NewTarget is undefined, then
6440  if (new_target->IsUndefined()) {
6441    // a. Throw a TypeError exception.
6442    THROW_NEW_ERROR(isolate,
6443                    NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
6444                                 isolate->factory()->NewStringFromAsciiChecked(
6445                                     method_name)),
6446                    JSTemporalInstant);
6447  }
6448  // 2. Let epochNanoseconds be ? ToBigInt(epochNanoseconds).
6449  Handle<BigInt> epoch_nanoseconds;
6450  ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_nanoseconds,
6451                             BigInt::FromObject(isolate, epoch_nanoseconds_obj),
6452                             JSTemporalInstant);
6453  // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
6454  // RangeError exception.
6455  if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
6456    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
6457                    JSTemporalInstant);
6458  }
6459  // 4. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).
6460  return temporal::CreateTemporalInstant(isolate, target, new_target,
6461                                         epoch_nanoseconds);
6462}
6463
6464namespace {
6465
6466// The logic in Temporal.Instant.fromEpochSeconds and fromEpochMilliseconds,
6467// are the same except a scaling factor, code all of them into the follow
6468// function.
6469MaybeHandle<JSTemporalInstant> ScaleNumberToNanosecondsVerifyAndMake(
6470    Isolate* isolate, Handle<BigInt> bigint, uint32_t scale) {
6471  TEMPORAL_ENTER_FUNC();
6472  DCHECK(scale == 1 || scale == 1000 || scale == 1000000 ||
6473         scale == 1000000000);
6474  // 2. Let epochNanoseconds be epochXseconds × scaleℤ.
6475  Handle<BigInt> epoch_nanoseconds;
6476  if (scale == 1) {
6477    epoch_nanoseconds = bigint;
6478  } else {
6479    ASSIGN_RETURN_ON_EXCEPTION(
6480        isolate, epoch_nanoseconds,
6481        BigInt::Multiply(isolate, BigInt::FromUint64(isolate, scale), bigint),
6482        JSTemporalInstant);
6483  }
6484  // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
6485  // RangeError exception.
6486  if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
6487    THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
6488                    JSTemporalInstant);
6489  }
6490  return temporal::CreateTemporalInstant(isolate, epoch_nanoseconds);
6491}
6492
6493MaybeHandle<JSTemporalInstant> ScaleNumberToNanosecondsVerifyAndMake(
6494    Isolate* isolate, Handle<Object> epoch_Xseconds, uint32_t scale) {
6495  TEMPORAL_ENTER_FUNC();
6496  // 1. Set epochXseconds to ? ToNumber(epochXseconds).
6497  ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_Xseconds,
6498                             Object::ToNumber(isolate, epoch_Xseconds),
6499                             JSTemporalInstant);
6500  // 2. Set epochMilliseconds to ? NumberToBigInt(epochMilliseconds).
6501  Handle<BigInt> bigint;
6502  ASSIGN_RETURN_ON_EXCEPTION(isolate, bigint,
6503                             BigInt::FromNumber(isolate, epoch_Xseconds),
6504                             JSTemporalInstant);
6505  return ScaleNumberToNanosecondsVerifyAndMake(isolate, bigint, scale);
6506}
6507
6508MaybeHandle<JSTemporalInstant> ScaleToNanosecondsVerifyAndMake(
6509    Isolate* isolate, Handle<Object> epoch_Xseconds, uint32_t scale) {
6510  TEMPORAL_ENTER_FUNC();
6511  // 1. Set epochMicroseconds to ? ToBigInt(epochMicroseconds).
6512  Handle<BigInt> bigint;
6513  ASSIGN_RETURN_ON_EXCEPTION(isolate, bigint,
6514                             BigInt::FromObject(isolate, epoch_Xseconds),
6515                             JSTemporalInstant);
6516  return ScaleNumberToNanosecondsVerifyAndMake(isolate, bigint, scale);
6517}
6518
6519}  // namespace
6520
6521// #sec-temporal.instant.fromepochseconds
6522MaybeHandle<JSTemporalInstant> JSTemporalInstant::FromEpochSeconds(
6523    Isolate* isolate, Handle<Object> epoch_seconds) {
6524  TEMPORAL_ENTER_FUNC();
6525  return ScaleNumberToNanosecondsVerifyAndMake(isolate, epoch_seconds,
6526                                               1000000000);
6527}
6528
6529// #sec-temporal.instant.fromepochmilliseconds
6530MaybeHandle<JSTemporalInstant> JSTemporalInstant::FromEpochMilliseconds(
6531    Isolate* isolate, Handle<Object> epoch_milliseconds) {
6532  TEMPORAL_ENTER_FUNC();
6533  return ScaleNumberToNanosecondsVerifyAndMake(isolate, epoch_milliseconds,
6534                                               1000000);
6535}
6536
6537// #sec-temporal.instant.fromepochmicroseconds
6538MaybeHandle<JSTemporalInstant> JSTemporalInstant::FromEpochMicroseconds(
6539    Isolate* isolate, Handle<Object> epoch_microseconds) {
6540  TEMPORAL_ENTER_FUNC();
6541  return ScaleToNanosecondsVerifyAndMake(isolate, epoch_microseconds, 1000);
6542}
6543
6544// #sec-temporal.instant.fromepochnanoeconds
6545MaybeHandle<JSTemporalInstant> JSTemporalInstant::FromEpochNanoseconds(
6546    Isolate* isolate, Handle<Object> epoch_nanoseconds) {
6547  TEMPORAL_ENTER_FUNC();
6548  return ScaleToNanosecondsVerifyAndMake(isolate, epoch_nanoseconds, 1);
6549}
6550
6551// #sec-temporal.instant.from
6552MaybeHandle<JSTemporalInstant> JSTemporalInstant::From(Isolate* isolate,
6553                                                       Handle<Object> item) {
6554  TEMPORAL_ENTER_FUNC();
6555  const char* method_name = "Temporal.Instant.from";
6556  //  1. If Type(item) is Object and item has an [[InitializedTemporalInstant]]
6557  //  internal slot, then
6558  if (item->IsJSTemporalInstant()) {
6559    // a. Return ? CreateTemporalInstant(item.[[Nanoseconds]]).
6560    return temporal::CreateTemporalInstant(
6561        isolate, handle(JSTemporalInstant::cast(*item).nanoseconds(), isolate));
6562  }
6563  // 2. Return ? ToTemporalInstant(item).
6564  return ToTemporalInstant(isolate, item, method_name);
6565}
6566
6567}  // namespace internal
6568}  // namespace v8
6569