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 
34 namespace v8 {
35 namespace internal {
36 
37 namespace {
38 
39 enum 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
60 struct 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 
72 struct DateRecord {
73   int32_t year;
74   int32_t month;
75   int32_t day;
76   Handle<String> calendar;
77 };
78 
79 struct InstantRecord : public DateTimeRecordCommon {
80   Handle<String> offset_string;
81 };
82 
83 struct DateTimeRecord : public DateTimeRecordCommon {
84   Handle<String> calendar;
85 };
86 
87 struct 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 
100 struct 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 
110 struct TimeZoneRecord {
111   bool z;
112   Handle<String> offset_string;
113   Handle<String> name;
114 };
115 
116 // Options
117 
118 V8_WARN_UNUSED_RESULT Handle<String> UnitToString(Isolate* isolate, Unit unit);
119 
120 // #sec-temporal-totemporaldisambiguation
121 enum class Disambiguation { kCompatible, kEarlier, kLater, kReject };
122 
123 // #sec-temporal-totemporaloverflow
124 enum class ShowOverflow { kConstrain, kReject };
125 
126 // ISO8601 String Parsing
127 
128 // #sec-temporal-parsetemporalcalendarstring
129 V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalCalendarString(
130     Isolate* isolate, Handle<String> iso_string);
131 
132 // #sec-temporal-parsetemporaldatestring
133 V8_WARN_UNUSED_RESULT Maybe<DateRecord> ParseTemporalDateString(
134     Isolate* isolate, Handle<String> iso_string);
135 
136 // #sec-temporal-parsetemporaltimestring
137 Maybe<TimeRecord> ParseTemporalTimeString(Isolate* isolate,
138                                           Handle<String> iso_string);
139 
140 // #sec-temporal-parsetemporaltimezone
141 V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalTimeZone(
142     Isolate* isolate, Handle<String> string);
143 
144 // #sec-temporal-parsetemporaltimezonestring
145 V8_WARN_UNUSED_RESULT Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(
146     Isolate* isolate, Handle<String> iso_string);
147 
148 // #sec-temporal-parsetimezoneoffsetstring
149 V8_WARN_UNUSED_RESULT Maybe<int64_t> ParseTimeZoneOffsetString(
150     Isolate* isolate, Handle<String> offset_string,
151     bool throwIfNotSatisfy = true);
152 
153 // #sec-temporal-parsetemporalinstant
154 V8_WARN_UNUSED_RESULT MaybeHandle<BigInt> ParseTemporalInstant(
155     Isolate* isolate, Handle<String> iso_string);
156 
157 void BalanceISODate(Isolate* isolate, int32_t* year, int32_t* month,
158                     int32_t* day);
159 
160 // Math and Misc
161 
162 V8_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
168 V8_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 
174 V8_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
182 V8_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
189 V8_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 
194 V8_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
201 bool IsValidEpochNanoseconds(Isolate* isolate,
202                              Handle<BigInt> epoch_nanoseconds);
203 
204 // #sec-temporal-isvalidduration
205 bool IsValidDuration(Isolate* isolate, const DurationRecord& dur);
206 
207 // #sec-temporal-nanosecondstodays
208 V8_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 
214 V8_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
220 enum class OffsetBehaviour { kOption, kExact, kWall };
221 
222 V8_WARN_UNUSED_RESULT
223 MaybeHandle<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 
230 int32_t DurationSign(Isolate* isolaet, const DurationRecord& dur);
231 
232 // #sec-temporal-isodaysinmonth
233 int32_t ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month);
234 
235 // #sec-temporal-isodaysinyear
236 int32_t ISODaysInYear(Isolate* isolate, int32_t year);
237 
238 bool 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
242 bool IsValidISODate(Isolate* isolate, int32_t year, int32_t month, int32_t day);
243 
244 // #sec-temporal-compareisodate
245 int32_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
249 void BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month);
250 
251 // #sec-temporal-balancetime
252 V8_WARN_UNUSED_RESULT DateTimeRecordCommon
253 BalanceTime(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
257 V8_WARN_UNUSED_RESULT DurationRecord
258 DifferenceTime(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
263 V8_WARN_UNUSED_RESULT DateTimeRecordCommon
264 AddTime(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
270 int64_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
276 Maybe<TimeRecord> ToTemporalTimeRecord(Isolate* isolate,
277                                        Handle<JSReceiver> temporal_time_like,
278                                        const char* method_name);
279 // Calendar Operations
280 
281 // #sec-temporal-calendardateadd
282 V8_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
287 V8_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
292 MaybeHandle<FixedArray> CalendarFields(Isolate* isolate,
293                                        Handle<JSReceiver> calendar,
294                                        Handle<FixedArray> field_names);
295 
296 // #sec-temporal-getoffsetnanosecondsfor
297 V8_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
302 MaybeHandle<JSReceiver> ToTemporalCalendarWithISODefault(
303     Isolate* isolate, Handle<Object> temporal_calendar_like,
304     const char* method_name);
305 
306 // #sec-temporal-isbuiltincalendar
307 bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id);
308 
309 // Internal Helper Function
310 int32_t CalendarIndex(Isolate* isolate, Handle<String> id);
311 
312 // #sec-isvalidtimezonename
313 bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone);
314 
315 // #sec-canonicalizetimezonename
316 V8_WARN_UNUSED_RESULT MaybeHandle<String> CanonicalizeTimeZoneName(
317     Isolate* isolate, Handle<String> identifier);
318 
319 // #sec-temporal-tointegerthrowoninfinity
320 MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
321                                              Handle<Object> argument);
322 
323 // #sec-temporal-topositiveinteger
324 MaybeHandle<Object> ToPositiveInteger(Isolate* isolate,
325                                       Handle<Object> argument);
326 
floor_divide(int64_t a, int64_t b)327 inline int64_t floor_divide(int64_t a, int64_t b) {
328   return (((a) / (b)) + ((((a) < 0) && (((a) % (b)) != 0)) ? -1 : 0));
329 }
modulo(int64_t a, int64_t b)330 inline 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
DefaultTimeZone(Isolate* isolate)362 MaybeHandle<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
ISODateTimeWithinLimits(Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond)370 bool 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
ISOYearMonthWithinLimits(int32_t year, int32_t month)413 bool 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
SystemUTCEpochNanoseconds(Isolate* isolate)449 MaybeHandle<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
CreateTemporalCalendar( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<String> identifier)464 MaybeHandle<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 
CreateTemporalCalendar( Isolate* isolate, Handle<String> identifier)485 MaybeHandle<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
CreateTemporalDate( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t iso_year, int32_t iso_month, int32_t iso_day, Handle<JSReceiver> calendar)493 MaybeHandle<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 
CreateTemporalDate( Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day, Handle<JSReceiver> calendar)533 MaybeHandle<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
CreateTemporalDateTime( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t iso_year, int32_t iso_month, int32_t iso_day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar)543 MaybeHandle<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 
CreateTemporalDateTimeDefaultTarget( Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar)607 MaybeHandle<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 
620 namespace temporal {
621 
CreateTemporalDateTime( Isolate* isolate, int32_t iso_year, int32_t iso_month, int32_t iso_day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar)622 MaybeHandle<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 
633 namespace {
634 // #sec-temporal-createtemporaltime
CreateTemporalTime( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond)635 MaybeHandle<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 
CreateTemporalTime( Isolate* isolate, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond)678 MaybeHandle<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
CreateTemporalMonthDay( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t iso_month, int32_t iso_day, Handle<JSReceiver> calendar, int32_t reference_iso_year)688 MaybeHandle<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
CreateTemporalYearMonth( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t iso_year, int32_t iso_month, Handle<JSReceiver> calendar, int32_t reference_iso_day)720 MaybeHandle<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
CreateTemporalZonedDateTime( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<BigInt> epoch_nanoseconds, Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar)757 MaybeHandle<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 }
CreateTemporalZonedDateTime( Isolate* isolate, Handle<BigInt> epoch_nanoseconds, Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar)783 MaybeHandle<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
CreateTemporalDuration( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int64_t years, int64_t months, int64_t weeks, int64_t days, int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds, int64_t microseconds, int64_t nanoseconds)793 MaybeHandle<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 
CreateTemporalDuration( Isolate* isolate, int64_t years, int64_t months, int64_t weeks, int64_t days, int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds, int64_t microseconds, int64_t nanoseconds)846 MaybeHandle<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 
859 namespace temporal {
860 
861 // #sec-temporal-createtemporalinstant
CreateTemporalInstant( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<BigInt> epoch_nanoseconds)862 MaybeHandle<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 
CreateTemporalInstant( Isolate* isolate, Handle<BigInt> epoch_nanoseconds)880 MaybeHandle<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 
889 namespace {
890 
CreateTemporalTimeZoneFromIndex( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, int32_t index)891 MaybeHandle<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 
CreateTemporalTimeZoneUTC( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target)905 MaybeHandle<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 
912 bool IsUTC(Isolate* isolate, Handle<String> time_zone);
913 
914 // #sec-temporal-createtemporaltimezone
CreateTemporalTimeZone( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<String> identifier)915 MaybeHandle<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 
CreateTemporalTimeZoneDefaultTarget( Isolate* isolate, Handle<String> identifier)960 MaybeHandle<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 
969 namespace temporal {
CreateTemporalTimeZone( Isolate* isolate, Handle<String> identifier)970 MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZone(
971     Isolate* isolate, Handle<String> identifier) {
972   return CreateTemporalTimeZoneDefaultTarget(isolate, identifier);
973 }
974 }  // namespace temporal
975 
976 namespace {
977 
978 // #sec-temporal-systeminstant
SystemInstant(Isolate* isolate)979 MaybeHandle<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
SystemTimeZone(Isolate* isolate)990 MaybeHandle<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 
GetISOPartsFromEpoch( Isolate* isolate, Handle<BigInt> epoch_nanoseconds)998 Maybe<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
BalanceISODateTime(Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int64_t nanosecond)1076 DateTimeRecordCommon 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 
1112 namespace temporal {
BuiltinTimeZoneGetPlainDateTimeFor( Isolate* isolate, Handle<JSReceiver> time_zone, Handle<JSTemporalInstant> instant, Handle<JSReceiver> calendar, const char* method_name)1113 MaybeHandle<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 
1149 namespace {
1150 // #sec-temporal-getpossibleinstantsfor
GetPossibleInstantsFor(Isolate* isolate, Handle<JSReceiver> time_zone, Handle<Object> date_time)1151 MaybeHandle<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
DisambiguatePossibleInstants( Isolate* isolate, Handle<FixedArray> possible_instants, Handle<JSReceiver> time_zone, Handle<Object> date_time_obj, Disambiguation disambiguation, const char* method_name)1196 MaybeHandle<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
GetTemporalCalendarWithISODefault( Isolate* isolate, Handle<JSReceiver> item, const char* method_name)1406 MaybeHandle<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 
1449 enum class RequiredFields { kNone, kTimeZone, kTimeZoneAndOffset, kDay };
1450 
1451 // The common part of PrepareTemporalFields and PreparePartialTemporalFields
1452 // #sec-temporal-preparetemporalfields
1453 // #sec-temporal-preparepartialtemporalfields
PrepareTemporalFieldsOrPartial( Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names, RequiredFields required, bool partial)1454 V8_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
PrepareTemporalFields( Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names, RequiredFields required)1559 V8_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
1569 template <typename T>
FromFields(Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields, Handle<Object> options, Handle<String> property, InstanceType type)1570 MaybeHandle<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
DateFromFields(Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields, Handle<Object> options)1594 MaybeHandle<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
YearMonthFromFields( Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields, Handle<Object> options)1604 MaybeHandle<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
MonthDayFromFields( Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> fields, Handle<Object> options)1614 MaybeHandle<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
ToTemporalOverflow(Isolate* isolate, Handle<JSReceiver> options, const char* method_name)1624 Maybe<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
BuiltinTimeZoneGetInstantFor( Isolate* isolate, Handle<JSReceiver> time_zone, Handle<JSTemporalPlainDateTime> date_time, Disambiguation disambiguation, const char* method_name)1634 MaybeHandle<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
ToTemporalInstant(Isolate* isolate, Handle<Object> item, const char* method)1652 MaybeHandle<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 
1687 namespace temporal {
1688 
1689 // #sec-temporal-totemporalcalendar
ToTemporalCalendar( Isolate* isolate, Handle<Object> temporal_calendar_like, const char* method_name)1690 MaybeHandle<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 
1763 namespace {
1764 // #sec-temporal-totemporalcalendarwithisodefault
ToTemporalCalendarWithISODefault( Isolate* isolate, Handle<Object> temporal_calendar_like, const char* method_name)1765 MaybeHandle<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
ToTemporalDate(Isolate* isolate, Handle<Object> item_obj, Handle<JSReceiver> options, const char* method_name)1781 MaybeHandle<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 
1905 namespace temporal {
1906 
1907 // #sec-temporal-regulatetime
RegulateTime(Isolate* isolate, TimeRecord* time, ShowOverflow overflow)1908 Maybe<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
ToTemporalTime(Isolate* isolate, Handle<Object> item_obj, ShowOverflow overflow, const char* method_name)1945 MaybeHandle<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
ToTemporalTimeZone( Isolate* isolate, Handle<Object> temporal_time_zone_like, const char* method_name)2069 MaybeHandle<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 
2129 namespace {
2130 // #sec-temporal-systemdatetime
SystemDateTime( Isolate* isolate, Handle<Object> temporal_time_zone_like, Handle<Object> calendar_like, const char* method_name)2131 MaybeHandle<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 
SystemZonedDateTime( Isolate* isolate, Handle<Object> temporal_time_zone_like, Handle<Object> calendar_like, const char* method_name)2167 MaybeHandle<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
FormatTimeZoneOffsetString(Isolate* isolate, int64_t offset_nanoseconds)2207 MaybeHandle<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
BuiltinTimeZoneGetOffsetStringFor( Isolate* isolate, Handle<JSReceiver> time_zone, Handle<JSTemporalInstant> instant, const char* method_name)2265 MaybeHandle<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
ParseISODateTime(Isolate* isolate, Handle<String> iso_string, const ParsedISO8601Result& parsed)2280 Maybe<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
ParseTemporalDateString(Isolate* isolate, Handle<String> iso_string)2368 Maybe<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
ParseTemporalTimeString(Isolate* isolate, Handle<String> iso_string)2404 Maybe<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
ParseTemporalInstantString(Isolate* isolate, Handle<String> iso_string)2443 Maybe<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
ParseTemporalInstant(Isolate* isolate, Handle<String> iso_string)2502 MaybeHandle<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
ParseTemporalTimeZoneString(Isolate* isolate, Handle<String> iso_string)2550 Maybe<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
ParseTemporalTimeZone(Isolate* isolate, Handle<String> string)2668 MaybeHandle<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 
ParseTimeZoneOffsetString(Isolate* isolate, Handle<String> iso_string, bool throwIfNotSatisfy)2692 Maybe<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 
IsValidTimeZoneNumericUTCOffsetString(Isolate* isolate, Handle<String> iso_string)2750 Maybe<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
ParseTemporalCalendarString(Isolate* isolate, Handle<String> iso_string)2760 MaybeHandle<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
CalendarFields(Isolate* isolate, Handle<JSReceiver> calendar, Handle<FixedArray> field_names)2795 MaybeHandle<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 
CalendarDateAdd(Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> date, Handle<Object> duration, Handle<Object> options)2827 MaybeHandle<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 
CalendarDateAdd( Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> date, Handle<Object> duration, Handle<Object> options, Handle<Object> date_add)2836 MaybeHandle<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 
CalendarDateUntil(Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> one, Handle<Object> two, Handle<Object> options)2864 MaybeHandle<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 
CalendarDateUntil( Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> one, Handle<Object> two, Handle<Object> options, Handle<Object> date_until)2873 MaybeHandle<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
DefaultMergeFields( Isolate* isolate, Handle<JSReceiver> fields, Handle<JSReceiver> additional_fields)2903 MaybeHandle<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
GetOffsetNanosecondsFor(Isolate* isolate, Handle<JSReceiver> time_zone_obj, Handle<Object> instant, const char* method_name)3012 Maybe<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
ToPositiveInteger(Isolate* isolate, Handle<Object> argument)3068 MaybeHandle<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 
3085 namespace temporal {
InvokeCalendarMethod(Isolate* isolate, Handle<JSReceiver> calendar, Handle<String> name, Handle<JSReceiver> date_like)3086 MaybeHandle<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
3133 CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Year, year, ToIntegerThrowOnInfinity)
3134 // #sec-temporal-calendarmonth
3135 CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Month, month, ToPositiveInteger)
3136 // #sec-temporal-calendarday
3137 CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Day, day, ToPositiveInteger)
3138 // #sec-temporal-calendarmonthcode
CalendarMonthCode(Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> date_like)3139 MaybeHandle<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
CalendarEraYear(Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> date_like)3160 MaybeHandle<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
CalendarEra(Isolate* isolate, Handle<JSReceiver> calendar, Handle<JSReceiver> date_like)3181 MaybeHandle<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
GetISO8601Calendar(Isolate* isolate)3203 MaybeHandle<JSTemporalCalendar> GetISO8601Calendar(Isolate* isolate) {
3204   return CreateTemporalCalendar(isolate, isolate->factory()->iso8601_string());
3205 }
3206 
3207 }  // namespace temporal
3208 
3209 namespace {
3210 
IsUTC(Isolate* isolate, Handle<String> time_zone)3211 bool 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
3229 class CalendarMap final {
3230  public:
CalendarMap()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   }
Contains(const std::string& id) const3249   bool Contains(const std::string& id) const {
3250     return calendar_id_indices.find(id) != calendar_id_indices.end();
3251   }
3252 
Id(int32_t index) const3253   std::string Id(int32_t index) const {
3254     DCHECK_LT(index, calendar_ids.size());
3255     return calendar_ids[index];
3256   }
3257 
Index(const char* id) const3258   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 
3267 DEFINE_LAZY_LEAKY_OBJECT_GETTER(CalendarMap, GetCalendarMap)
3268 
3269 // #sec-temporal-isbuiltincalendar
IsBuiltinCalendar(Isolate* isolate, const std::string& id)3270 bool IsBuiltinCalendar(Isolate* isolate, const std::string& id) {
3271   return GetCalendarMap()->Contains(id);
3272 }
3273 
IsBuiltinCalendar(Isolate* isolate, Handle<String> id)3274 bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id) {
3275   return IsBuiltinCalendar(isolate, id->ToCString().get());
3276 }
3277 
CalendarIdentifier(Isolate* isolate, int32_t index)3278 Handle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
3279   return isolate->factory()->NewStringFromAsciiChecked(
3280       GetCalendarMap()->Id(index).c_str());
3281 }
3282 
CalendarIndex(Isolate* isolate, Handle<String> id)3283 int32_t CalendarIndex(Isolate* isolate, Handle<String> id) {
3284   return GetCalendarMap()->Index(id->ToCString().get());
3285 }
3286 
IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone)3287 bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone) {
3288   return Intl::IsValidTimeZoneName(isolate, time_zone);
3289 }
3290 
CanonicalizeTimeZoneName(Isolate* isolate, Handle<String> identifier)3291 MaybeHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
3292                                              Handle<String> identifier) {
3293   return Intl::CanonicalizeTimeZoneName(isolate, identifier);
3294 }
3295 
3296 #else   // V8_INTL_SUPPORT
CalendarIdentifier(Isolate* isolate, int32_t index)3297 Handle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
3298   DCHECK_EQ(index, 0);
3299   return isolate->factory()->iso8601_string();
3300 }
3301 
3302 // #sec-temporal-isbuiltincalendar
IsBuiltinCalendar(Isolate* isolate, Handle<String> id)3303 bool 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 
CalendarIndex(Isolate* isolate, Handle<String> id)3309 int32_t CalendarIndex(Isolate* isolate, Handle<String> id) { return 0; }
3310 // #sec-isvalidtimezonename
IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone)3311 bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone) {
3312   return IsUTC(isolate, time_zone);
3313 }
3314 // #sec-canonicalizetimezonename
CanonicalizeTimeZoneName(Isolate* isolate, Handle<String> identifier)3315 MaybeHandle<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
ToTemporalTimeRecord(Isolate* isolate, Handle<JSReceiver> temporal_time_like, const char* method_name)3322 Maybe<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
MergeLargestUnitOption(Isolate* isolate, Handle<JSReceiver> options, Unit largest_unit)3377 MaybeHandle<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
ToIntegerThrowOnInfinity(Isolate* isolate, Handle<Object> argument)3403 MaybeHandle<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
LargerOfTwoTemporalUnits(Isolate* isolate, Unit u1, Unit u2)3419 Unit 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 
UnitToString(Isolate* isolate, Unit unit)3444 Handle<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
BalanceISODate(Isolate* isolate, int32_t* year, int32_t* month, int32_t* day)3472 void 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
AddDateTime( Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond, Handle<JSReceiver> calendar, const DurationRecord& dur, Handle<Object> options)3546 Maybe<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 
BalanceDuration(Isolate* isolate, int64_t* days, int64_t* hours, int64_t* minutes, int64_t* seconds, int64_t* milliseconds, int64_t* microseconds, int64_t* nanoseconds, Unit largest_unit, const char* method_name)3596 Maybe<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 
BalanceDuration(Isolate* isolate, int64_t* days, int64_t* hours, int64_t* minutes, int64_t* seconds, int64_t* milliseconds, int64_t* microseconds, int64_t* nanoseconds, Unit largest_unit, Handle<Object> relative_to_obj, const char* method_name)3609 Maybe<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
AddZonedDateTime(Isolate* isolate, Handle<BigInt> epoch_nanoseconds, Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar, const DurationRecord& duration, const char* method_name)3776 MaybeHandle<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
AddZonedDateTime(Isolate* isolate, Handle<BigInt> epoch_nanoseconds, Handle<JSReceiver> time_zone, Handle<JSReceiver> calendar, const DurationRecord& duration, Handle<JSReceiver> options, const char* method_name)3791 MaybeHandle<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
NanosecondsToDays(Isolate* isolate, int64_t nanoseconds, Handle<Object> relative_to_obj, int64_t* result_days, int64_t* result_nanoseconds, int64_t* result_day_length, const char* method_name)3881 Maybe<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 
NanosecondsToDays(Isolate* isolate, Handle<BigInt> nanoseconds, Handle<Object> relative_to_obj, int64_t* result_days, int64_t* result_nanoseconds, int64_t* result_day_length, const char* method_name)3891 Maybe<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 
DifferenceISODateTime( Isolate* isolate, int32_t y1, int32_t mon1, int32_t d1, int32_t h1, int32_t min1, int32_t s1, int32_t ms1, int32_t mus1, int32_t ns1, int32_t y2, int32_t mon2, int32_t d2, int32_t h2, int32_t min2, int32_t s2, int32_t ms2, int32_t mus2, int32_t ns2, Handle<JSReceiver> calendar, Unit largest_unit, Handle<Object> options_obj, const char* method_name)4099 Maybe<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
AddInstant(Isolate* isolate, Handle<BigInt> epoch_nanoseconds, int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds, int64_t microseconds, int64_t nanoseconds)4228 MaybeHandle<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
IsValidEpochNanoseconds(Isolate* isolate, Handle<BigInt> epoch_nanoseconds)4304 bool 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 
GetEpochFromISOParts(Isolate* isolate, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond)4316 MaybeHandle<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
DurationSign(Isolate* isolaet, const DurationRecord& dur)4362 int32_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
IsValidDuration(Isolate* isolate, const DurationRecord& dur)4393 bool 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
IsISOLeapYear(Isolate* isolate, int32_t year)4415 bool 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
ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month)4427 int32_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
ISODaysInYear(Isolate* isolate, int32_t year)4445 int32_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 
IsValidTime(Isolate* isolate, int32_t hour, int32_t minute, int32_t second, int32_t millisecond, int32_t microsecond, int32_t nanosecond)4455 bool 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
IsValidISODate(Isolate* isolate, int32_t year, int32_t month, int32_t day)4482 bool 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
CompareISODate(Isolate* isolate, int32_t y1, int32_t m1, int32_t d1, int32_t y2, int32_t m2, int32_t d2)4499 int32_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
BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month)4521 void 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
BalanceTime(Isolate* isolate, int64_t hour, int64_t minute, int64_t second, int64_t millisecond, int64_t microsecond, int64_t nanosecond)4533 DateTimeRecordCommon 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
DifferenceTime(Isolate* isolate, int32_t h1, int32_t min1, int32_t s1, int32_t ms1, int32_t mus1, int32_t ns1, int32_t h2, int32_t min2, int32_t s2, int32_t ms2, int32_t mus2, int32_t ns2)4579 DurationRecord 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
AddTime(Isolate* isolate, int64_t hour, int64_t minute, int64_t second, int64_t millisecond, int64_t microsecond, int64_t nanosecond, int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds, int64_t microseconds, int64_t nanoseconds)4629 DateTimeRecordCommon 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
TotalDurationNanoseconds(Isolate* isolate, int64_t days, int64_t hours, int64_t minutes, int64_t seconds, int64_t milliseconds, int64_t microseconds, int64_t nanoseconds, int64_t offset_shift)4657 int64_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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> years, Handle<Object> months, Handle<Object> weeks, Handle<Object> days, Handle<Object> hours, Handle<Object> minutes, Handle<Object> seconds, Handle<Object> milliseconds, Handle<Object> microseconds, Handle<Object> nanoseconds)4693 MaybeHandle<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
Sign(Isolate* isolate, Handle<JSTemporalDuration> duration)4786 MaybeHandle<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
Blank( Isolate* isolate, Handle<JSTemporalDuration> duration)4809 MaybeHandle<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 
4833 namespace {
4834 // #sec-temporal-createnegatedtemporalduration
CreateNegatedTemporalDuration( Isolate* isolate, Handle<JSTemporalDuration> duration)4835 MaybeHandle<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
Negated( Isolate* isolate, Handle<JSTemporalDuration> duration)4859 MaybeHandle<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
Abs( Isolate* isolate, Handle<JSTemporalDuration> duration)4870 MaybeHandle<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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> identifier_obj)4894 MaybeHandle<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 
4921 namespace {
4922 
4923 // #sec-temporal-toisodayofyear
ToISODayOfYear(Isolate* isolate, int32_t year, int32_t month, int32_t day)4924 int32_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 
IsPlainDatePlainDateTimeOrPlainYearMonth( Handle<Object> temporal_date_like)4939 bool 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
ToISODayOfWeek(Isolate* isolate, int32_t year, int32_t month, int32_t day)4947 int32_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
RegulateISODate(Isolate* isolate, ShowOverflow overflow, int32_t year, int32_t* month, int32_t* day)4970 Maybe<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
ResolveISOMonth(Isolate* isolate, Handle<JSReceiver> fields)5002 Maybe<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
ISODateFromFields(Isolate* isolate, Handle<JSReceiver> fields, Handle<JSReceiver> options, const char* method_name, int32_t* year, int32_t* month, int32_t* day)5083 Maybe<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
DaysInYear( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5152 MaybeHandle<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
DaysInMonth( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5190 MaybeHandle<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
Year(Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5233 MaybeHandle<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
DayOfYear( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5272 MaybeHandle<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
DayOfWeek( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5296 MaybeHandle<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
MonthsInYear( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5320 MaybeHandle<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
InLeapYear( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5347 MaybeHandle<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
DaysInWeek( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> temporal_date_like)5383 MaybeHandle<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
DateFromFields( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> fields_obj, Handle<Object> options_obj)5403 MaybeHandle<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
MergeFields( Isolate* isolate, Handle<JSTemporalCalendar> calendar, Handle<Object> fields_obj, Handle<Object> additional_fields_obj)5444 MaybeHandle<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
ToString( Isolate* isolate, Handle<JSTemporalCalendar> calendar, const char* method_name)5473 MaybeHandle<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
Now(Isolate* isolate)5480 MaybeHandle<JSTemporalTimeZone> JSTemporalTimeZone::Now(Isolate* isolate) {
5481   return SystemTimeZone(isolate);
5482 }
5483 
5484 // #sec-temporal.timezone
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> identifier_obj)5485 MaybeHandle<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
ToString( Isolate* isolate, Handle<JSTemporalTimeZone> time_zone, const char* method_name)5540 MaybeHandle<Object> JSTemporalTimeZone::ToString(
5541     Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
5542     const char* method_name) {
5543   return time_zone->id(isolate);
5544 }
5545 
time_zone_index() const5546 int32_t JSTemporalTimeZone::time_zone_index() const {
5547   DCHECK(is_offset() == false);
5548   return offset_milliseconds_or_time_zone_index();
5549 }
5550 
offset_nanoseconds() const5551 int64_t JSTemporalTimeZone::offset_nanoseconds() const {
5552   TEMPORAL_ENTER_FUNC();
5553   DCHECK(is_offset());
5554   return 1000000L * offset_milliseconds() + offset_sub_milliseconds();
5555 }
5556 
set_offset_nanoseconds(int64_t ns)5557 void 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 
id(Isolate* isolate) const5562 MaybeHandle<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 
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> iso_year_obj, Handle<Object> iso_month_obj, Handle<Object> iso_day_obj, Handle<Object> calendar_like)5576 MaybeHandle<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
WithCalendar( Isolate* isolate, Handle<JSTemporalPlainDate> temporal_date, Handle<Object> calendar_like)5617 MaybeHandle<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
Now( Isolate* isolate, Handle<Object> calendar_like, Handle<Object> temporal_time_zone_like)5638 MaybeHandle<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
NowISO( Isolate* isolate, Handle<Object> temporal_time_zone_like)5656 MaybeHandle<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
From( Isolate* isolate, Handle<Object> item, Handle<Object> options_obj)5678 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalPlainDate> temporal_date)5712 MaybeHandle<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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> iso_year_obj, Handle<Object> iso_month_obj, Handle<Object> iso_day_obj, Handle<Object> hour_obj, Handle<Object> minute_obj, Handle<Object> second_obj, Handle<Object> millisecond_obj, Handle<Object> microsecond_obj, Handle<Object> nanosecond_obj, Handle<Object> calendar_like)5742 MaybeHandle<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
WithCalendar( Isolate* isolate, Handle<JSTemporalPlainDateTime> date_time, Handle<Object> calendar_like)5784 MaybeHandle<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
Now( Isolate* isolate, Handle<Object> calendar_like, Handle<Object> temporal_time_zone_like)5811 MaybeHandle<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
NowISO( Isolate* isolate, Handle<Object> temporal_time_zone_like)5821 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalPlainDateTime> date_time)5835 MaybeHandle<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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> iso_month_obj, Handle<Object> iso_day_obj, Handle<Object> calendar_like, Handle<Object> reference_iso_year_obj)5883 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalPlainMonthDay> month_day)5924 MaybeHandle<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 
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> iso_year_obj, Handle<Object> iso_month_obj, Handle<Object> calendar_like, Handle<Object> reference_iso_day_obj)5953 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalPlainYearMonth> year_month)5996 MaybeHandle<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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> hour_obj, Handle<Object> minute_obj, Handle<Object> second_obj, Handle<Object> millisecond_obj, Handle<Object> microsecond_obj, Handle<Object> nanosecond_obj)6026 MaybeHandle<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
NowISO( Isolate* isolate, Handle<Object> temporal_time_zone_like)6057 MaybeHandle<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
From( Isolate* isolate, Handle<Object> item_obj, Handle<Object> options_obj)6082 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalPlainTime> temporal_time)6112 MaybeHandle<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
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> epoch_nanoseconds_obj, Handle<Object> time_zone_like, Handle<Object> calendar_like)6155 MaybeHandle<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
WithCalendar( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time, Handle<Object> calendar_like)6202 MaybeHandle<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
WithTimeZone( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time, Handle<Object> time_zone_like)6225 MaybeHandle<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
6249 template <typename T,
6250           MaybeHandle<T> (*from_fields_func)(
6251               Isolate*, Handle<JSReceiver>, Handle<JSReceiver>, Handle<Object>)>
ZonedDateTimeToPlainYearMonthOrMonthDay( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time, Handle<String> field_name_1, Handle<String> field_name_2, const char* method_name)6252 MaybeHandle<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
ToPlainYearMonth( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time)6300 MaybeHandle<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
ToPlainMonthDay( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time)6310 MaybeHandle<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
Now( Isolate* isolate, Handle<Object> calendar_like, Handle<Object> temporal_time_zone_like)6320 MaybeHandle<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
NowISO( Isolate* isolate, Handle<Object> temporal_time_zone_like)6330 MaybeHandle<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
GetISOFields( Isolate* isolate, Handle<JSTemporalZonedDateTime> zoned_date_time)6345 MaybeHandle<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
Now(Isolate* isolate)6428 MaybeHandle<JSTemporalInstant> JSTemporalInstant::Now(Isolate* isolate) {
6429   TEMPORAL_ENTER_FUNC();
6430   return SystemInstant(isolate);
6431 }
6432 
6433 // #sec-temporal.instant
Constructor( Isolate* isolate, Handle<JSFunction> target, Handle<HeapObject> new_target, Handle<Object> epoch_nanoseconds_obj)6434 MaybeHandle<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 
6464 namespace {
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.
ScaleNumberToNanosecondsVerifyAndMake( Isolate* isolate, Handle<BigInt> bigint, uint32_t scale)6469 MaybeHandle<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 
ScaleNumberToNanosecondsVerifyAndMake( Isolate* isolate, Handle<Object> epoch_Xseconds, uint32_t scale)6493 MaybeHandle<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 
ScaleToNanosecondsVerifyAndMake( Isolate* isolate, Handle<Object> epoch_Xseconds, uint32_t scale)6508 MaybeHandle<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
FromEpochSeconds( Isolate* isolate, Handle<Object> epoch_seconds)6522 MaybeHandle<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
FromEpochMilliseconds( Isolate* isolate, Handle<Object> epoch_milliseconds)6530 MaybeHandle<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
FromEpochMicroseconds( Isolate* isolate, Handle<Object> epoch_microseconds)6538 MaybeHandle<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
FromEpochNanoseconds( Isolate* isolate, Handle<Object> epoch_nanoseconds)6545 MaybeHandle<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
From(Isolate* isolate, Handle<Object> item)6552 MaybeHandle<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