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