v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-temporal-objects.cc
Go to the documentation of this file.
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
6
7#include <optional>
8#include <set>
9
10#include "src/common/globals.h"
11#include "src/date/date.h"
13#include "src/heap/factory.h"
24
25#ifdef V8_INTL_SUPPORT
29#include "unicode/calendar.h"
30#include "unicode/unistr.h"
31#endif // V8_INTL_SUPPORT
32
33namespace v8::internal {
34
35namespace {
36
37enum class Unit {
38 kNotPresent,
39 kAuto,
40 kYear,
41 kMonth,
42 kWeek,
43 kDay,
44 kHour,
45 kMinute,
46 kSecond,
47 kMillisecond,
48 kMicrosecond,
49 kNanosecond
50};
51
57// Struct
58
59// only for BalanceTime
60struct UnbalancedTimeRecord {
61 double hour;
62 double minute;
63 double second;
66 double nanosecond;
67};
68
69using temporal::DateRecord;
70using temporal::DateTimeRecord;
71using temporal::TimeRecord;
72
73struct DateRecordWithCalendar {
74 DateRecord date;
75 DirectHandle<Object> calendar; // String or Undefined
76};
77
78struct TimeRecordWithCalendar {
79 TimeRecord time;
80 DirectHandle<Object> calendar; // String or Undefined
81};
82
83struct TimeZoneRecord {
84 bool z;
85 DirectHandle<Object> offset_string; // String or Undefined
86 DirectHandle<Object> name; // String or Undefined
87};
88
89struct DateTimeRecordWithCalendar {
90 DateRecord date;
91 TimeRecord time;
92 TimeZoneRecord time_zone;
93 DirectHandle<Object> calendar; // String or Undefined
94};
95
96struct InstantRecord {
97 DateRecord date;
98 TimeRecord time;
99 DirectHandle<Object> offset_string; // String or Undefined
100};
101
102using temporal::DurationRecord;
104using temporal::TimeDurationRecord;
105
106struct DurationRecordWithRemainder {
107 DurationRecord record;
108 double remainder;
109};
110
111// #sec-temporal-date-duration-records
112struct DateDurationRecord {
113 double years;
114 double months;
115 double weeks;
116 double days;
117 // #sec-temporal-createdatedurationrecord
118 static Maybe<DateDurationRecord> Create(Isolate* isolate, double years,
119 double months, double weeks,
120 double days);
121};
122
123// Options
124
125V8_WARN_UNUSED_RESULT DirectHandle<String> UnitToString(Isolate* isolate,
126 Unit unit);
127
128// #sec-temporal-totemporaldisambiguation
129enum class Disambiguation { kCompatible, kEarlier, kLater, kReject };
130
131// #sec-temporal-totemporaloverflow
132enum class ShowOverflow { kConstrain, kReject };
133// #sec-temporal-toshowcalendaroption
134enum class ShowCalendar { kAuto, kAlways, kNever };
135
136// #sec-temporal-toshowtimezonenameoption
137enum class ShowTimeZone { kAuto, kNever };
138Maybe<ShowTimeZone> ToShowTimeZoneNameOption(Isolate* isolate,
139 DirectHandle<JSReceiver> options,
140 const char* method_name) {
141 // 1. Return ? GetOption(normalizedOptions, "timeZoneName", "string", «
142 // "auto", "never" », "auto").
144 isolate, options, "timeZoneName", method_name, {"auto", "never"},
145 {ShowTimeZone::kAuto, ShowTimeZone::kNever}, ShowTimeZone::kAuto);
146}
147
148// #sec-temporal-toshowoffsetoption
149enum class ShowOffset { kAuto, kNever };
150Maybe<ShowOffset> ToShowOffsetOption(Isolate* isolate,
151 DirectHandle<JSReceiver> options,
152 const char* method_name) {
153 // 1. Return ? GetOption(normalizedOptions, "offset", "string", « "auto",
154 // "never" », "auto").
156 isolate, options, "offset", method_name, {"auto", "never"},
157 {ShowOffset::kAuto, ShowOffset::kNever}, ShowOffset::kAuto);
158}
159
160enum class Precision { k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, kAuto, kMinute };
161
162// Enum for add/subtract
163enum class Arithmetic { kAdd, kSubtract };
164
165// Enum for since/until
166enum class TimePreposition { kSince, kUntil };
167
168enum class Offset { kPrefer, kUse, kIgnore, kReject };
169V8_WARN_UNUSED_RESULT Maybe<Offset> ToTemporalOffset(
170 Isolate* isolate, DirectHandle<Object> options, Offset fallback,
171 const char* method_name);
172
173// sec-temporal-totemporalroundingmode
174enum class RoundingMode {
175 kCeil,
176 kFloor,
177 kExpand,
178 kTrunc,
179 kHalfCeil,
180 kHalfFloor,
181 kHalfExpand,
182 kHalfTrunc,
183 kHalfEven
184};
185// #table-temporal-unsigned-rounding-modes
186enum class UnsignedRoundingMode {
187 kInfinity,
188 kZero,
189 kHalfInfinity,
190 kHalfZero,
191 kHalfEven
192};
193
194enum class MatchBehaviour { kMatchExactly, kMatchMinutes };
195
196// #sec-temporal-gettemporalunit
197enum class UnitGroup {
198 kDate,
199 kTime,
200 kDateTime,
201};
202
203struct DifferenceSettings {
208 DirectHandle<JSReceiver> options;
209};
210enum class DisallowedUnitsInDifferenceSettings {
211 kNone,
212 kWeekAndDay,
213};
214Maybe<DifferenceSettings> GetDifferenceSettings(
215 Isolate* isolate, TimePreposition operation, DirectHandle<Object> options,
216 UnitGroup unit_group, DisallowedUnitsInDifferenceSettings disallowed_units,
217 Unit fallback_smallest_unit, Unit smallest_largest_default_unit,
218 const char* method_name);
219
220// #sec-temporal-totemporaloffset
221// ISO8601 String Parsing
222
223// #sec-temporal-parsetemporalcalendarstring
224V8_WARN_UNUSED_RESULT MaybeDirectHandle<String> ParseTemporalCalendarString(
225 Isolate* isolate, DirectHandle<String> iso_string);
226
227// #sec-temporal-parsetemporaldatetimestring
228V8_WARN_UNUSED_RESULT Maybe<DateTimeRecordWithCalendar>
229ParseTemporalDateTimeString(Isolate* isolate, DirectHandle<String> iso_string);
230
231// #sec-temporal-parsetemporaldatestring
232V8_WARN_UNUSED_RESULT Maybe<DateRecordWithCalendar> ParseTemporalDateString(
233 Isolate* isolate, DirectHandle<String> iso_string);
234
235// #sec-temporal-parsetemporaltimestring
236Maybe<TimeRecordWithCalendar> ParseTemporalTimeString(
237 Isolate* isolate, DirectHandle<String> iso_string);
238
239// #sec-temporal-parsetemporaldurationstring
240V8_WARN_UNUSED_RESULT Maybe<DurationRecord> ParseTemporalDurationString(
241 Isolate* isolate, DirectHandle<String> iso_string);
242
243// #sec-temporal-parsetemporaltimezonestring
244V8_WARN_UNUSED_RESULT Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(
245 Isolate* isolate, DirectHandle<String> iso_string);
246
247// #sec-temporal-parsetimezoneoffsetstring
248V8_WARN_UNUSED_RESULT Maybe<int64_t> ParseTimeZoneOffsetString(
249 Isolate* isolate, DirectHandle<String> offset_string);
250
251// #sec-temporal-parsetemporalinstant
252V8_WARN_UNUSED_RESULT MaybeDirectHandle<BigInt> ParseTemporalInstant(
253 Isolate* isolate, DirectHandle<String> iso_string);
254V8_WARN_UNUSED_RESULT MaybeDirectHandle<BigInt> ParseTemporalInstant(
255 Isolate* isolate, DirectHandle<String> iso_string);
256
257DateRecord BalanceISODate(Isolate* isolate, const DateRecord& date);
258
259// Math and Misc
260
261V8_WARN_UNUSED_RESULT MaybeDirectHandle<BigInt> AddInstant(
262 Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds,
263 const TimeDurationRecord& addend);
264
265// #sec-temporal-balanceduration
266V8_WARN_UNUSED_RESULT Maybe<TimeDurationRecord> BalanceDuration(
267 Isolate* isolate, Unit largest_unit, DirectHandle<Object> relative_to,
268 const TimeDurationRecord& duration, const char* method_name);
269// The special case of BalanceDuration while the nanosecond is a large value
270// and the rest are 0.
271V8_WARN_UNUSED_RESULT Maybe<TimeDurationRecord> BalanceDuration(
272 Isolate* isolate, Unit largest_unit, DirectHandle<BigInt> nanoseconds,
273 const char* method_name);
274// A special version of BalanceDuration which add two TimeDurationRecord
275// internally as BigInt to avoid overflow double.
276V8_WARN_UNUSED_RESULT Maybe<TimeDurationRecord> BalanceDuration(
277 Isolate* isolate, Unit largest_unit, const TimeDurationRecord& dur1,
278 const TimeDurationRecord& dur2, const char* method_name);
279
280// sec-temporal-balancepossiblyinfiniteduration
281enum BalanceOverflow {
282 kNone,
283 kPositive,
284 kNegative,
285};
286struct BalancePossiblyInfiniteDurationResult {
287 TimeDurationRecord value;
288 BalanceOverflow overflow;
289};
290V8_WARN_UNUSED_RESULT Maybe<BalancePossiblyInfiniteDurationResult>
291BalancePossiblyInfiniteDuration(Isolate* isolate, Unit largest_unit,
292 DirectHandle<Object> relative_to,
293 const TimeDurationRecord& duration,
294 const char* method_name);
295
296// The special case of BalancePossiblyInfiniteDuration while the nanosecond is a
297// large value and days contains non-zero values but the rest are 0.
298// This version has no relative_to.
299V8_WARN_UNUSED_RESULT Maybe<BalancePossiblyInfiniteDurationResult>
300BalancePossiblyInfiniteDuration(Isolate* isolate, Unit largest_unit,
301 DirectHandle<Object> relative_to, double days,
302 DirectHandle<BigInt> nanoseconds,
303 const char* method_name);
304V8_WARN_UNUSED_RESULT Maybe<BalancePossiblyInfiniteDurationResult>
305BalancePossiblyInfiniteDuration(Isolate* isolate, Unit largest_unit,
306 double days, DirectHandle<BigInt> nanoseconds,
307 const char* method_name) {
308 return BalancePossiblyInfiniteDuration(isolate, largest_unit,
309 isolate->factory()->undefined_value(),
310 days, nanoseconds, method_name);
311}
312
313V8_WARN_UNUSED_RESULT Maybe<DurationRecord> DifferenceISODateTime(
314 Isolate* isolate, const DateTimeRecord& date_time1,
315 const DateTimeRecord& date_time2, DirectHandle<JSReceiver> calendar,
316 Unit largest_unit, DirectHandle<JSReceiver> relative_to,
317 const char* method_name);
318
319// #sec-temporal-adddatetime
320V8_WARN_UNUSED_RESULT Maybe<DateTimeRecord> AddDateTime(
321 Isolate* isolate, const DateTimeRecord& date_time,
322 DirectHandle<JSReceiver> calendar, const DurationRecord& addend,
323 DirectHandle<Object> options);
324
325// #sec-temporal-addzoneddatetime
326V8_WARN_UNUSED_RESULT MaybeDirectHandle<BigInt> AddZonedDateTime(
327 Isolate* isolate, DirectHandle<BigInt> eopch_nanoseconds,
328 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar,
329 const DurationRecord& addend, const char* method_name);
330
331V8_WARN_UNUSED_RESULT MaybeDirectHandle<BigInt> AddZonedDateTime(
332 Isolate* isolate, DirectHandle<BigInt> eopch_nanoseconds,
333 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar,
334 const DurationRecord& addend, DirectHandle<Object> options,
335 const char* method_name);
336
337// #sec-temporal-isvalidepochnanoseconds
338bool IsValidEpochNanoseconds(Isolate* isolate,
339 DirectHandle<BigInt> epoch_nanoseconds);
340
341struct NanosecondsToDaysResult {
342 double days;
343 double nanoseconds;
344 int64_t day_length;
345};
346
347// #sec-temporal-nanosecondstodays
348V8_WARN_UNUSED_RESULT Maybe<NanosecondsToDaysResult> NanosecondsToDays(
349 Isolate* isolate, DirectHandle<BigInt> nanoseconds,
350 DirectHandle<Object> relative_to_obj, const char* method_name);
351
352// #sec-temporal-interpretisodatetimeoffset
353enum class OffsetBehaviour { kOption, kExact, kWall };
354
355// sec-temporal-totemporalroundingmode
356Maybe<RoundingMode> ToTemporalRoundingMode(Isolate* isolate,
357 DirectHandle<JSReceiver> options,
358 RoundingMode fallback,
359 const char* method_name) {
360 // 1. Return ? GetOption(normalizedOptions, "roundingMode", "string", «
361 // "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand",
362 // "halfTrunc", "halfEven" », fallback).
363
365 isolate, options, "roundingMode", method_name,
366 {"ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor",
367 "halfExpand", "halfTrunc", "halfEven"},
368 {RoundingMode::kCeil, RoundingMode::kFloor, RoundingMode::kExpand,
369 RoundingMode::kTrunc, RoundingMode::kHalfCeil, RoundingMode::kHalfFloor,
370 RoundingMode::kHalfExpand, RoundingMode::kHalfTrunc,
371 RoundingMode::kHalfEven},
372 fallback);
373}
374
376DirectHandle<BigInt> GetEpochFromISOParts(Isolate* isolate,
377 const DateTimeRecord& date_time);
378
379// #sec-temporal-isodaysinmonth
380int32_t ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month);
381
382// #sec-temporal-isodaysinyear
383int32_t ISODaysInYear(Isolate* isolate, int32_t year);
384
385bool IsValidTime(Isolate* isolate, const TimeRecord& time);
386
387// #sec-temporal-isvalidisodate
388bool IsValidISODate(Isolate* isolate, const DateRecord& date);
389
390// #sec-temporal-compareisodate
391int32_t CompareISODate(const DateRecord& date1, const DateRecord& date2);
392
393// #sec-temporal-balanceisoyearmonth
394void BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month);
395
396// #sec-temporal-balancetime
397V8_WARN_UNUSED_RESULT DateTimeRecord
398BalanceTime(const UnbalancedTimeRecord& time);
399
400// #sec-temporal-differencetime
401V8_WARN_UNUSED_RESULT Maybe<TimeDurationRecord> DifferenceTime(
402 Isolate* isolate, const TimeRecord& time1, const TimeRecord& time2);
403
404// #sec-temporal-addtime
405V8_WARN_UNUSED_RESULT DateTimeRecord AddTime(Isolate* isolate,
406 const TimeRecord& time,
407 const TimeDurationRecord& addend);
408
409// #sec-temporal-totaldurationnanoseconds
410DirectHandle<BigInt> TotalDurationNanoseconds(
411 Isolate* isolate, const TimeDurationRecord& duration, double offset_shift);
412
413// #sec-temporal-totemporaltimerecord
414Maybe<TimeRecord> ToTemporalTimeRecord(
415 Isolate* isolate, DirectHandle<JSReceiver> temporal_time_like,
416 const char* method_name);
417// Calendar Operations
418
419// #sec-temporal-calendardateadd
420V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
421 Isolate* isolate, DirectHandle<JSReceiver> calendar,
422 DirectHandle<Object> date, DirectHandle<Object> durations,
423 DirectHandle<Object> options, DirectHandle<Object> date_add);
424V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
425 Isolate* isolate, DirectHandle<JSReceiver> calendar,
426 DirectHandle<Object> date, DirectHandle<Object> durations,
427 DirectHandle<Object> options);
428V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
429 Isolate* isolate, DirectHandle<JSReceiver> calendar,
430 DirectHandle<Object> date, DirectHandle<Object> durations);
431
432// #sec-temporal-calendardateuntil
433V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSTemporalDuration> CalendarDateUntil(
434 Isolate* isolate, DirectHandle<JSReceiver> calendar,
435 DirectHandle<Object> one, DirectHandle<Object> two,
436 DirectHandle<Object> options, DirectHandle<Object> date_until);
437
438// #sec-temporal-calendarfields
439MaybeDirectHandle<FixedArray> CalendarFields(
440 Isolate* isolate, DirectHandle<JSReceiver> calendar,
441 DirectHandle<FixedArray> field_names);
442
443// #sec-temporal-getoffsetnanosecondsfor
444V8_WARN_UNUSED_RESULT Maybe<int64_t> GetOffsetNanosecondsFor(
445 Isolate* isolate, DirectHandle<JSReceiver> time_zone,
446 DirectHandle<Object> instant, const char* method_name);
447
448// #sec-temporal-totemporalcalendarwithisodefault
449MaybeDirectHandle<JSReceiver> ToTemporalCalendarWithISODefault(
450 Isolate* isolate, DirectHandle<Object> temporal_calendar_like,
451 const char* method_name);
452
453// #sec-temporal-isbuiltincalendar
454bool IsBuiltinCalendar(Isolate* isolate, DirectHandle<String> id);
455
456// Internal Helper Function
457int32_t CalendarIndex(Isolate* isolate, DirectHandle<String> id);
458
459// #sec-isvalidtimezonename
460bool IsValidTimeZoneName(Isolate* isolate, DirectHandle<String> time_zone);
461
462// #sec-canonicalizetimezonename
463DirectHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
464 DirectHandle<String> identifier);
465
466// #sec-temporal-tointegerthrowoninfinity
467MaybeDirectHandle<Number> ToIntegerThrowOnInfinity(
468 Isolate* isolate, DirectHandle<Object> argument);
469
470// #sec-temporal-topositiveinteger
471MaybeDirectHandle<Number> ToPositiveInteger(Isolate* isolate,
472 DirectHandle<Object> argument);
473
474inline double modulo(double a, int32_t b) { return a - std::floor(a / b) * b; }
475
476#define STRINGIFY(x) #x
477#define TOSTRING(x) STRINGIFY(x)
478#define AT __FILE__ ":" TOSTRING(__LINE__)
479
480#ifdef DEBUG
481#define TEMPORAL_DEBUG_INFO AT
482#define TEMPORAL_ENTER_FUNC()
483// #define TEMPORAL_ENTER_FUNC() do { PrintF("Start: %s\n", __func__); } while
484// (false)
485#else
486// #define TEMPORAL_DEBUG_INFO ""
487#define TEMPORAL_DEBUG_INFO AT
488#define TEMPORAL_ENTER_FUNC()
489// #define TEMPORAL_ENTER_FUNC() do { PrintF("Start: %s\n", __func__); } while
490// (false)
491#endif // DEBUG
492
493#define NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR() \
494 NewTypeError( \
495 MessageTemplate::kInvalidArgumentForTemporal, \
496 isolate->factory()->NewStringFromStaticChars(TEMPORAL_DEBUG_INFO))
497
498#define NEW_TEMPORAL_INVALID_ARG_RANGE_ERROR() \
499 NewRangeError( \
500 MessageTemplate::kInvalidTimeValueForTemporal, \
501 isolate->factory()->NewStringFromStaticChars(TEMPORAL_DEBUG_INFO))
502
503// #sec-defaulttimezone
504#ifdef V8_INTL_SUPPORT
505DirectHandle<String> DefaultTimeZone(Isolate* isolate) {
507 return Intl::DefaultTimeZone(isolate);
508}
509#else // V8_INTL_SUPPORT
510DirectHandle<String> DefaultTimeZone(Isolate* isolate) {
512 return isolate->factory()->UTC_string();
513}
514#endif // V8_INTL_SUPPORT
515
516// #sec-temporal-isodatetimewithinlimits
517bool ISODateTimeWithinLimits(Isolate* isolate,
518 const DateTimeRecord& date_time) {
537 if (date_time.date.year > -271821 && date_time.date.year < 275760)
538 return true;
539 if (date_time.date.year < -271821 || date_time.date.year > 275760)
540 return false;
541 if (date_time.date.year == -271821) {
542 if (date_time.date.month > 4) return true;
543 if (date_time.date.month < 4) return false;
544 if (date_time.date.day > 19) return true;
545 if (date_time.date.day < 19) return false;
546 if (date_time.time.hour > 0) return true;
547 if (date_time.time.minute > 0) return true;
548 if (date_time.time.second > 0) return true;
549 if (date_time.time.millisecond > 0) return true;
550 if (date_time.time.microsecond > 0) return true;
551 return date_time.time.nanosecond > 0;
552 } else {
553 DCHECK_EQ(date_time.date.year, 275760);
554 if (date_time.date.month > 9) return false;
555 if (date_time.date.month < 9) return true;
556 return date_time.date.day < 14;
557 }
558 // 1. Assert: year, month, day, hour, minute, second, millisecond,
559 // microsecond, and nanosecond are integers.
560 // 2. Let ns be ! GetEpochFromISOParts(year, month, day, hour, minute,
561 // second, millisecond, microsecond, nanosecond).
562 // 3. If ns ≤ -8.64 × 10^21 - 8.64 × 10^13, then
563 // 4. If ns ≥ 8.64 × 10^21 + 8.64 × 10^13, then
564 // 5. Return true.
565}
566
567// #sec-temporal-isoyearmonthwithinlimits
568bool ISOYearMonthWithinLimits(int32_t year, int32_t month) {
570 // 1. Assert: year and month are integers.
571 // 2. If year < −271821 or year > 275760, then
572 // a. Return false.
573 if (year < -271821 || year > 275760) return false;
574 // 3. If year is −271821 and month < 4, then
575 // a. Return false.
576 if (year == -271821 && month < 4) return false;
577 // 4. If year is 275760 and month > 9, then
578 // a. Return false.
579 if (year == 275760 && month > 9) return false;
580 // 5. Return true.
581 return true;
582}
583
584#define ORDINARY_CREATE_FROM_CONSTRUCTOR(obj, target, new_target, T) \
585 DirectHandle<JSReceiver> new_target_receiver = Cast<JSReceiver>(new_target); \
586 DirectHandle<Map> map; \
587 ASSIGN_RETURN_ON_EXCEPTION( \
588 isolate, map, \
589 JSFunction::GetDerivedMap(isolate, target, new_target_receiver)); \
590 DirectHandle<T> object = \
591 Cast<T>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
592
593#define THROW_INVALID_RANGE(T) \
594 THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALID_ARG_RANGE_ERROR());
595
596#define CONSTRUCTOR(name) \
597 DirectHandle<JSFunction>( \
598 Cast<JSFunction>( \
599 isolate->context()->native_context()->temporal_##name##_function()), \
600 isolate)
601
602// #sec-temporal-systemutcepochnanoseconds
603DirectHandle<BigInt> SystemUTCEpochNanoseconds(Isolate* isolate) {
605 // 1. Let ns be the approximate current UTC date and time, in nanoseconds
606 // since the epoch.
607 double ms =
609 // 2. Set ns to the result of clamping ns between −8.64 × 10^21 and 8.64 ×
610 // 10^21.
611
612 // 3. Return ℤ(ns).
613 double ns = ms * 1000000.0;
614 ns = std::floor(std::max(-8.64e21, std::min(ns, 8.64e21)));
615 return BigInt::FromNumber(isolate, isolate->factory()->NewNumber(ns))
616 .ToHandleChecked();
617}
618
619// #sec-temporal-createtemporalcalendar
620MaybeDirectHandle<JSTemporalCalendar> CreateTemporalCalendar(
621 Isolate* isolate, DirectHandle<JSFunction> target,
622 DirectHandle<HeapObject> new_target, DirectHandle<String> identifier) {
624 // 1. Assert: ! IsBuiltinCalendar(identifier) is true.
625 // 2. If newTarget is not provided, set newTarget to %Temporal.Calendar%.
626 // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget,
627 // "%Temporal.Calendar.prototype%", « [[InitializedTemporalCalendar]],
628 // [[Identifier]] »).
629 int32_t index = CalendarIndex(isolate, identifier);
630
632 JSTemporalCalendar)
633
634 object->set_flags(0);
635 // 4. Set object.[[Identifier]] to identifier.
636 object->set_calendar_index(index);
637 // 5. Return object.
638 return object;
639}
640
641MaybeDirectHandle<JSTemporalCalendar> CreateTemporalCalendar(
642 Isolate* isolate, DirectHandle<String> identifier) {
644 return CreateTemporalCalendar(isolate, CONSTRUCTOR(calendar),
646}
647
648// #sec-temporal-createtemporaldate
649MaybeDirectHandle<JSTemporalPlainDate> CreateTemporalDate(
650 Isolate* isolate, DirectHandle<JSFunction> target,
651 DirectHandle<HeapObject> new_target, const DateRecord& date,
652 DirectHandle<JSReceiver> calendar) {
654 // 1. Assert: isoYear is an integer.
655 // 2. Assert: isoMonth is an integer.
656 // 3. Assert: isoDay is an integer.
657 // 4. Assert: Type(calendar) is Object.
658 // 5. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a
659 // RangeError exception.
660 if (!IsValidISODate(isolate, date)) {
661 THROW_INVALID_RANGE(JSTemporalPlainDate);
662 }
663 // 6. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0,
664 // 0) is false, throw a RangeError exception.
665 if (!ISODateTimeWithinLimits(isolate, {date, {12, 0, 0, 0, 0, 0}})) {
666 THROW_INVALID_RANGE(JSTemporalPlainDate);
667 }
668 // 7. If newTarget is not present, set it to %Temporal.PlainDate%.
669
670 // 8. Let object be ? OrdinaryCreateFromConstructor(newTarget,
671 // "%Temporal.PlainDate.prototype%", « [[InitializedTemporalDate]],
672 // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
674 JSTemporalPlainDate)
675 object->set_year_month_day(0);
676 // 9. Set object.[[ISOYear]] to isoYear.
677 object->set_iso_year(date.year);
678 // 10. Set object.[[ISOMonth]] to isoMonth.
679 object->set_iso_month(date.month);
680 // 11. Set object.[[ISODay]] to isoDay.
681 object->set_iso_day(date.day);
682 // 12. Set object.[[Calendar]] to calendar.
683 object->set_calendar(*calendar);
684 // 13. Return object.
685 return object;
686}
687
688MaybeDirectHandle<JSTemporalPlainDate> CreateTemporalDate(
689 Isolate* isolate, const DateRecord& date,
690 DirectHandle<JSReceiver> calendar) {
692 return CreateTemporalDate(isolate, CONSTRUCTOR(plain_date),
693 CONSTRUCTOR(plain_date), date, calendar);
694}
695
696// #sec-temporal-createtemporaldatetime
697MaybeDirectHandle<JSTemporalPlainDateTime> CreateTemporalDateTime(
698 Isolate* isolate, DirectHandle<JSFunction> target,
699 DirectHandle<HeapObject> new_target, const DateTimeRecord& date_time,
700 DirectHandle<JSReceiver> calendar) {
702 // 1. Assert: isoYear, isoMonth, isoDay, hour, minute, second, millisecond,
703 // microsecond, and nanosecond are integers.
704 // 2. Assert: Type(calendar) is Object.
705 // 3. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a
706 // RangeError exception.
707 if (!IsValidISODate(isolate, date_time.date)) {
708 THROW_INVALID_RANGE(JSTemporalPlainDateTime);
709 }
710 // 4. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
711 // nanosecond) is false, throw a RangeError exception.
712 if (!IsValidTime(isolate, date_time.time)) {
713 THROW_INVALID_RANGE(JSTemporalPlainDateTime);
714 }
715 // 5. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute,
716 // second, millisecond, microsecond, nanosecond) is false, then
717 if (!ISODateTimeWithinLimits(isolate, date_time)) {
718 // a. Throw a RangeError exception.
719 THROW_INVALID_RANGE(JSTemporalPlainDateTime);
720 }
721 // 6. If newTarget is not present, set it to %Temporal.PlainDateTime%.
722 // 7. Let object be ? OrdinaryCreateFromConstructor(newTarget,
723 // "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]],
724 // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]],
725 // [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]],
726 // [[Calendar]] »).
728 JSTemporalPlainDateTime)
729
730 object->set_year_month_day(0);
731 object->set_hour_minute_second(0);
732 object->set_second_parts(0);
733 // 8. Set object.[[ISOYear]] to isoYear.
734 object->set_iso_year(date_time.date.year);
735 // 9. Set object.[[ISOMonth]] to isoMonth.
736 object->set_iso_month(date_time.date.month);
737 // 10. Set object.[[ISODay]] to isoDay.
738 object->set_iso_day(date_time.date.day);
739 // 11. Set object.[[ISOHour]] to hour.
740 object->set_iso_hour(date_time.time.hour);
741 // 12. Set object.[[ISOMinute]] to minute.
742 object->set_iso_minute(date_time.time.minute);
743 // 13. Set object.[[ISOSecond]] to second.
744 object->set_iso_second(date_time.time.second);
745 // 14. Set object.[[ISOMillisecond]] to millisecond.
746 object->set_iso_millisecond(date_time.time.millisecond);
747 // 15. Set object.[[ISOMicrosecond]] to microsecond.
748 object->set_iso_microsecond(date_time.time.microsecond);
749 // 16. Set object.[[ISONanosecond]] to nanosecond.
750 object->set_iso_nanosecond(date_time.time.nanosecond);
751 // 17. Set object.[[Calendar]] to calendar.
752 object->set_calendar(*calendar);
753 // 18. Return object.
754 return object;
755}
756
757MaybeDirectHandle<JSTemporalPlainDateTime> CreateTemporalDateTimeDefaultTarget(
758 Isolate* isolate, const DateTimeRecord& date_time,
759 DirectHandle<JSReceiver> calendar) {
761 return CreateTemporalDateTime(isolate, CONSTRUCTOR(plain_date_time),
762 CONSTRUCTOR(plain_date_time), date_time,
763 calendar);
764}
765
766} // namespace
767
768namespace temporal {
769
771 Isolate* isolate, const DateTimeRecord& date_time,
773 return CreateTemporalDateTimeDefaultTarget(isolate, date_time, calendar);
774}
775
776} // namespace temporal
777
778namespace {
779// #sec-temporal-createtemporaltime
780MaybeDirectHandle<JSTemporalPlainTime> CreateTemporalTime(
781 Isolate* isolate, DirectHandle<JSFunction> target,
782 DirectHandle<HeapObject> new_target, const TimeRecord& time) {
784 // 2. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
785 // nanosecond) is false, throw a RangeError exception.
786 if (!IsValidTime(isolate, time)) {
787 THROW_INVALID_RANGE(JSTemporalPlainTime);
788 }
789
790 DirectHandle<JSTemporalCalendar> calendar =
792
793 // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget,
794 // "%Temporal.PlainTime.prototype%", « [[InitializedTemporalTime]],
795 // [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]],
796 // [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] »).
798 JSTemporalPlainTime)
799 object->set_hour_minute_second(0);
800 object->set_second_parts(0);
801 // 5. Set object.[[ISOHour]] to hour.
802 object->set_iso_hour(time.hour);
803 // 6. Set object.[[ISOMinute]] to minute.
804 object->set_iso_minute(time.minute);
805 // 7. Set object.[[ISOSecond]] to second.
806 object->set_iso_second(time.second);
807 // 8. Set object.[[ISOMillisecond]] to millisecond.
808 object->set_iso_millisecond(time.millisecond);
809 // 9. Set object.[[ISOMicrosecond]] to microsecond.
810 object->set_iso_microsecond(time.microsecond);
811 // 10. Set object.[[ISONanosecond]] to nanosecond.
812 object->set_iso_nanosecond(time.nanosecond);
813 // 11. Set object.[[Calendar]] to ? GetISO8601Calendar().
814 object->set_calendar(*calendar);
815
816 // 12. Return object.
817 return object;
818}
819
820MaybeDirectHandle<JSTemporalPlainTime> CreateTemporalTime(
821 Isolate* isolate, const TimeRecord& time) {
823 return CreateTemporalTime(isolate, CONSTRUCTOR(plain_time),
824 CONSTRUCTOR(plain_time), time);
825}
826
827// #sec-temporal-createtemporalmonthday
828MaybeDirectHandle<JSTemporalPlainMonthDay> CreateTemporalMonthDay(
829 Isolate* isolate, DirectHandle<JSFunction> target,
830 DirectHandle<HeapObject> new_target, int32_t iso_month, int32_t iso_day,
831 DirectHandle<JSReceiver> calendar, int32_t reference_iso_year) {
833 // 1. Assert: isoMonth, isoDay, and referenceISOYear are integers.
834 // 2. Assert: Type(calendar) is Object.
835 // 3. If ! IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw
836 if (!IsValidISODate(isolate, {reference_iso_year, iso_month, iso_day})) {
837 // a RangeError exception.
838 THROW_INVALID_RANGE(JSTemporalPlainMonthDay);
839 }
840 // 4. If ISODateTimeWithinLimits(referenceISOYear, isoMonth, isoDay, 12, 0, 0,
841 // 0, 0, 0) is false, throw a RangeError exception.
842 if (!ISODateTimeWithinLimits(
843 isolate,
844 {{reference_iso_year, iso_month, iso_day}, {12, 0, 0, 0, 0, 0}})) {
845 THROW_INVALID_RANGE(JSTemporalPlainMonthDay);
846 }
847
848 // 5. If newTarget is not present, set it to %Temporal.PlainMonthDay%.
849 // 6. Let object be ? OrdinaryCreateFromConstructor(newTarget,
850 // "%Temporal.PlainMonthDay.prototype%", « [[InitializedTemporalMonthDay]],
851 // [[ISOMonth]], [[ISODay]], [[ISOYear]], [[Calendar]] »).
853 JSTemporalPlainMonthDay)
854 object->set_year_month_day(0);
855 // 7. Set object.[[ISOMonth]] to isoMonth.
856 object->set_iso_month(iso_month);
857 // 8. Set object.[[ISODay]] to isoDay.
858 object->set_iso_day(iso_day);
859 // 9. Set object.[[Calendar]] to calendar.
860 object->set_calendar(*calendar);
861 // 10. Set object.[[ISOYear]] to referenceISOYear.
862 object->set_iso_year(reference_iso_year);
863 // 11. Return object.
864 return object;
865}
866
867MaybeDirectHandle<JSTemporalPlainMonthDay> CreateTemporalMonthDay(
868 Isolate* isolate, int32_t iso_month, int32_t iso_day,
869 DirectHandle<JSReceiver> calendar, int32_t reference_iso_year) {
870 return CreateTemporalMonthDay(isolate, CONSTRUCTOR(plain_month_day),
871 CONSTRUCTOR(plain_month_day), iso_month,
872 iso_day, calendar, reference_iso_year);
873}
874
875// #sec-temporal-createtemporalyearmonth
876MaybeDirectHandle<JSTemporalPlainYearMonth> CreateTemporalYearMonth(
877 Isolate* isolate, DirectHandle<JSFunction> target,
878 DirectHandle<HeapObject> new_target, int32_t iso_year, int32_t iso_month,
879 DirectHandle<JSReceiver> calendar, int32_t reference_iso_day) {
881 // 1. Assert: isoYear, isoMonth, and referenceISODay are integers.
882 // 2. Assert: Type(calendar) is Object.
883 // 3. If ! IsValidISODate(isoYear, isoMonth, referenceISODay) is false, throw
884 // a RangeError exception.
885 if (!IsValidISODate(isolate, {iso_year, iso_month, reference_iso_day})) {
886 THROW_INVALID_RANGE(JSTemporalPlainYearMonth);
887 }
888 // 4. If ! ISOYearMonthWithinLimits(isoYear, isoMonth) is false, throw a
889 // RangeError exception.
890 if (!ISOYearMonthWithinLimits(iso_year, iso_month)) {
891 THROW_INVALID_RANGE(JSTemporalPlainYearMonth);
892 }
893 // 5. If newTarget is not present, set it to %Temporal.PlainYearMonth%.
894 // 6. Let object be ? OrdinaryCreateFromConstructor(newTarget,
895 // "%Temporal.PlainYearMonth.prototype%", « [[InitializedTemporalYearMonth]],
896 // [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
898 JSTemporalPlainYearMonth)
899 object->set_year_month_day(0);
900 // 7. Set object.[[ISOYear]] to isoYear.
901 object->set_iso_year(iso_year);
902 // 8. Set object.[[ISOMonth]] to isoMonth.
903 object->set_iso_month(iso_month);
904 // 9. Set object.[[Calendar]] to calendar.
905 object->set_calendar(*calendar);
906 // 10. Set object.[[ISODay]] to referenceISODay.
907 object->set_iso_day(reference_iso_day);
908 // 11. Return object.
909 return object;
910}
911
912MaybeDirectHandle<JSTemporalPlainYearMonth> CreateTemporalYearMonth(
913 Isolate* isolate, int32_t iso_year, int32_t iso_month,
914 DirectHandle<JSReceiver> calendar, int32_t reference_iso_day) {
916 return CreateTemporalYearMonth(isolate, CONSTRUCTOR(plain_year_month),
917 CONSTRUCTOR(plain_year_month), iso_year,
918 iso_month, calendar, reference_iso_day);
919}
920
921// #sec-temporal-createtemporalzoneddatetime
922MaybeDirectHandle<JSTemporalZonedDateTime> CreateTemporalZonedDateTime(
923 Isolate* isolate, DirectHandle<JSFunction> target,
924 DirectHandle<HeapObject> new_target, DirectHandle<BigInt> epoch_nanoseconds,
925 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar) {
927 // 1. Assert: Type(epochNanoseconds) is BigInt.
928 // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
929 DCHECK(IsValidEpochNanoseconds(isolate, epoch_nanoseconds));
930 // 3. Assert: Type(timeZone) is Object.
931 // 4. Assert: Type(calendar) is Object.
932 // 5. If newTarget is not present, set it to %Temporal.ZonedDateTime%.
933 // 6. Let object be ? OrdinaryCreateFromConstructor(newTarget,
934 // "%Temporal.ZonedDateTime.prototype%", «
935 // [[InitializedTemporalZonedDateTime]], [[Nanoseconds]], [[TimeZone]],
936 // [[Calendar]] »).
938 JSTemporalZonedDateTime)
939 // 7. Set object.[[Nanoseconds]] to epochNanoseconds.
940 object->set_nanoseconds(*epoch_nanoseconds);
941 // 8. Set object.[[TimeZone]] to timeZone.
942 object->set_time_zone(*time_zone);
943 // 9. Set object.[[Calendar]] to calendar.
944 object->set_calendar(*calendar);
945 // 10. Return object.
946 return object;
947}
948
949MaybeDirectHandle<JSTemporalZonedDateTime> CreateTemporalZonedDateTime(
950 Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds,
951 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar) {
953 return CreateTemporalZonedDateTime(isolate, CONSTRUCTOR(zoned_date_time),
954 CONSTRUCTOR(zoned_date_time),
955 epoch_nanoseconds, time_zone, calendar);
956}
957
958inline double NormalizeMinusZero(double v) { return IsMinusZero(v) ? 0 : v; }
959
960// #sec-temporal-createdatedurationrecord
961Maybe<DateDurationRecord> DateDurationRecord::Create(
962 Isolate* isolate, double years, double months, double weeks, double days) {
963 // 1. If ! IsValidDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0) is
964 // false, throw a RangeError exception.
965 if (!IsValidDuration(isolate,
966 {years, months, weeks, {days, 0, 0, 0, 0, 0, 0}})) {
969 Nothing<DateDurationRecord>());
970 }
971 // 2. Return the Record { [[Years]]: ℝ(𝔽(years)), [[Months]]: ℝ(𝔽(months)),
972 // [[Weeks]]: ℝ(𝔽(weeks)), [[Days]]: ℝ(𝔽(days)) }.
973 DateDurationRecord record = {years, months, weeks, days};
974 return Just(record);
975}
976
977} // namespace
978
979namespace temporal {
980// #sec-temporal-createtimedurationrecord
981Maybe<TimeDurationRecord> TimeDurationRecord::Create(
982 Isolate* isolate, double days, double hours, double minutes, double seconds,
983 double milliseconds, double microseconds, double nanoseconds) {
984 // 1. If ! IsValidDuration(0, 0, 0, days, hours, minutes, seconds,
985 // milliseconds, microseconds, nanoseconds) is false, throw a RangeError
986 // exception.
987 TimeDurationRecord record = {days, hours, minutes, seconds,
988 milliseconds, microseconds, nanoseconds};
989 if (!IsValidDuration(isolate, {0, 0, 0, record})) {
992 Nothing<TimeDurationRecord>());
993 }
994 // 2. Return the Record { [[Days]]: ℝ(𝔽(days)), [[Hours]]: ℝ(𝔽(hours)),
995 // [[Minutes]]: ℝ(𝔽(minutes)), [[Seconds]]: ℝ(𝔽(seconds)), [[Milliseconds]]:
996 // ℝ(𝔽(milliseconds)), [[Microseconds]]: ℝ(𝔽(microseconds)), [[Nanoseconds]]:
997 // ℝ(𝔽(nanoseconds)) }.
998 return Just(record);
999}
1000
1001// #sec-temporal-createdurationrecord
1002Maybe<DurationRecord> DurationRecord::Create(
1003 Isolate* isolate, double years, double months, double weeks, double days,
1004 double hours, double minutes, double seconds, double milliseconds,
1005 double microseconds, double nanoseconds) {
1006 // 1. If ! IsValidDuration(years, months, weeks, days, hours, minutes,
1007 // seconds, milliseconds, microseconds, nanoseconds) is false, throw a
1008 // RangeError exception.
1010 years,
1011 months,
1012 weeks,
1013 {days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds}};
1014 if (!IsValidDuration(isolate, record)) {
1017 Nothing<DurationRecord>());
1018 }
1019 // 2. Return the Record { [[Years]]: ℝ(𝔽(years)), [[Months]]: ℝ(𝔽(months)),
1020 // [[Weeks]]: ℝ(𝔽(weeks)), [[Days]]: ℝ(𝔽(days)), [[Hours]]: ℝ(𝔽(hours)),
1021 // [[Minutes]]: ℝ(𝔽(minutes)), [[Seconds]]: ℝ(𝔽(seconds)), [[Milliseconds]]:
1022 // ℝ(𝔽(milliseconds)), [[Microseconds]]: ℝ(𝔽(microseconds)), [[Nanoseconds]]:
1023 // ℝ(𝔽(nanoseconds)) }.
1024 return Just(record);
1025}
1026} // namespace temporal
1027
1028namespace {
1029// #sec-temporal-createtemporalduration
1030MaybeDirectHandle<JSTemporalDuration> CreateTemporalDuration(
1031 Isolate* isolate, DirectHandle<JSFunction> target,
1034 Factory* factory = isolate->factory();
1035 // 1. If ! IsValidDuration(years, months, weeks, days, hours, minutes,
1036 // seconds, milliseconds, microseconds, nanoseconds) is false, throw a
1037 // RangeError exception.
1038 if (!IsValidDuration(isolate, duration)) {
1040 }
1041
1042 // 2. If newTarget is not present, set it to %Temporal.Duration%.
1043 // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget,
1044 // "%Temporal.Duration.prototype%", « [[InitializedTemporalDuration]],
1045 // [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]],
1046 // [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
1047 const TimeDurationRecord& time_duration = duration.time_duration;
1048 DirectHandle<Number> years =
1049 factory->NewNumber(NormalizeMinusZero(duration.years));
1050 DirectHandle<Number> months =
1051 factory->NewNumber(NormalizeMinusZero(duration.months));
1052 DirectHandle<Number> weeks =
1053 factory->NewNumber(NormalizeMinusZero(duration.weeks));
1054 DirectHandle<Number> days =
1055 factory->NewNumber(NormalizeMinusZero(time_duration.days));
1056 DirectHandle<Number> hours =
1057 factory->NewNumber(NormalizeMinusZero(time_duration.hours));
1058 DirectHandle<Number> minutes =
1059 factory->NewNumber(NormalizeMinusZero(time_duration.minutes));
1060 DirectHandle<Number> seconds =
1061 factory->NewNumber(NormalizeMinusZero(time_duration.seconds));
1062 DirectHandle<Number> milliseconds =
1063 factory->NewNumber(NormalizeMinusZero(time_duration.milliseconds));
1064 DirectHandle<Number> microseconds =
1065 factory->NewNumber(NormalizeMinusZero(time_duration.microseconds));
1066 DirectHandle<Number> nanoseconds =
1067 factory->NewNumber(NormalizeMinusZero(time_duration.nanoseconds));
1069 JSTemporalDuration)
1070 // 4. Set object.[[Years]] to ℝ(𝔽(years)).
1071 object->set_years(*years);
1072 // 5. Set object.[[Months]] to ℝ(𝔽(months)).
1073 object->set_months(*months);
1074 // 6. Set object.[[Weeks]] to ℝ(𝔽(weeks)).
1075 object->set_weeks(*weeks);
1076 // 7. Set object.[[Days]] to ℝ(𝔽(days)).
1077 object->set_days(*days);
1078 // 8. Set object.[[Hours]] to ℝ(𝔽(hours)).
1079 object->set_hours(*hours);
1080 // 9. Set object.[[Minutes]] to ℝ(𝔽(minutes)).
1081 object->set_minutes(*minutes);
1082 // 10. Set object.[[Seconds]] to ℝ(𝔽(seconds)).
1083 object->set_seconds(*seconds);
1084 // 11. Set object.[[Milliseconds]] to ℝ(𝔽(milliseconds)).
1085 object->set_milliseconds(*milliseconds);
1086 // 12. Set object.[[Microseconds]] to ℝ(𝔽(microseconds)).
1087 object->set_microseconds(*microseconds);
1088 // 13. Set object.[[Nanoseconds]] to ℝ(𝔽(nanoseconds)).
1089 object->set_nanoseconds(*nanoseconds);
1090 // 14. Return object.
1091 return object;
1092}
1093
1094MaybeDirectHandle<JSTemporalDuration> CreateTemporalDuration(
1095 Isolate* isolate, const DurationRecord& duration) {
1097 return CreateTemporalDuration(isolate, CONSTRUCTOR(duration),
1098 CONSTRUCTOR(duration), duration);
1099}
1100
1101} // namespace
1102
1103namespace temporal {
1104
1105// #sec-temporal-createtemporalinstant
1107 Isolate* isolate, DirectHandle<JSFunction> target,
1109 DirectHandle<BigInt> epoch_nanoseconds) {
1111 // 1. Assert: Type(epochNanoseconds) is BigInt.
1112 // 2. Assert: ! IsValidEpochNanoseconds(epochNanoseconds) is true.
1113 DCHECK(IsValidEpochNanoseconds(isolate, epoch_nanoseconds));
1114
1115 // 4. Let object be ? OrdinaryCreateFromConstructor(newTarget,
1116 // "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]],
1117 // [[Nanoseconds]] »).
1120 // 5. Set object.[[Nanoseconds]] to ns.
1121 object->set_nanoseconds(*epoch_nanoseconds);
1122 return object;
1123}
1124
1126 Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds) {
1128 return CreateTemporalInstant(isolate, CONSTRUCTOR(instant),
1129 CONSTRUCTOR(instant), epoch_nanoseconds);
1130}
1131
1132} // namespace temporal
1133
1134namespace {
1135
1136MaybeDirectHandle<JSTemporalTimeZone> CreateTemporalTimeZoneFromIndex(
1137 Isolate* isolate, DirectHandle<JSFunction> target,
1138 DirectHandle<HeapObject> new_target, int32_t index) {
1141 JSTemporalTimeZone)
1142 object->set_flags(0);
1143 object->set_details(0);
1144
1145 object->set_is_offset(false);
1146 object->set_offset_milliseconds_or_time_zone_index(index);
1147 return object;
1148}
1149
1150DirectHandle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(
1151 Isolate* isolate, DirectHandle<JSFunction> target,
1152 DirectHandle<HeapObject> new_target) {
1154 return CreateTemporalTimeZoneFromIndex(isolate, target, new_target, 0)
1155 .ToHandleChecked();
1156}
1157
1158DirectHandle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(Isolate* isolate) {
1160 return CreateTemporalTimeZoneUTC(isolate, CONSTRUCTOR(time_zone),
1162}
1163
1164bool IsUTC(Isolate* isolate, DirectHandle<String> time_zone);
1165
1166// #sec-temporal-createtemporaltimezone
1167MaybeDirectHandle<JSTemporalTimeZone> CreateTemporalTimeZone(
1168 Isolate* isolate, DirectHandle<JSFunction> target,
1169 DirectHandle<HeapObject> new_target, DirectHandle<String> identifier) {
1171
1172 // 1. If newTarget is not present, set it to %Temporal.TimeZone%.
1173 // 2. Let object be ? OrdinaryCreateFromConstructor(newTarget,
1174 // "%Temporal.TimeZone.prototype%", « [[InitializedTemporalTimeZone]],
1175 // [[Identifier]], [[OffsetNanoseconds]] »).
1176
1177 // 3. Let offsetNanosecondsResult be ParseTimeZoneOffsetString(identifier).
1178 Maybe<int64_t> maybe_offset_nanoseconds =
1179 ParseTimeZoneOffsetString(isolate, identifier);
1180 // 4. If offsetNanosecondsResult is an abrupt completion, then
1181 if (maybe_offset_nanoseconds.IsNothing()) {
1182 DCHECK(isolate->has_exception());
1183 isolate->clear_exception();
1184 // a. Assert: ! CanonicalizeTimeZoneName(identifier) is identifier.
1186 CanonicalizeTimeZoneName(isolate, identifier)));
1187
1188 // b. Set object.[[Identifier]] to identifier.
1189 // c. Set object.[[OffsetNanoseconds]] to undefined.
1190 if (IsUTC(isolate, identifier)) {
1191 return CreateTemporalTimeZoneUTC(isolate, target, new_target);
1192 }
1193#ifdef V8_INTL_SUPPORT
1194 int32_t time_zone_index = Intl::GetTimeZoneIndex(isolate, identifier);
1195 DCHECK_GE(time_zone_index, 0);
1196 return CreateTemporalTimeZoneFromIndex(isolate, target, new_target,
1197 time_zone_index);
1198#else
1199 UNREACHABLE();
1200#endif // V8_INTL_SUPPORT
1201 // 5. Else,
1202 } else {
1203 // a. Set object.[[Identifier]] to !
1204 // FormatTimeZoneOffsetString(offsetNanosecondsResult.[[Value]]). b. Set
1205 // object.[[OffsetNanoseconds]] to offsetNanosecondsResult.[[Value]].
1207 JSTemporalTimeZone)
1208 object->set_flags(0);
1209 object->set_details(0);
1210
1211 object->set_is_offset(true);
1212 object->set_offset_nanoseconds(maybe_offset_nanoseconds.FromJust());
1213 return object;
1214 }
1215 // 6. Return object.
1216}
1217
1218MaybeDirectHandle<JSTemporalTimeZone> CreateTemporalTimeZoneDefaultTarget(
1219 Isolate* isolate, DirectHandle<String> identifier) {
1223}
1224
1225} // namespace
1226
1227namespace temporal {
1230 return CreateTemporalTimeZoneDefaultTarget(isolate, identifier);
1231}
1232} // namespace temporal
1233
1234namespace {
1235
1236// #sec-temporal-systeminstant
1237DirectHandle<JSTemporalInstant> SystemInstant(Isolate* isolate) {
1239 // 1. Let ns be ! SystemUTCEpochNanoseconds().
1240 DirectHandle<BigInt> ns = SystemUTCEpochNanoseconds(isolate);
1241 // 2. Return ? CreateTemporalInstant(ns).
1242 return temporal::CreateTemporalInstant(isolate, ns).ToHandleChecked();
1243}
1244
1245// #sec-temporal-systemtimezone
1246DirectHandle<JSTemporalTimeZone> SystemTimeZone(Isolate* isolate) {
1248 DirectHandle<String> default_time_zone = DefaultTimeZone(isolate);
1249 return temporal::CreateTemporalTimeZone(isolate, default_time_zone)
1250 .ToHandleChecked();
1251}
1252
1253DateTimeRecord GetISOPartsFromEpoch(Isolate* isolate,
1254 DirectHandle<BigInt> epoch_nanoseconds) {
1256 DateTimeRecord result;
1257 // 1. Assert: ! IsValidEpochNanoseconds(ℤ(epochNanoseconds)) is true.
1258 DCHECK(IsValidEpochNanoseconds(isolate, epoch_nanoseconds));
1259 // 2. Let remainderNs be epochNanoseconds modulo 10^6.
1260 DirectHandle<BigInt> million = BigInt::FromUint64(isolate, 1000000);
1261 DirectHandle<BigInt> remainder_ns =
1262 BigInt::Remainder(isolate, epoch_nanoseconds, million).ToHandleChecked();
1263 // Need to do some remainder magic to negative remainder.
1264 if (remainder_ns->IsNegative()) {
1265 remainder_ns =
1266 BigInt::Add(isolate, remainder_ns, million).ToHandleChecked();
1267 }
1268
1269 // 3. Let epochMilliseconds be (epochNanoseconds − remainderNs) / 10^6.
1270 int64_t epoch_milliseconds =
1271 BigInt::Divide(isolate,
1272 BigInt::Subtract(isolate, epoch_nanoseconds, remainder_ns)
1273 .ToHandleChecked(),
1274 million)
1275 .ToHandleChecked()
1276 ->AsInt64();
1277 int year = 0;
1278 int month = 0;
1279 int day = 0;
1280 int wday = 0;
1281 int hour = 0;
1282 int min = 0;
1283 int sec = 0;
1284 int ms = 0;
1285 isolate->date_cache()->BreakDownTime(epoch_milliseconds, &year, &month, &day,
1286 &wday, &hour, &min, &sec, &ms);
1287
1288 // 4. Let year be ! YearFromTime(epochMilliseconds).
1289 result.date.year = year;
1290 // 5. Let month be ! MonthFromTime(epochMilliseconds) + 1.
1291 result.date.month = month + 1;
1292 DCHECK_GE(result.date.month, 1);
1293 DCHECK_LE(result.date.month, 12);
1294 // 6. Let day be ! DateFromTime(epochMilliseconds).
1295 result.date.day = day;
1296 DCHECK_GE(result.date.day, 1);
1297 DCHECK_LE(result.date.day, 31);
1298 // 7. Let hour be ! HourFromTime(epochMilliseconds).
1299 result.time.hour = hour;
1300 DCHECK_GE(result.time.hour, 0);
1301 DCHECK_LE(result.time.hour, 23);
1302 // 8. Let minute be ! MinFromTime(epochMilliseconds).
1303 result.time.minute = min;
1304 DCHECK_GE(result.time.minute, 0);
1305 DCHECK_LE(result.time.minute, 59);
1306 // 9. Let second be ! SecFromTime(epochMilliseconds).
1307 result.time.second = sec;
1308 DCHECK_GE(result.time.second, 0);
1309 DCHECK_LE(result.time.second, 59);
1310 // 10. Let millisecond be ! msFromTime(epochMilliseconds).
1311 result.time.millisecond = ms;
1312 DCHECK_GE(result.time.millisecond, 0);
1313 DCHECK_LE(result.time.millisecond, 999);
1314 // 11. Let microsecond be floor(remainderNs / 1000) modulo 1000.
1315 int64_t remainder = remainder_ns->AsInt64();
1316 result.time.microsecond = (remainder / 1000) % 1000;
1317 DCHECK_GE(result.time.microsecond, 0);
1318 // 12. 12. Assert: microsecond < 1000.
1319 DCHECK_LE(result.time.microsecond, 999);
1320 // 13. Let nanosecond be remainderNs modulo 1000.
1321 result.time.nanosecond = remainder % 1000;
1322 DCHECK_GE(result.time.nanosecond, 0);
1323 DCHECK_LE(result.time.nanosecond, 999);
1324 // 14. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day,
1325 // [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]:
1326 // millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond }.
1327 return result;
1328}
1329
1330// #sec-temporal-balanceisodatetime
1331DateTimeRecord BalanceISODateTime(Isolate* isolate,
1332 const DateTimeRecord& date_time) {
1334 // 1. Assert: year, month, day, hour, minute, second, millisecond,
1335 // microsecond, and nanosecond are integers.
1336 // 2. Let balancedTime be ! BalanceTime(hour, minute, second, millisecond,
1337 // microsecond, nanosecond).
1338 DateTimeRecord balanced_time =
1339 BalanceTime({static_cast<double>(date_time.time.hour),
1340 static_cast<double>(date_time.time.minute),
1341 static_cast<double>(date_time.time.second),
1342 static_cast<double>(date_time.time.millisecond),
1343 static_cast<double>(date_time.time.microsecond),
1344 static_cast<double>(date_time.time.nanosecond)});
1345 // 3. Let balancedDate be ! BalanceISODate(year, month, day +
1346 // balancedTime.[[Days]]).
1347 DateRecord added_date = date_time.date;
1348 added_date.day += balanced_time.date.day;
1349 DateRecord balanced_date = BalanceISODate(isolate, added_date);
1350 // 4. Return the Record { [[Year]]: balancedDate.[[Year]], [[Month]]:
1351 // balancedDate.[[Month]], [[Day]]: balancedDate.[[Day]], [[Hour]]:
1352 // balancedTime.[[Hour]], [[Minute]]: balancedTime.[[Minute]], [[Second]]:
1353 // balancedTime.[[Second]], [[Millisecond]]: balancedTime.[[Millisecond]],
1354 // [[Microsecond]]: balancedTime.[[Microsecond]], [[Nanosecond]]:
1355 // balancedTime.[[Nanosecond]] }.
1356 return {balanced_date, balanced_time.time};
1357}
1358
1359// #sec-temporal-roundtowardszero
1360double RoundTowardsZero(double x) {
1361 // 1. Return the mathematical value that is the same sign as x and whose
1362 // magnitude is floor(abs(x)).
1363 if (x < 0) {
1364 return -std::floor(std::abs(x));
1365 } else {
1366 return std::floor(std::abs(x));
1367 }
1368}
1369
1370// #sec-temporal-temporaldurationtostring
1371DirectHandle<String> TemporalDurationToString(Isolate* isolate,
1372 const DurationRecord& duration,
1373 Precision precision) {
1374 IncrementalStringBuilder builder(isolate);
1375 DCHECK(precision != Precision::kMinute);
1376 // 1. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes,
1377 // seconds, milliseconds, microseconds, nanoseconds).
1378 DurationRecord dur = duration;
1380 // Note: for the operation below, to avoid microseconds .. seconds lost
1381 // precision while the resulting value may exceed the precision limit, we use
1382 // extra double xx_add to hold the additional temp value.
1383 // 2. Set microseconds to microseconds + RoundTowardsZero(nanoseconds / 1000).
1384 double microseconds_add =
1385 RoundTowardsZero(dur.time_duration.nanoseconds / 1000);
1386 // 3. Set nanoseconds to remainder(nanoseconds, 1000).
1387 dur.time_duration.nanoseconds =
1388 std::fmod(dur.time_duration.nanoseconds, 1000);
1389 // 4. Set milliseconds to milliseconds + RoundTowardsZero(microseconds /
1390 // 1000).
1391 double milliseconds_add = RoundTowardsZero(
1392 dur.time_duration.microseconds / 1000 + microseconds_add / 1000);
1393 // 5. Set microseconds to remainder(microseconds, 1000).
1394 dur.time_duration.microseconds =
1395 std::fmod(std::fmod(dur.time_duration.microseconds, 1000) +
1396 std::fmod(microseconds_add, 1000),
1397 1000);
1398 // 6. Set seconds to seconds + RoundTowardsZero(milliseconds / 1000).
1399 double seconds_add = RoundTowardsZero(dur.time_duration.milliseconds / 1000 +
1400 milliseconds_add / 1000);
1401 // 7. Set milliseconds to remainder(milliseconds, 1000).
1402 dur.time_duration.milliseconds =
1403 std::fmod(std::fmod(dur.time_duration.milliseconds, 1000) +
1404 std::fmod(milliseconds_add, 1000),
1405 1000);
1406
1407 // 8. Let datePart be "".
1408 IncrementalStringBuilder date_part(isolate);
1409 // Number.MAX_VALUE.toString() is "1.7976931348623157e+308"
1410 // We add several more spaces to 320.
1411 base::ScopedVector<char> buf(320);
1412
1413 // 9. If years is not 0, then
1414 if (dur.years != 0) {
1415 // a. Set datePart to the string concatenation of abs(years) formatted as a
1416 // decimal number and the code unit 0x0059 (LATIN CAPITAL LETTER Y).
1417 SNPrintF(buf, "%.0f", std::abs(dur.years));
1418 date_part.AppendCString(buf.data());
1419 date_part.AppendCharacter('Y');
1420 }
1421 // 10. If months is not 0, then
1422 if (dur.months != 0) {
1423 // a. Set datePart to the string concatenation of datePart,
1424 // abs(months) formatted as a decimal number, and the code unit
1425 // 0x004D (LATIN CAPITAL LETTER M).
1426 SNPrintF(buf, "%.0f", std::abs(dur.months));
1427 date_part.AppendCString(buf.data());
1428 date_part.AppendCharacter('M');
1429 }
1430 // 11. If weeks is not 0, then
1431 if (dur.weeks != 0) {
1432 // a. Set datePart to the string concatenation of datePart,
1433 // abs(weeks) formatted as a decimal number, and the code unit
1434 // 0x0057 (LATIN CAPITAL LETTER W).
1435 SNPrintF(buf, "%.0f", std::abs(dur.weeks));
1436 date_part.AppendCString(buf.data());
1437 date_part.AppendCharacter('W');
1438 }
1439 // 12. If days is not 0, then
1440 if (dur.time_duration.days != 0) {
1441 // a. Set datePart to the string concatenation of datePart,
1442 // abs(days) formatted as a decimal number, and the code unit 0x0044
1443 // (LATIN CAPITAL LETTER D).
1444 SNPrintF(buf, "%.0f", std::abs(dur.time_duration.days));
1445 date_part.AppendCString(buf.data());
1446 date_part.AppendCharacter('D');
1447 }
1448 // 13. Let timePart be "".
1449 IncrementalStringBuilder time_part(isolate);
1450 // 14. If hours is not 0, then
1451 if (dur.time_duration.hours != 0) {
1452 // a. Set timePart to the string concatenation of abs(hours) formatted as a
1453 // decimal number and the code unit 0x0048 (LATIN CAPITAL LETTER H).
1454 SNPrintF(buf, "%.0f", std::abs(dur.time_duration.hours));
1455 time_part.AppendCString(buf.data());
1456 time_part.AppendCharacter('H');
1457 }
1458 // 15. If minutes is not 0, then
1459 if (dur.time_duration.minutes != 0) {
1460 // a. Set timePart to the string concatenation of timePart,
1461 // abs(minutes) formatted as a decimal number, and the code unit
1462 // 0x004D (LATIN CAPITAL LETTER M).
1463 SNPrintF(buf, "%.0f", std::abs(dur.time_duration.minutes));
1464 time_part.AppendCString(buf.data());
1465 time_part.AppendCharacter('M');
1466 }
1467 IncrementalStringBuilder seconds_part(isolate);
1468 IncrementalStringBuilder decimal_part(isolate);
1469 // 16. If any of seconds, milliseconds, microseconds, and nanoseconds are not
1470 // 0; or years, months, weeks, days, hours, and minutes are all 0, or
1471 // precision is not "auto" then
1472 if ((dur.time_duration.seconds != 0 || seconds_add != 0 ||
1473 dur.time_duration.milliseconds != 0 ||
1474 dur.time_duration.microseconds != 0 ||
1475 dur.time_duration.nanoseconds != 0) ||
1476 (dur.years == 0 && dur.months == 0 && dur.weeks == 0 &&
1477 dur.time_duration.days == 0 && dur.time_duration.hours == 0 &&
1478 dur.time_duration.minutes == 0) ||
1479 precision != Precision::kAuto) {
1480 // a. Let fraction be abs(milliseconds) × 10^6 + abs(microseconds) × 10^3 +
1481 // abs(nanoseconds).
1482 int64_t fraction = std::abs(dur.time_duration.milliseconds) * 1e6 +
1483 std::abs(dur.time_duration.microseconds) * 1e3 +
1484 std::abs(dur.time_duration.nanoseconds);
1485 // b. Let decimalPart be fraction formatted as a nine-digit decimal number,
1486 // padded to the left with zeroes if necessary.
1487 int64_t divisor = 100000000;
1488
1489 // c. If precision is "auto", then
1490 if (precision == Precision::kAuto) {
1491 // i. Set decimalPart to the longest possible substring of decimalPart
1492 // starting at position 0 and not ending with the code unit 0x0030 (DIGIT
1493 // ZERO).
1494 while (fraction > 0) {
1495 decimal_part.AppendInt(static_cast<int32_t>(fraction / divisor));
1496 fraction %= divisor;
1497 divisor /= 10;
1498 }
1499 // d. Else if precision = 0, then
1500 } else if (precision == Precision::k0) {
1501 // i. Set decimalPart to "".
1502 // e. Else,
1503 } else {
1504 // i. Set decimalPart to the substring of decimalPart from 0 to precision.
1505 int32_t precision_len = static_cast<int32_t>(precision);
1506 DCHECK_LE(0, precision_len);
1507 DCHECK_GE(9, precision_len);
1508 for (int32_t len = 0; len < precision_len; len++) {
1509 decimal_part.AppendInt(static_cast<int32_t>(fraction / divisor));
1510 fraction %= divisor;
1511 divisor /= 10;
1512 }
1513 }
1514 // f. Let secondsPart be abs(seconds) formatted as a decimal number.
1515 if (std::abs(seconds_add + dur.time_duration.seconds) < kMaxSafeInteger) {
1516 // Fast path: The seconds_add + dur.time_duration.seconds is in the range
1517 // the double could keep the precision.
1518 dur.time_duration.seconds += seconds_add;
1519 SNPrintF(buf, "%.0f", std::abs(dur.time_duration.seconds));
1520 seconds_part.AppendCString(buf.data());
1521 } else {
1522 // Slow path: The seconds_add + dur.time_duration.seconds is out of the
1523 // range which the double could keep the precision. Format by math via
1524 // BigInt.
1525 seconds_part.AppendString(
1527 isolate,
1529 isolate,
1530 BigInt::FromNumber(isolate, isolate->factory()->NewNumber(
1531 std::abs(seconds_add)))
1532 .ToHandleChecked(),
1533 BigInt::FromNumber(isolate,
1534 isolate->factory()->NewNumber(
1535 std::abs(dur.time_duration.seconds)))
1536 .ToHandleChecked())
1537 .ToHandleChecked())
1538 .ToHandleChecked());
1539 }
1540
1541 // g. If decimalPart is not "", then
1542 if (decimal_part.Length() != 0) {
1543 // i. Set secondsPart to the string-concatenation of secondsPart, the code
1544 // unit 0x002E (FULL STOP), and decimalPart.
1545 seconds_part.AppendCharacter('.');
1546 seconds_part.AppendString(decimal_part.Finish().ToHandleChecked());
1547 }
1548
1549 // h. Set timePart to the string concatenation of timePart, secondsPart, and
1550 // the code unit 0x0053 (LATIN CAPITAL LETTER S).
1551 time_part.AppendString(seconds_part.Finish().ToHandleChecked());
1552 time_part.AppendCharacter('S');
1553 }
1554 // 17. Let signPart be the code unit 0x002D (HYPHEN-MINUS) if sign < 0, and
1555 // otherwise the empty String.
1556 if (sign < 0) {
1557 builder.AppendCharacter('-');
1558 }
1559
1560 // 18. Let result be the string concatenation of signPart, the code unit
1561 // 0x0050 (LATIN CAPITAL LETTER P) and datePart.
1562 builder.AppendCharacter('P');
1563 builder.AppendString(date_part.Finish().ToHandleChecked());
1564
1565 // 19. If timePart is not "", then
1566 if (time_part.Length() > 0) {
1567 // a. Set result to the string concatenation of result, the code unit 0x0054
1568 // (LATIN CAPITAL LETTER T), and timePart.
1569 builder.AppendCharacter('T');
1570 builder.AppendString(time_part.Finish().ToHandleChecked());
1571 }
1572 return builder.Finish().ToHandleChecked();
1573}
1574
1575void ToZeroPaddedDecimalString(IncrementalStringBuilder* builder, int32_t n,
1576 int32_t min_length);
1577// #sec-temporal-formatsecondsstringpart
1578void FormatSecondsStringPart(IncrementalStringBuilder* builder, int32_t second,
1579 int32_t millisecond, int32_t microsecond,
1580 int32_t nanosecond, Precision precision) {
1581 // 1. Assert: second, millisecond, microsecond and nanosecond are integers.
1582 // 2. If precision is "minute", return "".
1583 if (precision == Precision::kMinute) {
1584 return;
1585 }
1586 // 3. Let secondsString be the string-concatenation of the code unit 0x003A
1587 // (COLON) and second formatted as a two-digit decimal number, padded to the
1588 // left with zeroes if necessary.
1589 builder->AppendCharacter(':');
1590 ToZeroPaddedDecimalString(builder, second, 2);
1591 // 4. Let fraction be millisecond × 10^6 + microsecond × 10^3 + nanosecond.
1592 int64_t fraction = millisecond * 1000000 + microsecond * 1000 + nanosecond;
1593 int64_t divisor = 100000000;
1594 // 5. If precision is "auto", then
1595 if (precision == Precision::kAuto) {
1596 // a. If fraction is 0, return secondsString.
1597 if (fraction == 0) {
1598 return;
1599 }
1600 builder->AppendCharacter('.');
1601 // b. Set fraction to ToZeroPaddedDecimalString(fraction, 9).
1602 // c. Set fraction to the longest possible substring of fraction starting at
1603 // position 0 and not ending with the code unit 0x0030 (DIGIT ZERO).
1604 while (fraction > 0) {
1605 builder->AppendInt(static_cast<int32_t>(fraction / divisor));
1606 fraction %= divisor;
1607 divisor /= 10;
1608 }
1609 // 6. Else,
1610 } else {
1611 // a. If precision is 0, return secondsString.
1612 if (precision == Precision::k0) {
1613 return;
1614 }
1615 builder->AppendCharacter('.');
1616 // b. Set fraction to ToZeroPaddedDecimalString(fraction, 9).
1617 // c. Set fraction to the substring of fraction from 0 to precision.
1618 int32_t precision_len = static_cast<int32_t>(precision);
1619 DCHECK_LE(0, precision_len);
1620 DCHECK_GE(9, precision_len);
1621 for (int32_t len = 0; len < precision_len; len++) {
1622 builder->AppendInt(static_cast<int32_t>(fraction / divisor));
1623 fraction %= divisor;
1624 divisor /= 10;
1625 }
1626 }
1627 // 7. Return the string-concatenation of secondsString, the code unit 0x002E
1628 // (FULL STOP), and fraction.
1629}
1630
1631// #sec-temporal-temporaltimetostring
1632DirectHandle<String> TemporalTimeToString(Isolate* isolate,
1633 const TimeRecord& time,
1634 Precision precision) {
1635 // 1. Assert: hour, minute, second, millisecond, microsecond and nanosecond
1636 // are integers.
1637 IncrementalStringBuilder builder(isolate);
1638 // 2. Let hour be ToZeroPaddedDecimalString(hour, 2).
1639 ToZeroPaddedDecimalString(&builder, time.hour, 2);
1640 builder.AppendCharacter(':');
1641 // 3. Let minute be ToZeroPaddedDecimalString(minute, 2).
1642 ToZeroPaddedDecimalString(&builder, time.minute, 2);
1643 // 4. Let seconds be ! FormatSecondsStringPart(second, millisecond,
1644 // microsecond, nanosecond, precision).
1645 FormatSecondsStringPart(&builder, time.second, time.millisecond,
1646 time.microsecond, time.nanosecond, precision);
1647 // 5. Return the string-concatenation of hour, the code unit 0x003A (COLON),
1648 // minute, and seconds.
1649 return builder.Finish().ToHandleChecked();
1650}
1651
1652DirectHandle<String> TemporalTimeToString(
1653 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
1654 Precision precision) {
1655 return TemporalTimeToString(
1656 isolate,
1657 {temporal_time->iso_hour(), temporal_time->iso_minute(),
1658 temporal_time->iso_second(), temporal_time->iso_millisecond(),
1659 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
1660 precision);
1661}
1662
1663} // namespace
1664
1665namespace temporal {
1669 const char* method_name) {
1671 // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
1672 int64_t offset_nanoseconds;
1674 isolate, offset_nanoseconds,
1675 GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
1677 // 2. Let result be ! GetISOPartsFromEpoch(instant.[[Nanoseconds]]).
1678 DateTimeRecord result = GetISOPartsFromEpoch(
1679 isolate, direct_handle(instant->nanoseconds(), isolate));
1680
1681 // 3. Set result to ! BalanceISODateTime(result.[[Year]], result.[[Month]],
1682 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
1683 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]] +
1684 // offsetNanoseconds).
1685
1686 // Note: Since offsetNanoseconds is bounded 86400x 10^9, the
1687 // result of result.[[Nanosecond]] + offsetNanoseconds may overflow int32_t
1688 // Therefore we distribute the sum to other fields below to make sure it won't
1689 // overflow each of the int32_t fields. But it will leave each field to be
1690 // balanced by BalanceISODateTime
1691 result.time.nanosecond += offset_nanoseconds % 1000;
1692 result.time.microsecond += (offset_nanoseconds / 1000) % 1000;
1693 result.time.millisecond += (offset_nanoseconds / 1000000L) % 1000;
1694 result.time.second += (offset_nanoseconds / 1000000000L) % 60;
1695 result.time.minute += (offset_nanoseconds / 60000000000L) % 60;
1696 result.time.hour += (offset_nanoseconds / 3600000000000L) % 24;
1697 result.date.day += (offset_nanoseconds / 86400000000000L);
1698
1699 result = BalanceISODateTime(isolate, result);
1700 // 4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
1701 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
1702 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
1703 // calendar).
1704 return temporal::CreateTemporalDateTime(isolate, result, calendar);
1705}
1706
1707} // namespace temporal
1708
1709namespace {
1710// #sec-temporal-getpossibleinstantsfor
1711MaybeDirectHandle<FixedArray> GetPossibleInstantsFor(
1712 Isolate* isolate, DirectHandle<JSReceiver> time_zone,
1713 DirectHandle<Object> date_time) {
1715 // 1. Let possibleInstants be ? Invoke(timeZone, "getPossibleInstantsFor", «
1716 // dateTime »).
1717 DirectHandle<Object> function;
1719 isolate, function,
1721 isolate->factory()->getPossibleInstantsFor_string()));
1722 if (!IsCallable(*function)) {
1724 isolate,
1725 NewTypeError(MessageTemplate::kCalledNonCallable,
1726 isolate->factory()->getPossibleInstantsFor_string()));
1727 }
1728 DirectHandle<Object> possible_instants;
1729 {
1730 DirectHandle<Object> args[] = {date_time};
1732 isolate, possible_instants,
1733 Execution::Call(isolate, function, time_zone, base::VectorOf(args)));
1734 }
1735
1736 // Step 4-6 of GetPossibleInstantsFor is implemented inside
1737 // temporal_instant_fixed_array_from_iterable.
1738 {
1739 DirectHandle<Object> args[] = {possible_instants};
1741 isolate, possible_instants,
1743 isolate, isolate->temporal_instant_fixed_array_from_iterable(),
1744 possible_instants, base::VectorOf(args)));
1745 }
1746 DCHECK(IsFixedArray(*possible_instants));
1747 // 7. Return list.
1748 return Cast<FixedArray>(possible_instants);
1749}
1750
1751// #sec-temporal-disambiguatepossibleinstants
1752MaybeDirectHandle<JSTemporalInstant> DisambiguatePossibleInstants(
1753 Isolate* isolate, DirectHandle<FixedArray> possible_instants,
1754 DirectHandle<JSReceiver> time_zone, DirectHandle<Object> date_time_obj,
1755 Disambiguation disambiguation, const char* method_name) {
1757 // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot.
1758 DCHECK(IsJSTemporalPlainDateTime(*date_time_obj));
1759 auto date_time = Cast<JSTemporalPlainDateTime>(date_time_obj);
1760
1761 // 2. Let n be possibleInstants's length.
1762 int32_t n = possible_instants->length();
1763
1764 // 3. If n = 1, then
1765 if (n == 1) {
1766 // a. Return possibleInstants[0].
1767 DirectHandle<Object> ret_obj(possible_instants->get(0), isolate);
1768 DCHECK(IsJSTemporalInstant(*ret_obj));
1769 return Cast<JSTemporalInstant>(ret_obj);
1770 }
1771 // 4. If n ≠ 0, then
1772 if (n != 0) {
1773 // a. If disambiguation is "earlier" or "compatible", then
1774 if (disambiguation == Disambiguation::kEarlier ||
1775 disambiguation == Disambiguation::kCompatible) {
1776 // i. Return possibleInstants[0].
1777 DirectHandle<Object> ret_obj(possible_instants->get(0), isolate);
1778 DCHECK(IsJSTemporalInstant(*ret_obj));
1779 return Cast<JSTemporalInstant>(ret_obj);
1780 }
1781 // b. If disambiguation is "later", then
1782 if (disambiguation == Disambiguation::kLater) {
1783 // i. Return possibleInstants[n − 1].
1784 DirectHandle<Object> ret_obj(possible_instants->get(n - 1), isolate);
1785 DCHECK(IsJSTemporalInstant(*ret_obj));
1786 return Cast<JSTemporalInstant>(ret_obj);
1787 }
1788 // c. Assert: disambiguation is "reject".
1789 DCHECK_EQ(disambiguation, Disambiguation::kReject);
1790 // d. Throw a RangeError exception.
1792 }
1793 // 5. Assert: n = 0.
1794 DCHECK_EQ(n, 0);
1795 // 6. If disambiguation is "reject", then
1796 if (disambiguation == Disambiguation::kReject) {
1797 // a. Throw a RangeError exception.
1799 }
1800 // 7. Let epochNanoseconds be ! GetEpochFromISOParts(dateTime.[[ISOYear]],
1801 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
1802 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
1803 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
1804 // dateTime.[[ISONanosecond]]).
1805 DirectHandle<BigInt> epoch_nanoseconds = GetEpochFromISOParts(
1806 isolate,
1807 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
1808 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
1809 date_time->iso_millisecond(), date_time->iso_microsecond(),
1810 date_time->iso_nanosecond()}});
1811
1812 // 8. Let dayBeforeNs be epochNanoseconds - ℤ(nsPerDay).
1813 DirectHandle<BigInt> one_day_in_ns =
1814 BigInt::FromUint64(isolate, 86400000000000ULL);
1815 DirectHandle<BigInt> day_before_ns =
1816 BigInt::Subtract(isolate, epoch_nanoseconds, one_day_in_ns)
1817 .ToHandleChecked();
1818 // 9. If ! IsValidEpochNanoseconds(dayBeforeNs) is false, throw a RangeError
1819 // exception.
1820 if (!IsValidEpochNanoseconds(isolate, day_before_ns)) {
1822 }
1823 // 10. Let dayBefore be ! CreateTemporalInstant(dayBeforeNs).
1824 DirectHandle<JSTemporalInstant> day_before =
1825 temporal::CreateTemporalInstant(isolate, day_before_ns).ToHandleChecked();
1826 // 11. Let dayAfterNs be epochNanoseconds + ℤ(nsPerDay).
1827 DirectHandle<BigInt> day_after_ns =
1828 BigInt::Add(isolate, epoch_nanoseconds, one_day_in_ns).ToHandleChecked();
1829 // 12. If ! IsValidEpochNanoseconds(dayAfterNs) is false, throw a RangeError
1830 // exception.
1831 if (!IsValidEpochNanoseconds(isolate, day_after_ns)) {
1833 }
1834 // 13. Let dayAfter be ! CreateTemporalInstant(dayAfterNs).
1835 DirectHandle<JSTemporalInstant> day_after =
1836 temporal::CreateTemporalInstant(isolate, day_after_ns).ToHandleChecked();
1837 // 10. Let offsetBefore be ? GetOffsetNanosecondsFor(timeZone, dayBefore).
1838 int64_t offset_before;
1840 isolate, offset_before,
1841 GetOffsetNanosecondsFor(isolate, time_zone, day_before, method_name),
1842 DirectHandle<JSTemporalInstant>());
1843 // 11. Let offsetAfter be ? GetOffsetNanosecondsFor(timeZone, dayAfter).
1844 int64_t offset_after;
1846 isolate, offset_after,
1847 GetOffsetNanosecondsFor(isolate, time_zone, day_after, method_name),
1848 DirectHandle<JSTemporalInstant>());
1849
1850 // 12. Let nanoseconds be offsetAfter − offsetBefore.
1851 double nanoseconds = offset_after - offset_before;
1852
1853 // 13. If disambiguation is "earlier", then
1854 if (disambiguation == Disambiguation::kEarlier) {
1855 // a. Let earlier be ? AddDateTime(dateTime.[[ISOYear]],
1856 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
1857 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
1858 // dateTime.[[ISOMillisecond]],
1859 // dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]],
1860 // dateTime.[[Calendar]], 0, 0, 0, 0, 0, 0, 0, 0, 0, −nanoseconds,
1861 // undefined).
1862 DateTimeRecord earlier;
1864 isolate, earlier,
1865 AddDateTime(
1866 isolate,
1867 {{date_time->iso_year(), date_time->iso_month(),
1868 date_time->iso_day()},
1869 {date_time->iso_hour(), date_time->iso_minute(),
1870 date_time->iso_second(), date_time->iso_millisecond(),
1871 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
1872 direct_handle(date_time->calendar(), isolate),
1873 {0, 0, 0, {0, 0, 0, 0, 0, 0, -nanoseconds}},
1874 isolate->factory()->undefined_value()),
1875 DirectHandle<JSTemporalInstant>());
1876 // See https://github.com/tc39/proposal-temporal/issues/1816
1877 // b. Let earlierDateTime be ? CreateTemporalDateTime(earlier.[[Year]],
1878 // earlier.[[Month]], earlier.[[Day]], earlier.[[Hour]], earlier.[[Minute]],
1879 // earlier.[[Second]], earlier.[[Millisecond]], earlier.[[Microsecond]],
1880 // earlier.[[Nanosecond]], dateTime.[[Calendar]]).
1881 DirectHandle<JSTemporalPlainDateTime> earlier_date_time;
1883 isolate, earlier_date_time,
1885 isolate, earlier, direct_handle(date_time->calendar(), isolate)));
1886
1887 // c. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
1888 // earlierDateTime).
1890 isolate, possible_instants,
1891 GetPossibleInstantsFor(isolate, time_zone, earlier_date_time));
1892
1893 // d. If possibleInstants is empty, throw a RangeError exception.
1894 if (possible_instants->length() == 0) {
1896 }
1897 // e. Return possibleInstants[0].
1898 DirectHandle<Object> ret_obj(possible_instants->get(0), isolate);
1899 DCHECK(IsJSTemporalInstant(*ret_obj));
1900 return Cast<JSTemporalInstant>(ret_obj);
1901 }
1902 // 14. Assert: disambiguation is "compatible" or "later".
1903 DCHECK(disambiguation == Disambiguation::kCompatible ||
1904 disambiguation == Disambiguation::kLater);
1905 // 15. Let later be ? AddDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
1906 // dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]],
1907 // dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]],
1908 // dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]],
1909 // dateTime.[[Calendar]], 0, 0, 0, 0, 0, 0, 0, 0, 0, nanoseconds, undefined).
1910 DateTimeRecord later;
1912 isolate, later,
1913 AddDateTime(isolate,
1914 {{date_time->iso_year(), date_time->iso_month(),
1915 date_time->iso_day()},
1916 {date_time->iso_hour(), date_time->iso_minute(),
1917 date_time->iso_second(), date_time->iso_millisecond(),
1918 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
1919 direct_handle(date_time->calendar(), isolate),
1920 {0, 0, 0, {0, 0, 0, 0, 0, 0, nanoseconds}},
1921 isolate->factory()->undefined_value()),
1922 DirectHandle<JSTemporalInstant>());
1923
1924 // See https://github.com/tc39/proposal-temporal/issues/1816
1925 // 16. Let laterDateTime be ? CreateTemporalDateTime(later.[[Year]],
1926 // later.[[Month]], later.[[Day]], later.[[Hour]], later.[[Minute]],
1927 // later.[[Second]], later.[[Millisecond]], later.[[Microsecond]],
1928 // later.[[Nanosecond]], dateTime.[[Calendar]]).
1929
1930 DirectHandle<JSTemporalPlainDateTime> later_date_time;
1932 isolate, later_date_time,
1934 isolate, later, direct_handle(date_time->calendar(), isolate)));
1935 // 17. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
1936 // laterDateTime).
1938 isolate, possible_instants,
1939 GetPossibleInstantsFor(isolate, time_zone, later_date_time));
1940 // 18. Set n to possibleInstants's length.
1941 n = possible_instants->length();
1942 // 19. If n = 0, throw a RangeError exception.
1943 if (n == 0) {
1945 }
1946 // 20. Return possibleInstants[n − 1].
1947 DirectHandle<Object> ret_obj(possible_instants->get(n - 1), isolate);
1948 DCHECK(IsJSTemporalInstant(*ret_obj));
1949 return Cast<JSTemporalInstant>(ret_obj);
1950}
1951
1952// #sec-temporal-gettemporalcalendarwithisodefault
1953MaybeDirectHandle<JSReceiver> GetTemporalCalendarWithISODefault(
1954 Isolate* isolate, DirectHandle<JSReceiver> item, const char* method_name) {
1956
1957 Factory* factory = isolate->factory();
1958 // 1. If item has an [[InitializedTemporalDate]],
1959 // [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
1960 // [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
1961 // [[InitializedTemporalZonedDateTime]] internal slot, then a. Return
1962 // item.[[Calendar]].
1963 if (IsJSTemporalPlainDate(*item)) {
1964 return direct_handle(Cast<JSTemporalPlainDate>(item)->calendar(), isolate);
1965 }
1966 if (IsJSTemporalPlainDateTime(*item)) {
1968 isolate);
1969 }
1970 if (IsJSTemporalPlainMonthDay(*item)) {
1972 isolate);
1973 }
1974 if (IsJSTemporalPlainTime(*item)) {
1975 return direct_handle(Cast<JSTemporalPlainTime>(item)->calendar(), isolate);
1976 }
1977 if (IsJSTemporalPlainYearMonth(*item)) {
1979 isolate);
1980 }
1981 if (IsJSTemporalZonedDateTime(*item)) {
1983 isolate);
1984 }
1985
1986 // 2. Let calendar be ? Get(item, "calendar").
1987 DirectHandle<Object> calendar;
1989 isolate, calendar,
1990 JSReceiver::GetProperty(isolate, item, factory->calendar_string()));
1991 // 3. Return ? ToTemporalCalendarWithISODefault(calendar).
1992 return ToTemporalCalendarWithISODefault(isolate, calendar, method_name);
1993}
1994
1995enum class RequiredFields {
1996 kNone,
1997 kTimeZone,
1998 kTimeZoneAndOffset,
1999 kDay,
2000 kYearAndDay
2001};
2002
2003// The common part of PrepareTemporalFields and PreparePartialTemporalFields
2004// #sec-temporal-preparetemporalfields
2005// #sec-temporal-preparepartialtemporalfields
2006V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSReceiver>
2007PrepareTemporalFieldsOrPartial(Isolate* isolate,
2008 DirectHandle<JSReceiver> fields,
2009 DirectHandle<FixedArray> field_names,
2010 RequiredFields required, bool partial) {
2012
2013 Factory* factory = isolate->factory();
2014 // 1. Let result be OrdinaryObjectCreate(null).
2015 DirectHandle<JSReceiver> result =
2016 isolate->factory()->NewJSObjectWithNullProto();
2017 // 2. Let any be false.
2018 bool any = false;
2019 // 3. For each value property of fieldNames, do
2020 int length = field_names->length();
2021 for (int i = 0; i < length; i++) {
2022 DirectHandle<Object> property_obj(field_names->get(i), isolate);
2023 DirectHandle<String> property = Cast<String>(property_obj);
2024 // a. Let value be ? Get(fields, property).
2025 DirectHandle<Object> value;
2027 isolate, value, JSReceiver::GetProperty(isolate, fields, property));
2028
2029 // b. If value is undefined, then
2030 if (IsUndefined(*value)) {
2031 // This part is only for PrepareTemporalFields
2032 // Skip for the case of PreparePartialTemporalFields.
2033 if (partial) continue;
2034
2035 // i. If requiredFields contains property, then
2036 if (((required == RequiredFields::kDay ||
2037 required == RequiredFields::kYearAndDay) &&
2038 String::Equals(isolate, property, factory->day_string())) ||
2039 ((required == RequiredFields::kTimeZone ||
2040 required == RequiredFields::kTimeZoneAndOffset) &&
2041 String::Equals(isolate, property, factory->timeZone_string())) ||
2042 (required == RequiredFields::kTimeZoneAndOffset &&
2043 String::Equals(isolate, property, factory->offset_string())) ||
2044 (required == RequiredFields::kYearAndDay &&
2045 String::Equals(isolate, property, factory->year_string()))) {
2046 // 1. Throw a TypeError exception.
2048 }
2049 // ii. Else,
2050 // 1. If property is in the Property column of Table 13, then
2051 // a. Set value to the corresponding Default value of the same row.
2052 if (String::Equals(isolate, property, factory->hour_string()) ||
2053 String::Equals(isolate, property, factory->minute_string()) ||
2054 String::Equals(isolate, property, factory->second_string()) ||
2055 String::Equals(isolate, property, factory->millisecond_string()) ||
2056 String::Equals(isolate, property, factory->microsecond_string()) ||
2057 String::Equals(isolate, property, factory->nanosecond_string())) {
2058 value = DirectHandle<Object>(Smi::zero(), isolate);
2059 }
2060 } else {
2061 // For both PrepareTemporalFields and PreparePartialTemporalFields
2062 any = partial;
2063 // c. Else,
2064 // i. If property is in the Property column of Table 13 and there is a
2065 // Conversion value in the same row, then
2066 // 1. Let Conversion represent the abstract operation named by the
2067 // Conversion value of the same row.
2068 // 2. Set value to ? Conversion(value).
2069 if (String::Equals(isolate, property, factory->month_string()) ||
2070 String::Equals(isolate, property, factory->day_string())) {
2071 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
2072 ToPositiveInteger(isolate, value));
2073 } else if (String::Equals(isolate, property, factory->year_string()) ||
2074 String::Equals(isolate, property, factory->hour_string()) ||
2075 String::Equals(isolate, property, factory->minute_string()) ||
2076 String::Equals(isolate, property, factory->second_string()) ||
2077 String::Equals(isolate, property,
2078 factory->millisecond_string()) ||
2079 String::Equals(isolate, property,
2080 factory->microsecond_string()) ||
2081 String::Equals(isolate, property,
2082 factory->nanosecond_string()) ||
2083 String::Equals(isolate, property, factory->eraYear_string())) {
2084 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
2085 ToIntegerThrowOnInfinity(isolate, value));
2086 } else if (String::Equals(isolate, property,
2087 factory->monthCode_string()) ||
2088 String::Equals(isolate, property, factory->offset_string()) ||
2089 String::Equals(isolate, property, factory->era_string())) {
2090 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
2091 Object::ToString(isolate, value));
2092 }
2093 }
2094
2095 // d. Perform ! CreateDataPropertyOrThrow(result, property, value).
2096 CHECK(JSReceiver::CreateDataProperty(isolate, result, property, value,
2098 .FromJust());
2099 }
2100
2101 // Only for PreparePartialTemporalFields
2102 if (partial) {
2103 // 5. If any is false, then
2104 if (!any) {
2105 // a. Throw a TypeError exception.
2107 }
2108 }
2109 // 4. Return result.
2110 return result;
2111}
2112
2113// #sec-temporal-preparetemporalfields
2114V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSReceiver> PrepareTemporalFields(
2115 Isolate* isolate, DirectHandle<JSReceiver> fields,
2116 DirectHandle<FixedArray> field_names, RequiredFields required) {
2118
2119 return PrepareTemporalFieldsOrPartial(isolate, fields, field_names, required,
2120 false);
2121}
2122
2123// #sec-temporal-preparepartialtemporalfields
2124V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSReceiver>
2125PreparePartialTemporalFields(Isolate* isolate, DirectHandle<JSReceiver> fields,
2126 DirectHandle<FixedArray> field_names) {
2128
2129 return PrepareTemporalFieldsOrPartial(isolate, fields, field_names,
2130 RequiredFields::kNone, true);
2131}
2132
2133// Template for DateFromFields, YearMonthFromFields, and MonthDayFromFields
2134template <typename T>
2135MaybeDirectHandle<T> FromFields(Isolate* isolate,
2136 DirectHandle<JSReceiver> calendar,
2137 DirectHandle<JSReceiver> fields,
2138 DirectHandle<Object> options,
2139 DirectHandle<String> property,
2140 InstanceType type) {
2141 DirectHandle<Object> function;
2142 ASSIGN_RETURN_ON_EXCEPTION(isolate, function,
2143 Object::GetProperty(isolate, calendar, property));
2144 if (!IsCallable(*function)) {
2146 isolate, NewTypeError(MessageTemplate::kCalledNonCallable, property));
2147 }
2148 DirectHandle<Object> args[] = {fields, options};
2149 DirectHandle<Object> result;
2151 isolate, result,
2152 Execution::Call(isolate, function, calendar, base::VectorOf(args)));
2153 if ((!IsHeapObject(*result)) ||
2154 Cast<HeapObject>(*result)->map()->instance_type() != type) {
2156 }
2157 return Cast<T>(result);
2158}
2159
2160// #sec-temporal-datefromfields
2161MaybeDirectHandle<JSTemporalPlainDate> DateFromFields(
2162 Isolate* isolate, DirectHandle<JSReceiver> calendar,
2163 DirectHandle<JSReceiver> fields, DirectHandle<Object> options) {
2164 return FromFields<JSTemporalPlainDate>(
2165 isolate, calendar, fields, options,
2166 isolate->factory()->dateFromFields_string(), JS_TEMPORAL_PLAIN_DATE_TYPE);
2167}
2168
2169// #sec-temporal-yearmonthfromfields
2170MaybeDirectHandle<JSTemporalPlainYearMonth> YearMonthFromFields(
2171 Isolate* isolate, DirectHandle<JSReceiver> calendar,
2172 DirectHandle<JSReceiver> fields, DirectHandle<Object> options) {
2173 return FromFields<JSTemporalPlainYearMonth>(
2174 isolate, calendar, fields, options,
2175 isolate->factory()->yearMonthFromFields_string(),
2176 JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE);
2177}
2178MaybeDirectHandle<JSTemporalPlainYearMonth> YearMonthFromFields(
2179 Isolate* isolate, DirectHandle<JSReceiver> calendar,
2180 DirectHandle<JSReceiver> fields) {
2181 // 1. If options is not present, set options to undefined.
2182 return YearMonthFromFields(isolate, calendar, fields,
2183 isolate->factory()->undefined_value());
2184}
2185
2186// #sec-temporal-monthdayfromfields
2187MaybeDirectHandle<JSTemporalPlainMonthDay> MonthDayFromFields(
2188 Isolate* isolate, DirectHandle<JSReceiver> calendar,
2189 DirectHandle<JSReceiver> fields, DirectHandle<Object> options) {
2190 return FromFields<JSTemporalPlainMonthDay>(
2191 isolate, calendar, fields, options,
2192 isolate->factory()->monthDayFromFields_string(),
2193 JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE);
2194}
2195MaybeDirectHandle<JSTemporalPlainMonthDay> MonthDayFromFields(
2196 Isolate* isolate, DirectHandle<JSReceiver> calendar,
2197 DirectHandle<JSReceiver> fields) {
2198 // 1. If options is not present, set options to undefined.
2199 return MonthDayFromFields(isolate, calendar, fields,
2200 isolate->factory()->undefined_value());
2201}
2202
2203// #sec-temporal-totemporaloverflow
2204Maybe<ShowOverflow> ToTemporalOverflow(Isolate* isolate,
2205 DirectHandle<Object> options,
2206 const char* method_name) {
2207 // 1. If options is undefined, return "constrain".
2208 if (IsUndefined(*options)) return Just(ShowOverflow::kConstrain);
2209 DCHECK(IsJSReceiver(*options));
2210 // 2. Return ? GetOption(options, "overflow", « String », « "constrain",
2211 // "reject" », "constrain").
2213 isolate, Cast<JSReceiver>(options), "overflow", method_name,
2214 {"constrain", "reject"},
2215 {ShowOverflow::kConstrain, ShowOverflow::kReject},
2216 ShowOverflow::kConstrain);
2217}
2218
2219// #sec-temporal-totemporaloffset
2220Maybe<Offset> ToTemporalOffset(Isolate* isolate, DirectHandle<Object> options,
2221 Offset fallback, const char* method_name) {
2222 // 1. If options is undefined, return fallback.
2223 if (IsUndefined(*options)) return Just(fallback);
2224 DCHECK(IsJSReceiver(*options));
2225
2226 // 2. Return ? GetOption(options, "offset", « String », « "prefer", "use",
2227 // "ignore", "reject" », fallback).
2229 isolate, Cast<JSReceiver>(options), "offset", method_name,
2230 {"prefer", "use", "ignore", "reject"},
2231 {Offset::kPrefer, Offset::kUse, Offset::kIgnore, Offset::kReject},
2232 fallback);
2233}
2234
2235// #sec-temporal-totemporaldisambiguation
2236Maybe<Disambiguation> ToTemporalDisambiguation(Isolate* isolate,
2237 DirectHandle<Object> options,
2238 const char* method_name) {
2239 // 1. If options is undefined, return "compatible".
2240 if (IsUndefined(*options)) return Just(Disambiguation::kCompatible);
2241 DCHECK(IsJSReceiver(*options));
2242 // 2. Return ? GetOption(options, "disambiguation", « String », «
2243 // "compatible", "earlier", "later", "reject" », "compatible").
2245 isolate, Cast<JSReceiver>(options), "disambiguation", method_name,
2246 {"compatible", "earlier", "later", "reject"},
2247 {Disambiguation::kCompatible, Disambiguation::kEarlier,
2248 Disambiguation::kLater, Disambiguation::kReject},
2249 Disambiguation::kCompatible);
2250}
2251
2252// #sec-temporal-builtintimezonegetinstantfor
2253MaybeDirectHandle<JSTemporalInstant> BuiltinTimeZoneGetInstantFor(
2254 Isolate* isolate, DirectHandle<JSReceiver> time_zone,
2255 DirectHandle<JSTemporalPlainDateTime> date_time,
2256 Disambiguation disambiguation, const char* method_name) {
2258 // 1. Assert: dateTime has an [[InitializedTemporalDateTime]] internal slot.
2259 // 2. Let possibleInstants be ? GetPossibleInstantsFor(timeZone, dateTime).
2260 DirectHandle<FixedArray> possible_instants;
2262 isolate, possible_instants,
2263 GetPossibleInstantsFor(isolate, time_zone, date_time));
2264 // 3. Return ? DisambiguatePossibleInstants(possibleInstants, timeZone,
2265 // dateTime, disambiguation).
2266 return DisambiguatePossibleInstants(isolate, possible_instants, time_zone,
2267 date_time, disambiguation, method_name);
2268}
2269
2270// #sec-temporal-totemporalinstant
2271MaybeDirectHandle<JSTemporalInstant> ToTemporalInstant(
2272 Isolate* isolate, DirectHandle<Object> item, const char* method_name) {
2274
2275 // 1. If Type(item) is Object, then
2276 // a. If item has an [[InitializedTemporalInstant]] internal slot, then
2277 if (IsJSTemporalInstant(*item)) {
2278 // i. Return item.
2279 return Cast<JSTemporalInstant>(item);
2280 }
2281 // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
2282 if (IsJSTemporalZonedDateTime(*item)) {
2283 // i. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
2284 DirectHandle<BigInt> nanoseconds(
2285 Cast<JSTemporalZonedDateTime>(*item)->nanoseconds(), isolate);
2287 .ToHandleChecked();
2288 }
2289 // 2. Let string be ? ToString(item).
2290 DirectHandle<String> string;
2291 ASSIGN_RETURN_ON_EXCEPTION(isolate, string, Object::ToString(isolate, item));
2292
2293 // 3. Let epochNanoseconds be ? ParseTemporalInstant(string).
2294 DirectHandle<BigInt> epoch_nanoseconds;
2295 ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_nanoseconds,
2296 ParseTemporalInstant(isolate, string));
2297
2298 // 4. Return ? CreateTemporalInstant(ℤ(epochNanoseconds)).
2299 return temporal::CreateTemporalInstant(isolate, epoch_nanoseconds);
2300}
2301
2302} // namespace
2303
2304namespace temporal {
2305// #sec-temporal-totemporalcalendar
2307 Isolate* isolate, DirectHandle<Object> temporal_calendar_like,
2308 const char* method_name) {
2309 Factory* factory = isolate->factory();
2310 // 1.If Type(temporalCalendarLike) is Object, then
2311 if (IsJSReceiver(*temporal_calendar_like)) {
2312 // a. If temporalCalendarLike has an [[InitializedTemporalDate]],
2313 // [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
2314 // [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
2315 // [[InitializedTemporalZonedDateTime]] internal slot, then i. Return
2316 // temporalCalendarLike.[[Calendar]].
2317
2318#define EXTRACT_CALENDAR(T, obj) \
2319 if (IsJSTemporal##T(*obj)) { \
2320 return direct_handle(Cast<JSTemporal##T>(obj)->calendar(), isolate); \
2321 }
2322
2323 EXTRACT_CALENDAR(PlainDate, temporal_calendar_like)
2324 EXTRACT_CALENDAR(PlainDateTime, temporal_calendar_like)
2325 EXTRACT_CALENDAR(PlainMonthDay, temporal_calendar_like)
2326 EXTRACT_CALENDAR(PlainTime, temporal_calendar_like)
2327 EXTRACT_CALENDAR(PlainYearMonth, temporal_calendar_like)
2328 EXTRACT_CALENDAR(ZonedDateTime, temporal_calendar_like)
2329
2330#undef EXTRACT_CALENDAR
2331 DirectHandle<JSReceiver> obj = Cast<JSReceiver>(temporal_calendar_like);
2332
2333 // b. If ? HasProperty(temporalCalendarLike, "calendar") is false, return
2334 // temporalCalendarLike.
2335 bool has;
2337 isolate, has,
2338 JSReceiver::HasProperty(isolate, obj, factory->calendar_string()),
2340 if (!has) {
2341 return obj;
2342 }
2343 // c. Set temporalCalendarLike to ? Get(temporalCalendarLike, "calendar").
2345 isolate, temporal_calendar_like,
2346 JSReceiver::GetProperty(isolate, obj, factory->calendar_string()));
2347 // d. If Type(temporalCalendarLike) is Object
2348 if (IsJSReceiver(*temporal_calendar_like)) {
2349 obj = Cast<JSReceiver>(temporal_calendar_like);
2350 // and ? HasProperty(temporalCalendarLike, "calendar") is false,
2352 isolate, has,
2353 JSReceiver::HasProperty(isolate, obj, factory->calendar_string()),
2355 if (!has) {
2356 // return temporalCalendarLike.
2357 return obj;
2358 }
2359 }
2360 }
2361
2362 // 2. Let identifier be ? ToString(temporalCalendarLike).
2365 Object::ToString(isolate, temporal_calendar_like));
2366 // 3. Let identifier be ? ParseTemporalCalendarString(identifier).
2368 ParseTemporalCalendarString(isolate, identifier));
2369 // 4. If IsBuiltinCalendar(identifier) is false, throw a RangeError
2370 // exception.
2371 if (!IsBuiltinCalendar(isolate, identifier)) {
2373 isolate, NewRangeError(MessageTemplate::kInvalidCalendar, identifier));
2374 }
2375 // 5. Return ? CreateTemporalCalendar(identifier).
2376 return CreateTemporalCalendar(isolate, identifier);
2377}
2378
2379} // namespace temporal
2380
2381namespace {
2382// #sec-temporal-totemporalcalendarwithisodefault
2383MaybeDirectHandle<JSReceiver> ToTemporalCalendarWithISODefault(
2384 Isolate* isolate, DirectHandle<Object> temporal_calendar_like,
2385 const char* method_name) {
2387
2388 // 1. If temporalCalendarLike is undefined, then
2389 if (IsUndefined(*temporal_calendar_like)) {
2390 // a. Return ? GetISO8601Calendar().
2391 return temporal::GetISO8601Calendar(isolate);
2392 }
2393 // 2. Return ? ToTemporalCalendar(temporalCalendarLike).
2394 return temporal::ToTemporalCalendar(isolate, temporal_calendar_like,
2395 method_name);
2396}
2397
2398// Create « "day", "hour", "microsecond", "millisecond", "minute", "month",
2399// "monthCode", "nanosecond", "second", "year" » in several AOs.
2400DirectHandle<FixedArray> All10UnitsInFixedArray(Isolate* isolate) {
2401 DirectHandle<FixedArray> field_names = isolate->factory()->NewFixedArray(10);
2402 field_names->set(0, ReadOnlyRoots(isolate).day_string());
2403 field_names->set(1, ReadOnlyRoots(isolate).hour_string());
2404 field_names->set(2, ReadOnlyRoots(isolate).microsecond_string());
2405 field_names->set(3, ReadOnlyRoots(isolate).millisecond_string());
2406 field_names->set(4, ReadOnlyRoots(isolate).minute_string());
2407 field_names->set(5, ReadOnlyRoots(isolate).month_string());
2408 field_names->set(6, ReadOnlyRoots(isolate).monthCode_string());
2409 field_names->set(7, ReadOnlyRoots(isolate).nanosecond_string());
2410 field_names->set(8, ReadOnlyRoots(isolate).second_string());
2411 field_names->set(9, ReadOnlyRoots(isolate).year_string());
2412 return field_names;
2413}
2414
2415// Create « "day", "month", "monthCode", "year" » in several AOs.
2416DirectHandle<FixedArray> DayMonthMonthCodeYearInFixedArray(Isolate* isolate) {
2417 DirectHandle<FixedArray> field_names = isolate->factory()->NewFixedArray(4);
2418 field_names->set(0, ReadOnlyRoots(isolate).day_string());
2419 field_names->set(1, ReadOnlyRoots(isolate).month_string());
2420 field_names->set(2, ReadOnlyRoots(isolate).monthCode_string());
2421 field_names->set(3, ReadOnlyRoots(isolate).year_string());
2422 return field_names;
2423}
2424
2425// Create « "month", "monthCode", "year" » in several AOs.
2426DirectHandle<FixedArray> MonthMonthCodeYearInFixedArray(Isolate* isolate) {
2427 DirectHandle<FixedArray> field_names = isolate->factory()->NewFixedArray(3);
2428 field_names->set(0, ReadOnlyRoots(isolate).month_string());
2429 field_names->set(1, ReadOnlyRoots(isolate).monthCode_string());
2430 field_names->set(2, ReadOnlyRoots(isolate).year_string());
2431 return field_names;
2432}
2433
2434// Create « "monthCode", "year" » in several AOs.
2435DirectHandle<FixedArray> MonthCodeYearInFixedArray(Isolate* isolate) {
2436 DirectHandle<FixedArray> field_names = isolate->factory()->NewFixedArray(2);
2437 field_names->set(0, ReadOnlyRoots(isolate).monthCode_string());
2438 field_names->set(1, ReadOnlyRoots(isolate).year_string());
2439 return field_names;
2440}
2441
2442// #sec-temporal-totemporaldate
2443MaybeDirectHandle<JSTemporalPlainDate> ToTemporalDate(
2444 Isolate* isolate, DirectHandle<Object> item_obj,
2445 DirectHandle<Object> options, const char* method_name) {
2447
2448 // 2. Assert: Type(options) is Object or Undefined.
2449 DCHECK(IsJSReceiver(*options) || IsUndefined(*options));
2450 // 3. If Type(item) is Object, then
2451 if (IsJSReceiver(*item_obj)) {
2452 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
2453 // a. If item has an [[InitializedTemporalDate]] internal slot, then
2454 // i. Return item.
2455 if (IsJSTemporalPlainDate(*item)) {
2456 return Cast<JSTemporalPlainDate>(item);
2457 }
2458 // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
2459 // then
2460 if (IsJSTemporalZonedDateTime(*item)) {
2461 // i. Perform ? ToTemporalOverflow(options).
2463 isolate, ToTemporalOverflow(isolate, options, method_name),
2464 DirectHandle<JSTemporalPlainDate>());
2465
2466 // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
2467 auto zoned_date_time = Cast<JSTemporalZonedDateTime>(item);
2468 DirectHandle<JSTemporalInstant> instant =
2470 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
2471 .ToHandleChecked();
2472 // iii. Let plainDateTime be ?
2473 // BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
2474 // instant, item.[[Calendar]]).
2475 DirectHandle<JSTemporalPlainDateTime> plain_date_time;
2477 isolate, plain_date_time,
2479 isolate,
2480 DirectHandle<JSReceiver>(zoned_date_time->time_zone(), isolate),
2481 instant,
2482 DirectHandle<JSReceiver>(zoned_date_time->calendar(), isolate),
2483 method_name));
2484 // iv. Return ! CreateTemporalDate(plainDateTime.[[ISOYear]],
2485 // plainDateTime.[[ISOMonth]], plainDateTime.[[ISODay]],
2486 // plainDateTime.[[Calendar]]).
2487 return CreateTemporalDate(
2488 isolate,
2489 {plain_date_time->iso_year(), plain_date_time->iso_month(),
2490 plain_date_time->iso_day()},
2491 direct_handle(plain_date_time->calendar(), isolate))
2492 .ToHandleChecked();
2493 }
2494
2495 // c. If item has an [[InitializedTemporalDateTime]] internal slot, then
2496 // item.[[ISODay]], item.[[Calendar]]).
2497 if (IsJSTemporalPlainDateTime(*item)) {
2498 // i. Perform ? ToTemporalOverflow(options).
2500 isolate, ToTemporalOverflow(isolate, options, method_name),
2501 DirectHandle<JSTemporalPlainDate>());
2502 // ii. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
2503 auto date_time = Cast<JSTemporalPlainDateTime>(item);
2504 return CreateTemporalDate(isolate,
2505 {date_time->iso_year(), date_time->iso_month(),
2506 date_time->iso_day()},
2507 direct_handle(date_time->calendar(), isolate))
2508 .ToHandleChecked();
2509 }
2510
2511 // d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
2512 DirectHandle<JSReceiver> calendar;
2514 isolate, calendar,
2515 GetTemporalCalendarWithISODefault(isolate, item, method_name));
2516 // e. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
2517 // "monthCode", "year" »).
2518 DirectHandle<FixedArray> field_names =
2519 DayMonthMonthCodeYearInFixedArray(isolate);
2520 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
2521 CalendarFields(isolate, calendar, field_names));
2522 // f. Let fields be ? PrepareTemporalFields(item,
2523 // fieldNames, «»).
2524 DirectHandle<JSReceiver> fields;
2525 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
2526 PrepareTemporalFields(isolate, item, field_names,
2527 RequiredFields::kNone));
2528 // g. Return ? DateFromFields(calendar, fields, options).
2529 return DateFromFields(isolate, calendar, fields, options);
2530 }
2531 // 4. Perform ? ToTemporalOverflow(options).
2533 isolate, ToTemporalOverflow(isolate, options, method_name),
2534 DirectHandle<JSTemporalPlainDate>());
2535
2536 // 5. Let string be ? ToString(item).
2537 DirectHandle<String> string;
2538 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
2539 Object::ToString(isolate, item_obj));
2540 // 6. Let result be ? ParseTemporalDateString(string).
2541 DateRecordWithCalendar result;
2543 isolate, result, ParseTemporalDateString(isolate, string),
2544 DirectHandle<JSTemporalPlainDate>());
2545
2546 // 7. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
2547 // result.[[Day]]) is true.
2548 DCHECK(IsValidISODate(isolate, result.date));
2549 // 8. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
2550 DirectHandle<JSReceiver> calendar;
2552 isolate, calendar,
2553 ToTemporalCalendarWithISODefault(isolate, result.calendar, method_name));
2554 // 9. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
2555 // result.[[Day]], calendar).
2556 return CreateTemporalDate(isolate, result.date, calendar);
2557}
2558
2559MaybeDirectHandle<JSTemporalPlainDate> ToTemporalDate(
2560 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name) {
2561 // 1. If options is not present, set options to undefined.
2562 return ToTemporalDate(isolate, item_obj,
2563 isolate->factory()->undefined_value(), method_name);
2564}
2565
2566// #sec-isintegralnumber
2567bool IsIntegralNumber(Isolate* isolate, DirectHandle<Object> argument) {
2568 // 1. If Type(argument) is not Number, return false.
2569 if (!IsNumber(*argument)) return false;
2570 // 2. If argument is NaN, +∞𝔽, or -∞𝔽, return false.
2571 double number = Object::NumberValue(Cast<Number>(*argument));
2572 if (!std::isfinite(number)) return false;
2573 // 3. If floor(abs(ℝ(argument))) ≠ abs(ℝ(argument)), return false.
2574 if (std::floor(std::abs(number)) != std::abs(number)) return false;
2575 // 4. Return true.
2576 return true;
2577}
2578
2579// #sec-temporal-tointegerwithoutrounding
2580Maybe<double> ToIntegerWithoutRounding(Isolate* isolate,
2581 DirectHandle<Object> argument) {
2582 // 1. Let number be ? ToNumber(argument).
2583 DirectHandle<Number> number;
2585 isolate, number, Object::ToNumber(isolate, argument), Nothing<double>());
2586 // 2. If number is NaN, +0𝔽, or −0𝔽 return 0.
2587 if (IsNaN(*number) || Object::NumberValue(*number) == 0) {
2588 return Just(static_cast<double>(0));
2589 }
2590 // 3. If IsIntegralNumber(number) is false, throw a RangeError exception.
2591 if (!IsIntegralNumber(isolate, number)) {
2594 }
2595 // 4. Return ℝ(number).
2596 return Just(Object::NumberValue(*number));
2597}
2598
2599} // namespace
2600
2601namespace temporal {
2602
2603// #sec-temporal-regulatetime
2605 ShowOverflow overflow) {
2607
2608 // 1. Assert: hour, minute, second, millisecond, microsecond and nanosecond
2609 // are integers.
2610 // 2. Assert: overflow is either "constrain" or "reject".
2611 switch (overflow) {
2612 case ShowOverflow::kConstrain: {
2613 TimeRecord result(time);
2614 // 3. If overflow is "constrain", then
2615 // a. Return ! ConstrainTime(hour, minute, second, millisecond,
2616 // microsecond, nanosecond).
2617 result.hour = std::max(std::min(result.hour, 23), 0);
2618 result.minute = std::max(std::min(result.minute, 59), 0);
2619 result.second = std::max(std::min(result.second, 59), 0);
2620 result.millisecond = std::max(std::min(result.millisecond, 999), 0);
2621 result.microsecond = std::max(std::min(result.microsecond, 999), 0);
2622 result.nanosecond = std::max(std::min(result.nanosecond, 999), 0);
2623 return Just(result);
2624 }
2625 case ShowOverflow::kReject:
2626 // 4. If overflow is "reject", then
2627 // a. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
2628 // nanosecond) is false, throw a RangeError exception.
2629 if (!IsValidTime(isolate, time)) {
2632 Nothing<TimeRecord>());
2633 }
2634 // b. Return the new Record { [[Hour]]: hour, [[Minute]]: minute,
2635 // [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]:
2636 // microsecond, [[Nanosecond]]: nanosecond }.
2637 return Just(time);
2638 }
2639}
2640
2641// #sec-temporal-totemporaltime
2643 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name,
2644 ShowOverflow overflow = ShowOverflow::kConstrain) {
2645 Factory* factory = isolate->factory();
2646 TimeRecordWithCalendar result;
2647 // 2. Assert: overflow is either "constrain" or "reject".
2648 // 3. If Type(item) is Object, then
2649 if (IsJSReceiver(*item_obj)) {
2650 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
2651 // a. If item has an [[InitializedTemporalTime]] internal slot, then
2652 // i. Return item.
2653 if (IsJSTemporalPlainTime(*item)) {
2654 return Cast<JSTemporalPlainTime>(item);
2655 }
2656 // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
2657 // then
2658 if (IsJSTemporalZonedDateTime(*item)) {
2659 // i. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
2660 auto zoned_date_time = Cast<JSTemporalZonedDateTime>(item);
2663 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
2664 .ToHandleChecked();
2665 // ii. Set plainDateTime to ?
2666 // BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
2667 // instant, item.[[Calendar]]).
2670 isolate, plain_date_time,
2672 isolate,
2673 DirectHandle<JSReceiver>(zoned_date_time->time_zone(), isolate),
2674 instant,
2675 DirectHandle<JSReceiver>(zoned_date_time->calendar(), isolate),
2676 method_name));
2677 // iii. Return !
2678 // CreateTemporalTime(plainDateTime.[[ISOHour]],
2679 // plainDateTime.[[ISOMinute]], plainDateTime.[[ISOSecond]],
2680 // plainDateTime.[[ISOMillisecond]], plainDateTime.[[ISOMicrosecond]],
2681 // plainDateTime.[[ISONanosecond]]).
2682 return CreateTemporalTime(isolate, {plain_date_time->iso_hour(),
2683 plain_date_time->iso_minute(),
2684 plain_date_time->iso_second(),
2685 plain_date_time->iso_millisecond(),
2686 plain_date_time->iso_microsecond(),
2687 plain_date_time->iso_nanosecond()})
2688 .ToHandleChecked();
2689 }
2690 // c. If item has an [[InitializedTemporalDateTime]] internal slot, then
2691 if (IsJSTemporalPlainDateTime(*item)) {
2692 // i. Return ! CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]],
2693 // item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]],
2694 // item.[[ISONanosecond]]).
2695 auto date_time = Cast<JSTemporalPlainDateTime>(item);
2696 return CreateTemporalTime(
2697 isolate,
2698 {date_time->iso_hour(), date_time->iso_minute(),
2699 date_time->iso_second(), date_time->iso_millisecond(),
2700 date_time->iso_microsecond(), date_time->iso_nanosecond()})
2701 .ToHandleChecked();
2702 }
2703 // d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
2706 isolate, calendar,
2707 GetTemporalCalendarWithISODefault(isolate, item, method_name));
2708 // e. If ? ToString(calendar) is not "iso8601", then
2711 Object::ToString(isolate, calendar));
2712 if (!String::Equals(isolate, factory->iso8601_string(), identifier)) {
2713 // i. Throw a RangeError exception.
2715 }
2716 // f. Let result be ? ToTemporalTimeRecord(item).
2718 isolate, result.time, ToTemporalTimeRecord(isolate, item, method_name),
2720 // g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]],
2721 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2722 // result.[[Nanosecond]], overflow).
2724 isolate, result.time, RegulateTime(isolate, result.time, overflow),
2726 } else {
2727 // 4. Else,
2728 // a. Let string be ? ToString(item).
2729 DirectHandle<String> string;
2730 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
2731 Object::ToString(isolate, item_obj));
2732 // b. Let result be ? ParseTemporalTimeString(string).
2734 isolate, result, ParseTemporalTimeString(isolate, string),
2736 // c. Assert: ! IsValidTime(result.[[Hour]], result.[[Minute]],
2737 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2738 // result.[[Nanosecond]]) is true.
2739 DCHECK(IsValidTime(isolate, result.time));
2740 // d. If result.[[Calendar]] is not one of undefined or "iso8601", then
2741 DCHECK(IsUndefined(*result.calendar) || IsString(*result.calendar));
2742 if (!IsUndefined(*result.calendar) &&
2743 !String::Equals(isolate, Cast<String>(result.calendar),
2744 isolate->factory()->iso8601_string())) {
2745 // i. Throw a RangeError exception.
2747 }
2748 }
2749 // 5. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]],
2750 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
2751 // result.[[Nanosecond]]).
2752 return CreateTemporalTime(isolate, result.time);
2753}
2754
2755// Helper function to loop through Table 8 Duration Record Fields
2756// This function implement
2757// "For each row of Table 8, except the header row, in table order, do"
2758// loop. It is designed to be used to implement the common part of
2759// ToPartialDuration, ToTemporalDurationRecord
2761 Isolate* isolate, DirectHandle<JSReceiver> temporal_duration_like,
2762 Maybe<bool> (*RowFunction)(Isolate*,
2763 DirectHandle<JSReceiver> temporal_duration_like,
2764 DirectHandle<String>, double*),
2766 Factory* factory = isolate->factory();
2767 std::array<std::pair<DirectHandle<String>, double*>, 10> table8 = {
2768 {{factory->days_string(), &record->time_duration.days},
2769 {factory->hours_string(), &record->time_duration.hours},
2770 {factory->microseconds_string(), &record->time_duration.microseconds},
2771 {factory->milliseconds_string(), &record->time_duration.milliseconds},
2772 {factory->minutes_string(), &record->time_duration.minutes},
2773 {factory->months_string(), &record->months},
2774 {factory->nanoseconds_string(), &record->time_duration.nanoseconds},
2775 {factory->seconds_string(), &record->time_duration.seconds},
2776 {factory->weeks_string(), &record->weeks},
2777 {factory->years_string(), &record->years}}};
2778
2779 // x. Let any be false.
2780 bool any = false;
2781 // x+1. For each row of Table 8, except the header row, in table order, do
2782 for (const auto& row : table8) {
2783 bool result;
2784 // row.first is prop: the Property Name value of the current row
2785 // row.second is the address of result's field whose name is the Field Name
2786 // value of the current row
2788 isolate, result,
2789 RowFunction(isolate, temporal_duration_like, row.first, row.second),
2790 Nothing<bool>());
2791 any |= result;
2792 }
2793 return Just(any);
2794}
2795
2796// #sec-temporal-totemporaldurationrecord
2798 Isolate* isolate, DirectHandle<Object> temporal_duration_like_obj,
2799 const char* method_name) {
2801
2802 // 1. If Type(temporalDurationLike) is not Object, then
2803 if (!IsJSReceiver(*temporal_duration_like_obj)) {
2804 // a. Let string be ? ToString(temporalDurationLike).
2805 DirectHandle<String> string;
2807 isolate, string, Object::ToString(isolate, temporal_duration_like_obj),
2808 Nothing<DurationRecord>());
2809 // b. Let result be ? ParseTemporalDurationString(string).
2810 return ParseTemporalDurationString(isolate, string);
2811 }
2812 DirectHandle<JSReceiver> temporal_duration_like =
2813 Cast<JSReceiver>(temporal_duration_like_obj);
2814 // 2. If temporalDurationLike has an [[InitializedTemporalDuration]] internal
2815 // slot, then
2816 if (IsJSTemporalDuration(*temporal_duration_like)) {
2817 // a. Return ! CreateDurationRecord(temporalDurationLike.[[Years]],
2818 // temporalDurationLike.[[Months]], temporalDurationLike.[[Weeks]],
2819 // temporalDurationLike.[[Days]], temporalDurationLike.[[Hours]],
2820 // temporalDurationLike.[[Minutes]], temporalDurationLike.[[Seconds]],
2821 // temporalDurationLike.[[Milliseconds]],
2822 // temporalDurationLike.[[Microseconds]],
2823 // temporalDurationLike.[[Nanoseconds]]).
2824 auto duration = Cast<JSTemporalDuration>(temporal_duration_like);
2825 return DurationRecord::Create(isolate,
2826 Object::NumberValue(duration->years()),
2827 Object::NumberValue(duration->months()),
2828 Object::NumberValue(duration->weeks()),
2829 Object::NumberValue(duration->days()),
2830 Object::NumberValue(duration->hours()),
2831 Object::NumberValue(duration->minutes()),
2832 Object::NumberValue(duration->seconds()),
2833 Object::NumberValue(duration->milliseconds()),
2834 Object::NumberValue(duration->microseconds()),
2835 Object::NumberValue(duration->nanoseconds()));
2836 }
2837 // 3. Let result be a new Record with all the internal slots given in the
2838 // Internal Slot column in Table 8.
2840 // 4. Let any be false.
2841 bool any = false;
2842
2843 // 5. For each row of Table 8, except the header row, in table order, do
2845 isolate, any,
2847 isolate, temporal_duration_like,
2848 [](Isolate* isolate, DirectHandle<JSReceiver> temporal_duration_like,
2849 DirectHandle<String> prop, double* field) -> Maybe<bool> {
2850 bool not_undefined = false;
2851 // a. Let prop be the Property value of the current row.
2853 // b. Let val be ? Get(temporalDurationLike, prop).
2855 isolate, val,
2856 JSReceiver::GetProperty(isolate, temporal_duration_like, prop),
2857 Nothing<bool>());
2858 // c. If val is undefined, then
2859 if (IsUndefined(*val)) {
2860 // i. Set result's internal slot whose name is the Internal Slot
2861 // value of the current row to 0.
2862 *field = 0;
2863 // d. Else,
2864 } else {
2865 // i. Set any to true.
2866 not_undefined = true;
2867 // ii. Let val be 𝔽(? ToIntegerWithoutRounding(val)).
2868 // iii. Set result's field whose name is the Field Name value of
2869 // the current row to val.
2871 isolate, *field, ToIntegerWithoutRounding(isolate, val),
2872 Nothing<bool>());
2873 }
2874 return Just(not_undefined);
2875 },
2876 &result),
2877 Nothing<DurationRecord>());
2878
2879 // 6. If any is false, then
2880 if (!any) {
2881 // a. Throw a TypeError exception.
2883 Nothing<DurationRecord>());
2884 }
2885 // 7. If ! IsValidDuration(result.[[Years]], result.[[Months]],
2886 // result.[[Weeks]] result.[[Days]], result.[[Hours]], result.[[Minutes]],
2887 // result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]],
2888 // result.[[Nanoseconds]]) is false, then
2889 if (!IsValidDuration(isolate, result)) {
2890 // a. Throw a RangeError exception.
2893 Nothing<DurationRecord>());
2894 }
2895 // 8. Return result.
2896 return Just(result);
2897}
2898
2899// #sec-temporal-totemporalduration
2901 Isolate* isolate, DirectHandle<Object> item, const char* method_name) {
2903
2905 // 1. If Type(item) is Object and item has an [[InitializedTemporalDuration]]
2906 // internal slot, then
2907 if (IsJSTemporalDuration(*item)) {
2908 // a. Return item.
2909 return Cast<JSTemporalDuration>(item);
2910 }
2911 // 2. Let result be ? ToTemporalDurationRecord(item).
2913 isolate, result, ToTemporalDurationRecord(isolate, item, method_name),
2915
2916 // 3. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]],
2917 // result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]],
2918 // result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]],
2919 // result.[[Nanoseconds]]).
2920 return CreateTemporalDuration(isolate, result);
2921}
2922
2923// #sec-temporal-totemporaltimezone
2925 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like,
2926 const char* method_name) {
2928
2929 Factory* factory = isolate->factory();
2930 // 1. If Type(temporalTimeZoneLike) is Object, then
2931 if (IsJSReceiver(*temporal_time_zone_like)) {
2932 // a. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]]
2933 // internal slot, then
2934 if (IsJSTemporalZonedDateTime(*temporal_time_zone_like)) {
2935 // i. Return temporalTimeZoneLike.[[TimeZone]].
2936 auto zoned_date_time =
2937 Cast<JSTemporalZonedDateTime>(temporal_time_zone_like);
2938 return direct_handle(zoned_date_time->time_zone(), isolate);
2939 }
2940 DirectHandle<JSReceiver> obj = Cast<JSReceiver>(temporal_time_zone_like);
2941 // b. If ? HasProperty(temporalTimeZoneLike, "timeZone") is false,
2942 bool has;
2944 isolate, has,
2945 JSReceiver::HasProperty(isolate, obj, factory->timeZone_string()),
2947 if (!has) {
2948 // return temporalTimeZoneLike.
2949 return obj;
2950 }
2951 // c. Set temporalTimeZoneLike to ?
2952 // Get(temporalTimeZoneLike, "timeZone").
2954 isolate, temporal_time_zone_like,
2955 JSReceiver::GetProperty(isolate, obj, factory->timeZone_string()));
2956 // d. If Type(temporalTimeZoneLike)
2957 if (IsJSReceiver(*temporal_time_zone_like)) {
2958 // is Object and ? HasProperty(temporalTimeZoneLike, "timeZone") is false,
2959 obj = Cast<JSReceiver>(temporal_time_zone_like);
2961 isolate, has,
2962 JSReceiver::HasProperty(isolate, obj, factory->timeZone_string()),
2964 if (!has) {
2965 // return temporalTimeZoneLike.
2966 return obj;
2967 }
2968 }
2969 }
2971 // 2. Let identifier be ? ToString(temporalTimeZoneLike).
2973 isolate, identifier, Object::ToString(isolate, temporal_time_zone_like));
2974
2975 // 3. Let parseResult be ? ParseTemporalTimeZoneString(identifier).
2976 TimeZoneRecord parse_result;
2978 isolate, parse_result, ParseTemporalTimeZoneString(isolate, identifier),
2980
2981 // 4. If parseResult.[[Name]] is not undefined, then
2982 if (!IsUndefined(*parse_result.name)) {
2983 DCHECK(IsString(*parse_result.name));
2984 // a. Let name be parseResult.[[Name]].
2985 DirectHandle<String> name = Cast<String>(parse_result.name);
2986 // b. If ParseText(StringToCodePoints(name, TimeZoneNumericUTCOffset)) is
2987 // a List of errors, then
2988 std::optional<ParsedISO8601Result> parsed_offset =
2989 TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, name);
2990 if (!parsed_offset.has_value()) {
2991 // i. If ! IsValidTimeZoneName(name) is false, throw a RangeError
2992 // exception.
2993 if (!IsValidTimeZoneName(isolate, name)) {
2995 }
2996 // ii. Set name to ! CanonicalizeTimeZoneName(name).
2997 name = CanonicalizeTimeZoneName(isolate, name);
2998 }
2999 // c. Return ! CreateTemporalTimeZone(name).
3000 return temporal::CreateTemporalTimeZone(isolate, name);
3001 }
3002 // 5. If parseResult.[[Z]] is true, return ! CreateTemporalTimeZone("UTC").
3003 if (parse_result.z) {
3004 return CreateTemporalTimeZoneUTC(isolate);
3005 }
3006 // 6. Return ! CreateTemporalTimeZone(parseResult.[[OffsetString]]).
3007 DCHECK(IsString(*parse_result.offset_string));
3008 return temporal::CreateTemporalTimeZone(
3009 isolate, Cast<String>(parse_result.offset_string));
3010}
3011
3012} // namespace temporal
3013
3014namespace {
3015// #sec-temporal-systemdatetime
3016MaybeDirectHandle<JSTemporalPlainDateTime> SystemDateTime(
3017 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like,
3018 DirectHandle<Object> calendar_like, const char* method_name) {
3020
3021 DirectHandle<JSReceiver> time_zone;
3022 // 1. 1. If temporalTimeZoneLike is undefined, then
3023 if (IsUndefined(*temporal_time_zone_like)) {
3024 // a. Let timeZone be ! SystemTimeZone().
3025 time_zone = SystemTimeZone(isolate);
3026 } else {
3027 // 2. Else,
3028 // a. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
3030 isolate, time_zone,
3031 temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
3032 method_name));
3033 }
3034 DirectHandle<JSReceiver> calendar;
3035 // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
3037 isolate, calendar,
3038 temporal::ToTemporalCalendar(isolate, calendar_like, method_name));
3039 // 4. Let instant be ! SystemInstant().
3040 DirectHandle<JSTemporalInstant> instant = SystemInstant(isolate);
3041 // 5. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
3042 // calendar).
3044 isolate, time_zone, instant, calendar, method_name);
3045}
3046
3047MaybeDirectHandle<JSTemporalZonedDateTime> SystemZonedDateTime(
3048 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like,
3049 DirectHandle<Object> calendar_like, const char* method_name) {
3051
3052 DirectHandle<JSReceiver> time_zone;
3053 // 1. 1. If temporalTimeZoneLike is undefined, then
3054 if (IsUndefined(*temporal_time_zone_like)) {
3055 // a. Let timeZone be ! SystemTimeZone().
3056 time_zone = SystemTimeZone(isolate);
3057 } else {
3058 // 2. Else,
3059 // a. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
3061 isolate, time_zone,
3062 temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
3063 method_name));
3064 }
3065 DirectHandle<JSReceiver> calendar;
3066 // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
3068 isolate, calendar,
3069 temporal::ToTemporalCalendar(isolate, calendar_like, method_name));
3070 // 4. Let ns be ! SystemUTCEpochNanoseconds().
3071 DirectHandle<BigInt> ns = SystemUTCEpochNanoseconds(isolate);
3072 // Return ? CreateTemporalZonedDateTime(ns, timeZone, calendar).
3073 return CreateTemporalZonedDateTime(isolate, ns, time_zone, calendar);
3074}
3075
3076int CompareResultToSign(ComparisonResult r) {
3078 return static_cast<int>(r);
3079}
3080
3081// #sec-temporal-formattimezoneoffsetstring
3082DirectHandle<String> FormatTimeZoneOffsetString(Isolate* isolate,
3083 int64_t offset_nanoseconds) {
3084 IncrementalStringBuilder builder(isolate);
3085 // 1. Assert: offsetNanoseconds is an integer.
3086 // 2. If offsetNanoseconds ≥ 0, let sign be "+"; otherwise, let sign be "-".
3087 builder.AppendCharacter((offset_nanoseconds >= 0) ? '+' : '-');
3088 // 3. Let offsetNanoseconds be abs(offsetNanoseconds).
3089 offset_nanoseconds = std::abs(offset_nanoseconds);
3090 // 4. Let nanoseconds be offsetNanoseconds modulo 10^9.
3091 int64_t nanoseconds = offset_nanoseconds % 1000000000;
3092 // 5. Let seconds be floor(offsetNanoseconds / 10^9) modulo 60.
3093 int32_t seconds = (offset_nanoseconds / 1000000000) % 60;
3094 // 6. Let minutes be floor(offsetNanoseconds / (6 × 10^10)) modulo 60.
3095 int32_t minutes = (offset_nanoseconds / 60000000000) % 60;
3096 // 7. Let hours be floor(offsetNanoseconds / (3.6 × 10^12)).
3097 int32_t hours = offset_nanoseconds / 3600000000000;
3098 // 8. Let h be ToZeroPaddedDecimalString(hours, 2).
3099 ToZeroPaddedDecimalString(&builder, hours, 2);
3100
3101 // 9. Let m be ToZeroPaddedDecimalString(minutes, 2).
3102 builder.AppendCharacter(':');
3103 ToZeroPaddedDecimalString(&builder, minutes, 2);
3104
3105 // 10. Let s be ToZeroPaddedDecimalString(seconds, 2).
3106 // 11. If nanoseconds ≠ 0, then
3107 if (nanoseconds != 0) {
3108 // a. Let fraction be ToZeroPaddedDecimalString(nanoseconds, 9).
3109 // b. Set fraction to the longest possible substring of fraction starting at
3110 // position 0 and not ending with the code unit 0x0030 (DIGIT ZERO). c. Let
3111 // post be the string-concatenation of the code unit 0x003A (COLON), s, the
3112 // code unit 0x002E (FULL STOP), and fraction.
3113 builder.AppendCharacter(':');
3114 ToZeroPaddedDecimalString(&builder, seconds, 2);
3115 builder.AppendCharacter('.');
3116 int64_t divisor = 100000000;
3117 do {
3118 builder.AppendInt(static_cast<int>(nanoseconds / divisor));
3119 nanoseconds %= divisor;
3120 divisor /= 10;
3121 } while (nanoseconds > 0);
3122 // 11. Else if seconds ≠ 0, then
3123 } else if (seconds != 0) {
3124 // a. Let post be the string-concatenation of the code unit 0x003A (COLON)
3125 // and s.
3126 builder.AppendCharacter(':');
3127 ToZeroPaddedDecimalString(&builder, seconds, 2);
3128 }
3129 // 12. Return the string-concatenation of sign, h, the code unit 0x003A
3130 // (COLON), m, and post.
3131 return builder.Finish().ToHandleChecked();
3132}
3133
3134double RoundNumberToIncrement(Isolate* isolate, double x, double increment,
3135 RoundingMode rounding_mode);
3136
3137// #sec-temporal-formatisotimezoneoffsetstring
3138DirectHandle<String> FormatISOTimeZoneOffsetString(Isolate* isolate,
3139 int64_t offset_nanoseconds) {
3140 IncrementalStringBuilder builder(isolate);
3141 // 1. Assert: offsetNanoseconds is an integer.
3142 // 2. Set offsetNanoseconds to ! RoundNumberToIncrement(offsetNanoseconds, 60
3143 // × 10^9, "halfExpand").
3144 offset_nanoseconds = RoundNumberToIncrement(
3145 isolate, offset_nanoseconds, 60000000000, RoundingMode::kHalfExpand);
3146 // 3. If offsetNanoseconds ≥ 0, let sign be "+"; otherwise, let sign be "-".
3147 builder.AppendCharacter((offset_nanoseconds >= 0) ? '+' : '-');
3148 // 4. Set offsetNanoseconds to abs(offsetNanoseconds).
3149 offset_nanoseconds = std::abs(offset_nanoseconds);
3150 // 5. Let minutes be offsetNanoseconds / (60 × 10^9) modulo 60.
3151 int32_t minutes = (offset_nanoseconds / 60000000000) % 60;
3152 // 6. Let hours be floor(offsetNanoseconds / (3600 × 10^9)).
3153 int32_t hours = offset_nanoseconds / 3600000000000;
3154 // 7. Let h be ToZeroPaddedDecimalString(hours, 2).
3155 ToZeroPaddedDecimalString(&builder, hours, 2);
3156
3157 // 8. Let m be ToZeroPaddedDecimalString(minutes, 2).
3158 builder.AppendCharacter(':');
3159 ToZeroPaddedDecimalString(&builder, minutes, 2);
3160 // 9. Return the string-concatenation of sign, h, the code unit 0x003A
3161 // (COLON), and m.
3162 return builder.Finish().ToHandleChecked();
3163}
3164
3165int32_t DecimalLength(int32_t n) {
3166 int32_t i = 1;
3167 while (n >= 10) {
3168 n /= 10;
3169 i++;
3170 }
3171 return i;
3172}
3173
3174// #sec-tozeropaddeddecimalstring
3175void ToZeroPaddedDecimalString(IncrementalStringBuilder* builder, int32_t n,
3176 int32_t min_length) {
3177 for (int32_t pad = min_length - DecimalLength(n); pad > 0; pad--) {
3178 builder->AppendCharacter('0');
3179 }
3180 builder->AppendInt(n);
3181}
3182
3183// #sec-temporal-padisoyear
3184void PadISOYear(IncrementalStringBuilder* builder, int32_t y) {
3185 // 1. Assert: y is an integer.
3186 // 2. If y ≥ 0 and y ≤ 9999, then
3187 if (y >= 0 && y <= 9999) {
3188 // a. Return ToZeroPaddedDecimalString(y, 4).
3189 ToZeroPaddedDecimalString(builder, y, 4);
3190 return;
3191 }
3192 // 3. If y > 0, let yearSign be "+"; otherwise, let yearSign be "-".
3193 if (y > 0) {
3194 builder->AppendCharacter('+');
3195 } else {
3196 builder->AppendCharacter('-');
3197 }
3198 // 4. Let year be ToZeroPaddedDecimalString(abs(y), 6).
3199 ToZeroPaddedDecimalString(builder, std::abs(y), 6);
3200 // 5. Return the string-concatenation of yearSign and year.
3201}
3202
3203// #sec-temporal-formatcalendarannotation
3204DirectHandle<String> FormatCalendarAnnotation(Isolate* isolate,
3205 DirectHandle<String> id,
3206 ShowCalendar show_calendar) {
3207 // 1.Assert: showCalendar is "auto", "always", or "never".
3208 // 2. If showCalendar is "never", return the empty String.
3209 if (show_calendar == ShowCalendar::kNever) {
3210 return isolate->factory()->empty_string();
3211 }
3212 // 3. If showCalendar is "auto" and id is "iso8601", return the empty String.
3213 if (show_calendar == ShowCalendar::kAuto &&
3214 String::Equals(isolate, id, isolate->factory()->iso8601_string())) {
3215 return isolate->factory()->empty_string();
3216 }
3217 // 4. Return the string-concatenation of "[u-ca=", id, and "]".
3218 IncrementalStringBuilder builder(isolate);
3219 builder.AppendCStringLiteral("[u-ca=");
3220 builder.AppendString(id);
3221 builder.AppendCharacter(']');
3222 return builder.Finish().ToHandleChecked();
3223}
3224
3225// #sec-temporal-maybeformatcalendarannotation
3226MaybeDirectHandle<String> MaybeFormatCalendarAnnotation(
3227 Isolate* isolate, DirectHandle<JSReceiver> calendar_object,
3228 ShowCalendar show_calendar) {
3229 // 1. If showCalendar is "never", return the empty String.
3230 if (show_calendar == ShowCalendar::kNever) {
3231 return isolate->factory()->empty_string();
3232 }
3233 // 2. Let calendarID be ? ToString(calendarObject).
3234 DirectHandle<String> calendar_id;
3235 ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar_id,
3236 Object::ToString(isolate, calendar_object));
3237 // 3. Return FormatCalendarAnnotation(calendarID, showCalendar).
3238 return FormatCalendarAnnotation(isolate, calendar_id, show_calendar);
3239}
3240
3241// #sec-temporal-temporaldatetostring
3242MaybeDirectHandle<String> TemporalDateToString(
3243 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
3244 ShowCalendar show_calendar) {
3245 IncrementalStringBuilder builder(isolate);
3246 // 1. Assert: Type(temporalDate) is Object.
3247 // 2. Assert: temporalDate has an [[InitializedTemporalDate]] internal slot.
3248 // 3. Let year be ! PadISOYear(temporalDate.[[ISOYear]]).
3249 PadISOYear(&builder, temporal_date->iso_year());
3250 // 4. Let month be ToZeroPaddedDecimalString(temporalDate.[[ISOMonth]], 2).
3251 builder.AppendCharacter('-');
3252 ToZeroPaddedDecimalString(&builder, temporal_date->iso_month(), 2);
3253 // 5. Let day be ToZeroPaddedDecimalString(temporalDate.[[ISODay]], 2).
3254 builder.AppendCharacter('-');
3255 ToZeroPaddedDecimalString(&builder, temporal_date->iso_day(), 2);
3256 // 6. Let calendar be ?
3257 // MaybeFormatCalendarAnnotation(temporalDate.[[Calendar]], showCalendar).
3258 DirectHandle<String> calendar;
3260 isolate, calendar,
3261 MaybeFormatCalendarAnnotation(
3262 isolate, direct_handle(temporal_date->calendar(), isolate),
3263 show_calendar));
3264
3265 // 7. Return the string-concatenation of year, the code unit 0x002D
3266 // (HYPHEN-MINUS), month, the code unit 0x002D (HYPHEN-MINUS), day, and
3267 // calendar.
3268 builder.AppendString(calendar);
3269 return builder.Finish().ToHandleChecked();
3270}
3271
3272// #sec-temporal-temporalmonthdaytostring
3273MaybeDirectHandle<String> TemporalMonthDayToString(
3274 Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day,
3275 ShowCalendar show_calendar) {
3276 // 1. Assert: Type(monthDay) is Object.
3277 // 2. Assert: monthDay has an [[InitializedTemporalMonthDay]] internal slot.
3278 IncrementalStringBuilder builder(isolate);
3279 // 6. Let calendarID be ? ToString(monthDay.[[Calendar]]).
3280 DirectHandle<String> calendar_id;
3282 isolate, calendar_id,
3283 Object::ToString(isolate, handle(month_day->calendar(), isolate)));
3284 // 7. If showCalendar is "always" or if calendarID is not "iso8601", then
3285 if (show_calendar == ShowCalendar::kAlways ||
3286 !String::Equals(isolate, calendar_id,
3287 isolate->factory()->iso8601_string())) {
3288 // a. Let year be ! PadISOYear(monthDay.[[ISOYear]]).
3289 PadISOYear(&builder, month_day->iso_year());
3290 // b. Set result to the string-concatenation of year, the code unit
3291 // 0x002D (HYPHEN-MINUS), and result.
3292 builder.AppendCharacter('-');
3293 }
3294 // 3. Let month be ToZeroPaddedDecimalString(monthDay.[[ISOMonth]], 2).
3295 ToZeroPaddedDecimalString(&builder, month_day->iso_month(), 2);
3296 // 5. Let result be the string-concatenation of month, the code unit 0x002D
3297 // (HYPHEN-MINUS), and day.
3298 builder.AppendCharacter('-');
3299 // 4. Let day be ToZeroPaddedDecimalString(monthDay.[[ISODay]], 2).
3300 ToZeroPaddedDecimalString(&builder, month_day->iso_day(), 2);
3301 // 8. Let calendarString be ! FormatCalendarAnnotation(calendarID,
3302 // showCalendar).
3303 DirectHandle<String> calendar_string =
3304 FormatCalendarAnnotation(isolate, calendar_id, show_calendar);
3305 // 9. Set result to the string-concatenation of result and calendarString.
3306 builder.AppendString(calendar_string);
3307 // 10. Return result.
3308 return builder.Finish().ToHandleChecked();
3309}
3310
3311// #sec-temporal-temporalyearmonthtostring
3312MaybeDirectHandle<String> TemporalYearMonthToString(
3313 Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
3314 ShowCalendar show_calendar) {
3315 // 1. Assert: Type(yearMonth) is Object.
3316 // 2. Assert: yearMonth has an [[InitializedTemporalYearMonth]] internal slot.
3317 IncrementalStringBuilder builder(isolate);
3318 // 3. Let year be ! PadISOYear(yearMonth.[[ISOYear]]).
3319 PadISOYear(&builder, year_month->iso_year());
3320 // 4. Let month be ToZeroPaddedDecimalString(yearMonth.[[ISOMonth]], 2).
3321 // 5. Let result be the string-concatenation of year, the code unit 0x002D
3322 // (HYPHEN-MINUS), and month.
3323 builder.AppendCharacter('-');
3324 ToZeroPaddedDecimalString(&builder, year_month->iso_month(), 2);
3325 // 6. Let calendarID be ? ToString(yearMonth.[[Calendar]]).
3326 DirectHandle<String> calendar_id;
3328 isolate, calendar_id,
3329 Object::ToString(isolate, handle(year_month->calendar(), isolate)));
3330 // 7. If showCalendar is "always" or if *_calendarID_ is not *"iso8601", then
3331 if (show_calendar == ShowCalendar::kAlways ||
3332 !String::Equals(isolate, calendar_id,
3333 isolate->factory()->iso8601_string())) {
3334 // a. Let day be ToZeroPaddedDecimalString(yearMonth.[[ISODay]], 2).
3335 // b. Set result to the string-concatenation of result, the code unit 0x002D
3336 // (HYPHEN-MINUS), and day.
3337 builder.AppendCharacter('-');
3338 ToZeroPaddedDecimalString(&builder, year_month->iso_day(), 2);
3339 }
3340 // 8. Let calendarString be ! FormatCalendarAnnotation(calendarID,
3341 // showCalendar).
3342 DirectHandle<String> calendar_string =
3343 FormatCalendarAnnotation(isolate, calendar_id, show_calendar);
3344 // 9. Set result to the string-concatenation of result and calendarString.
3345 builder.AppendString(calendar_string);
3346 // 10. Return result.
3347 return builder.Finish().ToHandleChecked();
3348}
3349
3350// #sec-temporal-builtintimezonegetoffsetstringfor
3351MaybeDirectHandle<String> BuiltinTimeZoneGetOffsetStringFor(
3352 Isolate* isolate, DirectHandle<JSReceiver> time_zone,
3353 DirectHandle<JSTemporalInstant> instant, const char* method_name) {
3355 // 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
3356 int64_t offset_nanoseconds;
3358 isolate, offset_nanoseconds,
3359 GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
3360 DirectHandle<String>());
3361
3362 // 2. Return ! FormatTimeZoneOffsetString(offsetNanoseconds).
3363 return FormatTimeZoneOffsetString(isolate, offset_nanoseconds);
3364}
3365
3366// #sec-temporal-parseisodatetime
3367Maybe<DateTimeRecordWithCalendar> ParseISODateTime(
3368 Isolate* isolate, DirectHandle<String> iso_string,
3369 const ParsedISO8601Result& parsed);
3370// Note: We split ParseISODateTime to two function because the spec text
3371// repeats some parsing unnecessarily. If a function is calling ParseISODateTime
3372// from a AO which already call ParseText() for TemporalDateTimeString,
3373// TemporalInstantString, TemporalMonthDayString, TemporalTimeString,
3374// TemporalYearMonthString, TemporalZonedDateTimeString. But for the usage in
3375// ParseTemporalTimeZoneString, we use the following version.
3376Maybe<DateTimeRecordWithCalendar> ParseISODateTime(
3377 Isolate* isolate, DirectHandle<String> iso_string) {
3378 // 2. For each nonterminal goal of « TemporalDateTimeString,
3379 // TemporalInstantString, TemporalMonthDayString, TemporalTimeString,
3380 // TemporalYearMonthString, TemporalZonedDateTimeString », do
3381
3382 // a. If parseResult is not a Parse Node, set parseResult to
3383 // ParseText(StringToCodePoints(isoString), goal).
3384 std::optional<ParsedISO8601Result> parsed;
3385 if ((parsed =
3386 TemporalParser::ParseTemporalDateTimeString(isolate, iso_string))
3387 .has_value() ||
3388 (parsed = TemporalParser::ParseTemporalInstantString(isolate, iso_string))
3389 .has_value() ||
3390 (parsed =
3391 TemporalParser::ParseTemporalMonthDayString(isolate, iso_string))
3392 .has_value() ||
3393 (parsed = TemporalParser::ParseTemporalTimeString(isolate, iso_string))
3394 .has_value() ||
3395 (parsed =
3396 TemporalParser::ParseTemporalYearMonthString(isolate, iso_string))
3397 .has_value() ||
3398 (parsed = TemporalParser::ParseTemporalZonedDateTimeString(isolate,
3399 iso_string))
3400 .has_value()) {
3401 return ParseISODateTime(isolate, iso_string, *parsed);
3402 }
3403
3404 // 3. If parseResult is not a Parse Node, throw a RangeError exception.
3407}
3408
3409Maybe<DateTimeRecordWithCalendar> ParseISODateTime(
3410 Isolate* isolate, DirectHandle<String> iso_string,
3411 const ParsedISO8601Result& parsed) {
3413
3414 DateTimeRecordWithCalendar result;
3415 // 6. Set yearMV to ! ToIntegerOrInfinity(year).
3416 result.date.year = parsed.date_year;
3417 // 7. If month is undefined, then
3418 if (parsed.date_month_is_undefined()) {
3419 // a. Set monthMV to 1.
3420 result.date.month = 1;
3421 // 8. Else,
3422 } else {
3423 // a. Set monthMV to ! ToIntegerOrInfinity(month).
3424 result.date.month = parsed.date_month;
3425 }
3426
3427 // 9. If day is undefined, then
3428 if (parsed.date_day_is_undefined()) {
3429 // a. Set dayMV to 1.
3430 result.date.day = 1;
3431 // 10. Else,
3432 } else {
3433 // a. Set dayMV to ! ToIntegerOrInfinity(day).
3434 result.date.day = parsed.date_day;
3435 }
3436 // 11. Set hourMV to ! ToIntegerOrInfinity(hour).
3437 result.time.hour = parsed.time_hour_is_undefined() ? 0 : parsed.time_hour;
3438 // 12. Set minuteMV to ! ToIntegerOrInfinity(minute).
3439 result.time.minute =
3440 parsed.time_minute_is_undefined() ? 0 : parsed.time_minute;
3441 // 13. Set secondMV to ! ToIntegerOrInfinity(second).
3442 result.time.second =
3443 parsed.time_second_is_undefined() ? 0 : parsed.time_second;
3444 // 14. If secondMV is 60, then
3445 if (result.time.second == 60) {
3446 // a. Set secondMV to 59.
3447 result.time.second = 59;
3448 }
3449 // 15. If fSeconds is not empty, then
3450 if (!parsed.time_nanosecond_is_undefined()) {
3451 // a. Let fSecondsDigits be the substring of CodePointsToString(fSeconds)
3452 // from 1.
3453 //
3454 // b. Let fSecondsDigitsExtended be the string-concatenation of
3455 // fSecondsDigits and "000000000".
3456 //
3457 // c. Let millisecond be the substring of fSecondsDigitsExtended from 0 to
3458 // 3.
3459 //
3460 // d. Let microsecond be the substring of fSecondsDigitsExtended from 3 to
3461 // 6.
3462 //
3463 // e. Let nanosecond be the substring of fSecondsDigitsExtended from 6 to 9.
3464 //
3465 // f. Let millisecondMV be ! ToIntegerOrInfinity(millisecond).
3466 result.time.millisecond = parsed.time_nanosecond / 1000000;
3467 // g. Let microsecondMV be ! ToIntegerOrInfinity(microsecond).
3468 result.time.microsecond = (parsed.time_nanosecond / 1000) % 1000;
3469 // h. Let nanosecondMV be ! ToIntegerOrInfinity(nanosecond).
3470 result.time.nanosecond = (parsed.time_nanosecond % 1000);
3471 // 16. Else,
3472 } else {
3473 // a. Let millisecondMV be 0.
3474 result.time.millisecond = 0;
3475 // b. Let microsecondMV be 0.
3476 result.time.microsecond = 0;
3477 // c. Let nanosecondMV be 0.
3478 result.time.nanosecond = 0;
3479 }
3480 // 17. If ! IsValidISODate(yearMV, monthMV, dayMV) is false, throw a
3481 // RangeError exception.
3482 if (!IsValidISODate(isolate, result.date)) {
3486 }
3487 // 18. If ! IsValidTime(hourMV, minuteMV, secondMV, millisecondMV,
3488 // microsecondMV, nanosecond) is false, throw a RangeError exception.
3489 if (!IsValidTime(isolate, result.time)) {
3493 }
3494
3495 // 19. Let timeZoneResult be the Record { [[Z]]: false, [[OffsetString]]:
3496 // undefined, [[Name]]: undefined }.
3497 result.time_zone = {false, isolate->factory()->undefined_value(),
3498 isolate->factory()->undefined_value()};
3499 // 20. If parseResult contains a TimeZoneIdentifier Parse Node, then
3500 if (parsed.tzi_name_length != 0) {
3501 // a. Let name be the source text matched by the TimeZoneIdentifier Parse
3502 // Node contained within parseResult.
3503 //
3504 // b. Set timeZoneResult.[[Name]] to CodePointsToString(name).
3505 result.time_zone.name = isolate->factory()->NewSubString(
3506 iso_string, parsed.tzi_name_start,
3507 parsed.tzi_name_start + parsed.tzi_name_length);
3508 }
3509 // 21. If parseResult contains a UTCDesignator Parse Node, then
3510 if (parsed.utc_designator) {
3511 // a. Set timeZoneResult.[[Z]] to true.
3512 result.time_zone.z = true;
3513 // 22. Else,
3514 } else {
3515 // a. If parseResult contains a TimeZoneNumericUTCOffset Parse Node, then
3516 if (parsed.offset_string_length != 0) {
3517 // i. Let offset be the source text matched by the
3518 // TimeZoneNumericUTCOffset Parse Node contained within parseResult.
3519 // ii. Set timeZoneResult.[[OffsetString]] to CodePointsToString(offset).
3520 result.time_zone.offset_string = isolate->factory()->NewSubString(
3521 iso_string, parsed.offset_string_start,
3522 parsed.offset_string_start + parsed.offset_string_length);
3523 }
3524 }
3525
3526 // 23. If calendar is empty, then
3527 if (parsed.calendar_name_length == 0) {
3528 // a. Let calendarVal be undefined.
3529 result.calendar = isolate->factory()->undefined_value();
3530 // 24. Else,
3531 } else {
3532 // a. Let calendarVal be CodePointsToString(calendar).
3533 result.calendar = isolate->factory()->NewSubString(
3534 iso_string, parsed.calendar_name_start,
3535 parsed.calendar_name_start + parsed.calendar_name_length);
3536 }
3537 // 24. Return the Record { [[Year]]: yearMV, [[Month]]: monthMV, [[Day]]:
3538 // dayMV, [[Hour]]: hourMV, [[Minute]]: minuteMV, [[Second]]: secondMV,
3539 // [[Millisecond]]: millisecondMV, [[Microsecond]]: microsecondMV,
3540 // [[Nanosecond]]: nanosecondMV, [[TimeZone]]: timeZoneResult,
3541 // [[Calendar]]: calendarVal, }.
3542 return Just(result);
3543}
3544
3545// #sec-temporal-parsetemporaldatestring
3546Maybe<DateRecordWithCalendar> ParseTemporalDateString(
3547 Isolate* isolate, DirectHandle<String> iso_string) {
3549 // 1. Let parts be ? ParseTemporalDateTimeString(isoString).
3550 // 2. Return the Record { [[Year]]: parts.[[Year]], [[Month]]:
3551 // parts.[[Month]], [[Day]]: parts.[[Day]], [[Calendar]]: parts.[[Calendar]]
3552 // }.
3553 DateTimeRecordWithCalendar record;
3555 isolate, record, ParseTemporalDateTimeString(isolate, iso_string),
3557 DateRecordWithCalendar result = {record.date, record.calendar};
3558 return Just(result);
3559}
3560
3561// #sec-temporal-parsetemporaltimestring
3562Maybe<TimeRecordWithCalendar> ParseTemporalTimeString(
3563 Isolate* isolate, DirectHandle<String> iso_string) {
3565
3566 // 1. Assert: Type(isoString) is String.
3567 // 2. If isoString does not satisfy the syntax of a TemporalTimeString
3568 // (see 13.33), then
3569 std::optional<ParsedISO8601Result> parsed =
3570 TemporalParser::ParseTemporalTimeString(isolate, iso_string);
3571 if (!parsed.has_value()) {
3572 // a. Throw a *RangeError* exception.
3576 }
3577
3578 // 3. If _isoString_ contains a |UTCDesignator|, then
3579 if (parsed->utc_designator) {
3580 // a. Throw a *RangeError* exception.
3584 }
3585
3586 // 3. Let result be ? ParseISODateTime(isoString).
3587 DateTimeRecordWithCalendar result;
3589 isolate, result, ParseISODateTime(isolate, iso_string, *parsed),
3591 // 4. Return the Record { [[Hour]]: result.[[Hour]], [[Minute]]:
3592 // result.[[Minute]], [[Second]]: result.[[Second]], [[Millisecond]]:
3593 // result.[[Millisecond]], [[Microsecond]]: result.[[Microsecond]],
3594 // [[Nanosecond]]: result.[[Nanosecond]], [[Calendar]]: result.[[Calendar]] }.
3595 TimeRecordWithCalendar ret = {result.time, result.calendar};
3596 return Just(ret);
3597}
3598
3599// #sec-temporal-parsetemporalinstantstring
3600Maybe<InstantRecord> ParseTemporalInstantString(
3601 Isolate* isolate, DirectHandle<String> iso_string) {
3603
3604 // 1. If ParseText(StringToCodePoints(isoString), TemporalInstantString) is a
3605 // List of errors, throw a RangeError exception.
3606 std::optional<ParsedISO8601Result> parsed =
3607 TemporalParser::ParseTemporalInstantString(isolate, iso_string);
3608 if (!parsed.has_value()) {
3612 }
3613
3614 // 2. Let result be ? ParseISODateTime(isoString).
3615 DateTimeRecordWithCalendar result;
3617 isolate, result, ParseISODateTime(isolate, iso_string, *parsed),
3619
3620 // 3. Let offsetString be result.[[TimeZone]].[[OffsetString]].
3621 DirectHandle<Object> offset_string = result.time_zone.offset_string;
3622
3623 // 4. If result.[[TimeZone]].[[Z]] is true, then
3624 if (result.time_zone.z) {
3625 // a. Set offsetString to "+00:00".
3626 offset_string = isolate->factory()->NewStringFromStaticChars("+00:00");
3627 }
3628 // 5. Assert: offsetString is not undefined.
3629 DCHECK(!IsUndefined(*offset_string));
3630
3631 // 6. Return the new Record { [[Year]]: result.[[Year]],
3632 // [[Month]]: result.[[Month]], [[Day]]: result.[[Day]],
3633 // [[Hour]]: result.[[Hour]], [[Minute]]: result.[[Minute]],
3634 // [[Second]]: result.[[Second]],
3635 // [[Millisecond]]: result.[[Millisecond]],
3636 // [[Microsecond]]: result.[[Microsecond]],
3637 // [[Nanosecond]]: result.[[Nanosecond]],
3638 // [[TimeZoneOffsetString]]: offsetString }.
3639 InstantRecord record({result.date, result.time, offset_string});
3640 return Just(record);
3641}
3642
3643// #sec-temporal-parsetemporalrelativetostring
3644Maybe<DateTimeRecordWithCalendar> ParseTemporalRelativeToString(
3645 Isolate* isolate, DirectHandle<String> iso_string) {
3647
3648 // 1. If ParseText(StringToCodePoints(isoString), TemporalDateTimeString) is a
3649 // List of errors, throw a RangeError exception.
3650 std::optional<ParsedISO8601Result> parsed =
3651 TemporalParser::ParseTemporalDateTimeString(isolate, iso_string);
3652 if (!parsed.has_value()) {
3653 // a. Throw a *RangeError* exception.
3657 }
3658 // 2. Returns ? ParseISODateTime(isoString).
3659 return ParseISODateTime(isolate, iso_string, *parsed);
3660}
3661
3662// #sec-temporal-parsetemporalinstant
3663MaybeDirectHandle<BigInt> ParseTemporalInstant(
3664 Isolate* isolate, DirectHandle<String> iso_string) {
3666
3667 // 1. Assert: Type(isoString) is String.
3668 // 2. Let result be ? ParseTemporalInstantString(isoString).
3669 InstantRecord result;
3671 isolate, result, ParseTemporalInstantString(isolate, iso_string),
3672 DirectHandle<BigInt>());
3673
3674 // 3. Let offsetString be result.[[TimeZoneOffsetString]].
3675 // 4. Assert: offsetString is not undefined.
3676 DCHECK(!IsUndefined(*result.offset_string));
3677
3678 // 5. Let utc be ? GetEpochFromISOParts(result.[[Year]], result.[[Month]],
3679 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
3680 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).
3681 DirectHandle<BigInt> utc =
3682 GetEpochFromISOParts(isolate, {result.date, result.time});
3683
3684 // 6. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(offsetString).
3685 int64_t offset_nanoseconds;
3686 DCHECK(IsString(*result.offset_string));
3688 isolate, offset_nanoseconds,
3689 ParseTimeZoneOffsetString(isolate, Cast<String>(result.offset_string)),
3690 DirectHandle<BigInt>());
3691
3692 // 7. Let result be utc - ℤ(offsetNanoseconds).
3693 DirectHandle<BigInt> result_value =
3694 BigInt::Subtract(isolate, utc,
3695 BigInt::FromInt64(isolate, offset_nanoseconds))
3696 .ToHandleChecked();
3697 // 8. If ! IsValidEpochNanoseconds(result) is false, then
3698 if (!IsValidEpochNanoseconds(isolate, result_value)) {
3699 // a. Throw a RangeError exception.
3701 }
3702 // 9. Return result.
3703 return result_value;
3704}
3705
3706// #sec-temporal-parsetemporalzoneddatetimestring
3707Maybe<DateTimeRecordWithCalendar> ParseTemporalZonedDateTimeString(
3708 Isolate* isolate, DirectHandle<String> iso_string) {
3710 // 1. If ParseText(StringToCodePoints(isoString), TemporalZonedDateTimeString)
3711 // is a List of errors, throw a RangeError exception.
3712 std::optional<ParsedISO8601Result> parsed =
3713 TemporalParser::ParseTemporalZonedDateTimeString(isolate, iso_string);
3714 if (!parsed.has_value()) {
3718 }
3719
3720 // 2. Return ? ParseISODateTime(isoString).
3721 return ParseISODateTime(isolate, iso_string, *parsed);
3722}
3723
3724// #sec-temporal-createdurationrecord
3725Maybe<DurationRecord> CreateDurationRecord(Isolate* isolate,
3726 const DurationRecord& duration) {
3727 // 1. If ! IsValidDuration(years, months, weeks, days, hours, minutes,
3728 // seconds, milliseconds, microseconds, nanoseconds) is false, throw a
3729 // RangeError exception.
3730 if (!IsValidDuration(isolate, duration)) {
3734 }
3735 // 2. Return the Record { [[Years]]: ℝ(𝔽(years)), [[Months]]: ℝ(𝔽(months)),
3736 // [[Weeks]]: ℝ(𝔽(weeks)), [[Days]]: ℝ(𝔽(days)), [[Hours]]: ℝ(𝔽(hours)),
3737 // [[Minutes]]: ℝ(𝔽(minutes)), [[Seconds]]: ℝ(𝔽(seconds)), [[Milliseconds]]:
3738 // ℝ(𝔽(milliseconds)), [[Microseconds]]: ℝ(𝔽(microseconds)), [[Nanoseconds]]:
3739 // ℝ(𝔽(nanoseconds)) }.
3740 return Just(duration);
3741}
3742
3743inline double IfEmptyReturnZero(double value) {
3744 return value == ParsedISO8601Duration::kEmpty ? 0 : value;
3745}
3746
3747// #sec-temporal-parsetemporaldurationstring
3748Maybe<DurationRecord> ParseTemporalDurationString(
3749 Isolate* isolate, DirectHandle<String> iso_string) {
3751 // In this function, we use 'double' as type for all mathematical values
3752 // because in
3753 // https://tc39.es/proposal-temporal/#sec-properties-of-temporal-duration-instances
3754 // they are "A float64-representable integer representing the number" in the
3755 // internal slots.
3756 // 1. Let duration be ParseText(StringToCodePoints(isoString),
3757 // TemporalDurationString).
3758 // 2. If duration is a List of errors, throw a RangeError exception.
3759 // 3. Let each of sign, years, months, weeks, days, hours, fHours, minutes,
3760 // fMinutes, seconds, and fSeconds be the source text matched by the
3761 // respective Sign, DurationYears, DurationMonths, DurationWeeks,
3762 // DurationDays, DurationWholeHours, DurationHoursFraction,
3763 // DurationWholeMinutes, DurationMinutesFraction, DurationWholeSeconds, and
3764 // DurationSecondsFraction Parse Node enclosed by duration, or an empty
3765 // sequence of code points if not present.
3766 std::optional<ParsedISO8601Duration> parsed =
3767 TemporalParser::ParseTemporalDurationString(isolate, iso_string);
3768 if (!parsed.has_value()) {
3772 }
3773 // 4. Let yearsMV be ! ToIntegerOrInfinity(CodePointsToString(years)).
3774 double years_mv = IfEmptyReturnZero(parsed->years);
3775 // 5. Let monthsMV be ! ToIntegerOrInfinity(CodePointsToString(months)).
3776 double months_mv = IfEmptyReturnZero(parsed->months);
3777 // 6. Let weeksMV be ! ToIntegerOrInfinity(CodePointsToString(weeks)).
3778 double weeks_mv = IfEmptyReturnZero(parsed->weeks);
3779 // 7. Let daysMV be ! ToIntegerOrInfinity(CodePointsToString(days)).
3780 double days_mv = IfEmptyReturnZero(parsed->days);
3781 // 8. Let hoursMV be ! ToIntegerOrInfinity(CodePointsToString(hours)).
3782 double hours_mv = IfEmptyReturnZero(parsed->whole_hours);
3783 // 9. If fHours is not empty, then
3784 double minutes_mv;
3785 if (parsed->hours_fraction != ParsedISO8601Duration::kEmpty) {
3786 // a. If any of minutes, fMinutes, seconds, fSeconds is not empty, throw a
3787 // RangeError exception.
3788 if (parsed->whole_minutes != ParsedISO8601Duration::kEmpty ||
3789 parsed->minutes_fraction != ParsedISO8601Duration::kEmpty ||
3790 parsed->whole_seconds != ParsedISO8601Duration::kEmpty ||
3791 parsed->seconds_fraction != ParsedISO8601Duration::kEmpty) {
3795 }
3796 // b. Let fHoursDigits be the substring of CodePointsToString(fHours)
3797 // from 1.
3798 //
3799 // c. Let fHoursScale be the length of fHoursDigits.
3800 //
3801 // d. Let
3802 // minutesMV be ! ToIntegerOrInfinity(fHoursDigits) / 10^fHoursScale × 60.
3803 minutes_mv = IfEmptyReturnZero(parsed->hours_fraction) * 60.0 / 1e9;
3804 // 10. Else,
3805 } else {
3806 // a. Let minutesMV be ! ToIntegerOrInfinity(CodePointsToString(minutes)).
3807 minutes_mv = IfEmptyReturnZero(parsed->whole_minutes);
3808 }
3809 double seconds_mv;
3810 // 11. If fMinutes is not empty, then
3811 if (parsed->minutes_fraction != ParsedISO8601Duration::kEmpty) {
3812 // a. If any of seconds, fSeconds is not empty, throw a RangeError
3813 // exception.
3814 if (parsed->whole_seconds != ParsedISO8601Duration::kEmpty ||
3815 parsed->seconds_fraction != ParsedISO8601Duration::kEmpty) {
3819 }
3820 // b. Let fMinutesDigits be the substring of CodePointsToString(fMinutes)
3821 // from 1.
3822 //
3823 // c. Let fMinutesScale be the length of fMinutesDigits.
3824 //
3825 // d. Let secondsMV be ! ToIntegerOrInfinity(fMinutesDigits) /
3826 // 10^fMinutesScale × 60.
3827 seconds_mv = IfEmptyReturnZero(parsed->minutes_fraction) * 60.0 / 1e9;
3828 // 12. Else if seconds is not empty, then
3829 } else if (parsed->whole_seconds != ParsedISO8601Duration::kEmpty) {
3830 // a. Let secondsMV be ! ToIntegerOrInfinity(CodePointsToString(seconds)).
3831 seconds_mv = parsed->whole_seconds;
3832 // 13. Else,
3833 } else {
3834 // a. Let secondsMV be remainder(minutesMV, 1) × 60.
3835 seconds_mv = (minutes_mv - std::floor(minutes_mv)) * 60.0;
3836 }
3837 double milliseconds_mv, microseconds_mv, nanoseconds_mv;
3838 // Note: In step 14-17, we calculate from nanoseconds_mv to miilliseconds_mv
3839 // in the reversee order of the spec text to avoid numerical errors would be
3840 // introduced by multiple division inside the remainder operations. If we
3841 // strickly follow the order by using double, the end result of nanoseconds_mv
3842 // will be wrong due to numerical errors.
3843 //
3844 // 14. If fSeconds is not empty, then
3845 if (parsed->seconds_fraction != ParsedISO8601Duration::kEmpty) {
3846 // a. Let fSecondsDigits be the substring of CodePointsToString(fSeconds)
3847 // from 1.
3848 //
3849 // b. Let fSecondsScale be the length of fSecondsDigits.
3850 //
3851 // c. Let millisecondsMV be ! ToIntegerOrInfinity(fSecondsDigits) /
3852 // 10^fSecondsScale × 1000.
3853 DCHECK_LE(IfEmptyReturnZero(parsed->seconds_fraction), 1e9);
3854 nanoseconds_mv = std::round(IfEmptyReturnZero(parsed->seconds_fraction));
3855 // 15. Else,
3856 } else {
3857 // a. Let millisecondsMV be remainder(secondsMV, 1) × 1000.
3858 nanoseconds_mv = std::round((seconds_mv - std::floor(seconds_mv)) * 1e9);
3859 }
3860 milliseconds_mv = std::floor(nanoseconds_mv / 1000000);
3861 // 16. Let microsecondsMV be remainder(millisecondsMV, 1) × 1000.
3862 microseconds_mv = std::floor(nanoseconds_mv / 1000) -
3863 std::floor(nanoseconds_mv / 1000000) * 1000;
3864 // 17. Let nanosecondsMV be remainder(microsecondsMV, 1) × 1000.
3865 nanoseconds_mv -= std::floor(nanoseconds_mv / 1000) * 1000;
3866
3867 // 18. If sign contains the code point 0x002D (HYPHEN-MINUS) or 0x2212 (MINUS
3868 // SIGN), then a. Let factor be −1.
3869 // 19. Else,
3870 // a. Let factor be 1.
3871 double factor = parsed->sign;
3872
3873 // 20. Return ? CreateDurationRecord(yearsMV × factor, monthsMV × factor,
3874 // weeksMV × factor, daysMV × factor, hoursMV × factor, floor(minutesMV) ×
3875 // factor, floor(secondsMV) × factor, floor(millisecondsMV) × factor,
3876 // floor(microsecondsMV) × factor, floor(nanosecondsMV) × factor).
3877
3878 return CreateDurationRecord(
3879 isolate,
3880 {years_mv * factor,
3881 months_mv * factor,
3882 weeks_mv * factor,
3883 {days_mv * factor, hours_mv * factor, std::floor(minutes_mv) * factor,
3884 std::floor(seconds_mv) * factor, milliseconds_mv * factor,
3885 microseconds_mv * factor, nanoseconds_mv * factor}});
3886}
3887
3888// #sec-temporal-parsetemporaltimezonestring
3889Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(
3890 Isolate* isolate, DirectHandle<String> time_zone_string) {
3892
3893 // 1. Let parseResult be ParseText(StringToCodePoints(timeZoneString),
3894 // TimeZoneIdentifier).
3895 std::optional<ParsedISO8601Result> parsed =
3896 TemporalParser::ParseTimeZoneIdentifier(isolate, time_zone_string);
3897 // 2. If parseResult is a Parse Node, then
3898 if (parsed.has_value()) {
3899 // a. Return the Record { [[Z]]: false, [[OffsetString]]: undefined,
3900 // [[Name]]: timeZoneString }.
3901 return Just(TimeZoneRecord(
3902 {false, isolate->factory()->undefined_value(), time_zone_string}));
3903 }
3904
3905 // 3. Let result be ? ParseISODateTime(timeZoneString).
3906 DateTimeRecordWithCalendar result;
3908 isolate, result, ParseISODateTime(isolate, time_zone_string),
3910
3911 // 4. Let timeZoneResult be result.[[TimeZone]].
3912 // 5. If timeZoneResult.[[Z]] is false, timeZoneResult.[[OffsetString]] is
3913 // undefined, and timeZoneResult.[[Name]] is undefined, throw a RangeError
3914 // exception.
3915 if (!result.time_zone.z && IsUndefined(*result.time_zone.offset_string) &&
3916 IsUndefined(*result.time_zone.name)) {
3920 }
3921 // 6. Return timeZoneResult.
3922 return Just(result.time_zone);
3923}
3924
3925Maybe<int64_t> ParseTimeZoneOffsetString(Isolate* isolate,
3926 DirectHandle<String> iso_string) {
3928
3929 // 1. Assert: Type(offsetString) is String.
3930 // 2. If offsetString does not satisfy the syntax of a
3931 // TimeZoneNumericUTCOffset (see 13.33), then
3932 std::optional<ParsedISO8601Result> parsed =
3933 TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, iso_string);
3934 if (!parsed.has_value()) {
3935 /* a. Throw a RangeError exception. */
3938 }
3939 // 3. Let sign, hours, minutes, seconds, and fraction be the parts of
3940 // offsetString produced respectively by the TimeZoneUTCOffsetSign,
3941 // TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute, TimeZoneUTCOffsetSecond,
3942 // and TimeZoneUTCOffsetFraction productions, or undefined if not present.
3943 // 4. If either hours or sign are undefined, throw a RangeError exception.
3944 if (parsed->tzuo_hour_is_undefined() || parsed->tzuo_sign_is_undefined()) {
3947 }
3948 // 5. If sign is the code unit 0x002D (HYPHEN-MINUS) or 0x2212 (MINUS SIGN),
3949 // then a. Set sign to −1.
3950 // 6. Else,
3951 // a. Set sign to 1.
3952 int64_t sign = parsed->tzuo_sign;
3953
3954 // 7. Set hours to ! ToIntegerOrInfinity(hours).
3955 int64_t hours = parsed->tzuo_hour;
3956 // 8. Set minutes to ! ToIntegerOrInfinity(minutes).
3957 int64_t minutes =
3958 parsed->tzuo_minute_is_undefined() ? 0 : parsed->tzuo_minute;
3959 // 9. Set seconds to ! ToIntegerOrInfinity(seconds).
3960 int64_t seconds =
3961 parsed->tzuo_second_is_undefined() ? 0 : parsed->tzuo_second;
3962 // 10. If fraction is not undefined, then
3963 int64_t nanoseconds;
3964 if (!parsed->tzuo_nanosecond_is_undefined()) {
3965 // a. Set fraction to the string-concatenation of the previous value of
3966 // fraction and the string "000000000".
3967 // b. Let nanoseconds be the String value equal to the substring of fraction
3968 // consisting of the code units with indices 0 (inclusive) through 9
3969 // (exclusive). c. Set nanoseconds to ! ToIntegerOrInfinity(nanoseconds).
3970 nanoseconds = parsed->tzuo_nanosecond;
3971 // 11. Else,
3972 } else {
3973 // a. Let nanoseconds be 0.
3974 nanoseconds = 0;
3975 }
3976 // 12. Return sign × (((hours × 60 + minutes) × 60 + seconds) × 10^9 +
3977 // nanoseconds).
3978 return Just(sign * (((hours * 60 + minutes) * 60 + seconds) * 1000000000 +
3979 nanoseconds));
3980}
3981
3982bool IsValidTimeZoneNumericUTCOffsetString(Isolate* isolate,
3983 DirectHandle<String> iso_string) {
3985
3986 std::optional<ParsedISO8601Result> parsed =
3987 TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, iso_string);
3988 return parsed.has_value();
3989}
3990
3991// #sec-temporal-parsetemporalcalendarstring
3992MaybeDirectHandle<String> ParseTemporalCalendarString(
3993 Isolate* isolate, DirectHandle<String> iso_string) {
3995
3996 // 1. Let parseResult be Completion(ParseISODateTime(isoString)).
3997 Maybe<DateTimeRecordWithCalendar> parse_result =
3998 ParseISODateTime(isolate, iso_string);
3999 // 2. If parseResult is a normal completion, then
4000 if (parse_result.IsJust()) {
4001 // a. Let calendar be parseResult.[[Value]].[[Calendar]].
4002 DirectHandle<Object> calendar = parse_result.FromJust().calendar;
4003 // b. If calendar is undefined, return "iso8601".
4004 if (IsUndefined(*calendar)) {
4005 return isolate->factory()->iso8601_string();
4006 // c. Else, return calendar.
4007 } else {
4008 CHECK(IsString(*calendar));
4009 return Cast<String>(calendar);
4010 }
4011 // 3. Else,
4012 } else {
4013 DCHECK(isolate->has_exception());
4014 isolate->clear_exception();
4015 // a. Set parseResult to ParseText(StringToCodePoints(isoString),
4016 // CalendarName).
4017 std::optional<ParsedISO8601Result> parsed =
4018 TemporalParser::ParseCalendarName(isolate, iso_string);
4019 // b. If parseResult is a List of errors, throw a RangeError exception.
4020 if (!parsed.has_value()) {
4021 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidCalendar,
4022 iso_string));
4023 }
4024 // c. Else, return isoString.
4025 return iso_string;
4026 }
4027}
4028
4029// #sec-temporal-calendarequals
4030Maybe<bool> CalendarEqualsBool(Isolate* isolate, DirectHandle<JSReceiver> one,
4031 DirectHandle<JSReceiver> two) {
4032 // 1. If one and two are the same Object value, return true.
4033 if (one.is_identical_to(two)) {
4034 return Just(true);
4035 }
4036 // 2. Let calendarOne be ? ToString(one).
4037 DirectHandle<String> calendar_one;
4039 isolate, calendar_one, Object::ToString(isolate, one), Nothing<bool>());
4040 // 3. Let calendarTwo be ? ToString(two).
4041 DirectHandle<String> calendar_two;
4043 isolate, calendar_two, Object::ToString(isolate, two), Nothing<bool>());
4044 // 4. If calendarOne is calendarTwo, return true.
4045 if (String::Equals(isolate, calendar_one, calendar_two)) {
4046 return Just(true);
4047 }
4048 // 5. Return false.
4049 return Just(false);
4050}
4051MaybeDirectHandle<Oddball> CalendarEquals(Isolate* isolate,
4052 DirectHandle<JSReceiver> one,
4053 DirectHandle<JSReceiver> two) {
4054 bool result;
4056 CalendarEqualsBool(isolate, one, two),
4057 DirectHandle<Oddball>());
4058 return isolate->factory()->ToBoolean(result);
4059}
4060
4061// #sec-temporal-calendarfields
4062MaybeDirectHandle<FixedArray> CalendarFields(
4063 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4064 DirectHandle<FixedArray> field_names) {
4065 // 1. Let fields be ? GetMethod(calendar, "fields").
4066 DirectHandle<Object> fields;
4068 isolate, fields,
4069 Object::GetMethod(isolate, calendar,
4070 isolate->factory()->fields_string()));
4071 // 2. Let fieldsArray be ! CreateArrayFromList(fieldNames).
4072 DirectHandle<Object> fields_array =
4073 isolate->factory()->NewJSArrayWithElements(field_names);
4074 // 3. If fields is not undefined, then
4075 if (!IsUndefined(*fields)) {
4076 // a. Set fieldsArray to ? Call(fields, calendar, « fieldsArray »).
4077 DirectHandle<Object> args[] = {fields_array};
4079 isolate, fields_array,
4080 Execution::Call(isolate, fields, calendar, base::VectorOf(args)));
4081 }
4082 // 4. Return ? IterableToListOfType(fieldsArray, « String »).
4083 DirectHandle<Object> args[] = {fields_array};
4085 isolate, fields_array,
4086 Execution::CallBuiltin(isolate,
4087 isolate->string_fixed_array_from_iterable(),
4088 fields_array, base::VectorOf(args)));
4089 DCHECK(IsFixedArray(*fields_array));
4090 return Cast<FixedArray>(fields_array);
4091}
4092
4093MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
4094 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4095 DirectHandle<Object> date, DirectHandle<Object> duration) {
4096 // 2. If options is not present, set options to undefined.
4097 return CalendarDateAdd(isolate, calendar, date, duration,
4098 isolate->factory()->undefined_value());
4099}
4100
4101MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
4102 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4103 DirectHandle<Object> date, DirectHandle<Object> duration,
4104 DirectHandle<Object> options) {
4105 DirectHandle<Object> date_add;
4106 // 4. If dateAdd is not present, set dateAdd to ? GetMethod(calendar,
4108 isolate, date_add,
4109 Object::GetMethod(isolate, calendar,
4110 isolate->factory()->dateAdd_string()));
4111 return CalendarDateAdd(isolate, calendar, date, duration, options, date_add);
4112}
4113
4114MaybeDirectHandle<JSTemporalPlainDate> CalendarDateAdd(
4115 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4116 DirectHandle<Object> date, DirectHandle<Object> duration,
4117 DirectHandle<Object> options, DirectHandle<Object> date_add) {
4118 // 1. Assert: Type(options) is Object or Undefined.
4119 DCHECK(IsJSReceiver(*options) || IsUndefined(*options));
4120
4121 // 3. Let addedDate be ? Call(dateAdd, calendar, « date, duration, options »).
4122 DirectHandle<Object> args[] = {date, duration, options};
4123 DirectHandle<Object> added_date;
4125 isolate, added_date,
4126 Execution::Call(isolate, date_add, calendar, base::VectorOf(args)));
4127 // 4. Perform ? RequireInternalSlot(addedDate, [[InitializedTemporalDate]]).
4128 if (!IsJSTemporalPlainDate(*added_date)) {
4130 }
4131 // 5. Return addedDate.
4132 return Cast<JSTemporalPlainDate>(added_date);
4133}
4134
4135MaybeDirectHandle<JSTemporalDuration> CalendarDateUntil(
4136 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4137 DirectHandle<Object> one, DirectHandle<Object> two,
4138 DirectHandle<Object> options) {
4139 return CalendarDateUntil(isolate, calendar, one, two, options,
4140 isolate->factory()->undefined_value());
4141}
4142
4143MaybeDirectHandle<JSTemporalDuration> CalendarDateUntil(
4144 Isolate* isolate, DirectHandle<JSReceiver> calendar,
4145 DirectHandle<Object> one, DirectHandle<Object> two,
4146 DirectHandle<Object> options, DirectHandle<Object> date_until) {
4147 // 1. Assert: Type(calendar) is Object.
4148 // 2. If dateUntil is not present, set dateUntil to ? GetMethod(calendar,
4149 // "dateUntil").
4150 if (IsUndefined(*date_until)) {
4152 isolate, date_until,
4153 Object::GetMethod(isolate, calendar,
4154 isolate->factory()->dateUntil_string()));
4155 }
4156 // 3. Let duration be ? Call(dateUntil, calendar, « one, two, options »).
4157 DirectHandle<Object> args[] = {one, two, options};
4158 DirectHandle<Object> duration;
4160 isolate, duration,
4161 Execution::Call(isolate, date_until, calendar, base::VectorOf(args)));
4162 // 4. Perform ? RequireInternalSlot(duration,
4163 // [[InitializedTemporalDuration]]).
4164 if (!IsJSTemporalDuration(*duration)) {
4166 }
4167 // 5. Return duration.
4168 return Cast<JSTemporalDuration>(duration);
4169}
4170
4171// #sec-temporal-defaultmergefields
4172MaybeDirectHandle<JSReceiver> DefaultMergeFields(
4173 Isolate* isolate, DirectHandle<JSReceiver> fields,
4174 DirectHandle<JSReceiver> additional_fields) {
4175 Factory* factory = isolate->factory();
4176 // 1. Let merged be ! OrdinaryObjectCreate(%Object.prototype%).
4177 DirectHandle<JSObject> merged =
4178 isolate->factory()->NewJSObject(isolate->object_function());
4179
4180 // 2. Let originalKeys be ? EnumerableOwnPropertyNames(fields, key).
4181 DirectHandle<FixedArray> original_keys;
4183 isolate, original_keys,
4187 // 3. For each element nextKey of originalKeys, do
4188 for (int i = 0; i < original_keys->length(); i++) {
4189 // a. If nextKey is not "month" or "monthCode", then
4190 DirectHandle<Object> next_key(original_keys->get(i), isolate);
4191 DCHECK(IsString(*next_key));
4192 DirectHandle<String> next_key_string = Cast<String>(next_key);
4193 if (!(String::Equals(isolate, factory->month_string(), next_key_string) ||
4194 String::Equals(isolate, factory->monthCode_string(),
4195 next_key_string))) {
4196 // i. Let propValue be ? Get(fields, nextKey).
4197 DirectHandle<Object> prop_value;
4199 isolate, prop_value,
4200 Object::GetPropertyOrElement(isolate, fields, next_key_string));
4201 // ii. If propValue is not undefined, then
4202 if (!IsUndefined(*prop_value)) {
4203 // 1. Perform ! CreateDataPropertyOrThrow(merged, nextKey,
4204 // propValue).
4205 CHECK(JSReceiver::CreateDataProperty(isolate, merged, next_key_string,
4206 prop_value, Just(kDontThrow))
4207 .FromJust());
4208 }
4209 }
4210 }
4211 // 4. Let newKeys be ? EnumerableOwnPropertyNames(additionalFields, key).
4212 DirectHandle<FixedArray> new_keys;
4214 isolate, new_keys,
4215 KeyAccumulator::GetKeys(isolate, additional_fields,
4218 bool new_keys_has_month_or_month_code = false;
4219 // 5. For each element nextKey of newKeys, do
4220 for (int i = 0; i < new_keys->length(); i++) {
4221 DirectHandle<Object> next_key(new_keys->get(i), isolate);
4222 DCHECK(IsString(*next_key));
4223 DirectHandle<String> next_key_string = Cast<String>(next_key);
4224 // a. Let propValue be ? Get(additionalFields, nextKey).
4225 DirectHandle<Object> prop_value;
4227 isolate, prop_value,
4228 Object::GetPropertyOrElement(isolate, additional_fields,
4229 next_key_string));
4230 // b. If propValue is not undefined, then
4231 if (!IsUndefined(*prop_value)) {
4232 // 1. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
4233 CHECK(JSReceiver::CreateDataProperty(isolate, merged, next_key_string,
4234 prop_value, Just(kDontThrow))
4235 .FromJust());
4236 }
4237 new_keys_has_month_or_month_code |=
4238 String::Equals(isolate, factory->month_string(), next_key_string) ||
4239 String::Equals(isolate, factory->monthCode_string(), next_key_string);
4240 }
4241 // 6. If newKeys does not contain either "month" or "monthCode", then
4242 if (!new_keys_has_month_or_month_code) {
4243 // a. Let month be ? Get(fields, "month").
4244 DirectHandle<Object> month;
4246 isolate, month,
4247 JSReceiver::GetProperty(isolate, fields, factory->month_string()));
4248 // b. If month is not undefined, then
4249 if (!IsUndefined(*month)) {
4250 // i. Perform ! CreateDataPropertyOrThrow(merged, "month", month).
4251 CHECK(JSReceiver::CreateDataProperty(isolate, merged,
4252 factory->month_string(), month,
4254 .FromJust());
4255 }
4256 // c. Let monthCode be ? Get(fields, "monthCode").
4257 DirectHandle<Object> month_code;
4259 isolate, month_code,
4260 JSReceiver::GetProperty(isolate, fields, factory->monthCode_string()));
4261 // d. If monthCode is not undefined, then
4262 if (!IsUndefined(*month_code)) {
4263 // i. Perform ! CreateDataPropertyOrThrow(merged, "monthCode", monthCode).
4264 CHECK(JSReceiver::CreateDataProperty(isolate, merged,
4265 factory->monthCode_string(),
4266 month_code, Just(kDontThrow))
4267 .FromJust());
4268 }
4269 }
4270 // 7. Return merged.
4271 return merged;
4272}
4273
4274// #sec-temporal-getoffsetnanosecondsfor
4275Maybe<int64_t> GetOffsetNanosecondsFor(Isolate* isolate,
4276 DirectHandle<JSReceiver> time_zone_obj,
4277 DirectHandle<Object> instant,
4278 const char* method_name) {
4280 // 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone,
4281 // "getOffsetNanosecondsFor").
4282 DirectHandle<Object> get_offset_nanoseconds_for;
4284 isolate, get_offset_nanoseconds_for,
4285 Object::GetMethod(isolate, time_zone_obj,
4286 isolate->factory()->getOffsetNanosecondsFor_string()),
4288 if (!IsCallable(*get_offset_nanoseconds_for)) {
4290 isolate,
4291 NewTypeError(MessageTemplate::kCalledNonCallable,
4292 isolate->factory()->getOffsetNanosecondsFor_string()),
4294 }
4295 DirectHandle<Object> offset_nanoseconds_obj;
4296 // 3. Let offsetNanoseconds be ? Call(getOffsetNanosecondsFor, timeZone, «
4297 // instant »).
4298 DirectHandle<Object> args[] = {instant};
4300 isolate, offset_nanoseconds_obj,
4301 Execution::Call(isolate, get_offset_nanoseconds_for, time_zone_obj,
4304
4305 // 4. If Type(offsetNanoseconds) is not Number, throw a TypeError exception.
4306 if (!IsNumber(*offset_nanoseconds_obj)) {
4309 }
4310
4311 // 5. If ! IsIntegralNumber(offsetNanoseconds) is false, throw a RangeError
4312 // exception.
4313 if (!IsIntegralNumber(isolate, offset_nanoseconds_obj)) {
4316 }
4317 double offset_nanoseconds =
4318 Object::NumberValue(Cast<Number>(*offset_nanoseconds_obj));
4319
4320 // 6. Set offsetNanoseconds to ℝ(offsetNanoseconds).
4321 int64_t offset_nanoseconds_int = static_cast<int64_t>(offset_nanoseconds);
4322 // 7. If abs(offsetNanoseconds) >= 86400 × 10^9, throw a RangeError exception.
4323 if (std::abs(offset_nanoseconds_int) >= 86400e9) {
4326 }
4327 // 8. Return offsetNanoseconds.
4328 return Just(offset_nanoseconds_int);
4329}
4330
4331// #sec-temporal-topositiveinteger
4332MaybeDirectHandle<Number> ToPositiveInteger(Isolate* isolate,
4333 DirectHandle<Object> argument) {
4335
4336 // 1. Let integer be ? ToInteger(argument).
4337 DirectHandle<Number> integer;
4338 ASSIGN_RETURN_ON_EXCEPTION(isolate, integer,
4339 ToIntegerThrowOnInfinity(isolate, argument));
4340 // 2. If integer ≤ 0, then
4341 if (NumberToInt32(*integer) <= 0) {
4342 // a. Throw a RangeError exception.
4344 }
4345 return integer;
4346}
4347
4348} // namespace
4349
4350namespace temporal {
4355 /* 1. Assert: Type(calendar) is Object. */
4356 DCHECK(calendar->TaggedImpl::IsObject());
4357 /* 2. Let result be ? Invoke(calendar, #name, « dateLike »). */
4358 DirectHandle<Object> function;
4359 ASSIGN_RETURN_ON_EXCEPTION(isolate, function,
4360 Object::GetProperty(isolate, calendar, name));
4361 if (!IsCallable(*function)) {
4362 THROW_NEW_ERROR(isolate,
4363 NewTypeError(MessageTemplate::kCalledNonCallable, name));
4364 }
4365 DirectHandle<Object> args[] = {date_like};
4367 isolate, result,
4368 Execution::Call(isolate, function, calendar, base::VectorOf(args)));
4369 return result;
4370}
4371
4372#define CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Name, name, Action) \
4373 MaybeDirectHandle<Smi> Calendar##Name(Isolate* isolate, \
4374 DirectHandle<JSReceiver> calendar, \
4375 DirectHandle<JSReceiver> date_like) { \
4376 /* 1. Assert: Type(calendar) is Object. */ \
4377 /* 2. Let result be ? Invoke(calendar, property, « dateLike »). */ \
4378 DirectHandle<Object> result; \
4379 ASSIGN_RETURN_ON_EXCEPTION( \
4380 isolate, result, \
4381 InvokeCalendarMethod(isolate, calendar, \
4382 isolate->factory()->name##_string(), date_like)); \
4383 /* 3. If result is undefined, throw a RangeError exception. */ \
4384 if (IsUndefined(*result)) { \
4385 THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALID_ARG_RANGE_ERROR()); \
4386 } \
4387 /* 4. Return ? Action(result). */ \
4388 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Action(isolate, result)); \
4389 return direct_handle( \
4390 Smi::FromInt(Object::NumberValue(Cast<Number>(*result))), isolate); \
4391 }
4392
4393#define CALENDAR_ABSTRACT_OPERATION(Name, property) \
4394 MaybeDirectHandle<Object> Calendar##Name( \
4395 Isolate* isolate, DirectHandle<JSReceiver> calendar, \
4396 DirectHandle<JSReceiver> date_like) { \
4397 return InvokeCalendarMethod(isolate, calendar, \
4398 isolate->factory()->property##_string(), \
4399 date_like); \
4400 }
4401
4402// #sec-temporal-calendaryear
4403CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Year, year, ToIntegerThrowOnInfinity)
4404// #sec-temporal-calendarmonth
4405CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Month, month, ToPositiveInteger)
4406// #sec-temporal-calendarday
4407CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Day, day, ToPositiveInteger)
4408// #sec-temporal-calendarmonthcode
4409MaybeDirectHandle<Object> CalendarMonthCode(
4411 DirectHandle<JSReceiver> date_like) {
4412 // 1. Assert: Type(calendar) is Object.
4413 // 2. Let result be ? Invoke(calendar, monthCode , « dateLike »).
4416 isolate, result,
4418 isolate->factory()->monthCode_string(), date_like));
4419 /* 3. If result is undefined, throw a RangeError exception. */
4420 if (IsUndefined(*result)) {
4422 }
4423 // 4. Return ? ToString(result).
4424 return Object::ToString(isolate, result);
4425}
4426
4427#ifdef V8_INTL_SUPPORT
4428// #sec-temporal-calendarerayear
4429MaybeDirectHandle<Object> CalendarEraYear(Isolate* isolate,
4431 DirectHandle<JSReceiver> date_like) {
4432 // 1. Assert: Type(calendar) is Object.
4433 // 2. Let result be ? Invoke(calendar, eraYear , « dateLike »).
4436 isolate, result,
4437 InvokeCalendarMethod(isolate, calendar,
4438 isolate->factory()->eraYear_string(), date_like));
4439 // 3. If result is not undefined, set result to ? ToIntegerOrInfinity(result).
4440 if (!IsUndefined(*result)) {
4442 ToIntegerThrowOnInfinity(isolate, result));
4443 }
4444 // 4. Return result.
4445 return result;
4446}
4447
4448// #sec-temporal-calendarera
4449MaybeDirectHandle<Object> CalendarEra(Isolate* isolate,
4450 DirectHandle<JSReceiver> calendar,
4451 DirectHandle<JSReceiver> date_like) {
4452 // 1. Assert: Type(calendar) is Object.
4453 // 2. Let result be ? Invoke(calendar, era , « dateLike »).
4454 DirectHandle<Object> result;
4456 isolate, result,
4457 InvokeCalendarMethod(isolate, calendar, isolate->factory()->era_string(),
4458 date_like));
4459 // 3. If result is not undefined, set result to ? ToString(result).
4460 if (!IsUndefined(*result)) {
4462 Object::ToString(isolate, result));
4463 }
4464 // 4. Return result.
4465 return result;
4466}
4467
4468#endif // V8_INTL_SUPPORT
4469
4470// #sec-temporal-calendardayofweek
4471CALENDAR_ABSTRACT_OPERATION(DayOfWeek, dayOfWeek)
4472// #sec-temporal-calendardayofyear
4473CALENDAR_ABSTRACT_OPERATION(DayOfYear, dayOfYear)
4474// #sec-temporal-calendarweekofyear
4475CALENDAR_ABSTRACT_OPERATION(WeekOfYear, weekOfYear)
4476// #sec-temporal-calendardaysinweek
4477CALENDAR_ABSTRACT_OPERATION(DaysInWeek, daysInWeek)
4478// #sec-temporal-calendardaysinmonth
4479CALENDAR_ABSTRACT_OPERATION(DaysInMonth, daysInMonth)
4480// #sec-temporal-calendardaysinyear
4481CALENDAR_ABSTRACT_OPERATION(DaysInYear, daysInYear)
4482// #sec-temporal-calendarmonthsinyear
4483CALENDAR_ABSTRACT_OPERATION(MonthsInYear, monthsInYear)
4484// #sec-temporal-calendarinleapyear
4485CALENDAR_ABSTRACT_OPERATION(InLeapYear, inLeapYear)
4486
4487// #sec-temporal-getiso8601calendar
4488DirectHandle<JSTemporalCalendar> GetISO8601Calendar(Isolate* isolate) {
4489 return CreateTemporalCalendar(isolate, isolate->factory()->iso8601_string())
4490 .ToHandleChecked();
4491}
4492
4493} // namespace temporal
4494
4495namespace {
4496
4497bool IsUTC(Isolate* isolate, DirectHandle<String> time_zone) {
4498 // 1. Assert: Type(timeZone) is String.
4499 // 2. Let tzText be ! StringToCodePoints(timeZone).
4500 // 3. Let tzUpperText be the result of toUppercase(tzText), according to the
4501 // Unicode Default Case Conversion algorithm.
4502 // 4. Let tzUpper be ! CodePointsToString(tzUpperText).
4503 // 5. If tzUpper and "UTC" are the same sequence of code points, return true.
4504 // 6. Return false.
4505 if (time_zone->length() != 3) return false;
4508 const String::FlatContent& flat = time_zone->GetFlatContent(no_gc);
4509 return (flat.Get(0) == u'U' || flat.Get(0) == u'u') &&
4510 (flat.Get(1) == u'T' || flat.Get(1) == u't') &&
4511 (flat.Get(2) == u'C' || flat.Get(2) == u'c');
4512}
4513
4514#ifdef V8_INTL_SUPPORT
4515class CalendarMap final {
4516 public:
4517 CalendarMap() {
4518 icu::Locale locale("und");
4519 UErrorCode status = U_ZERO_ERROR;
4520 std::unique_ptr<icu::StringEnumeration> enumeration(
4521 icu::Calendar::getKeywordValuesForLocale("ca", locale, false, status));
4522 calendar_ids.push_back("iso8601");
4523 calendar_id_indices.insert({"iso8601", 0});
4524 int32_t i = 1;
4525 for (const char* item = enumeration->next(nullptr, status);
4526 U_SUCCESS(status) && item != nullptr;
4527 item = enumeration->next(nullptr, status)) {
4528 if (strcmp(item, "iso8601") != 0) {
4529 const char* type = uloc_toUnicodeLocaleType("ca", item);
4530 calendar_ids.push_back(type);
4531 calendar_id_indices.insert({type, i++});
4532 }
4533 }
4534 }
4535 bool Contains(const std::string& id) const {
4536 return calendar_id_indices.find(id) != calendar_id_indices.end();
4537 }
4538
4539 std::string Id(int32_t index) const {
4540 DCHECK_LT(index, calendar_ids.size());
4541 return calendar_ids[index];
4542 }
4543
4544 int32_t Index(const char* id) const {
4545 return calendar_id_indices.find(id)->second;
4546 }
4547
4548 private:
4549 std::map<std::string, int32_t> calendar_id_indices;
4550 std::vector<std::string> calendar_ids;
4551};
4552
4553DEFINE_LAZY_LEAKY_OBJECT_GETTER(CalendarMap, GetCalendarMap)
4554
4555bool IsBuiltinCalendar(Isolate* isolate, DirectHandle<String> id) {
4556 // 1. Let calendars be AvailableCalendars().
4557 // 2. If calendars contains the ASCII-lowercase of id, return true.
4558 // 3. Return false.
4559 id = Intl::ConvertToLower(isolate, String::Flatten(isolate, id))
4560 .ToHandleChecked();
4561 return GetCalendarMap()->Contains(id->ToCString().get());
4562}
4563
4564DirectHandle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
4565 return isolate->factory()->NewStringFromAsciiChecked(
4566 GetCalendarMap()->Id(index).c_str());
4567}
4568
4569int32_t CalendarIndex(Isolate* isolate, DirectHandle<String> id) {
4570 id = Intl::ConvertToLower(isolate, String::Flatten(isolate, id))
4571 .ToHandleChecked();
4572 return GetCalendarMap()->Index(id->ToCString().get());
4573}
4574
4575bool IsValidTimeZoneName(Isolate* isolate, DirectHandle<String> time_zone) {
4576 return Intl::IsValidTimeZoneName(isolate, time_zone);
4577}
4578
4579DirectHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
4580 DirectHandle<String> identifier) {
4581 return Intl::CanonicalizeTimeZoneName(isolate, identifier).ToHandleChecked();
4582}
4583
4584#else // V8_INTL_SUPPORT
4585DirectHandle<String> CalendarIdentifier(Isolate* isolate, int32_t index) {
4586 DCHECK_EQ(index, 0);
4587 return isolate->factory()->iso8601_string();
4588}
4589
4590// #sec-temporal-isbuiltincalendar
4591bool IsBuiltinCalendar(Isolate* isolate, DirectHandle<String> id) {
4592 // Note: For build without intl support, the only item in AvailableCalendars()
4593 // is "iso8601".
4594 // 1. Let calendars be AvailableCalendars().
4595 // 2. If calendars contains the ASCII-lowercase of id, return true.
4596 // 3. Return false.
4597
4598 // Fast path
4599 if (isolate->factory()->iso8601_string()->Equals(*id)) return true;
4600 if (id->length() != 7) return false;
4601 id = String::Flatten(isolate, id);
4602
4604 const String::FlatContent& flat = id->GetFlatContent(no_gc);
4605 // Return true if id is case insensitive equals to "iso8601".
4606 return AsciiAlphaToLower(flat.Get(0)) == 'i' &&
4607 AsciiAlphaToLower(flat.Get(1)) == 's' &&
4608 AsciiAlphaToLower(flat.Get(2)) == 'o' && flat.Get(3) == '8' &&
4609 flat.Get(4) == '6' && flat.Get(5) == '0' && flat.Get(6) == '1';
4610}
4611
4612int32_t CalendarIndex(Isolate* isolate, DirectHandle<String> id) { return 0; }
4613
4614// #sec-isvalidtimezonename
4615bool IsValidTimeZoneName(Isolate* isolate, DirectHandle<String> time_zone) {
4616 return IsUTC(isolate, time_zone);
4617}
4618
4619// #sec-canonicalizetimezonename
4620DirectHandle<String> CanonicalizeTimeZoneName(Isolate* isolate,
4621 DirectHandle<String> identifier) {
4622 return isolate->factory()->UTC_string();
4623}
4624#endif // V8_INTL_SUPPORT
4625
4626// Common routine shared by ToTemporalTimeRecord and ToPartialTime
4627// #sec-temporal-topartialtime
4628// #sec-temporal-totemporaltimerecord
4629Maybe<TimeRecord> ToTemporalTimeRecordOrPartialTime(
4630 Isolate* isolate, DirectHandle<JSReceiver> temporal_time_like,
4631 const TimeRecord& time, bool skip_undefined, const char* method_name) {
4633
4634 TimeRecord result(time);
4635 Factory* factory = isolate->factory();
4636 // 1. Assert: Type(temporalTimeLike) is Object.
4637 // 2. Let result be the new Record { [[Hour]]: undefined, [[Minute]]:
4638 // undefined, [[Second]]: undefined, [[Millisecond]]: undefined,
4639 // [[Microsecond]]: undefined, [[Nanosecond]]: undefined }.
4640 // See https://github.com/tc39/proposal-temporal/pull/1862
4641 // 3. Let _any_ be *false*.
4642 bool any = false;
4643 // 4. For each row of Table 4, except the header row, in table order, do
4644 std::array<std::pair<DirectHandle<String>, int32_t*>, 6> table4 = {
4645 {{factory->hour_string(), &result.hour},
4646 {factory->microsecond_string(), &result.microsecond},
4647 {factory->millisecond_string(), &result.millisecond},
4648 {factory->minute_string(), &result.minute},
4649 {factory->nanosecond_string(), &result.nanosecond},
4650 {factory->second_string(), &result.second}}};
4651 for (const auto& row : table4) {
4652 DirectHandle<Object> value;
4653 // a. Let property be the Property value of the current row.
4654 // b. Let value be ? Get(temporalTimeLike, property).
4656 isolate, value,
4657 JSReceiver::GetProperty(isolate, temporal_time_like, row.first),
4659 // c. If value is not undefined, then
4660 if (!IsUndefined(*value)) {
4661 // i. Set _any_ to *true*.
4662 any = true;
4663 // If it is inside ToPartialTime, we only continue if it is not undefined.
4664 } else if (skip_undefined) {
4665 continue;
4666 }
4667 // d. / ii. Set value to ? ToIntegerThrowOnOInfinity(value).
4668 DirectHandle<Number> value_number;
4669 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value_number,
4670 ToIntegerThrowOnInfinity(isolate, value),
4672 // e. / iii. Set result's internal slot whose name is the Internal Slot
4673 // value of the current row to value.
4674 *(row.second) = Object::NumberValue(*value_number);
4675 }
4676
4677 // 5. If _any_ is *false*, then
4678 if (!any) {
4679 // a. Throw a *TypeError* exception.
4682 }
4683 // 4. Return result.
4684 return Just(result);
4685}
4686
4687// #sec-temporal-topartialtime
4688Maybe<TimeRecord> ToPartialTime(Isolate* isolate,
4689 DirectHandle<JSReceiver> temporal_time_like,
4690 const TimeRecord& time,
4691 const char* method_name) {
4692 return ToTemporalTimeRecordOrPartialTime(isolate, temporal_time_like, time,
4693 true, method_name);
4694}
4695
4696// #sec-temporal-totemporaltimerecord
4697Maybe<TimeRecord> ToTemporalTimeRecord(
4698 Isolate* isolate, DirectHandle<JSReceiver> temporal_time_like,
4699 const char* method_name) {
4700 return ToTemporalTimeRecordOrPartialTime(
4701 isolate, temporal_time_like,
4703 method_name);
4704}
4705
4706// #sec-temporal-gettemporalunit
4707// In the spec text, the extraValues is defined as an optional argument of
4708// "a List of ECMAScript language values". Most of the caller does not pass in
4709// value for extraValues, which is represented by the default Unit::kNotPresent.
4710// For the three places in the spec text calling GetTemporalUnit with
4711// an extraValues argument:
4712// << "day" >> is passed in as in the algorithm of
4713// Temporal.PlainDateTime.prototype.round() and
4714// Temporal.ZonedDateTime.prototype.round();
4715// << "auto" >> is passed in as in the algorithm of
4716// Temporal.Duration.prototype.round().
4717// Therefore we can simply use a Unit of three possible value, the default
4718// Unit::kNotPresent, Unit::kDay, and Unit::kAuto to cover all the possible
4719// value for extraValues.
4720Maybe<Unit> GetTemporalUnit(Isolate* isolate,
4721 DirectHandle<JSReceiver> normalized_options,
4722 const char* key, UnitGroup unit_group,
4723 Unit default_value, bool default_is_required,
4724 const char* method_name,
4725 Unit extra_values = Unit::kNotPresent) {
4726 std::vector<const char*> str_values;
4727 std::vector<Unit> enum_values;
4728 switch (unit_group) {
4729 case UnitGroup::kDate:
4730 if (default_value == Unit::kAuto || extra_values == Unit::kAuto) {
4731 str_values = {"year", "month", "week", "day", "auto",
4732 "years", "months", "weeks", "days"};
4733 enum_values = {Unit::kYear, Unit::kMonth, Unit::kWeek,
4734 Unit::kDay, Unit::kAuto, Unit::kYear,
4735 Unit::kMonth, Unit::kWeek, Unit::kDay};
4736 } else {
4737 DCHECK(default_value == Unit::kNotPresent ||
4738 default_value == Unit::kYear || default_value == Unit::kMonth ||
4739 default_value == Unit::kWeek || default_value == Unit::kDay);
4740 str_values = {"year", "month", "week", "day",
4741 "years", "months", "weeks", "days"};
4742 enum_values = {Unit::kYear, Unit::kMonth, Unit::kWeek, Unit::kDay,
4743 Unit::kYear, Unit::kMonth, Unit::kWeek, Unit::kDay};
4744 }
4745 break;
4746 case UnitGroup::kTime:
4747 if (default_value == Unit::kAuto || extra_values == Unit::kAuto) {
4748 str_values = {"hour", "minute", "second",
4749 "millisecond", "microsecond", "nanosecond",
4750 "auto", "hours", "minutes",
4751 "seconds", "milliseconds", "microseconds",
4752 "nanoseconds"};
4753 enum_values = {
4754 Unit::kHour, Unit::kMinute, Unit::kSecond,
4755 Unit::kMillisecond, Unit::kMicrosecond, Unit::kNanosecond,
4756 Unit::kAuto, Unit::kHour, Unit::kMinute,
4757 Unit::kSecond, Unit::kMillisecond, Unit::kMicrosecond,
4758 Unit::kNanosecond};
4759 } else if (default_value == Unit::kDay || extra_values == Unit::kDay) {
4760 str_values = {"hour", "minute", "second",
4761 "millisecond", "microsecond", "nanosecond",
4762 "day", "hours", "minutes",
4763 "seconds", "milliseconds", "microseconds",
4764 "nanoseconds", "days"};
4765 enum_values = {
4766 Unit::kHour, Unit::kMinute, Unit::kSecond,
4767 Unit::kMillisecond, Unit::kMicrosecond, Unit::kNanosecond,
4768 Unit::kDay, Unit::kHour, Unit::kMinute,
4769 Unit::kSecond, Unit::kMillisecond, Unit::kMicrosecond,
4770 Unit::kNanosecond, Unit::kDay};
4771 } else {
4772 DCHECK(default_value == Unit::kNotPresent ||
4773 default_value == Unit::kHour || default_value == Unit::kMinute ||
4774 default_value == Unit::kSecond ||
4775 default_value == Unit::kMillisecond ||
4776 default_value == Unit::kMicrosecond ||
4777 default_value == Unit::kNanosecond);
4778 str_values = {"hour", "minute", "second",
4779 "millisecond", "microsecond", "nanosecond",
4780 "hours", "minutes", "seconds",
4781 "milliseconds", "microseconds", "nanoseconds"};
4782 enum_values = {
4783 Unit::kHour, Unit::kMinute, Unit::kSecond,
4784 Unit::kMillisecond, Unit::kMicrosecond, Unit::kNanosecond,
4785 Unit::kHour, Unit::kMinute, Unit::kSecond,
4786 Unit::kMillisecond, Unit::kMicrosecond, Unit::kNanosecond};
4787 }
4788 break;
4789 case UnitGroup::kDateTime:
4790 if (default_value == Unit::kAuto || extra_values == Unit::kAuto) {
4791 str_values = {"year", "month", "week",
4792 "day", "hour", "minute",
4793 "second", "millisecond", "microsecond",
4794 "nanosecond", "auto", "years",
4795 "months", "weeks", "days",
4796 "hours", "minutes", "seconds",
4797 "milliseconds", "microseconds", "nanoseconds"};
4798 enum_values = {
4799 Unit::kYear, Unit::kMonth, Unit::kWeek,
4800 Unit::kDay, Unit::kHour, Unit::kMinute,
4801 Unit::kSecond, Unit::kMillisecond, Unit::kMicrosecond,
4802 Unit::kNanosecond, Unit::kAuto, Unit::kYear,
4803 Unit::kMonth, Unit::kWeek, Unit::kDay,
4804 Unit::kHour, Unit::kMinute, Unit::kSecond,
4805 Unit::kMillisecond, Unit::kMicrosecond, Unit::kNanosecond};
4806 } else {
4807 str_values = {
4808 "year", "month", "week", "day",
4809 "hour", "minute", "second", "millisecond",
4810 "microsecond", "nanosecond", "years", "months",
4811 "weeks", "days", "hours", "minutes",
4812 "seconds", "milliseconds", "microseconds", "nanoseconds"};
4813 enum_values = {
4814 Unit::kYear, Unit::kMonth, Unit::kWeek,
4815 Unit::kDay, Unit::kHour, Unit::kMinute,
4816 Unit::kSecond, Unit::kMillisecond, Unit::kMicrosecond,
4817 Unit::kNanosecond, Unit::kYear, Unit::kMonth,
4818 Unit::kWeek, Unit::kDay, Unit::kHour,
4819 Unit::kMinute, Unit::kSecond, Unit::kMillisecond,
4820 Unit::kMicrosecond, Unit::kNanosecond};
4821 }
4822 break;
4823 }
4824
4825 // 4. If default is required, then
4826 if (default_is_required) default_value = Unit::kNotPresent;
4827 // a. Let defaultValue be undefined.
4828 // 5. Else,
4829 // a. Let defaultValue be default.
4830 // b. If defaultValue is not undefined and singularNames does not contain
4831 // defaultValue, then i. Append defaultValue to singularNames.
4832
4833 // 9. Let value be ? GetOption(normalizedOptions, key, "string",
4834 // allowedValues, defaultValue).
4835 Unit value;
4837 isolate, value,
4838 GetStringOption<Unit>(isolate, normalized_options, key, method_name,
4839 str_values, enum_values, default_value),
4840 Nothing<Unit>());
4841
4842 // 10. If value is undefined and default is required, throw a RangeError
4843 // exception.
4844 if (default_is_required && value == Unit::kNotPresent) {
4846 isolate,
4847 NewRangeError(
4848 MessageTemplate::kValueOutOfRange,
4849 isolate->factory()->undefined_value(),
4850 isolate->factory()->NewStringFromAsciiChecked(method_name),
4851 isolate->factory()->NewStringFromAsciiChecked(key)),
4852 Nothing<Unit>());
4853 }
4854 // 12. Return value.
4855 return Just(value);
4856}
4857
4858// #sec-temporal-mergelargestunitoption
4859MaybeDirectHandle<JSReceiver> MergeLargestUnitOption(
4860 Isolate* isolate, DirectHandle<JSReceiver> options, Unit largest_unit) {
4862 // 1. Let merged be OrdinaryObjectCreate(null).
4863 DirectHandle<JSReceiver> merged =
4864 isolate->factory()->NewJSObjectWithNullProto();
4865 // 2. Let keys be ? EnumerableOwnPropertyNames(options, key).
4866 // 3. For each element nextKey of keys, do
4867 // a. Let propValue be ? Get(options, nextKey).
4868 // b. Perform ! CreateDataPropertyOrThrow(merged, nextKey, propValue).
4870 isolate, merged, options, PropertiesEnumerationMode::kEnumerationOrder,
4871 {}, false)
4872 .Check();
4873
4874 // 4. Perform ! CreateDataPropertyOrThrow(merged, "largestUnit", largestUnit).
4876 isolate, merged, isolate->factory()->largestUnit_string(),
4877 UnitToString(isolate, largest_unit), Just(kThrowOnError))
4878 .FromJust());
4879 // 5. Return merged.
4880 return merged;
4881}
4882
4883// #sec-temporal-tointegerthrowoninfinity
4884MaybeDirectHandle<Number> ToIntegerThrowOnInfinity(
4885 Isolate* isolate, DirectHandle<Object> argument) {
4887
4888 // 1. Let integer be ? ToIntegerOrInfinity(argument).
4889 DirectHandle<Number> integer;
4890 ASSIGN_RETURN_ON_EXCEPTION(isolate, integer,
4891 Object::ToInteger(isolate, argument));
4892 // 2. If integer is +∞ or -∞, throw a RangeError exception.
4893 if (!std::isfinite(Object::NumberValue(*integer))) {
4894 // a. Throw a RangeError exception.
4896 }
4897 return integer;
4898}
4899
4900// #sec-temporal-largeroftwotemporalunits
4901Unit LargerOfTwoTemporalUnits(Unit u1, Unit u2) {
4902 // 1. If either u1 or u2 is "year", return "year".
4903 if (u1 == Unit::kYear || u2 == Unit::kYear) return Unit::kYear;
4904 // 2. If either u1 or u2 is "month", return "month".
4905 if (u1 == Unit::kMonth || u2 == Unit::kMonth) return Unit::kMonth;
4906 // 3. If either u1 or u2 is "week", return "week".
4907 if (u1 == Unit::kWeek || u2 == Unit::kWeek) return Unit::kWeek;
4908 // 4. If either u1 or u2 is "day", return "day".
4909 if (u1 == Unit::kDay || u2 == Unit::kDay) return Unit::kDay;
4910 // 5. If either u1 or u2 is "hour", return "hour".
4911 if (u1 == Unit::kHour || u2 == Unit::kHour) return Unit::kHour;
4912 // 6. If either u1 or u2 is "minute", return "minute".
4913 if (u1 == Unit::kMinute || u2 == Unit::kMinute) return Unit::kMinute;
4914 // 7. If either u1 or u2 is "second", return "second".
4915 if (u1 == Unit::kSecond || u2 == Unit::kSecond) return Unit::kSecond;
4916 // 8. If either u1 or u2 is "millisecond", return "millisecond".
4917 if (u1 == Unit::kMillisecond || u2 == Unit::kMillisecond)
4918 return Unit::kMillisecond;
4919 // 9. If either u1 or u2 is "microsecond", return "microsecond".
4920 if (u1 == Unit::kMicrosecond || u2 == Unit::kMicrosecond)
4921 return Unit::kMicrosecond;
4922 // 10. Return "nanosecond".
4923 return Unit::kNanosecond;
4924}
4925
4926DirectHandle<String> UnitToString(Isolate* isolate, Unit unit) {
4927 switch (unit) {
4928 case Unit::kYear:
4929 return isolate->factory()->year_string();
4930 case Unit::kMonth:
4931 return isolate->factory()->month_string();
4932 case Unit::kWeek:
4933 return isolate->factory()->week_string();
4934 case Unit::kDay:
4935 return isolate->factory()->day_string();
4936 case Unit::kHour:
4937 return isolate->factory()->hour_string();
4938 case Unit::kMinute:
4939 return isolate->factory()->minute_string();
4940 case Unit::kSecond:
4941 return isolate->factory()->second_string();
4942 case Unit::kMillisecond:
4943 return isolate->factory()->millisecond_string();
4944 case Unit::kMicrosecond:
4945 return isolate->factory()->microsecond_string();
4946 case Unit::kNanosecond:
4947 return isolate->factory()->nanosecond_string();
4948 case Unit::kNotPresent:
4949 case Unit::kAuto:
4950 UNREACHABLE();
4951 }
4952}
4953
4954// #sec-temporal-create-iso-date-record
4955DateRecord CreateISODateRecord(Isolate* isolate, const DateRecord& date) {
4956 // 1. Assert: IsValidISODate(year, month, day) is true.
4957 DCHECK(IsValidISODate(isolate, date));
4958 // 2. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }.
4959 return date;
4960}
4961
4962// #sec-temporal-balanceisodate
4963DateRecord BalanceISODate(Isolate* isolate, const DateRecord& date) {
4965 // 1. Let epochDays be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
4966 double epoch_days = MakeDay(date.year, date.month - 1, date.day);
4967 // 2. Assert: epochDays is finite.
4968 DCHECK(std::isfinite(epoch_days));
4969 // 3. Let ms be MakeDate(epochDays, +0𝔽).
4970 double ms = MakeDate(epoch_days, 0);
4971 // 4. Return CreateISODateRecordWithCalendar(ℝ(YearFromTime(ms)),
4972 // ℝ(MonthFromTime(ms)) + 1, ℝ(DateFromTime(ms))).
4973 int year = 0;
4974 int month = 0;
4975 int day = 0;
4976 int wday = 0;
4977 int hour = 0;
4978 int minute = 0;
4979 int second = 0;
4980 int millisecond = 0;
4981
4982 DCHECK(std::isfinite(ms));
4983 DCHECK_LT(ms, static_cast<double>(std::numeric_limits<int64_t>::max()));
4984 DCHECK_GT(ms, static_cast<double>(std::numeric_limits<int64_t>::min()));
4985 isolate->date_cache()->BreakDownTime(ms, &year, &month, &day, &wday, &hour,
4987
4988 return CreateISODateRecord(isolate, {year, month + 1, day});
4989}
4990
4991// #sec-temporal-adddatetime
4992Maybe<DateTimeRecord> AddDateTime(Isolate* isolate,
4993 const DateTimeRecord& date_time,
4994 DirectHandle<JSReceiver> calendar,
4995 const DurationRecord& dur,
4996 DirectHandle<Object> options) {
4998
4999 // 1. Assert: ISODateTimeWithinLimits(year, month, day, hour, minute, second,
5000 // millisecond, microsecond, nanosecond) is true.
5001 DCHECK(ISODateTimeWithinLimits(isolate, date_time));
5002 // 2. Let timeResult be ! AddTime(hour, minute, second, millisecond,
5003 // microsecond, nanosecond, hours, minutes, seconds, milliseconds,
5004 // microseconds, nanoseconds).
5005 const TimeDurationRecord& time = dur.time_duration;
5006 DateTimeRecord time_result =
5007 AddTime(isolate, date_time.time,
5008 {0, time.hours, time.minutes, time.seconds, time.milliseconds,
5009 time.microseconds, time.nanoseconds});
5010
5011 // 3. Let datePart be ? CreateTemporalDate(year, month, day, calendar).
5012 DirectHandle<JSTemporalPlainDate> date_part;
5014 isolate, date_part, CreateTemporalDate(isolate, date_time.date, calendar),
5016 // 4. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days
5017 // + timeResult.[[Days]], 0, 0, 0, 0, 0, 0).
5018 DirectHandle<JSTemporalDuration> date_duration;
5020 isolate, date_duration,
5021 CreateTemporalDuration(
5022 isolate,
5023 {dur.years,
5024 dur.months,
5025 dur.weeks,
5026 {dur.time_duration.days + time_result.date.day, 0, 0, 0, 0, 0, 0}}),
5028 // 5. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration,
5029 // options).
5030 DirectHandle<JSTemporalPlainDate> added_date;
5032 isolate, added_date,
5033 CalendarDateAdd(isolate, calendar, date_part, date_duration, options),
5035 // 6. Return the new Record { [[Year]]: addedDate.[[ISOYear]], [[Month]]:
5036 // addedDate.[[ISOMonth]], [[Day]]: addedDate.[[ISODay]], [[Hour]]:
5037 // timeResult.[[Hour]], [[Minute]]: timeResult.[[Minute]], [[Second]]:
5038 // timeResult.[[Second]], [[Millisecond]]: timeResult.[[Millisecond]],
5039 // [[Microsecond]]: timeResult.[[Microsecond]], [[Nanosecond]]:
5040 // timeResult.[[Nanosecond]], }.
5041 time_result.date = {added_date->iso_year(), added_date->iso_month(),
5042 added_date->iso_day()};
5043 return Just(time_result);
5044}
5045
5046// #sec-temporal-balanceduration
5047Maybe<TimeDurationRecord> BalanceDuration(Isolate* isolate, Unit largest_unit,
5048 const TimeDurationRecord& duration,
5049 const char* method_name) {
5051
5052 // 1. If relativeTo is not present, set relativeTo to undefined.
5053 return BalanceDuration(isolate, largest_unit,
5054 isolate->factory()->undefined_value(), duration,
5055 method_name);
5056}
5057
5058Maybe<TimeDurationRecord> BalanceDuration(Isolate* isolate, Unit largest_unit,
5059 DirectHandle<BigInt> nanoseconds,
5060 const char* method_name) {
5061 // 1. Let balanceResult be ? BalancePossiblyInfiniteDuration(days, hours,
5062 // minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit,
5063 // relativeTo).
5064 BalancePossiblyInfiniteDurationResult balance_result;
5066 isolate, balance_result,
5067 BalancePossiblyInfiniteDuration(isolate, largest_unit, 0, nanoseconds,
5068 method_name),
5070
5071 // 2. If balanceResult is positive overflow or negative overflow, then
5072 if (balance_result.overflow != BalanceOverflow::kNone) {
5073 // a. Throw a RangeError exception.
5077 // 3. Else,
5078 } else {
5079 // a. Return balanceResult.
5080 return Just(balance_result.value);
5081 }
5082}
5083
5084Maybe<TimeDurationRecord> BalanceDuration(Isolate* isolate, Unit largest_unit,
5085 const TimeDurationRecord& dur1,
5086 const TimeDurationRecord& dur2,
5087 const char* method_name) {
5088 // Add the two TimeDurationRecord as BigInt in nanoseconds.
5089 DirectHandle<BigInt> nanoseconds =
5090 BigInt::Add(isolate, TotalDurationNanoseconds(isolate, dur1, 0),
5091 TotalDurationNanoseconds(isolate, dur2, 0))
5092 .ToHandleChecked();
5093 return BalanceDuration(isolate, largest_unit, nanoseconds, method_name);
5094}
5095
5096// #sec-temporal-balanceduration
5097Maybe<TimeDurationRecord> BalanceDuration(Isolate* isolate, Unit largest_unit,
5098 DirectHandle<Object> relative_to_obj,
5099 const TimeDurationRecord& value,
5100 const char* method_name) {
5101 // 1. Let balanceResult be ? BalancePossiblyInfiniteDuration(days, hours,
5102 // minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit,
5103 // relativeTo).
5104 BalancePossiblyInfiniteDurationResult balance_result;
5106 isolate, balance_result,
5107 BalancePossiblyInfiniteDuration(isolate, largest_unit, relative_to_obj,
5108 value, method_name),
5110
5111 // 2. If balanceResult is positive overflow or negative overflow, then
5112 if (balance_result.overflow != BalanceOverflow::kNone) {
5113 // a. Throw a RangeError exception.
5117 // 3. Else,
5118 } else {
5119 // a. Return balanceResult.
5120 return Just(balance_result.value);
5121 }
5122}
5123
5124// sec-temporal-balancepossiblyinfiniteduration
5125Maybe<BalancePossiblyInfiniteDurationResult> BalancePossiblyInfiniteDuration(
5126 Isolate* isolate, Unit largest_unit, DirectHandle<Object> relative_to_obj,
5127 const TimeDurationRecord& value, const char* method_name) {
5129 TimeDurationRecord duration = value;
5130 DirectHandle<BigInt> nanoseconds;
5131
5132 // 2. If Type(relativeTo) is Object and relativeTo has an
5133 // [[InitializedTemporalZonedDateTime]] internal slot, then
5134 if (IsJSTemporalZonedDateTime(*relative_to_obj)) {
5135 auto relative_to = Cast<JSTemporalZonedDateTime>(relative_to_obj);
5136 // a. Let endNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]],
5137 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, hours,
5138 // minutes, seconds, milliseconds, microseconds, nanoseconds).
5139 DirectHandle<BigInt> end_ns;
5141 isolate, end_ns,
5142 AddZonedDateTime(isolate,
5143 direct_handle(relative_to->nanoseconds(), isolate),
5144 direct_handle(relative_to->time_zone(), isolate),
5145 direct_handle(relative_to->calendar(), isolate),
5146 {0, 0, 0, duration}, method_name),
5148 // b. Set nanoseconds to endNs − relativeTo.[[Nanoseconds]].
5150 isolate, nanoseconds,
5151 BigInt::Subtract(isolate, end_ns,
5152 direct_handle(relative_to->nanoseconds(), isolate)),
5154 // 3. Else,
5155 } else {
5156 // a. Set nanoseconds to ℤ(! TotalDurationNanoseconds(days, hours, minutes,
5157 // seconds, milliseconds, microseconds, nanoseconds, 0)).
5158 nanoseconds = TotalDurationNanoseconds(isolate, duration, 0);
5159 }
5160
5161 // Call the BigInt version for the same process after step 4
5162 // The only value need to pass in is nanoseconds and days because
5163 // 1) step 4 and 5 use nanoseconds and days only, and
5164 // 2) step 6 is "Set hours, minutes, seconds, milliseconds, and microseconds
5165 // to 0."
5166 return BalancePossiblyInfiniteDuration(isolate, largest_unit, relative_to_obj,
5167 duration.days, nanoseconds,
5168 method_name);
5169}
5170
5171// The special case of BalancePossiblyInfiniteDuration while the nanosecond is a
5172// large value and days contains non-zero values but the rest are 0.
5173// This version has no relative_to.
5174Maybe<BalancePossiblyInfiniteDurationResult> BalancePossiblyInfiniteDuration(
5175 Isolate* isolate, Unit largest_unit, DirectHandle<Object> relative_to_obj,
5176 double days, DirectHandle<BigInt> nanoseconds, const char* method_name) {
5178
5179 // 4. If largestUnit is one of "year", "month", "week", or "day", then
5180 if (largest_unit == Unit::kYear || largest_unit == Unit::kMonth ||
5181 largest_unit == Unit::kWeek || largest_unit == Unit::kDay) {
5182 // a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo).
5183 NanosecondsToDaysResult result;
5185 isolate, result,
5186 NanosecondsToDays(isolate, nanoseconds, relative_to_obj, method_name),
5188 // b. Set days to result.[[Days]].
5189 days = result.days;
5190 // c. Set nanoseconds to result.[[Nanoseconds]].
5191 nanoseconds = BigInt::FromInt64(isolate, result.nanoseconds);
5192 // 5. Else,
5193 } else {
5194 // a. Set days to 0.
5195 days = 0;
5196 }
5197 // 6. Set hours, minutes, seconds, milliseconds, and microseconds to 0.
5198 DirectHandle<BigInt> thousand = BigInt::FromInt64(isolate, 1000);
5199 DirectHandle<BigInt> sixty = BigInt::FromInt64(isolate, 60);
5200 DirectHandle<BigInt> zero = BigInt::FromInt64(isolate, 0);
5201 DirectHandle<BigInt> hours = zero;
5202 DirectHandle<BigInt> minutes = zero;
5203 DirectHandle<BigInt> seconds = zero;
5204 DirectHandle<BigInt> milliseconds = zero;
5205 DirectHandle<BigInt> microseconds = zero;
5206
5207 // 7. If nanoseconds < 0, let sign be −1; else, let sign be 1.
5208 // 8. Set nanoseconds to abs(nanoseconds).
5209 int32_t sign = 1;
5210 if (nanoseconds->IsNegative()) {
5211 sign = -1;
5213 }
5214
5215 // 9 If largestUnit is "year", "month", "week", "day", or "hour", then
5216 switch (largest_unit) {
5217 case Unit::kYear:
5218 case Unit::kMonth:
5219 case Unit::kWeek:
5220 case Unit::kDay:
5221 case Unit::kHour:
5222 // a. Set microseconds to floor(nanoseconds / 1000).
5223 microseconds =
5224 BigInt::Divide(isolate, nanoseconds, thousand).ToHandleChecked();
5225 // b. Set nanoseconds to nanoseconds modulo 1000.
5226 nanoseconds =
5227 BigInt::Remainder(isolate, nanoseconds, thousand).ToHandleChecked();
5228 // c. Set milliseconds to floor(microseconds / 1000).
5229 milliseconds =
5230 BigInt::Divide(isolate, microseconds, thousand).ToHandleChecked();
5231 // d. Set microseconds to microseconds modulo 1000.
5232 microseconds =
5233 BigInt::Remainder(isolate, microseconds, thousand).ToHandleChecked();
5234 // e. Set seconds to floor(milliseconds / 1000).
5235 seconds =
5236 BigInt::Divide(isolate, milliseconds, thousand).ToHandleChecked();
5237 // f. Set milliseconds to milliseconds modulo 1000.
5238 milliseconds =
5239 BigInt::Remainder(isolate, milliseconds, thousand).ToHandleChecked();
5240 // g. Set minutes to floor(seconds, 60).
5241 minutes = BigInt::Divide(isolate, seconds, sixty).ToHandleChecked();
5242 // h. Set seconds to seconds modulo 60.
5243 seconds = BigInt::Remainder(isolate, seconds, sixty).ToHandleChecked();
5244 // i. Set hours to floor(minutes / 60).
5245 hours = BigInt::Divide(isolate, minutes, sixty).ToHandleChecked();
5246 // j. Set minutes to minutes modulo 60.
5247 minutes = BigInt::Remainder(isolate, minutes, sixty).ToHandleChecked();
5248 break;
5249 // 10. Else if largestUnit is "minute", then
5250 case Unit::kMinute:
5251 // a. Set microseconds to floor(nanoseconds / 1000).
5252 microseconds =
5253 BigInt::Divide(isolate, nanoseconds, thousand).ToHandleChecked();
5254 // b. Set nanoseconds to nanoseconds modulo 1000.
5255 nanoseconds =
5256 BigInt::Remainder(isolate, nanoseconds, thousand).ToHandleChecked();
5257 // c. Set milliseconds to floor(microseconds / 1000).
5258 milliseconds =
5259 BigInt::Divide(isolate, microseconds, thousand).ToHandleChecked();
5260 // d. Set microseconds to microseconds modulo 1000.
5261 microseconds =
5262 BigInt::Remainder(isolate, microseconds, thousand).ToHandleChecked();
5263 // e. Set seconds to floor(milliseconds / 1000).
5264 seconds =
5265 BigInt::Divide(isolate, milliseconds, thousand).ToHandleChecked();
5266 // f. Set milliseconds to milliseconds modulo 1000.
5267 milliseconds =
5268 BigInt::Remainder(isolate, milliseconds, thousand).ToHandleChecked();
5269 // g. Set minutes to floor(seconds / 60).
5270 minutes = BigInt::Divide(isolate, seconds, sixty).ToHandleChecked();
5271 // h. Set seconds to seconds modulo 60.
5272 seconds = BigInt::Remainder(isolate, seconds, sixty).ToHandleChecked();
5273 break;
5274 // 11. Else if largestUnit is "second", then
5275 case Unit::kSecond:
5276 // a. Set microseconds to floor(nanoseconds / 1000).
5277 microseconds =
5278 BigInt::Divide(isolate, nanoseconds, thousand).ToHandleChecked();
5279 // b. Set nanoseconds to nanoseconds modulo 1000.
5280 nanoseconds =
5281 BigInt::Remainder(isolate, nanoseconds, thousand).ToHandleChecked();
5282 // c. Set milliseconds to floor(microseconds / 1000).
5283 milliseconds =
5284 BigInt::Divide(isolate, microseconds, thousand).ToHandleChecked();
5285 // d. Set microseconds to microseconds modulo 1000.
5286 microseconds =
5287 BigInt::Remainder(isolate, microseconds, thousand).ToHandleChecked();
5288 // e. Set seconds to floor(milliseconds / 1000).
5289 seconds =
5290 BigInt::Divide(isolate, milliseconds, thousand).ToHandleChecked();
5291 // f. Set milliseconds to milliseconds modulo 1000.
5292 milliseconds =
5293 BigInt::Remainder(isolate, milliseconds, thousand).ToHandleChecked();
5294 break;
5295 // 12. Else if largestUnit is "millisecond", then
5296 case Unit::kMillisecond:
5297 // a. Set microseconds to floor(nanoseconds / 1000).
5298 microseconds =
5299 BigInt::Divide(isolate, nanoseconds, thousand).ToHandleChecked();
5300 // b. Set nanoseconds to nanoseconds modulo 1000.
5301 nanoseconds =
5302 BigInt::Remainder(isolate, nanoseconds, thousand).ToHandleChecked();
5303 // c. Set milliseconds to floor(microseconds / 1000).
5304 milliseconds =
5305 BigInt::Divide(isolate, microseconds, thousand).ToHandleChecked();
5306 // d. Set microseconds to microseconds modulo 1000.
5307 microseconds =
5308 BigInt::Remainder(isolate, microseconds, thousand).ToHandleChecked();
5309 break;
5310 // 13. Else if largestUnit is "microsecond", then
5311 case Unit::kMicrosecond:
5312 // a. Set microseconds to floor(nanoseconds / 1000).
5313 microseconds =
5314 BigInt::Divide(isolate, nanoseconds, thousand).ToHandleChecked();
5315 // b. Set nanoseconds to nanoseconds modulo 1000.
5316 nanoseconds =
5317 BigInt::Remainder(isolate, nanoseconds, thousand).ToHandleChecked();
5318 break;
5319 // 14. Else,
5320 case Unit::kNanosecond:
5321 // a. Assert: largestUnit is "nanosecond".
5322 break;
5323 case Unit::kAuto:
5324 case Unit::kNotPresent:
5325 UNREACHABLE();
5326 }
5327 // 15. For each value v of « days, hours, minutes, seconds, milliseconds,
5328 // microseconds, nanoseconds », do a. If 𝔽(v) is not finite, then i. If sign
5329 // = 1, then
5330 // 1. Return positive overflow.
5331 // ii. Else if sign = -1, then
5332 // 1. Return negative overflow.
5333 double hours_value = Object::NumberValue(*BigInt::ToNumber(isolate, hours));
5334 double minutes_value =
5335 Object::NumberValue(*BigInt::ToNumber(isolate, minutes));
5336 double seconds_value =
5337 Object::NumberValue(*BigInt::ToNumber(isolate, seconds));
5338 double milliseconds_value =
5339 Object::NumberValue(*BigInt::ToNumber(isolate, milliseconds));
5340 double microseconds_value =
5341 Object::NumberValue(*BigInt::ToNumber(isolate, microseconds));
5342 double nanoseconds_value =
5344 if (std::isinf(days) || std::isinf(hours_value) ||
5345 std::isinf(minutes_value) || std::isinf(seconds_value) ||
5346 std::isinf(milliseconds_value) || std::isinf(microseconds_value) ||
5347 std::isinf(nanoseconds_value)) {
5348 return Just(BalancePossiblyInfiniteDurationResult(
5349 {{0, 0, 0, 0, 0, 0, 0},
5350 sign == 1 ? BalanceOverflow::kPositive : BalanceOverflow::kNegative}));
5351 }
5352
5353 // 16. Return ? CreateTimeDurationRecord(days, hours × sign, minutes × sign,
5354 // seconds × sign, milliseconds × sign, microseconds × sign, nanoseconds ×
5355 // sign).
5356 TimeDurationRecord result;
5358 isolate, result,
5360 isolate, days, hours_value * sign, minutes_value * sign,
5361 seconds_value * sign, milliseconds_value * sign,
5362 microseconds_value * sign, nanoseconds_value * sign),
5364 return Just(
5365 BalancePossiblyInfiniteDurationResult({result, BalanceOverflow::kNone}));
5366}
5367
5368// #sec-temporal-addzoneddatetime
5369MaybeDirectHandle<BigInt> AddZonedDateTime(
5370 Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds,
5371 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar,
5372 const DurationRecord& duration, const char* method_name) {
5374
5375 // 1. If options is not present, set options to undefined.
5376 return AddZonedDateTime(isolate, epoch_nanoseconds, time_zone, calendar,
5377 duration, isolate->factory()->undefined_value(),
5378 method_name);
5379}
5380
5381// #sec-temporal-addzoneddatetime
5382MaybeDirectHandle<BigInt> AddZonedDateTime(
5383 Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds,
5384 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar,
5385 const DurationRecord& duration, DirectHandle<Object> options,
5386 const char* method_name) {
5388
5389 TimeDurationRecord time_duration = duration.time_duration;
5390 // 2. If all of years, months, weeks, and days are 0, then
5391 if (duration.years == 0 && duration.months == 0 && duration.weeks == 0 &&
5392 time_duration.days == 0) {
5393 // a. Return ? AddInstant(epochNanoseconds, hours, minutes, seconds,
5394 // milliseconds, microseconds, nanoseconds).
5395 return AddInstant(isolate, epoch_nanoseconds, time_duration);
5396 }
5397 // 3. Let instant be ! CreateTemporalInstant(epochNanoseconds).
5398 DirectHandle<JSTemporalInstant> instant =
5399 temporal::CreateTemporalInstant(isolate, epoch_nanoseconds)
5400 .ToHandleChecked();
5401
5402 // 4. Let temporalDateTime be ?
5403 // BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
5404 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
5406 isolate, temporal_date_time,
5408 calendar, method_name));
5409 // 5. Let datePart be ? CreateTemporalDate(temporalDateTime.[[ISOYear]],
5410 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], calendar).
5411 DirectHandle<JSTemporalPlainDate> date_part;
5413 isolate, date_part,
5414 CreateTemporalDate(
5415 isolate,
5416 {temporal_date_time->iso_year(), temporal_date_time->iso_month(),
5417 temporal_date_time->iso_day()},
5418 calendar));
5419 // 6. Let dateDuration be ? CreateTemporalDuration(years, months, weeks, days,
5420 // 0, 0, 0, 0, 0, 0).
5421 DirectHandle<JSTemporalDuration> date_duration;
5423 isolate, date_duration,
5424 CreateTemporalDuration(isolate,
5425 {duration.years,
5426 duration.months,
5427 duration.weeks,
5428 {time_duration.days, 0, 0, 0, 0, 0, 0}}));
5429 // 7. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration,
5430 // options).
5431 DirectHandle<JSTemporalPlainDate> added_date;
5433 isolate, added_date,
5434 CalendarDateAdd(isolate, calendar, date_part, date_duration, options));
5435 // 8. Let intermediateDateTime be ?
5436 // CreateTemporalDateTime(addedDate.[[ISOYear]], addedDate.[[ISOMonth]],
5437 // addedDate.[[ISODay]], temporalDateTime.[[ISOHour]],
5438 // temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
5439 // temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
5440 // temporalDateTime.[[ISONanosecond]], calendar).
5441 DirectHandle<JSTemporalPlainDateTime> intermediate_date_time;
5443 isolate, intermediate_date_time,
5445 isolate,
5446 {{added_date->iso_year(), added_date->iso_month(),
5447 added_date->iso_day()},
5448 {temporal_date_time->iso_hour(), temporal_date_time->iso_minute(),
5449 temporal_date_time->iso_second(),
5450 temporal_date_time->iso_millisecond(),
5451 temporal_date_time->iso_microsecond(),
5452 temporal_date_time->iso_nanosecond()}},
5453 calendar));
5454 // 9. Let intermediateInstant be ? BuiltinTimeZoneGetInstantFor(timeZone,
5455 // intermediateDateTime, "compatible").
5456 DirectHandle<JSTemporalInstant> intermediate_instant;
5458 isolate, intermediate_instant,
5459 BuiltinTimeZoneGetInstantFor(isolate, time_zone, intermediate_date_time,
5460 Disambiguation::kCompatible, method_name));
5461 // 10. Return ? AddInstant(intermediateInstant.[[Nanoseconds]], hours,
5462 // minutes, seconds, milliseconds, microseconds, nanoseconds).
5463 time_duration.days = 0;
5464 return AddInstant(isolate,
5465 direct_handle(intermediate_instant->nanoseconds(), isolate),
5466 time_duration);
5467}
5468
5469Maybe<NanosecondsToDaysResult> NanosecondsToDays(
5470 Isolate* isolate, DirectHandle<BigInt> nanoseconds,
5471 DirectHandle<Object> relative_to_obj, const char* method_name) {
5473 // 1. Let dayLengthNs be nsPerDay.
5474 constexpr int64_t kDayLengthNs = 86400000000000LLU;
5475 DirectHandle<BigInt> day_length_ns = BigInt::FromInt64(isolate, kDayLengthNs);
5476 double sign;
5478 direct_handle(Smi::zero(), isolate))) {
5479 // 2. If nanoseconds = 0, then
5481 // a. Return the Record { [[Days]]: 0, [[Nanoseconds]]: 0, [[DayLength]]:
5482 // dayLengthNs }.
5483 return Just(NanosecondsToDaysResult({0, 0, kDayLengthNs}));
5484 // 3. If nanoseconds < 0, let sign be -1; else, let sign be 1.
5486 sign = -1;
5487 break;
5489 sign = 1;
5490 break;
5491 default:
5492 UNREACHABLE();
5493 }
5494
5495 // 4. If Type(relativeTo) is not Object or relativeTo does not have an
5496 // [[InitializedTemporalZonedDateTime]] internal slot, then
5497 if (!IsJSTemporalZonedDateTime(*relative_to_obj)) {
5498 // a. Return the Record { [[Days]]: RoundTowardsZero(nanoseconds /
5499 // dayLengthNs), [[Nanoseconds]]: (abs(nanoseconds) modulo dayLengthNs) ×
5500 // sign, [[DayLength]]: dayLengthNs }.
5501 if (sign == -1) {
5503 }
5504 DirectHandle<BigInt> days_bigint;
5506 isolate, days_bigint,
5507 BigInt::Divide(isolate, nanoseconds, day_length_ns),
5510 isolate, nanoseconds,
5511 BigInt::Remainder(isolate, nanoseconds, day_length_ns),
5513 if (sign == -1) {
5514 days_bigint = BigInt::UnaryMinus(isolate, days_bigint);
5516 }
5517 return Just(NanosecondsToDaysResult(
5518 {Object::NumberValue(*BigInt::ToNumber(isolate, days_bigint)),
5520 kDayLengthNs}));
5521 }
5522 auto relative_to = Cast<JSTemporalZonedDateTime>(relative_to_obj);
5523 // 5. Let startNs be ℝ(relativeTo.[[Nanoseconds]]).
5524 DirectHandle<BigInt> start_ns(relative_to->nanoseconds(), isolate);
5525 // 6. Let startInstant be ! CreateTemporalInstant(ℤ(startNs)).
5526 DirectHandle<JSTemporalInstant> start_instant =
5528 isolate, direct_handle(relative_to->nanoseconds(), isolate))
5529 .ToHandleChecked();
5530
5531 // 7. Let startDateTime be ?
5532 // BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]],
5533 // startInstant, relativeTo.[[Calendar]]).
5534 DirectHandle<JSReceiver> time_zone(relative_to->time_zone(), isolate);
5535 DirectHandle<JSReceiver> calendar(relative_to->calendar(), isolate);
5536 DirectHandle<JSTemporalPlainDateTime> start_date_time;
5538 isolate, start_date_time,
5540 isolate, time_zone, start_instant, calendar, method_name),
5542
5543 // 8. Let endNs be startNs + nanoseconds.
5544 DirectHandle<BigInt> end_ns;
5545 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, end_ns,
5546 BigInt::Add(isolate, start_ns, nanoseconds),
5548
5549 // 9. If ! IsValidEpochNanoseconds(ℤ(endNs)) is false, throw a RangeError
5550 // exception.
5551 if (!IsValidEpochNanoseconds(isolate, end_ns)) {
5555 }
5556
5557 // 10. Let endInstant be ! CreateTemporalInstant(ℤ(endNs)).
5558 DirectHandle<JSTemporalInstant> end_instant =
5559 temporal::CreateTemporalInstant(isolate, end_ns).ToHandleChecked();
5560 // 11. Let endDateTime be ?
5561 // BuiltinTimeZoneGetPlainDateTimeFor(relativeTo.[[TimeZone]],
5562 // endInstant, relativeTo.[[Calendar]]).
5563 DirectHandle<JSTemporalPlainDateTime> end_date_time;
5565 isolate, end_date_time,
5567 isolate, time_zone, end_instant, calendar, method_name),
5569
5570 // 12. Let dateDifference be ?
5571 // DifferenceISODateTime(startDateTime.[[ISOYear]],
5572 // startDateTime.[[ISOMonth]], startDateTime.[[ISODay]],
5573 // startDateTime.[[ISOHour]], startDateTime.[[ISOMinute]],
5574 // startDateTime.[[ISOSecond]], startDateTime.[[ISOMillisecond]],
5575 // startDateTime.[[ISOMicrosecond]], startDateTime.[[ISONanosecond]],
5576 // endDateTime.[[ISOYear]], endDateTime.[[ISOMonth]], endDateTime.[[ISODay]],
5577 // endDateTime.[[ISOHour]], endDateTime.[[ISOMinute]],
5578 // endDateTime.[[ISOSecond]], endDateTime.[[ISOMillisecond]],
5579 // endDateTime.[[ISOMicrosecond]], endDateTime.[[ISONanosecond]],
5580 // relativeTo.[[Calendar]], "day", OrdinaryObjectCreate(null)).
5581 DurationRecord date_difference;
5583 isolate, date_difference,
5584 DifferenceISODateTime(
5585 isolate,
5586 {{start_date_time->iso_year(), start_date_time->iso_month(),
5587 start_date_time->iso_day()},
5588 {start_date_time->iso_hour(), start_date_time->iso_minute(),
5589 start_date_time->iso_second(), start_date_time->iso_millisecond(),
5590 start_date_time->iso_microsecond(),
5591 start_date_time->iso_nanosecond()}},
5592 {{end_date_time->iso_year(), end_date_time->iso_month(),
5593 end_date_time->iso_day()},
5594 {end_date_time->iso_hour(), end_date_time->iso_minute(),
5595 end_date_time->iso_second(), end_date_time->iso_millisecond(),
5596 end_date_time->iso_microsecond(), end_date_time->iso_nanosecond()}},
5597 calendar, Unit::kDay, isolate->factory()->NewJSObjectWithNullProto(),
5598 method_name),
5600
5601 // 13. Let days be dateDifference.[[Days]].
5602 double days = date_difference.time_duration.days;
5603
5604 // 14. Let intermediateNs be ℝ(? AddZonedDateTime(ℤ(startNs),
5605 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0, 0,
5606 // 0, 0, 0)).
5607 DirectHandle<BigInt> intermediate_ns;
5609 isolate, intermediate_ns,
5610 AddZonedDateTime(isolate, start_ns, time_zone, calendar,
5611 {0, 0, 0, {days, 0, 0, 0, 0, 0, 0}}, method_name),
5613
5614 // 15. If sign is 1, then
5615 if (sign == 1) {
5616 // a. Repeat, while days > 0 and intermediateNs > endNs,
5617 while (days > 0 && BigInt::CompareToBigInt(intermediate_ns, end_ns) ==
5619 // i. Set days to days − 1.
5620 days -= 1;
5621 // ii. Set intermediateNs to ℝ(? AddZonedDateTime(ℤ(startNs),
5622 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, 0, 0,
5623 // 0, 0, 0, 0)).
5625 isolate, intermediate_ns,
5626 AddZonedDateTime(isolate, start_ns, time_zone, calendar,
5627 {0, 0, 0, {days, 0, 0, 0, 0, 0, 0}}, method_name),
5629 }
5630 }
5631
5632 // 16. Set nanoseconds to endNs − intermediateNs.
5634 isolate, nanoseconds, BigInt::Subtract(isolate, end_ns, intermediate_ns),
5636
5637 // 17. Let done be false.
5638 bool done = false;
5639
5640 // 18. Repeat, while done is false,
5641 while (!done) {
5642 // a. Let oneDayFartherNs be ℝ(? AddZonedDateTime(ℤ(intermediateNs),
5643 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, sign, 0, 0, 0,
5644 // 0, 0, 0)).
5645 DirectHandle<BigInt> one_day_farther_ns;
5647 isolate, one_day_farther_ns,
5648 AddZonedDateTime(isolate, intermediate_ns, time_zone, calendar,
5649 {0, 0, 0, {sign, 0, 0, 0, 0, 0, 0}}, method_name),
5651
5652 // b. Set dayLengthNs to oneDayFartherNs − intermediateNs.
5654 isolate, day_length_ns,
5655 BigInt::Subtract(isolate, one_day_farther_ns, intermediate_ns),
5657
5658 // c. If (nanoseconds − dayLengthNs) × sign ≥ 0, then
5659 if (sign * CompareResultToSign(
5660 BigInt::CompareToBigInt(nanoseconds, day_length_ns)) >=
5661 0) {
5662 // i. Set nanoseconds to nanoseconds − dayLengthNs.
5664 isolate, nanoseconds,
5665 BigInt::Subtract(isolate, nanoseconds, day_length_ns),
5667
5668 // ii. Set intermediateNs to oneDayFartherNs.
5669 intermediate_ns = one_day_farther_ns;
5670
5671 // iii. Set days to days + sign.
5672 days += sign;
5673 // d. Else,
5674 } else {
5675 // i. Set done to true.
5676 done = true;
5677 }
5678 }
5679
5680 // 20. Return the new Record { [[Days]]: days, [[Nanoseconds]]: nanoseconds,
5681 // [[DayLength]]: abs(dayLengthNs) }.
5682 NanosecondsToDaysResult result(
5684 std::abs(day_length_ns->AsInt64())});
5685 return Just(result);
5686}
5687
5688// #sec-temporal-differenceisodatetime
5689Maybe<DurationRecord> DifferenceISODateTime(Isolate* isolate,
5690 const DateTimeRecord& date_time1,
5691 const DateTimeRecord& date_time2,
5692 DirectHandle<JSReceiver> calendar,
5693 Unit largest_unit,
5694 DirectHandle<JSReceiver> options,
5695 const char* method_name) {
5697 // 1. Assert: ISODateTimeWithinLimits(y1, mon1, d1, h1, min1, s1, ms1, mus1,
5698 // ns1) is true.
5699 DCHECK(ISODateTimeWithinLimits(isolate, date_time1));
5700 // 2. Assert: ISODateTimeWithinLimits(y2, mon2, d2, h2, min2, s2, ms2, mus2,
5701 // ns2) is true.
5702 DCHECK(ISODateTimeWithinLimits(isolate, date_time2));
5703 // 3. Let timeDifference be ! DifferenceTime(h1, min1, s1, ms1, mus1, ns1, h2,
5704 // min2, s2, ms2, mus2, ns2).
5705 TimeDurationRecord time_difference =
5706 DifferenceTime(isolate, date_time1.time, date_time2.time).ToChecked();
5707
5708 // 4. Let timeSign be ! DurationSign(0, 0, 0, 0, timeDifference.[[Hours]],
5709 // timeDifference.[[Minutes]], timeDifference.[[Seconds]],
5710 // timeDifference.[[Milliseconds]], timeDifference.[[Microseconds]],
5711 // timeDifference.[[Nanoseconds]]).
5712 time_difference.days = 0;
5713 double time_sign = DurationRecord::Sign({0, 0, 0, time_difference});
5714
5715 // 5. Let dateSign be ! CompareISODate(y2, mon2, d2, y1, mon1, d1).
5716 double date_sign = CompareISODate(date_time2.date, date_time1.date);
5717
5718 // 6. Let adjustedDate be CreateISODateRecordWithCalendar(y1, mon1, d1).
5719 DateRecord adjusted_date = date_time1.date;
5720 CHECK(IsValidISODate(isolate, adjusted_date));
5721
5722 // 7. If timeSign is -dateSign, then
5723 if (time_sign == -date_sign) {
5724 adjusted_date.day -= time_sign;
5725 // a. Set adjustedDate to BalanceISODate(adjustedDate.[[Year]],
5726 // adjustedDate.[[Month]], adjustedDate.[[Day]] - timeSign).
5727 adjusted_date = BalanceISODate(isolate, adjusted_date);
5728 // b. Set timeDifference to ! BalanceDuration(-timeSign,
5729 // timeDifference.[[Hours]], timeDifference.[[Minutes]],
5730 // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
5731 // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]],
5732 // largestUnit).
5733 time_difference.days = -time_sign;
5734 time_difference =
5735 BalanceDuration(isolate, largest_unit, time_difference, method_name)
5736 .ToChecked();
5737 }
5738
5739 // 8. Let date1 be ! CreateTemporalDate(adjustedDate.[[Year]],
5740 // adjustedDate.[[Month]], adjustedDate.[[Day]], calendar).
5741 DirectHandle<JSTemporalPlainDate> date1 =
5742 CreateTemporalDate(isolate, adjusted_date, calendar).ToHandleChecked();
5743
5744 // 9. Let date2 be ! CreateTemporalDate(y2, mon2, d2, calendar).
5745 DirectHandle<JSTemporalPlainDate> date2 =
5746 CreateTemporalDate(isolate, date_time2.date, calendar).ToHandleChecked();
5747 // 10. Let dateLargestUnit be ! LargerOfTwoTemporalUnits("day", largestUnit).
5748 Unit date_largest_unit = LargerOfTwoTemporalUnits(Unit::kDay, largest_unit);
5749
5750 // 11. Let untilOptions be ? MergeLargestUnitOption(options, dateLargestUnit).
5751 DirectHandle<JSReceiver> until_options;
5753 isolate, until_options,
5754 MergeLargestUnitOption(isolate, options, date_largest_unit),
5756 // 12. Let dateDifference be ? CalendarDateUntil(calendar, date1, date2,
5757 // untilOptions).
5758 DirectHandle<JSTemporalDuration> date_difference;
5760 isolate, date_difference,
5761 CalendarDateUntil(isolate, calendar, date1, date2, until_options),
5763 // 13. Let balanceResult be ? BalanceDuration(dateDifference.[[Days]],
5764 // timeDifference.[[Hours]], timeDifference.[[Minutes]],
5765 // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
5766 // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]],
5767 // largestUnit).
5768
5769 time_difference.days = Object::NumberValue(date_difference->days());
5771 isolate, time_difference,
5772 BalanceDuration(isolate, largest_unit, time_difference, method_name),
5774
5775 // 14. Return ! CreateDurationRecord(dateDifference.[[Years]],
5776 // dateDifference.[[Months]], dateDifference.[[Weeks]],
5777 // balanceResult.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]],
5778 // balanceResult.[[Seconds]], balanceResult.[[Milliseconds]],
5779 // balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]]).
5780
5781 return Just(CreateDurationRecord(
5782 isolate, {Object::NumberValue(date_difference->years()),
5783 Object::NumberValue(date_difference->months()),
5784 Object::NumberValue(date_difference->weeks()),
5785 time_difference})
5786 .ToChecked());
5787}
5788
5789// #sec-temporal-addinstant
5790MaybeDirectHandle<BigInt> AddInstant(Isolate* isolate,
5791 DirectHandle<BigInt> epoch_nanoseconds,
5792 const TimeDurationRecord& addend) {
5794 Factory* factory = isolate->factory();
5795
5796 // 1. Assert: hours, minutes, seconds, milliseconds, microseconds, and
5797 // nanoseconds are integer Number values.
5798 // 2. Let result be epochNanoseconds + ℤ(nanoseconds) +
5799 // ℤ(microseconds) × 1000ℤ + ℤ(milliseconds) × 10^6ℤ + ℤ(seconds) × 10^9ℤ +
5800 // ℤ(minutes) × 60ℤ × 10^9ℤ + ℤ(hours) × 3600ℤ × 10^9ℤ.
5801
5802 // epochNanoseconds + ℤ(nanoseconds)
5803 DirectHandle<BigInt> result =
5805 isolate, epoch_nanoseconds,
5806 BigInt::FromNumber(isolate, factory->NewNumber(addend.nanoseconds))
5807 .ToHandleChecked())
5808 .ToHandleChecked();
5809
5810 // + ℤ(microseconds) × 1000ℤ
5811 DirectHandle<BigInt> temp =
5813 isolate,
5814 BigInt::FromNumber(isolate, factory->NewNumber(addend.microseconds))
5815 .ToHandleChecked(),
5816 BigInt::FromInt64(isolate, 1000))
5817 .ToHandleChecked();
5818 result = BigInt::Add(isolate, result, temp).ToHandleChecked();
5819
5820 // + ℤ(milliseconds) × 10^6ℤ
5821 temp = BigInt::Multiply(isolate,
5823 isolate, factory->NewNumber(addend.milliseconds))
5824 .ToHandleChecked(),
5825 BigInt::FromInt64(isolate, 1000000))
5826 .ToHandleChecked();
5827 result = BigInt::Add(isolate, result, temp).ToHandleChecked();
5828
5829 // + ℤ(seconds) × 10^9ℤ
5830 temp = BigInt::Multiply(
5831 isolate,
5832 BigInt::FromNumber(isolate, factory->NewNumber(addend.seconds))
5833 .ToHandleChecked(),
5834 BigInt::FromInt64(isolate, 1000000000))
5835 .ToHandleChecked();
5836 result = BigInt::Add(isolate, result, temp).ToHandleChecked();
5837
5838 // + ℤ(minutes) × 60ℤ × 10^9ℤ.
5839 temp = BigInt::Multiply(
5840 isolate,
5841 BigInt::FromNumber(isolate, factory->NewNumber(addend.minutes))
5842 .ToHandleChecked(),
5843 BigInt::FromInt64(isolate, 60000000000))
5844 .ToHandleChecked();
5845 result = BigInt::Add(isolate, result, temp).ToHandleChecked();
5846
5847 // + ℤ(hours) × 3600ℤ × 10^9ℤ.
5848 temp = BigInt::Multiply(
5849 isolate,
5850 BigInt::FromNumber(isolate, factory->NewNumber(addend.hours))
5851 .ToHandleChecked(),
5852 BigInt::FromInt64(isolate, 3600000000000))
5853 .ToHandleChecked();
5854 result = BigInt::Add(isolate, result, temp).ToHandleChecked();
5855
5856 // 3. If ! IsValidEpochNanoseconds(result) is false, throw a RangeError
5857 // exception.
5858 if (!IsValidEpochNanoseconds(isolate, result)) {
5860 }
5861 // 4. Return result.
5862 return result;
5863}
5864
5865// #sec-temporal-isvalidepochnanoseconds
5866bool IsValidEpochNanoseconds(Isolate* isolate,
5867 DirectHandle<BigInt> epoch_nanoseconds) {
5869 // nsMinInstant = -nsMaxInstant = -8.64 × 10^21
5870 constexpr double kNsMinInstant = -8.64e21;
5871 // nsMaxInstant = 10^8 × nsPerDay = 8.64 × 1021
5872 constexpr double kNsMaxInstant = 8.64e21;
5873
5874 // 1. Assert: Type(epochNanoseconds) is BigInt.
5875 // 2. If ℝ(epochNanoseconds) < nsMinInstant or ℝ(epochNanoseconds) >
5876 // nsMaxInstant, then
5877 if (BigInt::CompareToNumber(epoch_nanoseconds,
5878 isolate->factory()->NewNumber(kNsMinInstant)) ==
5880 BigInt::CompareToNumber(epoch_nanoseconds,
5881 isolate->factory()->NewNumber(kNsMaxInstant)) ==
5883 // a. Return false.
5884 return false;
5885 }
5886 return true;
5887}
5888
5889DirectHandle<BigInt> GetEpochFromISOParts(Isolate* isolate,
5890 const DateTimeRecord& date_time) {
5892 // 1. Assert: year, month, day, hour, minute, second, millisecond,
5893 // microsecond, and nanosecond are integers.
5894 // 2. Assert: ! IsValidISODate(year, month, day) is true.
5895 DCHECK(IsValidISODate(isolate, date_time.date));
5896 // 3. Assert: ! IsValidTime(hour, minute, second, millisecond, microsecond,
5897 // nanosecond) is true.
5898 DCHECK(IsValidTime(isolate, date_time.time));
5899 // 4. Let date be ! MakeDay(𝔽(year), 𝔽(month − 1), 𝔽(day)).
5900 double date = MakeDay(date_time.date.year, date_time.date.month - 1,
5901 date_time.date.day);
5902 // 5. Let time be ! MakeTime(𝔽(hour), 𝔽(minute), 𝔽(second), 𝔽(millisecond)).
5903 double time = MakeTime(date_time.time.hour, date_time.time.minute,
5904 date_time.time.second, date_time.time.millisecond);
5905 // 6. Let ms be ! MakeDate(date, time).
5906 double ms = MakeDate(date, time);
5907 // 7. Assert: ms is finite.
5908 // 8. Return ℝ(ms) × 10^6 + microsecond × 10^3 + nanosecond.
5909 return BigInt::Add(
5910 isolate,
5912 isolate,
5914 isolate,
5915 BigInt::FromNumber(isolate,
5916 isolate->factory()->NewNumber(ms))
5917 .ToHandleChecked(),
5918 BigInt::FromInt64(isolate, 1000000))
5919 .ToHandleChecked(),
5921 isolate,
5922 BigInt::FromInt64(isolate, date_time.time.microsecond),
5923 BigInt::FromInt64(isolate, 1000))
5924 .ToHandleChecked())
5925 .ToHandleChecked(),
5926 BigInt::FromInt64(isolate, date_time.time.nanosecond))
5927 .ToHandleChecked();
5928}
5929
5930} // namespace
5931
5932namespace temporal {
5933
5934// #sec-temporal-durationsign
5935int32_t DurationRecord::Sign(const DurationRecord& dur) {
5937
5938 // 1. For each value v of « years, months, weeks, days, hours, minutes,
5939 // seconds, milliseconds, microseconds, nanoseconds », do a. If v < 0, return
5940 // −1. b. If v > 0, return 1.
5941 // 2. Return 0.
5942 if (dur.years < 0) return -1;
5943 if (dur.years > 0) return 1;
5944 if (dur.months < 0) return -1;
5945 if (dur.months > 0) return 1;
5946 if (dur.weeks < 0) return -1;
5947 if (dur.weeks > 0) return 1;
5948 const TimeDurationRecord& time = dur.time_duration;
5949 if (time.days < 0) return -1;
5950 if (time.days > 0) return 1;
5951 if (time.hours < 0) return -1;
5952 if (time.hours > 0) return 1;
5953 if (time.minutes < 0) return -1;
5954 if (time.minutes > 0) return 1;
5955 if (time.seconds < 0) return -1;
5956 if (time.seconds > 0) return 1;
5957 if (time.milliseconds < 0) return -1;
5958 if (time.milliseconds > 0) return 1;
5959 if (time.microseconds < 0) return -1;
5960 if (time.microseconds > 0) return 1;
5961 if (time.nanoseconds < 0) return -1;
5962 if (time.nanoseconds > 0) return 1;
5963 return 0;
5964}
5965
5966// #sec-temporal-isvalidduration
5967bool IsValidDuration(Isolate* isolate, const DurationRecord& dur) {
5969
5970 // 1. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes,
5971 // seconds, milliseconds, microseconds, nanoseconds).
5972 int32_t sign = DurationRecord::Sign(dur);
5973 // 2. For each value v of « years, months, weeks, days, hours, minutes,
5974 // seconds, milliseconds, microseconds, nanoseconds », do a. If v is not
5975 // finite, return false. b. If v < 0 and sign > 0, return false. c. If v > 0
5976 // and sign < 0, return false.
5977 // 3. Return true.
5978 const TimeDurationRecord& time = dur.time_duration;
5979
5980 if (!(std::isfinite(dur.years) && std::isfinite(dur.months) &&
5981 std::isfinite(dur.weeks) && std::isfinite(time.days) &&
5982 std::isfinite(time.hours) && std::isfinite(time.minutes) &&
5983 std::isfinite(time.seconds) && std::isfinite(time.milliseconds) &&
5984 std::isfinite(time.microseconds) && std::isfinite(time.nanoseconds))) {
5985 return false;
5986 }
5987 if ((sign > 0 && (dur.years < 0 || dur.months < 0 || dur.weeks < 0 ||
5988 time.days < 0 || time.hours < 0 || time.minutes < 0 ||
5989 time.seconds < 0 || time.milliseconds < 0 ||
5990 time.microseconds < 0 || time.nanoseconds < 0)) ||
5991 (sign < 0 && (dur.years > 0 || dur.months > 0 || dur.weeks > 0 ||
5992 time.days > 0 || time.hours > 0 || time.minutes > 0 ||
5993 time.seconds > 0 || time.milliseconds > 0 ||
5994 time.microseconds > 0 || time.nanoseconds > 0))) {
5995 return false;
5996 }
5997 static const double kPower32Of2 = static_cast<double>(int64_t(1) << 32);
5998 static const int64_t kPower53Of2 = int64_t(1) << 53;
5999 // 3. If abs(years) ≥ 2**32, return false.
6000 if (std::abs(dur.years) >= kPower32Of2) {
6001 return false;
6002 }
6003 // 4. If abs(months) ≥ 2**32, return false.
6004 if (std::abs(dur.months) >= kPower32Of2) {
6005 return false;
6006 }
6007 // 5. If abs(weeks) ≥ 2**32, return false.
6008 if (std::abs(dur.weeks) >= kPower32Of2) {
6009 return false;
6010 }
6011 // 6. Let normalizedSeconds be days × 86,400 + hours × 3600 + minutes × 60 +
6012 // seconds + ℝ(𝔽(milliseconds)) × 10**-3 + ℝ(𝔽(microseconds)) × 10**-6 +
6013 // ℝ(𝔽(nanoseconds)) × 10**-9.
6014 // 7. NOTE: The above step cannot be implemented directly using floating-point
6015 // arithmetic. Multiplying by 10**-3, 10**-6, and 10**-9 respectively may be
6016 // imprecise when milliseconds, microseconds, or nanoseconds is an unsafe
6017 // integer. This multiplication can be implemented in C++ with an
6018 // implementation of std::remquo() with sufficient bits in the quotient.
6019 // String manipulation will also give an exact result, since the
6020 // multiplication is by a power of 10.
6021 // 8. If abs(normalizedSeconds) ≥ 2**53, return false.
6022
6023 int64_t allowed = kPower53Of2;
6024 double in_seconds = std::abs(time.days * 86400.0 + time.hours * 3600.0 +
6025 time.minutes * 60.0 + time.seconds);
6026
6027 if (in_seconds >= allowed) {
6028 return false;
6029 }
6030 allowed -= in_seconds;
6031
6032 // Check the part > 1 seconds.
6033 in_seconds = std::floor(std::abs(time.milliseconds / 1e3)) +
6034 std::floor(std::abs(time.microseconds / 1e6)) +
6035 std::floor(std::abs(time.nanoseconds / 1e9));
6036 if (in_seconds >= allowed) {
6037 return false;
6038 }
6039 allowed -= in_seconds;
6040
6041 // Sum of the three remainings will surely < 3
6042 if (allowed > 3) {
6043 return true;
6044 }
6045
6046 allowed *= 1000000000; // convert to ns
6047 int64_t remainders = std::abs(fmod(time.milliseconds, 1e3)) * 1000000 +
6048 std::abs(fmod(time.microseconds, 1e6)) * 1000 +
6049 std::abs(fmod(time.nanoseconds, 1e9));
6050 if (remainders >= allowed) {
6051 return false;
6052 }
6053 return true;
6054}
6055
6056} // namespace temporal
6057
6058namespace {
6059
6060// #sec-temporal-isisoleapyear
6061bool IsISOLeapYear(Isolate* isolate, int32_t year) {
6063
6064 // 1. Assert: year is an integer.
6065 // 2. If year modulo 4 ≠ 0, return false.
6066 // 3. If year modulo 400 = 0, return true.
6067 // 4. If year modulo 100 = 0, return false.
6068 // 5. Return true.
6069 return isolate->date_cache()->IsLeap(year);
6070}
6071
6072// #sec-temporal-isodaysinmonth
6073int32_t ISODaysInMonth(Isolate* isolate, int32_t year, int32_t month) {
6075
6076 // 1. Assert: year is an integer.
6077 // 2. Assert: month is an integer, month ≥ 1, and month ≤ 12.
6078 DCHECK_GE(month, 1);
6079 DCHECK_LE(month, 12);
6080 // 3. If month is 1, 3, 5, 7, 8, 10, or 12, return 31.
6081 if (month % 2 == ((month < 8) ? 1 : 0)) return 31;
6082 // 4. If month is 4, 6, 9, or 11, return 30.
6083 DCHECK(month == 2 || month == 4 || month == 6 || month == 9 || month == 11);
6084 if (month != 2) return 30;
6085 // 5. If ! IsISOLeapYear(year) is true, return 29.
6086 return IsISOLeapYear(isolate, year) ? 29 : 28;
6087 // 6. Return 28.
6088}
6089
6090// #sec-temporal-isodaysinyear
6091int32_t ISODaysInYear(Isolate* isolate, int32_t year) {
6093
6094 // 1. Assert: year is an integer.
6095 // 2. If ! IsISOLeapYear(year) is true, then
6096 // a. Return 366.
6097 // 3. Return 365.
6098 return IsISOLeapYear(isolate, year) ? 366 : 365;
6099}
6100
6101bool IsValidTime(Isolate* isolate, const TimeRecord& time) {
6103
6104 // 2. If hour < 0 or hour > 23, then
6105 // a. Return false.
6106 if (time.hour < 0 || time.hour > 23) return false;
6107 // 3. If minute < 0 or minute > 59, then
6108 // a. Return false.
6109 if (time.minute < 0 || time.minute > 59) return false;
6110 // 4. If second < 0 or second > 59, then
6111 // a. Return false.
6112 if (time.second < 0 || time.second > 59) return false;
6113 // 5. If millisecond < 0 or millisecond > 999, then
6114 // a. Return false.
6115 if (time.millisecond < 0 || time.millisecond > 999) return false;
6116 // 6. If microsecond < 0 or microsecond > 999, then
6117 // a. Return false.
6118 if (time.microsecond < 0 || time.microsecond > 999) return false;
6119 // 7. If nanosecond < 0 or nanosecond > 999, then
6120 // a. Return false.
6121 if (time.nanosecond < 0 || time.nanosecond > 999) return false;
6122 // 8. Return true.
6123 return true;
6124}
6125
6126// #sec-temporal-isvalidisodate
6127bool IsValidISODate(Isolate* isolate, const DateRecord& date) {
6129
6130 // 1. Assert: year, month, and day are integers.
6131 // 2. If month < 1 or month > 12, then
6132 // a. Return false.
6133 if (date.month < 1 || date.month > 12) return false;
6134 // 3. Let daysInMonth be ! ISODaysInMonth(year, month).
6135 // 4. If day < 1 or day > daysInMonth, then
6136 // a. Return false.
6137 if (date.day < 1 ||
6138 date.day > ISODaysInMonth(isolate, date.year, date.month)) {
6139 return false;
6140 }
6141 // 5. Return true.
6142 return true;
6143}
6144
6145// #sec-temporal-compareisodate
6146int32_t CompareISODate(const DateRecord& one, const DateRecord& two) {
6148
6149 // 1. Assert: y1, m1, d1, y2, m2, and d2 are integers.
6150 // 2. If y1 > y2, return 1.
6151 if (one.year > two.year) return 1;
6152 // 3. If y1 < y2, return -1.
6153 if (one.year < two.year) return -1;
6154 // 4. If m1 > m2, return 1.
6155 if (one.month > two.month) return 1;
6156 // 5. If m1 < m2, return -1.
6157 if (one.month < two.month) return -1;
6158 // 6. If d1 > d2, return 1.
6159 if (one.day > two.day) return 1;
6160 // 7. If d1 < d2, return -1.
6161 if (one.day < two.day) return -1;
6162 // 8. Return 0.
6163 return 0;
6164}
6165
6166int32_t CompareTemporalTime(const TimeRecord& time1, const TimeRecord& time2);
6167
6168// #sec-temporal-compareisodatetime
6169int32_t CompareISODateTime(const DateTimeRecord& one,
6170 const DateTimeRecord& two) {
6171 // 2. Let dateResult be ! CompareISODate(y1, mon1, d1, y2, mon2, d2).
6172 int32_t date_result = CompareISODate(one.date, two.date);
6173 // 3. If dateResult is not 0, then
6174 if (date_result != 0) {
6175 // a. Return dateResult.
6176 return date_result;
6177 }
6178 // 4. Return ! CompareTemporalTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2,
6179 // ms2, mus2, ns2).
6180 return CompareTemporalTime(one.time, two.time);
6181}
6182
6183inline int32_t floor_divid(int32_t a, int32_t b) {
6184 return (((a) / (b)) + ((((a) < 0) && (((a) % (b)) != 0)) ? -1 : 0));
6185}
6186// #sec-temporal-balanceisoyearmonth
6187void BalanceISOYearMonth(Isolate* isolate, int32_t* year, int32_t* month) {
6189
6190 // 1. Assert: year and month are integers.
6191 // 2. Set year to year + floor((month - 1) / 12).
6192 *year += floor_divid((*month - 1), 12);
6193 // 3. Set month to (month − 1) modulo 12 + 1.
6194 *month = static_cast<int32_t>(modulo(*month - 1, 12)) + 1;
6195
6196 // 4. Return the new Record { [[Year]]: year, [[Month]]: month }.
6197}
6198// #sec-temporal-balancetime
6199DateTimeRecord BalanceTime(const UnbalancedTimeRecord& input) {
6201 UnbalancedTimeRecord time(input);
6202 TimeRecord result;
6203
6204 // 1. Assert: hour, minute, second, millisecond, microsecond, and nanosecond
6205 // are integers.
6206 // 2. Set microsecond to microsecond + floor(nanosecond / 1000).
6207 time.microsecond += std::floor(time.nanosecond / 1000.0);
6208 // 3. Set nanosecond to nanosecond modulo 1000.
6209 result.nanosecond = modulo(time.nanosecond, 1000);
6210 // 4. Set millisecond to millisecond + floor(microsecond / 1000).
6211 time.millisecond += std::floor(time.microsecond / 1000.0);
6212 // 5. Set microsecond to microsecond modulo 1000.
6213 result.microsecond = modulo(time.microsecond, 1000);
6214 // 6. Set second to second + floor(millisecond / 1000).
6215 time.second += std::floor(time.millisecond / 1000.0);
6216 // 7. Set millisecond to millisecond modulo 1000.
6217 result.millisecond = modulo(time.millisecond, 1000);
6218 // 8. Set minute to minute + floor(second / 60).
6219 time.minute += std::floor(time.second / 60.0);
6220 // 9. Set second to second modulo 60.
6221 result.second = modulo(time.second, 60);
6222 // 10. Set hour to hour + floor(minute / 60).
6223 time.hour += std::floor(time.minute / 60.0);
6224 // 11. Set minute to minute modulo 60.
6225 result.minute = modulo(time.minute, 60);
6226 // 12. Let days be floor(hour / 24).
6227 int32_t days = std::floor(time.hour / 24.0);
6228 // 13. Set hour to hour modulo 24.
6229 result.hour = modulo(time.hour, 24);
6230 // 14. Return the new Record { [[Days]]: days, [[Hour]]: hour, [[Minute]]:
6231 // minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]:
6232 // microsecond, [[Nanosecond]]: nanosecond }.
6233 return {{0, 0, days}, result};
6234}
6235
6236// #sec-temporal-differencetime
6237Maybe<TimeDurationRecord> DifferenceTime(Isolate* isolate,
6238 const TimeRecord& time1,
6239 const TimeRecord& time2) {
6241
6242 // 1. Assert: h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, and ns2
6243 // are integers.
6244 TimeDurationRecord dur;
6245 // 2. Let hours be h2 − h1.
6246 dur.hours = time2.hour - time1.hour;
6247 // 3. Let minutes be min2 − min1.
6248 dur.minutes = time2.minute - time1.minute;
6249 // 4. Let seconds be s2 − s1.
6250 dur.seconds = time2.second - time1.second;
6251 // 5. Let milliseconds be ms2 − ms1.
6252 dur.milliseconds = time2.millisecond - time1.millisecond;
6253 // 6. Let microseconds be mus2 − mus1.
6254 dur.microseconds = time2.microsecond - time1.microsecond;
6255 // 7. Let nanoseconds be ns2 − ns1.
6256 dur.nanoseconds = time2.nanosecond - time1.nanosecond;
6257 // 8. Let sign be ! DurationSign(0, 0, 0, 0, hours, minutes, seconds,
6258 // milliseconds, microseconds, nanoseconds).
6259 double sign = DurationRecord::Sign(
6260 {0,
6261 0,
6262 0,
6263 {0, dur.hours, dur.minutes, dur.seconds, dur.milliseconds,
6264 dur.microseconds, dur.nanoseconds}});
6265
6266 // 9. Let bt be ! BalanceTime(hours × sign, minutes × sign, seconds × sign,
6267 // milliseconds × sign, microseconds × sign, nanoseconds × sign).
6268 DateTimeRecord bt =
6269 BalanceTime({dur.hours * sign, dur.minutes * sign, dur.seconds * sign,
6270 dur.milliseconds * sign, dur.microseconds * sign,
6271 dur.nanoseconds * sign});
6272
6273 // 9. Return ! CreateTimeDurationRecord(bt.[[Days]] × sign, bt.[[Hour]] ×
6274 // sign, bt.[[Minute]] × sign, bt.[[Second]] × sign, bt.[[Millisecond]] ×
6275 // sign, bt.[[Microsecond]] × sign, bt.[[Nanosecond]] × sign).
6277 isolate, bt.date.day * sign, bt.time.hour * sign, bt.time.minute * sign,
6278 bt.time.second * sign, bt.time.millisecond * sign,
6279 bt.time.microsecond * sign, bt.time.nanosecond * sign);
6280}
6281
6282// #sec-temporal-addtime
6283DateTimeRecord AddTime(Isolate* isolate, const TimeRecord& time,
6284 const TimeDurationRecord& addend) {
6286
6287 DCHECK_EQ(addend.days, 0);
6288 // 1. Assert: hour, minute, second, millisecond, microsecond, nanosecond,
6289 // hours, minutes, seconds, milliseconds, microseconds, and nanoseconds are
6290 // integers.
6291 // 2. Let hour be hour + hours.
6292 return BalanceTime({time.hour + addend.hours,
6293 // 3. Let minute be minute + minutes.
6294 time.minute + addend.minutes,
6295 // 4. Let second be second + seconds.
6296 time.second + addend.seconds,
6297 // 5. Let millisecond be millisecond + milliseconds.
6298 time.millisecond + addend.milliseconds,
6299 // 6. Let microsecond be microsecond + microseconds.
6300 time.microsecond + addend.microseconds,
6301 // 7. Let nanosecond be nanosecond + nanoseconds.
6302 time.nanosecond + addend.nanoseconds});
6303 // 8. Return ! BalanceTime(hour, minute, second, millisecond, microsecond,
6304 // nanosecond).
6305}
6306
6307// #sec-temporal-totaldurationnanoseconds
6308DirectHandle<BigInt> TotalDurationNanoseconds(Isolate* isolate,
6309 const TimeDurationRecord& value,
6310 double offset_shift) {
6312
6313 TimeDurationRecord duration(value);
6314
6315 DirectHandle<BigInt> nanoseconds =
6316 BigInt::FromNumber(isolate,
6317 isolate->factory()->NewNumber(value.nanoseconds))
6318 .ToHandleChecked();
6319
6320 // 1. Assert: offsetShift is an integer.
6321 // 2. Set nanoseconds to ℝ(nanoseconds).
6322 // 3. If days ≠ 0, then
6323 if (duration.days != 0) {
6324 // a. Set nanoseconds to nanoseconds − offsetShift.
6326 isolate, nanoseconds,
6328 isolate, isolate->factory()->NewNumber(offset_shift))
6329 .ToHandleChecked())
6330 .ToHandleChecked();
6331 }
6332
6333 DirectHandle<BigInt> thousand = BigInt::FromInt64(isolate, 1000);
6334 DirectHandle<BigInt> sixty = BigInt::FromInt64(isolate, 60);
6335 DirectHandle<BigInt> twentyfour = BigInt::FromInt64(isolate, 24);
6336 // 4. Set hours to ℝ(hours) + ℝ(days) × 24.
6337
6338 DirectHandle<BigInt> x =
6339 BigInt::FromNumber(isolate, isolate->factory()->NewNumber(value.days))
6340 .ToHandleChecked();
6341 x = BigInt::Multiply(isolate, twentyfour, x).ToHandleChecked();
6342 x = BigInt::Add(isolate, x,
6343 BigInt::FromNumber(isolate,
6344 isolate->factory()->NewNumber(value.hours))
6345 .ToHandleChecked())
6346 .ToHandleChecked();
6347
6348 // 5. Set minutes to ℝ(minutes) + hours × 60.
6349 x = BigInt::Multiply(isolate, sixty, x).ToHandleChecked();
6350 x = BigInt::Add(isolate, x,
6352 isolate, isolate->factory()->NewNumber(value.minutes))
6353 .ToHandleChecked())
6354 .ToHandleChecked();
6355 // 6. Set seconds to ℝ(seconds) + minutes × 60.
6356 x = BigInt::Multiply(isolate, sixty, x).ToHandleChecked();
6357 x = BigInt::Add(isolate, x,
6359 isolate, isolate->factory()->NewNumber(value.seconds))
6360 .ToHandleChecked())
6361 .ToHandleChecked();
6362 // 7. Set milliseconds to ℝ(milliseconds) + seconds × 1000.
6363 x = BigInt::Multiply(isolate, thousand, x).ToHandleChecked();
6364 x = BigInt::Add(isolate, x,
6365 BigInt::FromNumber(isolate, isolate->factory()->NewNumber(
6366 value.milliseconds))
6367 .ToHandleChecked())
6368 .ToHandleChecked();
6369 // 8. Set microseconds to ℝ(microseconds) + milliseconds × 1000.
6370 x = BigInt::Multiply(isolate, thousand, x).ToHandleChecked();
6371 x = BigInt::Add(isolate, x,
6372 BigInt::FromNumber(isolate, isolate->factory()->NewNumber(
6373 value.microseconds))
6374 .ToHandleChecked())
6375 .ToHandleChecked();
6376 // 9. Return nanoseconds + microseconds × 1000.
6377 x = BigInt::Multiply(isolate, thousand, x).ToHandleChecked();
6378 x = BigInt::Add(isolate, x, nanoseconds).ToHandleChecked();
6379 return x;
6380}
6381
6382Maybe<DateRecord> RegulateISODate(Isolate* isolate, ShowOverflow overflow,
6383 const DateRecord& date);
6384Maybe<int32_t> ResolveISOMonth(Isolate* isolate,
6385 DirectHandle<JSReceiver> fields);
6386
6387// #sec-temporal-isomonthdayfromfields
6388Maybe<DateRecord> ISOMonthDayFromFields(Isolate* isolate,
6389 DirectHandle<JSReceiver> fields,
6390 DirectHandle<JSReceiver> options,
6391 const char* method_name) {
6392 Factory* factory = isolate->factory();
6393 // 1. Assert: Type(fields) is Object.
6394 // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month",
6395 // "monthCode", "year" », «"day"»).
6396 DirectHandle<FixedArray> field_names =
6397 DayMonthMonthCodeYearInFixedArray(isolate);
6399 isolate, fields,
6400 PrepareTemporalFields(isolate, fields, field_names, RequiredFields::kDay),
6402 // 3. Let overflow be ? ToTemporalOverflow(options).
6403 ShowOverflow overflow;
6405 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
6407 // 4. Let month be ! Get(fields, "month").
6408 DirectHandle<Object> month_obj =
6409 JSReceiver::GetProperty(isolate, fields, factory->month_string())
6410 .ToHandleChecked();
6411 // 5. Let monthCode be ! Get(fields, "monthCode").
6412 DirectHandle<Object> month_code_obj =
6413 JSReceiver::GetProperty(isolate, fields, factory->monthCode_string())
6414 .ToHandleChecked();
6415 // 6. Let year be ! Get(fields, "year").
6416 DirectHandle<Object> year_obj =
6417 JSReceiver::GetProperty(isolate, fields, factory->year_string())
6418 .ToHandleChecked();
6419 // 7. If month is not undefined, and monthCode and year are both undefined,
6420 // then
6421 if (!IsUndefined(*month_obj, isolate) &&
6422 IsUndefined(*month_code_obj, isolate) &&
6423 IsUndefined(*year_obj, isolate)) {
6424 // a. Throw a TypeError exception.
6427 }
6428 // 8. Set month to ? ResolveISOMonth(fields).
6429 DateRecord result;
6431 ResolveISOMonth(isolate, fields),
6433
6434 // 9. Let day be ! Get(fields, "day").
6435 DirectHandle<Object> day_obj =
6436 JSReceiver::GetProperty(isolate, fields, factory->day_string())
6437 .ToHandleChecked();
6438 // 10. Assert: Type(day) is Number.
6439 // Note: "day" in fields is always converted by
6440 // ToIntegerThrowOnInfinity inside the PrepareTemporalFields above.
6441 // Therefore the day_obj is always an integer.
6442 result.day = FastD2I(floor(Object::NumberValue(Cast<Number>(*day_obj))));
6443 // 11. Let referenceISOYear be 1972 (the first leap year after the Unix
6444 // epoch).
6445 int32_t reference_iso_year = 1972;
6446 // 12. If monthCode is undefined, then
6447 if (IsUndefined(*month_code_obj, isolate)) {
6448 result.year = FastD2I(floor(Object::NumberValue(Cast<Number>(*year_obj))));
6449 // a. Let result be ? RegulateISODate(year, month, day, overflow).
6450 } else {
6451 // 13. Else,
6452 // a. Let result be ? RegulateISODate(referenceISOYear, month, day,
6453 // overflow).
6454 result.year = reference_iso_year;
6455 }
6457 isolate, result, RegulateISODate(isolate, overflow, result),
6459 // 14. Return the new Record { [[Month]]: result.[[Month]], [[Day]]:
6460 // result.[[Day]], [[ReferenceISOYear]]: referenceISOYear }.
6461 result.year = reference_iso_year;
6462 return Just(result);
6463}
6464
6465} // namespace
6466
6467// #sec-temporal.duration
6469 Isolate* isolate, DirectHandle<JSFunction> target,
6474 DirectHandle<Object> milliseconds, DirectHandle<Object> microseconds,
6476 const char* method_name = "Temporal.Duration";
6477 // 1. If NewTarget is undefined, then
6478 if (IsUndefined(*new_target)) {
6479 // a. Throw a TypeError exception.
6480 THROW_NEW_ERROR(isolate,
6481 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
6482 isolate->factory()->NewStringFromAsciiChecked(
6483 method_name)));
6484 }
6485 // 2. Let y be ? ToIntegerWithoutRounding(years).
6486 double y;
6488 isolate, y, ToIntegerWithoutRounding(isolate, years),
6490
6491 // 3. Let mo be ? ToIntegerWithoutRounding(months).
6492 double mo;
6494 isolate, mo, ToIntegerWithoutRounding(isolate, months),
6496
6497 // 4. Let w be ? ToIntegerWithoutRounding(weeks).
6498 double w;
6500 isolate, w, ToIntegerWithoutRounding(isolate, weeks),
6502
6503 // 5. Let d be ? ToIntegerWithoutRounding(days).
6504 double d;
6506 isolate, d, ToIntegerWithoutRounding(isolate, days),
6508
6509 // 6. Let h be ? ToIntegerWithoutRounding(hours).
6510 double h;
6512 isolate, h, ToIntegerWithoutRounding(isolate, hours),
6514
6515 // 7. Let m be ? ToIntegerWithoutRounding(minutes).
6516 double m;
6518 isolate, m, ToIntegerWithoutRounding(isolate, minutes),
6520
6521 // 8. Let s be ? ToIntegerWithoutRounding(seconds).
6522 double s;
6524 isolate, s, ToIntegerWithoutRounding(isolate, seconds),
6526
6527 // 9. Let ms be ? ToIntegerWithoutRounding(milliseconds).
6528 double ms;
6530 isolate, ms, ToIntegerWithoutRounding(isolate, milliseconds),
6532
6533 // 10. Let mis be ? ToIntegerWithoutRounding(microseconds).
6534 double mis;
6536 isolate, mis, ToIntegerWithoutRounding(isolate, microseconds),
6538
6539 // 11. Let ns be ? ToIntegerWithoutRounding(nanoseconds).
6540 double ns;
6542 isolate, ns, ToIntegerWithoutRounding(isolate, nanoseconds),
6544
6545 // 12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns,
6546 // NewTarget).
6547 return CreateTemporalDuration(isolate, target, new_target,
6548 {y, mo, w, {d, h, m, s, ms, mis, ns}});
6549}
6550
6551namespace {
6552
6553// #sec-temporal-torelativetemporalobject
6554MaybeDirectHandle<Object> ToRelativeTemporalObject(
6555 Isolate* isolate, DirectHandle<JSReceiver> options,
6556 const char* method_name);
6557
6558// #sec-temporal-defaulttemporallargestunit
6559Unit DefaultTemporalLargestUnit(const DurationRecord& dur);
6560
6561// #sec-temporal-roundtemporalinstant
6562DirectHandle<BigInt> RoundTemporalInstant(Isolate* isolate,
6564 double increment, Unit unit,
6566
6567// #sec-temporal-differenceinstant
6568TimeDurationRecord DifferenceInstant(Isolate* isolate, DirectHandle<BigInt> ns1,
6570 double rounding_increment,
6571 Unit smallest_unit, Unit largest_unit,
6573 const char* method_name);
6574
6575// #sec-temporal-differencezoneddatetime
6576Maybe<DurationRecord> DifferenceZonedDateTime(
6580 const char* method_name);
6581
6582// #sec-temporal-addduration
6583Maybe<DurationRecord> AddDuration(Isolate* isolate, const DurationRecord& dur1,
6584 const DurationRecord& dur2,
6585 DirectHandle<Object> relative_to_obj,
6586 const char* method_name);
6587
6588// #sec-temporal-adjustroundeddurationdays
6589Maybe<DurationRecord> AdjustRoundedDurationDays(
6590 Isolate* isolate, const DurationRecord& duration, double increment,
6591 Unit unit, RoundingMode rounding_mode, DirectHandle<Object> relative_to_obj,
6592 const char* method_name) {
6593 // 1. If Type(relativeTo) is not Object; or relativeTo does not have an
6594 // [[InitializedTemporalZonedDateTime]] internal slot; or unit is one of
6595 // "year", "month", "week", or "day"; or unit is "nanosecond" and increment is
6596 // 1, then
6597 if (!IsJSTemporalZonedDateTime(*relative_to_obj) ||
6598 (unit == Unit::kYear || unit == Unit::kMonth || unit == Unit::kWeek ||
6599 unit == Unit::kDay) ||
6600 (unit == Unit::kNanosecond && increment == 1)) {
6601 // a. Return ! CreateDurationRecord(years, months, weeks, days, hours,
6602 // minutes, seconds, milliseconds, microseconds, nanoseconds).
6603 return Just(CreateDurationRecord(isolate, duration).ToChecked());
6604 }
6605 DirectHandle<JSTemporalZonedDateTime> relative_to =
6606 Cast<JSTemporalZonedDateTime>(relative_to_obj);
6607 // 2. Let timeRemainderNs be ! TotalDurationNanoseconds(0, hours, minutes,
6608 // seconds, milliseconds, microseconds, nanoseconds, 0).
6609 DirectHandle<BigInt> time_remainder_ns = TotalDurationNanoseconds(
6610 isolate,
6611 {0, duration.time_duration.hours, duration.time_duration.minutes,
6614 0);
6615
6617 time_remainder_ns, direct_handle(Smi::zero(), isolate));
6618 double direction;
6619 // 3. If timeRemainderNs = 0, let direction be 0.
6621 direction = 0;
6622 // 4. Else if timeRemainderNs < 0, let direction be -1.
6623 } else if (compare == ComparisonResult::kLessThan) {
6624 direction = -1;
6625 // 5. Else, let direction be 1.
6626 } else {
6627 direction = 1;
6628 }
6629
6630 // 6. Let dayStart be ? AddZonedDateTime(relativeTo.[[Nanoseconds]],
6631 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], years, months, weeks,
6632 // days, 0, 0, 0, 0, 0, 0).
6633 DirectHandle<BigInt> day_start;
6635 isolate, day_start,
6636 AddZonedDateTime(isolate,
6637 direct_handle(relative_to->nanoseconds(), isolate),
6638 direct_handle(relative_to->time_zone(), isolate),
6639 direct_handle(relative_to->calendar(), isolate),
6640 {duration.years,
6641 duration.months,
6642 duration.weeks,
6643 {duration.time_duration.days, 0, 0, 0, 0, 0, 0}},
6644 method_name),
6646 // 7. Let dayEnd be ? AddZonedDateTime(dayStart, relativeTo.[[TimeZone]],
6647 // relativeTo.[[Calendar]], 0, 0, 0, direction, 0, 0, 0, 0, 0, 0).
6648 DirectHandle<BigInt> day_end;
6650 isolate, day_end,
6651 AddZonedDateTime(isolate, day_start,
6652 direct_handle(relative_to->time_zone(), isolate),
6653 direct_handle(relative_to->calendar(), isolate),
6654 {0, 0, 0, {direction, 0, 0, 0, 0, 0, 0}}, method_name),
6656 // 8. Let dayLengthNs be ℝ(dayEnd - dayStart).
6657 DirectHandle<BigInt> day_length_ns =
6658 BigInt::Subtract(isolate, day_end, day_start).ToHandleChecked();
6659 // 9. If (timeRemainderNs - dayLengthNs) × direction < 0, then
6660 DirectHandle<BigInt> time_remainder_ns_minus_day_length_ns =
6661 BigInt::Subtract(isolate, time_remainder_ns, day_length_ns)
6662 .ToHandleChecked();
6663
6664 if (time_remainder_ns_minus_day_length_ns->AsInt64() * direction < 0) {
6665 // a. Return ! CreateDurationRecord(years, months, weeks, days, hours,
6666 // minutes, seconds, milliseconds, microseconds, nanoseconds).
6667 return Just(CreateDurationRecord(isolate, duration).ToChecked());
6668 }
6669 // 10. Set timeRemainderNs to ! RoundTemporalInstant(ℤ(timeRemainderNs -
6670 // dayLengthNs), increment, unit, roundingMode).
6671 time_remainder_ns =
6672 RoundTemporalInstant(isolate, time_remainder_ns_minus_day_length_ns,
6674 // 11. Let adjustedDateDuration be ? AddDuration(years, months, weeks, days,
6675 // 0, 0, 0, 0, 0, 0, 0, 0, 0, direction, 0, 0, 0, 0, 0, 0, relativeTo).
6676 DurationRecord adjusted_date_duration;
6678 isolate, adjusted_date_duration,
6679 AddDuration(isolate,
6680 {duration.years,
6681 duration.months,
6682 duration.weeks,
6683 {duration.time_duration.days, 0, 0, 0, 0, 0, 0}},
6684 {0, 0, 0, {direction, 0, 0, 0, 0, 0, 0}}, relative_to,
6685 method_name),
6687 // 12. Let adjustedTimeDuration be ? BalanceDuration(0, 0, 0, 0, 0, 0,
6688 // timeRemainderNs, "hour").
6689 TimeDurationRecord adjusted_time_duration;
6691 isolate, adjusted_time_duration,
6692 BalanceDuration(isolate, Unit::kHour, time_remainder_ns, method_name),
6694 // 13. Return ! CreateDurationRecord(adjustedDateDuration.[[Years]],
6695 // adjustedDateDuration.[[Months]], adjustedDateDuration.[[Weeks]],
6696 // adjustedDateDuration.[[Days]], adjustedTimeDuration.[[Hours]],
6697 // adjustedTimeDuration.[[Minutes]], adjustedTimeDuration.[[Seconds]],
6698 // adjustedTimeDuration.[[Milliseconds]],
6699 // adjustedTimeDuration.[[Microseconds]],
6700 // adjustedTimeDuration.[[Nanoseconds]]).
6701 adjusted_time_duration.days = adjusted_date_duration.time_duration.days;
6702 return Just(
6703 CreateDurationRecord(
6704 isolate, {adjusted_date_duration.years, adjusted_date_duration.months,
6705 adjusted_date_duration.weeks, adjusted_time_duration})
6706 .ToChecked());
6707}
6708
6709// #sec-temporal-calculateoffsetshift
6710Maybe<int64_t> CalculateOffsetShift(Isolate* isolate,
6711 DirectHandle<Object> relative_to_obj,
6712 const DateDurationRecord& dur,
6713 const char* method_name) {
6715
6716 // 1. If Type(relativeTo) is not Object or relativeTo does not have an
6717 // [[InitializedTemporalZonedDateTime]] internal slot, return 0.
6718 if (!IsJSTemporalZonedDateTime(*relative_to_obj)) {
6719 return Just(static_cast<int64_t>(0));
6720 }
6721 auto relative_to = Cast<JSTemporalZonedDateTime>(relative_to_obj);
6722 // 2. Let instant be ! CreateTemporalInstant(relativeTo.[[Nanoseconds]]).
6723 DirectHandle<JSTemporalInstant> instant =
6725 isolate, direct_handle(relative_to->nanoseconds(), isolate))
6726 .ToHandleChecked();
6727 // 3. Let offsetBefore be ? GetOffsetNanosecondsFor(relativeTo.[[TimeZone]],
6728 // instant).
6729 int64_t offset_before;
6731 isolate, offset_before,
6732 GetOffsetNanosecondsFor(isolate,
6733 direct_handle(relative_to->time_zone(), isolate),
6734 instant, method_name),
6736 // 4. Let after be ? AddZonedDateTime(relativeTo.[[Nanoseconds]],
6737 // relativeTo.[[TimeZone]], relativeTo.[[Calendar]], y, mon, w, d, 0, 0, 0, 0,
6738 // 0, 0).
6739 DirectHandle<BigInt> after;
6741 isolate, after,
6742 AddZonedDateTime(
6743 isolate, direct_handle(relative_to->nanoseconds(), isolate),
6744 direct_handle(relative_to->time_zone(), isolate),
6745 direct_handle(relative_to->calendar(), isolate),
6746 {dur.years, dur.months, dur.weeks, {dur.days, 0, 0, 0, 0, 0, 0}},
6747 method_name),
6749 // 5. Let instantAfter be ! CreateTemporalInstant(after).
6750 DirectHandle<JSTemporalInstant> instant_after =
6751 temporal::CreateTemporalInstant(isolate, after).ToHandleChecked();
6752 // 6. Let offsetAfter be ? GetOffsetNanosecondsFor(relativeTo.[[TimeZone]],
6753 // instantAfter).
6754 int64_t offset_after;
6756 isolate, offset_after,
6757 GetOffsetNanosecondsFor(isolate,
6758 direct_handle(relative_to->time_zone(), isolate),
6759 instant_after, method_name),
6761 // 7. Return offsetAfter − offsetBefore
6762 return Just(offset_after - offset_before);
6763}
6764
6765// #sec-temporal-moverelativedate
6766struct MoveRelativeDateResult {
6767 DirectHandle<JSTemporalPlainDate> relative_to;
6768 double days;
6769};
6770Maybe<MoveRelativeDateResult> MoveRelativeDate(
6771 Isolate* isolate, DirectHandle<JSReceiver> calendar,
6772 DirectHandle<JSTemporalPlainDate> relative_to,
6773 DirectHandle<JSTemporalDuration> duration, const char* method_name);
6774
6775// #sec-temporal-unbalancedurationrelative
6776Maybe<DateDurationRecord> UnbalanceDurationRelative(
6777 Isolate* isolate, const DateDurationRecord& dur, Unit largest_unit,
6778 DirectHandle<Object> relative_to_obj, const char* method_name) {
6780
6781 Factory* factory = isolate->factory();
6782 // 1. If largestUnit is "year", or years, months, weeks, and days are all 0,
6783 // then
6784 if (largest_unit == Unit::kYear ||
6785 (dur.years == 0 && dur.months == 0 && dur.weeks == 0 && dur.days == 0)) {
6786 // a. Return ! CreateDateDurationRecord(years, months, weeks, days).
6787 return Just(DateDurationRecord::Create(isolate, dur.years, dur.months,
6788 dur.weeks, dur.days)
6789 .ToChecked());
6790 }
6791 // 2. Let sign be ! DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0,
6792 // 0).
6793 double sign = DurationRecord::Sign(
6794 {dur.years, dur.months, dur.weeks, {dur.days, 0, 0, 0, 0, 0, 0}});
6795 // 3. Assert: sign ≠ 0.
6796 DCHECK_NE(sign, 0);
6797 // 4. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0,
6798 // 0).
6799 DirectHandle<JSTemporalDuration> one_year =
6800 CreateTemporalDuration(isolate, {sign, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
6801 .ToHandleChecked();
6802 // 5. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0,
6803 // 0).
6804 DirectHandle<JSTemporalDuration> one_month =
6805 CreateTemporalDuration(isolate, {0, sign, 0, {0, 0, 0, 0, 0, 0, 0}})
6806 .ToHandleChecked();
6807 // 6. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0,
6808 // 0).
6809 DirectHandle<JSTemporalDuration> one_week =
6810 CreateTemporalDuration(isolate, {0, 0, sign, {0, 0, 0, 0, 0, 0, 0}})
6811 .ToHandleChecked();
6812 // 7. If relativeTo is not undefined, then
6813 DirectHandle<JSTemporalPlainDate> relative_to;
6814 DirectHandle<JSReceiver> calendar;
6815 if (!IsUndefined(*relative_to_obj)) {
6816 // a. Set relativeTo to ? ToTemporalDate(relativeTo).
6818 isolate, relative_to,
6819 ToTemporalDate(isolate, relative_to_obj, method_name),
6821 // b. Let calendar be relativeTo.[[Calendar]].
6822 calendar = direct_handle(relative_to->calendar(), isolate);
6823 // 8. Else,
6824 } else {
6825 // a. Let calendar be undefined.
6826 }
6827 DateDurationRecord result = dur;
6828 // 9. If largestUnit is "month", then
6829 if (largest_unit == Unit::kMonth) {
6830 // a. If calendar is undefined, then
6831 if (calendar.is_null()) {
6832 // i. Throw a RangeError exception.
6836 }
6837 // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
6838 DirectHandle<Object> date_add;
6840 isolate, date_add,
6841 Object::GetMethod(isolate, calendar, factory->dateAdd_string()),
6843 // c. Let dateUntil be ? GetMethod(calendar, "dateUntil").
6844 DirectHandle<Object> date_until;
6846 isolate, date_until,
6847 Object::GetMethod(isolate, calendar, factory->dateUntil_string()),
6849 // d. Repeat, while years ≠ 0,
6850 while (result.years != 0) {
6851 // i. Let newRelativeTo be ? CalendarDateAdd(calendar, relativeTo,
6852 // oneYear, undefined, dateAdd).
6853 DirectHandle<JSTemporalPlainDate> new_relative_to;
6855 isolate, new_relative_to,
6856 CalendarDateAdd(isolate, calendar, relative_to, one_year,
6857 factory->undefined_value(), date_add),
6859 // ii. Let untilOptions be ! OrdinaryObjectCreate(null).
6860 DirectHandle<JSObject> until_options =
6861 factory->NewJSObjectWithNullProto();
6862 // iii. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit",
6863 // "month").
6865 isolate, until_options, factory->largestUnit_string(),
6866 factory->month_string(), Just(kThrowOnError))
6867 .FromJust());
6868 // iv. Let untilResult be ? CalendarDateUntil(calendar, relativeTo,
6869 // newRelativeTo, untilOptions, dateUntil).
6870 DirectHandle<JSTemporalDuration> until_result;
6872 isolate, until_result,
6873 CalendarDateUntil(isolate, calendar, relative_to, new_relative_to,
6874 until_options, date_until),
6876 // v. Let oneYearMonths be untilResult.[[Months]].
6877 double one_year_months = Object::NumberValue(until_result->months());
6878 // vi. Set relativeTo to newRelativeTo.
6879 relative_to = new_relative_to;
6880 // vii. Set years to years − sign.
6881 result.years -= sign;
6882 // viii. Set months to months + oneYearMonths.
6883 result.months += one_year_months;
6884 }
6885 // 10. Else if largestUnit is "week", then
6886 } else if (largest_unit == Unit::kWeek) {
6887 // a. If calendar is undefined, then
6888 if (calendar.is_null()) {
6889 // i. Throw a RangeError exception.
6893 }
6894 // b. Repeat, while years ≠ 0,
6895 while (result.years != 0) {
6896 // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
6897 MoveRelativeDateResult move_result;
6899 isolate, move_result,
6900 MoveRelativeDate(isolate, calendar, relative_to, one_year,
6901 method_name),
6903 // ii. Set relativeTo to moveResult.[[RelativeTo]].
6904 relative_to = move_result.relative_to;
6905 // iii. Set days to days + moveResult.[[Days]].
6906 result.days += move_result.days;
6907 // iv. Set years to years - sign.
6908 result.years -= sign;
6909 }
6910 // c. Repeat, while months ≠ 0,
6911 while (result.months != 0) {
6912 // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo,
6913 // oneMonth).
6914 MoveRelativeDateResult move_result;
6916 isolate, move_result,
6917 MoveRelativeDate(isolate, calendar, relative_to, one_month,
6918 method_name),
6920 // ii. Set relativeTo to moveResult.[[RelativeTo]].
6921 relative_to = move_result.relative_to;
6922 // iii. Set days to days + moveResult.[[Days]].
6923 result.days += move_result.days;
6924 // iv. Set months to months - sign.
6925 result.months -= sign;
6926 }
6927 // 11. Else,
6928 } else {
6929 // a. If any of years, months, and weeks are not zero, then
6930 if ((result.years != 0) || (result.months != 0) || (result.weeks != 0)) {
6931 // i. If calendar is undefined, then
6932 if (calendar.is_null()) {
6933 // i. Throw a RangeError exception.
6937 }
6938 // b. Repeat, while years ≠ 0,
6939 while (result.years != 0) {
6940 // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo,
6941 // oneYear).
6942 MoveRelativeDateResult move_result;
6944 isolate, move_result,
6945 MoveRelativeDate(isolate, calendar, relative_to, one_year,
6946 method_name),
6948 // ii. Set relativeTo to moveResult.[[RelativeTo]].
6949 relative_to = move_result.relative_to;
6950 // iii. Set days to days + moveResult.[[Days]].
6951 result.days += move_result.days;
6952 // iv. Set years to years - sign.
6953 result.years -= sign;
6954 }
6955 // c. Repeat, while months ≠ 0,
6956 while (result.months != 0) {
6957 // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo,
6958 // oneMonth).
6959 MoveRelativeDateResult move_result;
6961 isolate, move_result,
6962 MoveRelativeDate(isolate, calendar, relative_to, one_month,
6963 method_name),
6965 // ii. Set relativeTo to moveResult.[[RelativeTo]].
6966 relative_to = move_result.relative_to;
6967 // iii. Set days to days + moveResult.[[Days]].
6968 result.days += move_result.days;
6969 // iv. Set months to years - sign.
6970 result.months -= sign;
6971 }
6972 // d. Repeat, while weeks ≠ 0,
6973 while (result.weeks != 0) {
6974 // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo,
6975 // oneWeek).
6976 MoveRelativeDateResult move_result;
6978 isolate, move_result,
6979 MoveRelativeDate(isolate, calendar, relative_to, one_week,
6980 method_name),
6982 // ii. Set relativeTo to moveResult.[[RelativeTo]].
6983 relative_to = move_result.relative_to;
6984 // iii. Set days to days + moveResult.[[Days]].
6985 result.days += move_result.days;
6986 // iv. Set weeks to years - sign.
6987 result.weeks -= sign;
6988 }
6989 }
6990 }
6991 // 12. Return ? CreateDateDurationRecord(years, months, weeks, days).
6992 return DateDurationRecord::Create(isolate, result.years, result.months,
6993 result.weeks, result.days);
6994}
6995
6996// #sec-temporal-balancedurationrelative
6997Maybe<DateDurationRecord> BalanceDurationRelative(
6998 Isolate* isolate, const DateDurationRecord& dur, Unit largest_unit,
6999 DirectHandle<Object> relative_to_obj, const char* method_name) {
7001
7002 Factory* factory = isolate->factory();
7003 // 1. If largestUnit is not one of "year", "month", or "week", or years,
7004 // months, weeks, and days are all 0, then
7005
7006 if ((largest_unit != Unit::kYear && largest_unit != Unit::kMonth &&
7007 largest_unit != Unit::kWeek) ||
7008 (dur.years == 0 && dur.months == 0 && dur.weeks == 0 && dur.days == 0)) {
7009 // a. Return ! CreateDateDurationRecord(years, months, weeks, days).
7010 return Just(DateDurationRecord::Create(isolate, dur.years, dur.months,
7011 dur.weeks, dur.days)
7012 .ToChecked());
7013 }
7014 // 2. If relativeTo is undefined, then
7015 if (IsUndefined(*relative_to_obj)) {
7016 // a. Throw a RangeError exception.
7020 }
7021
7022 // 3. Let sign be ! DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0,
7023 // 0).
7024 double sign = DurationRecord::Sign(
7025 {dur.years, dur.months, dur.weeks, {dur.days, 0, 0, 0, 0, 0, 0}});
7026 // 4. Assert: sign ≠ 0.
7027 DCHECK_NE(sign, 0);
7028 // 5. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0,
7029 // 0).
7030 DirectHandle<JSTemporalDuration> one_year =
7031 CreateTemporalDuration(isolate, {sign, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
7032 .ToHandleChecked();
7033 // 6. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0,
7034 // 0).
7035 DirectHandle<JSTemporalDuration> one_month =
7036 CreateTemporalDuration(isolate, {0, sign, 0, {0, 0, 0, 0, 0, 0, 0}})
7037 .ToHandleChecked();
7038 // 7. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0,
7039 // 0).
7040 DirectHandle<JSTemporalDuration> one_week =
7041 CreateTemporalDuration(isolate, {0, 0, sign, {0, 0, 0, 0, 0, 0, 0}})
7042 .ToHandleChecked();
7043 // 8. Set relativeTo to ? ToTemporalDate(relativeTo).
7044 DirectHandle<JSTemporalPlainDate> relative_to;
7046 isolate, relative_to,
7047 ToTemporalDate(isolate, relative_to_obj, method_name),
7049 // 9. Let calendar be relativeTo.[[Calendar]].
7050 DirectHandle<JSReceiver> calendar(relative_to->calendar(), isolate);
7051
7052 DateDurationRecord result = dur;
7053 // 10. If largestUnit is "year", then
7054 if (largest_unit == Unit::kYear) {
7055 // a. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
7056 MoveRelativeDateResult move_result;
7058 isolate, move_result,
7059 MoveRelativeDate(isolate, calendar, relative_to, one_year, method_name),
7061 // b. Let newRelativeTo be moveResult.[[RelativeTo]].
7062 DirectHandle<JSTemporalPlainDate> new_relative_to = move_result.relative_to;
7063 // c. Let oneYearDays be moveResult.[[Days]].
7064 double one_year_days = move_result.days;
7065 // d. Repeat, while abs(days) ≥ abs(oneYearDays),
7066 while (std::abs(result.days) >= std::abs(one_year_days)) {
7067 // i. Set days to days - oneYearDays.
7068 result.days -= one_year_days;
7069 // ii. Set years to years + sign.
7070 result.years += sign;
7071 // iii. Set relativeTo to newRelativeTo.
7072 relative_to = new_relative_to;
7073 // iv. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
7074 // oneYear).
7076 isolate, move_result,
7077 MoveRelativeDate(isolate, calendar, relative_to, one_year,
7078 method_name),
7080
7081 // iv. Set newRelativeTo to moveResult.[[RelativeTo]].
7082 new_relative_to = move_result.relative_to;
7083 // v. Set oneYearDays to moveResult.[[Days]].
7084 one_year_days = move_result.days;
7085 }
7086 // e. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth).
7088 isolate, move_result,
7089 MoveRelativeDate(isolate, calendar, relative_to, one_month,
7090 method_name),
7092 // f. Set newRelativeTo to moveResult.[[RelativeTo]].
7093 new_relative_to = move_result.relative_to;
7094 // g. Let oneMonthDays be moveResult.[[Days]].
7095 double one_month_days = move_result.days;
7096 // h. Repeat, while abs(days) ≥ abs(oneMonthDays),
7097 while (std::abs(result.days) >= std::abs(one_month_days)) {
7098 // i. Set days to days - oneMonthDays.
7099 result.days -= one_month_days;
7100 // ii. Set months to months + sign.
7101 result.months += sign;
7102 // iii. Set relativeTo to newRelativeTo.
7103 relative_to = new_relative_to;
7104 // iv. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
7105 // oneMonth).
7107 isolate, move_result,
7108 MoveRelativeDate(isolate, calendar, relative_to, one_month,
7109 method_name),
7111 // iv. Set newRrelativeTo to moveResult.[[RelativeTo]].
7112 new_relative_to = move_result.relative_to;
7113 // v. Set oneMonthDays to moveResult.[[Days]].
7114 one_month_days = move_result.days;
7115 }
7116 // i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
7117 DirectHandle<Object> date_add;
7119 isolate, date_add,
7120 Object::GetMethod(isolate, calendar, factory->dateAdd_string()),
7122 // j. Set newRelativeTo be ? CalendarDateAdd(calendar, relativeTo, oneYear,
7123 // undefined, dateAdd).
7125 isolate, new_relative_to,
7126 CalendarDateAdd(isolate, calendar, relative_to, one_year,
7127 factory->undefined_value(), date_add),
7129 // k. Let dateUntil be ? GetMethod(calendar, "dateUntil").
7130 DirectHandle<Object> date_until;
7132 isolate, date_until,
7133 Object::GetMethod(isolate, calendar, factory->dateUntil_string()),
7135 // l. Let untilOptions be OrdinaryObjectCreate(null).
7136 DirectHandle<JSObject> until_options = factory->NewJSObjectWithNullProto();
7137 // m. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit",
7138 // "month").
7140 isolate, until_options, factory->largestUnit_string(),
7141 factory->month_string(), Just(kThrowOnError))
7142 .FromJust());
7143 // n. Let untilResult be ? CalendarDateUntil(calendar, relativeTo,
7144 // newRelativeTo, untilOptions, dateUntil).
7145 DirectHandle<JSTemporalDuration> until_result;
7147 isolate, until_result,
7148 CalendarDateUntil(isolate, calendar, relative_to, new_relative_to,
7149 until_options, date_until),
7151 // o. Let oneYearMonths be untilResult.[[Months]].
7152 double one_year_months = Object::NumberValue(until_result->months());
7153 // p. Repeat, while abs(months) ≥ abs(oneYearMonths),
7154 while (std::abs(result.months) >= std::abs(one_year_months)) {
7155 // i. Set months to months - oneYearMonths.
7156 result.months -= one_year_months;
7157 // ii. Set years to years + sign.
7158 result.years += sign;
7159 // iii. Set relativeTo to newRelativeTo.
7160 relative_to = new_relative_to;
7161 // iv. Set newRelativeTo to ? CalendarDateAdd(calendar, relativeTo,
7162 // oneYear, undefined, dateAdd).
7164 isolate, new_relative_to,
7165 CalendarDateAdd(isolate, calendar, relative_to, one_year,
7166 factory->undefined_value(), date_add),
7168 // v. Set untilOptions to OrdinaryObjectCreate(null).
7169 until_options = factory->NewJSObjectWithNullProto();
7170 // vi. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit",
7171 // "month").
7173 isolate, until_options, factory->largestUnit_string(),
7174 factory->month_string(), Just(kThrowOnError))
7175 .FromJust());
7176 // vii. Set untilResult to ? CalendarDateUntil(calendar, relativeTo,
7177 // newRelativeTo, untilOptions, dateUntil).
7179 isolate, until_result,
7180 CalendarDateUntil(isolate, calendar, relative_to, new_relative_to,
7181 until_options, date_until),
7183 // viii. Set oneYearMonths to untilResult.[[Months]].
7184 one_year_months = Object::NumberValue(until_result->months());
7185 }
7186 // 11. Else if largestUnit is "month", then
7187 } else if (largest_unit == Unit::kMonth) {
7188 // a. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth).
7189 MoveRelativeDateResult move_result;
7191 isolate, move_result,
7192 MoveRelativeDate(isolate, calendar, relative_to, one_month,
7193 method_name),
7195 // b. Let newRelativeTo be moveResult.[[RelativeTo]].
7196 DirectHandle<JSTemporalPlainDate> new_relative_to = move_result.relative_to;
7197 // c. Let oneMonthDays be moveResult.[[Days]].
7198 double one_month_days = move_result.days;
7199 // d. Repeat, while abs(days) ≥ abs(oneMonthDays),
7200 while (std::abs(result.days) >= std::abs(one_month_days)) {
7201 // i. Set days to days - oneMonthDays.
7202 result.days -= one_month_days;
7203 // ii. Set months to months + sign.
7204 result.months += sign;
7205 // iii. Set relativeTo to newRelativeTo.
7206 relative_to = new_relative_to;
7207 // iv. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
7208 // oneMonth).
7210 isolate, move_result,
7211 MoveRelativeDate(isolate, calendar, relative_to, one_month,
7212 method_name),
7214 // v. Set newRelativeTo to moveResult.[[RelativeTo]].
7215 new_relative_to = move_result.relative_to;
7216 // vi. Set oneMonthDays to moveResult.[[Days]].
7217 one_month_days = move_result.days;
7218 }
7219 // 12. Else
7220 } else {
7221 // a. Assert: largestUnit is "week".
7222 DCHECK_EQ(largest_unit, Unit::kWeek);
7223 // b. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek).
7224 MoveRelativeDateResult move_result;
7226 isolate, move_result,
7227 MoveRelativeDate(isolate, calendar, relative_to, one_week, method_name),
7229 // c. Let newRelativeTo be moveResult.[[RelativeTo]].
7230 DirectHandle<JSTemporalPlainDate> new_relative_to = move_result.relative_to;
7231 // d. Let oneWeekDays be moveResult.[[Days]].
7232 double one_week_days = move_result.days;
7233 // e. Repeat, while abs(days) ≥ abs(oneWeekDays),
7234 while (std::abs(result.days) >= std::abs(one_week_days)) {
7235 // i. Set days to days - oneWeekDays.
7236 result.days -= one_week_days;
7237 // ii. Set weeks to weeks + sign.
7238 result.weeks += sign;
7239 // iii. Set relativeTo to newRelativeTo.
7240 relative_to = new_relative_to;
7241 // v. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
7242 // oneWeek).
7244 isolate, move_result,
7245 MoveRelativeDate(isolate, calendar, relative_to, one_week,
7246 method_name),
7248 // v. Set newRelativeTo to moveResult.[[RelativeTo]].
7249 new_relative_to = move_result.relative_to;
7250 // vi. Set oneWeekDays to moveResult.[[Days]].
7251 one_week_days = move_result.days;
7252 }
7253 }
7254 // 12. Return ? CreateDateDurationRecord(years, months, weeks, days).
7255 return DateDurationRecord::Create(isolate, result.years, result.months,
7256 result.weeks, result.days);
7257}
7258
7259} // namespace
7260
7261// #sec-temporal.duration.compare
7263 Isolate* isolate, DirectHandle<Object> one_obj,
7264 DirectHandle<Object> two_obj, DirectHandle<Object> options_obj) {
7265 const char* method_name = "Temporal.Duration.compare";
7266 // 1. Set one to ? ToTemporalDuration(one).
7269 isolate, one,
7270 temporal::ToTemporalDuration(isolate, one_obj, method_name));
7271 // 2. Set two to ? ToTemporalDuration(two).
7274 isolate, two,
7275 temporal::ToTemporalDuration(isolate, two_obj, method_name));
7276 // 3. Set options to ? GetOptionsObject(options).
7279 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
7280 // 4. Let relativeTo be ? ToRelativeTemporalObject(options).
7283 isolate, relative_to,
7284 ToRelativeTemporalObject(isolate, options, method_name));
7285 // 5. LetCalculateOffsetShift shift1 be ? CalculateOffsetShift(relativeTo,
7286 // one.[[Years]], one.[[Months]], one.[[Weeks]], one.[[Days]]).
7287 int64_t shift1;
7289 isolate, shift1,
7290 CalculateOffsetShift(
7291 isolate, relative_to,
7292 {Object::NumberValue(one->years()),
7293 Object::NumberValue(one->months()),
7294 Object::NumberValue(one->weeks()), Object::NumberValue(one->days())},
7295 method_name),
7297 // 6. Let shift2 be ? CalculateOffsetShift(relativeTo, two.[[Years]],
7298 // two.[[Months]], two.[[Weeks]], two.[[Days]]).
7299 int64_t shift2;
7301 isolate, shift2,
7302 CalculateOffsetShift(
7303 isolate, relative_to,
7304 {Object::NumberValue(two->years()),
7305 Object::NumberValue(two->months()),
7306 Object::NumberValue(two->weeks()), Object::NumberValue(two->days())},
7307 method_name),
7309 // 7. If any of one.[[Years]], two.[[Years]], one.[[Months]], two.[[Months]],
7310 // one.[[Weeks]], or two.[[Weeks]] are not 0, then
7311 double days1, days2;
7312 if (Object::NumberValue(one->years()) != 0 ||
7313 Object::NumberValue(two->years()) != 0 ||
7314 Object::NumberValue(one->months()) != 0 ||
7315 Object::NumberValue(two->months()) != 0 ||
7316 Object::NumberValue(one->weeks()) != 0 ||
7317 Object::NumberValue(two->weeks()) != 0) {
7318 // a. Let unbalanceResult1 be ? UnbalanceDurationRelative(one.[[Years]],
7319 // one.[[Months]], one.[[Weeks]], one.[[Days]], "day", relativeTo).
7320 DateDurationRecord unbalance_result1;
7322 isolate, unbalance_result1,
7323 UnbalanceDurationRelative(isolate,
7324 {Object::NumberValue(one->years()),
7325 Object::NumberValue(one->months()),
7326 Object::NumberValue(one->weeks()),
7327 Object::NumberValue(one->days())},
7328 Unit::kDay, relative_to, method_name),
7330 // b. Let unbalanceResult2 be ? UnbalanceDurationRelative(two.[[Years]],
7331 // two.[[Months]], two.[[Weeks]], two.[[Days]], "day", relativeTo).
7332 DateDurationRecord unbalance_result2;
7334 isolate, unbalance_result2,
7335 UnbalanceDurationRelative(isolate,
7336 {Object::NumberValue(two->years()),
7337 Object::NumberValue(two->months()),
7338 Object::NumberValue(two->weeks()),
7339 Object::NumberValue(two->days())},
7340 Unit::kDay, relative_to, method_name),
7342 // c. Let days1 be unbalanceResult1.[[Days]].
7343 days1 = unbalance_result1.days;
7344 // d. Let days2 be unbalanceResult2.[[Days]].
7345 days2 = unbalance_result2.days;
7346 // 8. Else,
7347 } else {
7348 // a. Let days1 be one.[[Days]].
7349 days1 = Object::NumberValue(one->days());
7350 // b. Let days2 be two.[[Days]].
7351 days2 = Object::NumberValue(two->days());
7352 }
7353 // 9. Let ns1 be ! TotalDurationNanoseconds(days1, one.[[Hours]],
7354 // one.[[Minutes]], one.[[Seconds]], one.[[Milliseconds]],
7355 // one.[[Microseconds]], one.[[Nanoseconds]], shift1).
7356 DirectHandle<BigInt> ns1 = TotalDurationNanoseconds(
7357 isolate,
7358 {days1, Object::NumberValue(one->hours()),
7359 Object::NumberValue(one->minutes()), Object::NumberValue(one->seconds()),
7360 Object::NumberValue(one->milliseconds()),
7361 Object::NumberValue(one->microseconds()),
7362 Object::NumberValue(one->nanoseconds())},
7363 shift1);
7364 // 10. Let ns2 be ! TotalDurationNanoseconds(days2, two.[[Hours]],
7365 // two.[[Minutes]], two.[[Seconds]], two.[[Milliseconds]],
7366 // two.[[Microseconds]], two.[[Nanoseconds]], shift2).
7367 DirectHandle<BigInt> ns2 = TotalDurationNanoseconds(
7368 isolate,
7369 {days2, Object::NumberValue(two->hours()),
7370 Object::NumberValue(two->minutes()), Object::NumberValue(two->seconds()),
7371 Object::NumberValue(two->milliseconds()),
7372 Object::NumberValue(two->microseconds()),
7373 Object::NumberValue(two->nanoseconds())},
7374 shift2);
7375 switch (BigInt::CompareToBigInt(ns1, ns2)) {
7376 // 11. If ns1 > ns2, return 1𝔽.
7378 return direct_handle(Smi::FromInt(1), isolate);
7379 // 12. If ns1 < ns2, return -1𝔽.
7381 return direct_handle(Smi::FromInt(-1), isolate);
7382 // 13. Return +0𝔽.
7383 default:
7384 return direct_handle(Smi::FromInt(0), isolate);
7385 }
7386}
7387
7388// #sec-temporal.duration.from
7390 Isolate* isolate, DirectHandle<Object> item) {
7391 // 1. If Type(item) is Object and item has an [[InitializedTemporalDuration]]
7392 // internal slot, then
7393 if (IsJSTemporalDuration(*item)) {
7394 // a. Return ? CreateTemporalDuration(item.[[Years]], item.[[Months]],
7395 // item.[[Weeks]], item.[[Days]], item.[[Hours]], item.[[Minutes]],
7396 // item.[[Seconds]], item.[[Milliseconds]], item.[[Microseconds]],
7397 // item.[[Nanoseconds]]).
7398 auto duration = Cast<JSTemporalDuration>(item);
7399 return CreateTemporalDuration(
7400 isolate, {Object::NumberValue(duration->years()),
7401 Object::NumberValue(duration->months()),
7402 Object::NumberValue(duration->weeks()),
7403 {Object::NumberValue(duration->days()),
7404 Object::NumberValue(duration->hours()),
7405 Object::NumberValue(duration->minutes()),
7406 Object::NumberValue(duration->seconds()),
7407 Object::NumberValue(duration->milliseconds()),
7408 Object::NumberValue(duration->microseconds()),
7409 Object::NumberValue(duration->nanoseconds())}});
7410 }
7411 // 2. Return ? ToTemporalDuration(item).
7412 return temporal::ToTemporalDuration(isolate, item, "Temporal.Duration.from");
7413}
7414
7415namespace {
7416// #sec-temporal-maximumtemporaldurationroundingincrement
7417struct Maximum {
7419 double value;
7420};
7421Maximum MaximumTemporalDurationRoundingIncrement(Unit unit);
7422// #sec-temporal-totemporalroundingincrement
7423Maybe<double> ToTemporalRoundingIncrement(
7424 Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
7425 double dividend, bool dividend_is_defined, bool inclusive);
7426
7427// #sec-temporal-moverelativezoneddatetime
7428MaybeDirectHandle<JSTemporalZonedDateTime> MoveRelativeZonedDateTime(
7429 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
7430 const DateDurationRecord& duration, const char* method_name);
7431
7432// #sec-temporal-roundduration
7433Maybe<DurationRecordWithRemainder> RoundDuration(
7434 Isolate* isolate, const DurationRecord& duration, double increment,
7435 Unit unit, RoundingMode rounding_mode, DirectHandle<Object> relative_to,
7436 const char* method_name);
7437} // namespace
7438
7439// #sec-temporal.duration.prototype.round
7441 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
7442 DirectHandle<Object> round_to_obj) {
7443 const char* method_name = "Temporal.Duration.prototype.round";
7444 Factory* factory = isolate->factory();
7445 // 1. Let duration be the this value.
7446 // 2. Perform ? RequireInternalSlot(duration,
7447 // [[InitializedTemporalDuration]]).
7448 // 3. If roundTo is undefined, then
7449 if (IsUndefined(*round_to_obj)) {
7450 // a. Throw a TypeError exception.
7452 }
7453 DirectHandle<JSReceiver> round_to;
7454 // 4. If Type(roundTo) is String, then
7455 if (IsString(*round_to_obj)) {
7456 // a. Let paramString be roundTo.
7457 DirectHandle<String> param_string = Cast<String>(round_to_obj);
7458 // b. Set roundTo to ! OrdinaryObjectCreate(null).
7459 round_to = factory->NewJSObjectWithNullProto();
7460 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "_smallestUnit_",
7461 // paramString).
7462 CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
7463 factory->smallestUnit_string(),
7464 param_string, Just(kThrowOnError))
7465 .FromJust());
7466 } else {
7467 // a. Set roundTo to ? GetOptionsObject(roundTo).
7469 isolate, round_to,
7470 GetOptionsObject(isolate, round_to_obj, method_name));
7471 }
7472 // 6. Let smallestUnitPresent be true.
7473 bool smallest_unit_present = true;
7474 // 7. Let largestUnitPresent be true.
7475 bool largest_unit_present = true;
7476 // 8. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime,
7477 // undefined).
7478 Unit smallest_unit;
7480 isolate, smallest_unit,
7481 GetTemporalUnit(isolate, round_to, "smallestUnit", UnitGroup::kDateTime,
7482 Unit::kNotPresent, false, method_name),
7484 // 9. If smallestUnit is undefined, then
7485 if (smallest_unit == Unit::kNotPresent) {
7486 // a. Set smallestUnitPresent to false.
7487 smallest_unit_present = false;
7488 // b. Set smallestUnit to "nanosecond".
7489 smallest_unit = Unit::kNanosecond;
7490 }
7491 // 10. Let defaultLargestUnit be !
7492 // DefaultTemporalLargestUnit(duration.[[Years]], duration.[[Months]],
7493 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
7494 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
7495 // duration.[[Microseconds]]).
7496 Unit default_largest_unit = DefaultTemporalLargestUnit(
7497 {Object::NumberValue(duration->years()),
7498 Object::NumberValue(duration->months()),
7499 Object::NumberValue(duration->weeks()),
7500 {Object::NumberValue(duration->days()),
7501 Object::NumberValue(duration->hours()),
7502 Object::NumberValue(duration->minutes()),
7503 Object::NumberValue(duration->seconds()),
7504 Object::NumberValue(duration->milliseconds()),
7505 Object::NumberValue(duration->microseconds()),
7506 Object::NumberValue(duration->nanoseconds())}});
7507
7508 // 11. Set defaultLargestUnit to !
7509 // LargerOfTwoTemporalUnits(defaultLargestUnit, smallestUnit).
7510 default_largest_unit =
7511 LargerOfTwoTemporalUnits(default_largest_unit, smallest_unit);
7512 // 12. Let largestUnit be ? GetTemporalUnit(roundTo, "largestUnit", datetime,
7513 // undefined, « "auto" »).
7514 Unit largest_unit;
7516 isolate, largest_unit,
7517 GetTemporalUnit(isolate, round_to, "largestUnit", UnitGroup::kDateTime,
7518 Unit::kNotPresent, false, method_name, Unit::kAuto),
7520 // 13. If largestUnit is undefined, then
7521 if (largest_unit == Unit::kNotPresent) {
7522 // a. Set largestUnitPresent to false.
7523 largest_unit_present = false;
7524 // b. Set largestUnit to defaultLargestUnit.
7525 largest_unit = default_largest_unit;
7526 // 14. Else if largestUnit is "auto", then
7527 } else if (largest_unit == Unit::kAuto) {
7528 // a. Set largestUnit to defaultLargestUnit.
7529 largest_unit = default_largest_unit;
7530 }
7531 // 15. If smallestUnitPresent is false and largestUnitPresent is false, then
7532 if (!smallest_unit_present && !largest_unit_present) {
7533 // a. Throw a RangeError exception.
7535 }
7536 // 16. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not
7537 // largestUnit, throw a RangeError exception.
7538 if (LargerOfTwoTemporalUnits(largest_unit, smallest_unit) != largest_unit) {
7540 }
7541 // 17. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
7544 isolate, rounding_mode,
7545 ToTemporalRoundingMode(isolate, round_to, RoundingMode::kHalfExpand,
7546 method_name),
7548 // 18. Let maximum be !
7549 // MaximumTemporalDurationRoundingIncrement(smallestUnit).
7550 Maximum maximum = MaximumTemporalDurationRoundingIncrement(smallest_unit);
7551
7552 // 19. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo,
7553 // maximum, false).
7554 double rounding_increment;
7556 isolate, rounding_increment,
7557 ToTemporalRoundingIncrement(isolate, round_to, maximum.value,
7558 maximum.defined, false),
7560 // 20. Let relativeTo be ? ToRelativeTemporalObject(roundTo).
7563 isolate, relative_to,
7564 ToRelativeTemporalObject(isolate, round_to, method_name));
7565 // 21. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]],
7566 // duration.[[Months]], duration.[[Weeks]], duration.[[Days]], largestUnit,
7567 // relativeTo).
7568 DateDurationRecord unbalance_result;
7570 isolate, unbalance_result,
7571 UnbalanceDurationRelative(isolate,
7572 {Object::NumberValue(duration->years()),
7573 Object::NumberValue(duration->months()),
7574 Object::NumberValue(duration->weeks()),
7575 Object::NumberValue(duration->days())},
7576 largest_unit, relative_to, method_name),
7578 // 22. Let roundResult be (? RoundDuration(unbalanceResult.[[Years]],
7579 // unbalanceResult.[[Months]], unbalanceResult.[[Weeks]],
7580 // unbalanceResult.[[Days]], duration.[[Hours]], duration.[[Minutes]],
7581 // duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]],
7582 // duration.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode,
7583 // relativeTo)).[[DurationRecord]].
7584 DurationRecordWithRemainder round_result;
7586 isolate, round_result,
7587 RoundDuration(
7588 isolate,
7589 {unbalance_result.years,
7590 unbalance_result.months,
7591 unbalance_result.weeks,
7592 {unbalance_result.days, Object::NumberValue(duration->hours()),
7593 Object::NumberValue(duration->minutes()),
7594 Object::NumberValue(duration->seconds()),
7595 Object::NumberValue(duration->milliseconds()),
7596 Object::NumberValue(duration->microseconds()),
7597 Object::NumberValue(duration->nanoseconds())}},
7599 method_name),
7601
7602 // 23. Let adjustResult be ? AdjustRoundedDurationDays(roundResult.[[Years]],
7603 // roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]],
7604 // roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]],
7605 // roundResult.[[Milliseconds]], roundResult.[[Microseconds]],
7606 // roundResult.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode,
7607 // relativeTo).
7608 DurationRecord adjust_result;
7610 isolate, adjust_result,
7611 AdjustRoundedDurationDays(isolate, round_result.record,
7613 rounding_mode, relative_to, method_name),
7615 // 24. Let balanceResult be ? BalanceDurationRelative(adjustResult.[[Years]],
7616 // adjustResult.[[Months]], adjustResult.[[Weeks]], adjustResult.[[Days]],
7617 // largestUnit, relativeTo).
7618 DateDurationRecord balance_result;
7620 isolate, balance_result,
7621 BalanceDurationRelative(
7622 isolate,
7623 {adjust_result.years, adjust_result.months, adjust_result.weeks,
7624 adjust_result.time_duration.days},
7625 largest_unit, relative_to, method_name),
7627 // 25. If Type(relativeTo) is Object and relativeTo has an
7628 // [[InitializedTemporalZonedDateTime]] internal slot, then
7629 if (IsJSTemporalZonedDateTime(*relative_to)) {
7630 // a. Set relativeTo to ? MoveRelativeZonedDateTime(relativeTo,
7631 // balanceResult.[[Years]], balanceResult.[[Months]],
7632 // balanceResult.[[Weeks]], 0).
7634 isolate, relative_to,
7635 MoveRelativeZonedDateTime(isolate,
7637 {balance_result.years, balance_result.months,
7638 balance_result.weeks, 0},
7639 method_name));
7640 }
7641 // 26. Let result be ? BalanceDuration(balanceResult.[[Days]],
7642 // adjustResult.[[Hours]], adjustResult.[[Minutes]], adjustResult.[[Seconds]],
7643 // adjustResult.[[Milliseconds]], adjustResult.[[Microseconds]],
7644 // adjustResult.[[Nanoseconds]], largestUnit, relativeTo).
7645 TimeDurationRecord result;
7647 isolate, result,
7648 BalanceDuration(isolate, largest_unit, relative_to,
7649 {balance_result.days, adjust_result.time_duration.hours,
7650 adjust_result.time_duration.minutes,
7651 adjust_result.time_duration.seconds,
7652 adjust_result.time_duration.milliseconds,
7653 adjust_result.time_duration.microseconds,
7654 adjust_result.time_duration.nanoseconds},
7655 method_name),
7657 // 27. Return ! CreateTemporalDuration(balanceResult.[[Years]],
7658 // balanceResult.[[Months]], balanceResult.[[Weeks]], result.[[Days]],
7659 // result.[[Hours]], result.[[Minutes]], result.[[Seconds]],
7660 // result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
7661 return CreateTemporalDuration(isolate,
7662 {balance_result.years, balance_result.months,
7663 balance_result.weeks, result})
7664 .ToHandleChecked();
7665}
7666
7667// #sec-temporal.duration.prototype.total
7669 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
7670 DirectHandle<Object> total_of_obj) {
7671 const char* method_name = "Temporal.Duration.prototype.total";
7672 Factory* factory = isolate->factory();
7673 // 1. Let duration be the this value.
7674 // 2. Perform ? RequireInternalSlot(duration,
7675 // [[InitializedTemporalDuration]]).
7676 // 3. If totalOf is undefined, throw a TypeError exception.
7677 if (IsUndefined(*total_of_obj, isolate)) {
7679 }
7680
7681 DirectHandle<JSReceiver> total_of;
7682 // 4. If Type(totalOf) is String, then
7683 if (IsString(*total_of_obj)) {
7684 // a. Let paramString be totalOf.
7685 DirectHandle<String> param_string = Cast<String>(total_of_obj);
7686 // b. Set totalOf to ! OrdinaryObjectCreate(null).
7687 total_of = factory->NewJSObjectWithNullProto();
7688 // c. Perform ! CreateDataPropertyOrThrow(total_of, "unit", paramString).
7689 CHECK(JSReceiver::CreateDataProperty(isolate, total_of,
7690 factory->unit_string(), param_string,
7692 .FromJust());
7693 } else {
7694 // 5. Set totalOf to ? GetOptionsObject(totalOf).
7696 isolate, total_of,
7697 GetOptionsObject(isolate, total_of_obj, method_name));
7698 }
7699
7700 // 6. Let relativeTo be ? ToRelativeTemporalObject(totalOf).
7703 isolate, relative_to,
7704 ToRelativeTemporalObject(isolate, total_of, method_name));
7705 // 7. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required).
7706 Unit unit;
7708 isolate, unit,
7709 GetTemporalUnit(isolate, total_of, "unit", UnitGroup::kDateTime,
7710 Unit::kNotPresent, true, method_name),
7712 // 8. Let unbalanceResult be ? UnbalanceDurationRelative(duration.[[Years]],
7713 // duration.[[Months]], duration.[[Weeks]], duration.[[Days]], unit,
7714 // relativeTo).
7715 DateDurationRecord unbalance_result;
7717 isolate, unbalance_result,
7718 UnbalanceDurationRelative(isolate,
7719 {Object::NumberValue(duration->years()),
7720 Object::NumberValue(duration->months()),
7721 Object::NumberValue(duration->weeks()),
7722 Object::NumberValue(duration->days())},
7723 unit, relative_to, method_name),
7725
7726 // 9. Let intermediate be undefined.
7727 DirectHandle<Object> intermediate = factory->undefined_value();
7728
7729 // 8. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot,
7730 // then
7731 if (IsJSTemporalZonedDateTime(*relative_to)) {
7732 // a. Set intermediate to ? MoveRelativeZonedDateTime(relativeTo,
7733 // unbalanceResult.[[Years]], unbalanceResult.[[Months]],
7734 // unbalanceResult.[[Weeks]], 0).
7736 isolate, intermediate,
7737 MoveRelativeZonedDateTime(
7739 {unbalance_result.years, unbalance_result.months,
7740 unbalance_result.weeks, 0},
7741 method_name));
7742 }
7743
7744 // 11. Let balanceResult be ?
7745 // BalancePossiblyInfiniteDuration(unbalanceResult.[[Days]],
7746 // duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]],
7747 // duration.[[Milliseconds]], duration.[[Microseconds]],
7748 // duration.[[Nanoseconds]], unit, intermediate).
7749 BalancePossiblyInfiniteDurationResult balance_result;
7751 isolate, balance_result,
7752 BalancePossiblyInfiniteDuration(
7753 isolate, unit, intermediate,
7754 {unbalance_result.days, Object::NumberValue(duration->hours()),
7755 Object::NumberValue(duration->minutes()),
7756 Object::NumberValue(duration->seconds()),
7757 Object::NumberValue(duration->milliseconds()),
7758 Object::NumberValue(duration->microseconds()),
7759 Object::NumberValue(duration->nanoseconds())},
7760 method_name),
7762 // 12. If balanceResult is positive overflow, return +∞𝔽.
7763 if (balance_result.overflow == BalanceOverflow::kPositive) {
7764 return factory->infinity_value();
7765 }
7766 // 13. If balanceResult is negative overflow, return -∞𝔽.
7767 if (balance_result.overflow == BalanceOverflow::kNegative) {
7768 return factory->minus_infinity_value();
7769 }
7770 // 14. Assert: balanceResult is a Time Duration Record.
7771 DCHECK_EQ(balance_result.overflow, BalanceOverflow::kNone);
7772 // 15. Let roundRecord be ? RoundDuration(unbalanceResult.[[Years]],
7773 // unbalanceResult.[[Months]], unbalanceResult.[[Weeks]],
7774 // balanceResult.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]],
7775 // balanceResult.[[Seconds]], balanceResult.[[Milliseconds]],
7776 // balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]], 1, unit,
7777 // "trunc", relativeTo).
7778 DurationRecordWithRemainder round_record;
7780 isolate, round_record,
7781 RoundDuration(isolate,
7782 {unbalance_result.years, unbalance_result.months,
7783 unbalance_result.weeks, balance_result.value},
7784 1, unit, RoundingMode::kTrunc, relative_to, method_name),
7786 // 16. Let roundResult be roundRecord.[[DurationRecord]].
7787 DurationRecord& round_result = round_record.record;
7788
7789 double whole;
7790 switch (unit) {
7791 // 17. If unit is "year", then
7792 case Unit::kYear:
7793 // a. Let whole be roundResult.[[Years]].
7794 whole = round_result.years;
7795 break;
7796 // 18. If unit is "month", then
7797 case Unit::kMonth:
7798 // a. Let whole be roundResult.[[Months]].
7799 whole = round_result.months;
7800 break;
7801 // 19. If unit is "week", then
7802 case Unit::kWeek:
7803 // a. Let whole be roundResult.[[Weeks]].
7804 whole = round_result.weeks;
7805 break;
7806 // 20. If unit is "day", then
7807 case Unit::kDay:
7808 // a. Let whole be roundResult.[[Days]].
7809 whole = round_result.time_duration.days;
7810 break;
7811 // 21. If unit is "hour", then
7812 case Unit::kHour:
7813 // a. Let whole be roundResult.[[Hours]].
7814 whole = round_result.time_duration.hours;
7815 break;
7816 // 22. If unit is "minute", then
7817 case Unit::kMinute:
7818 // a. Let whole be roundResult.[[Minutes]].
7819 whole = round_result.time_duration.minutes;
7820 break;
7821 // 23. If unit is "second", then
7822 case Unit::kSecond:
7823 // a. Let whole be roundResult.[[Seconds]].
7824 whole = round_result.time_duration.seconds;
7825 break;
7826 // 24. If unit is "millisecond", then
7827 case Unit::kMillisecond:
7828 // a. Let whole be roundResult.[[Milliseconds]].
7829 whole = round_result.time_duration.milliseconds;
7830 break;
7831 // 25. If unit is "microsecond", then
7832 case Unit::kMicrosecond:
7833 // a. Let whole be roundResult.[[Microseconds]].
7834 whole = round_result.time_duration.microseconds;
7835 break;
7836 // 26. If unit is "naoosecond", then
7837 case Unit::kNanosecond:
7838 // a. Let whole be roundResult.[[Nanoseconds]].
7839 whole = round_result.time_duration.nanoseconds;
7840 break;
7841 default:
7842 UNREACHABLE();
7843 }
7844 // 27. Return 𝔽(whole + roundRecord.[[Remainder]]).
7845 return factory->NewNumber(whole + round_record.remainder);
7846}
7847
7848namespace temporal {
7849// #sec-temporal-topartialduration
7851 Isolate* isolate, DirectHandle<Object> temporal_duration_like_obj,
7852 const DurationRecord& input) {
7853 // 1. If Type(temporalDurationLike) is not Object, then
7854 if (!IsJSReceiver(*temporal_duration_like_obj)) {
7855 // a. Throw a TypeError exception.
7858 }
7859 DirectHandle<JSReceiver> temporal_duration_like =
7860 Cast<JSReceiver>(temporal_duration_like_obj);
7861
7862 // 2. Let result be a new partial Duration Record with each field set to
7863 // undefined.
7864 DurationRecord result = input;
7865
7866 // 3. Let any be false.
7867 bool any = false;
7868
7869 // Table 8: Duration Record Fields
7870 // #table-temporal-duration-record-fields
7871 // 4. For each row of Table 8, except the header row, in table order, do
7873 isolate, any,
7875 isolate, temporal_duration_like,
7876 [](Isolate* isolate, DirectHandle<JSReceiver> temporal_duration_like,
7877 DirectHandle<String> prop, double* field) -> Maybe<bool> {
7878 bool not_undefined = false;
7879 // a. Let prop be the Property value of the current row.
7881 // b. Let val be ? Get(temporalDurationLike, prop).
7883 isolate, val,
7884 JSReceiver::GetProperty(isolate, temporal_duration_like, prop),
7885 Nothing<bool>());
7886 // c. If val is not undefined, then
7887 if (!IsUndefined(*val)) {
7888 // i. Set any to true.
7889 not_undefined = true;
7890 // ii. Let val be 𝔽(? ToIntegerWithoutRounding(val)).
7891 // iii. Set result's field whose name is the Field Name value of
7892 // the current row to val.
7894 isolate, *field, ToIntegerWithoutRounding(isolate, val),
7895 Nothing<bool>());
7896 }
7897 return Just(not_undefined);
7898 },
7899 &result),
7901
7902 // 5. If any is false, then
7903 if (!any) {
7904 // a. Throw a TypeError exception.
7907 }
7908 // 6. Return result.
7909 return Just(result);
7910}
7911
7912} // namespace temporal
7913
7914// #sec-temporal.duration.prototype.with
7916 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
7917 DirectHandle<Object> temporal_duration_like) {
7918 DurationRecord partial;
7920 isolate, partial,
7922 isolate, temporal_duration_like,
7923 {Object::NumberValue(duration->years()),
7924 Object::NumberValue(duration->months()),
7925 Object::NumberValue(duration->weeks()),
7926 {Object::NumberValue(duration->days()),
7927 Object::NumberValue(duration->hours()),
7928 Object::NumberValue(duration->minutes()),
7929 Object::NumberValue(duration->seconds()),
7930 Object::NumberValue(duration->milliseconds()),
7931 Object::NumberValue(duration->microseconds()),
7932 Object::NumberValue(duration->nanoseconds())}}),
7934
7935 // 24. Return ? CreateTemporalDuration(years, months, weeks, days, hours,
7936 // minutes, seconds, milliseconds, microseconds, nanoseconds).
7937 return CreateTemporalDuration(isolate, partial);
7938}
7939
7940// #sec-get-temporal.duration.prototype.sign
7942 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
7943 // 1. Let duration be the this value.
7944 // 2. Perform ? RequireInternalSlot(duration,
7945 // [[InitializedTemporalDuration]]).
7946 // 3. Return ! DurationSign(duration.[[Years]], duration.[[Months]],
7947 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
7948 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
7949 // duration.[[Microseconds]], duration.[[Nanoseconds]]).
7951 {Object::NumberValue(duration->years()),
7952 Object::NumberValue(duration->months()),
7953 Object::NumberValue(duration->weeks()),
7954 {Object::NumberValue(duration->days()),
7955 Object::NumberValue(duration->hours()),
7956 Object::NumberValue(duration->minutes()),
7957 Object::NumberValue(duration->seconds()),
7958 Object::NumberValue(duration->milliseconds()),
7959 Object::NumberValue(duration->microseconds()),
7960 Object::NumberValue(duration->nanoseconds())}})),
7961 isolate);
7962}
7963
7964// #sec-get-temporal.duration.prototype.blank
7966 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
7967 // 1. Let duration be the this value.
7968 // 2. Perform ? RequireInternalSlot(duration,
7969 // [[InitializedTemporalDuration]]).
7970 // 3. Let sign be ! DurationSign(duration.[[Years]], duration.[[Months]],
7971 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
7972 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
7973 // duration.[[Microseconds]], duration.[[Nanoseconds]]).
7974 // 4. If sign = 0, return true.
7975 // 5. Return false.
7976 int32_t sign =
7977 DurationRecord::Sign({Object::NumberValue(duration->years()),
7978 Object::NumberValue(duration->months()),
7979 Object::NumberValue(duration->weeks()),
7980 {Object::NumberValue(duration->days()),
7981 Object::NumberValue(duration->hours()),
7982 Object::NumberValue(duration->minutes()),
7983 Object::NumberValue(duration->seconds()),
7984 Object::NumberValue(duration->milliseconds()),
7985 Object::NumberValue(duration->microseconds()),
7986 Object::NumberValue(duration->nanoseconds())}});
7987 return isolate->factory()->ToBoolean(sign == 0);
7988}
7989
7990namespace {
7991// #sec-temporal-createnegateddurationrecord
7992// see https://github.com/tc39/proposal-temporal/pull/2281
7993Maybe<DurationRecord> CreateNegatedDurationRecord(
7994 Isolate* isolate, const DurationRecord& duration) {
7995 return CreateDurationRecord(
7996 isolate,
7997 {-duration.years,
7998 -duration.months,
7999 -duration.weeks,
8000 {-duration.time_duration.days, -duration.time_duration.hours,
8001 -duration.time_duration.minutes, -duration.time_duration.seconds,
8002 -duration.time_duration.milliseconds,
8003 -duration.time_duration.microseconds,
8004 -duration.time_duration.nanoseconds}});
8005}
8006
8007// #sec-temporal-createnegatedtemporalduration
8008MaybeDirectHandle<JSTemporalDuration> CreateNegatedTemporalDuration(
8009 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
8011 // 1. Assert: Type(duration) is Object.
8012 // 2. Assert: duration has an [[InitializedTemporalDuration]] internal slot.
8013 // 3. Return ! CreateTemporalDuration(−duration.[[Years]],
8014 // −duration.[[Months]], −duration.[[Weeks]], −duration.[[Days]],
8015 // −duration.[[Hours]], −duration.[[Minutes]], −duration.[[Seconds]],
8016 // −duration.[[Milliseconds]], −duration.[[Microseconds]],
8017 // −duration.[[Nanoseconds]]).
8018 return CreateTemporalDuration(
8019 isolate, {-Object::NumberValue(duration->years()),
8020 -Object::NumberValue(duration->months()),
8021 -Object::NumberValue(duration->weeks()),
8022 {-Object::NumberValue(duration->days()),
8023 -Object::NumberValue(duration->hours()),
8024 -Object::NumberValue(duration->minutes()),
8025 -Object::NumberValue(duration->seconds()),
8026 -Object::NumberValue(duration->milliseconds()),
8027 -Object::NumberValue(duration->microseconds()),
8028 -Object::NumberValue(duration->nanoseconds())}})
8029 .ToHandleChecked();
8030}
8031
8032} // namespace
8033
8034// #sec-temporal.duration.prototype.negated
8036 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
8037 // Let duration be the this value.
8038 // 2. Perform ? RequireInternalSlot(duration,
8039 // [[InitializedTemporalDuration]]).
8040
8041 // 3. Return ! CreateNegatedTemporalDuration(duration).
8042 return CreateNegatedTemporalDuration(isolate, duration).ToHandleChecked();
8043}
8044
8045// #sec-temporal.duration.prototype.abs
8047 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
8048 // 1. Let duration be the this value.
8049 // 2. Perform ? RequireInternalSlot(duration,
8050 // [[InitializedTemporalDuration]]).
8051 // 3. Return ? CreateTemporalDuration(abs(duration.[[Years]]),
8052 // abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]),
8053 // abs(duration.[[Hours]]), abs(duration.[[Minutes]]),
8054 // abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]),
8055 // abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])).
8056 return CreateTemporalDuration(
8057 isolate, {std::abs(Object::NumberValue(duration->years())),
8058 std::abs(Object::NumberValue(duration->months())),
8059 std::abs(Object::NumberValue(duration->weeks())),
8060 {std::abs(Object::NumberValue(duration->days())),
8061 std::abs(Object::NumberValue(duration->hours())),
8062 std::abs(Object::NumberValue(duration->minutes())),
8063 std::abs(Object::NumberValue(duration->seconds())),
8064 std::abs(Object::NumberValue(duration->milliseconds())),
8065 std::abs(Object::NumberValue(duration->microseconds())),
8066 std::abs(Object::NumberValue(duration->nanoseconds()))}});
8067}
8068
8069namespace {
8070
8071// #sec-temporal-interpretisodatetimeoffset
8072MaybeDirectHandle<BigInt> InterpretISODateTimeOffset(
8073 Isolate* isolate, const DateTimeRecord& data,
8074 OffsetBehaviour offset_behaviour, int64_t offset_nanoseconds,
8075 DirectHandle<JSReceiver> time_zone, Disambiguation disambiguation,
8076 Offset offset_option, MatchBehaviour match_behaviour,
8077 const char* method_name);
8078
8079// #sec-temporal-interprettemporaldatetimefields
8080Maybe<temporal::DateTimeRecord> InterpretTemporalDateTimeFields(
8083 const char* method_name);
8084
8085// #sec-temporal-torelativetemporalobject
8086MaybeDirectHandle<Object> ToRelativeTemporalObject(
8087 Isolate* isolate, DirectHandle<JSReceiver> options,
8088 const char* method_name) {
8090
8091 Factory* factory = isolate->factory();
8092 // 1. Assert: Type(options) is Object.
8093 // 2. Let value be ? Get(options, "relativeTo").
8094 DirectHandle<Object> value_obj;
8096 isolate, value_obj,
8097 JSReceiver::GetProperty(isolate, options, factory->relativeTo_string()));
8098 // 3. If value is undefined, then
8099 if (IsUndefined(*value_obj)) {
8100 // a. Return value.
8101 return value_obj;
8102 }
8103 // 4. Let offsetBehaviour be option.
8104 OffsetBehaviour offset_behaviour = OffsetBehaviour::kOption;
8105
8106 // 5. Let matchBehaviour be match exactly.
8107 MatchBehaviour match_behaviour = MatchBehaviour::kMatchExactly;
8108
8109 DirectHandle<Object> time_zone_obj = factory->undefined_value();
8110 DirectHandle<Object> offset_string_obj;
8111 temporal::DateTimeRecord result;
8112 DirectHandle<JSReceiver> calendar;
8113 // 6. If Type(value) is Object, then
8114 if (IsJSReceiver(*value_obj)) {
8115 DirectHandle<JSReceiver> value = Cast<JSReceiver>(value_obj);
8116 // a. If value has either an [[InitializedTemporalDate]] or
8117 // [[InitializedTemporalZonedDateTime]] internal slot, then
8118 if (IsJSTemporalPlainDate(*value) || IsJSTemporalZonedDateTime(*value)) {
8119 // i. Return value.
8120 return value;
8121 }
8122 // b. If value has an [[InitializedTemporalDateTime]] internal slot, then
8123 if (IsJSTemporalPlainDateTime(*value)) {
8124 auto date_time_value = Cast<JSTemporalPlainDateTime>(value);
8125 // i. Return ? CreateTemporalDateTime(value.[[ISOYear]],
8126 // value.[[ISOMonth]], value.[[ISODay]],
8127 // value.[[Calendar]]).
8128 return CreateTemporalDate(
8129 isolate,
8130 {date_time_value->iso_year(), date_time_value->iso_month(),
8131 date_time_value->iso_day()},
8132 direct_handle(date_time_value->calendar(), isolate));
8133 }
8134 // c. Let calendar be ? GetTemporalCalendarWithISODefault(value).
8136 isolate, calendar,
8137 GetTemporalCalendarWithISODefault(isolate, value, method_name));
8138 // d. Let fieldNames be ? CalendarFields(calendar, « "day", "hour",
8139 // "microsecond", "millisecond", "minute", "month", "monthCode",
8140 // "nanosecond", "second", "year" »).
8141 DirectHandle<FixedArray> field_names = All10UnitsInFixedArray(isolate);
8142 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
8143 CalendarFields(isolate, calendar, field_names));
8144 // e. Let fields be ? PrepareTemporalFields(value, fieldNames, «»).
8145 DirectHandle<JSReceiver> fields;
8147 isolate, fields,
8148 PrepareTemporalFields(isolate, value, field_names,
8149 RequiredFields::kNone));
8150 // f. Let dateOptions be ! OrdinaryObjectCreate(null).
8151 DirectHandle<JSObject> date_options = factory->NewJSObjectWithNullProto();
8152 // g. Perform ! CreateDataPropertyOrThrow(dateOptions, "overflow",
8153 // "constrain").
8155 isolate, date_options, factory->overflow_string(),
8156 factory->constrain_string(), Just(kThrowOnError))
8157 .FromJust());
8158 // h. Let result be ? InterpretTemporalDateTimeFields(calendar, fields,
8159 // dateOptions).
8161 isolate, result,
8162 InterpretTemporalDateTimeFields(isolate, calendar, fields, date_options,
8163 method_name),
8164 DirectHandle<Object>());
8165 // i. Let offsetString be ? Get(value, "offset").
8167 isolate, offset_string_obj,
8168 JSReceiver::GetProperty(isolate, value, factory->offset_string()));
8169 // j. Let timeZone be ? Get(value, "timeZone").
8171 isolate, time_zone_obj,
8172 JSReceiver::GetProperty(isolate, value, factory->timeZone_string()));
8173 // k. If timeZone is not undefined, then
8174 if (!IsUndefined(*time_zone_obj)) {
8175 // i. Set timeZone to ? ToTemporalTimeZone(timeZone).
8176 DirectHandle<JSReceiver> time_zone;
8178 isolate, time_zone,
8179 temporal::ToTemporalTimeZone(isolate, time_zone_obj, method_name));
8180 time_zone_obj = time_zone;
8181 }
8182
8183 // l. If offsetString is undefined, then
8184 if (IsUndefined(*offset_string_obj)) {
8185 // i. Set offsetBehaviour to wall.
8186 offset_behaviour = OffsetBehaviour::kWall;
8187 }
8188 // 6. Else,
8189 } else {
8190 // a. Let string be ? ToString(value).
8191 DirectHandle<String> string;
8192 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
8193 Object::ToString(isolate, value_obj));
8194 DateTimeRecordWithCalendar parsed_result;
8195 // b. Let result be ? ParseTemporalRelativeToString(string).
8197 isolate, parsed_result, ParseTemporalRelativeToString(isolate, string),
8198 DirectHandle<Object>());
8199 result = {parsed_result.date, parsed_result.time};
8200 // c. Let calendar be ?
8201 // ToTemporalCalendarWithISODefault(result.[[Calendar]]).
8203 isolate, calendar,
8204 ToTemporalCalendarWithISODefault(isolate, parsed_result.calendar,
8205 method_name));
8206
8207 // d. Let offsetString be result.[[TimeZone]].[[OffsetString]].
8208 offset_string_obj = parsed_result.time_zone.offset_string;
8209
8210 // e. Let timeZoneName be result.[[TimeZone]].[[Name]].
8211 DirectHandle<Object> time_zone_name_obj = parsed_result.time_zone.name;
8212
8213 // f. If timeZoneName is undefined, then
8214 if (IsUndefined(*time_zone_name_obj)) {
8215 // i. Let timeZone be undefined.
8216 time_zone_obj = factory->undefined_value();
8217 // g. Else,
8218 } else {
8219 // i. If ParseText(StringToCodePoints(timeZoneName),
8220 // TimeZoneNumericUTCOffset) is a List of errors, then
8221 DCHECK(IsString(*time_zone_name_obj));
8222 DirectHandle<String> time_zone_name = Cast<String>(time_zone_name_obj);
8223 std::optional<ParsedISO8601Result> parsed =
8224 TemporalParser::ParseTimeZoneNumericUTCOffset(isolate,
8225 time_zone_name);
8226 if (!parsed.has_value()) {
8227 // 1. If ! IsValidTimeZoneName(timeZoneName) is false, throw a
8228 // RangeError exception.
8229 if (!IsValidTimeZoneName(isolate, time_zone_name)) {
8232 DirectHandle<Object>());
8233 }
8234 // 2. Set timeZoneName to ! CanonicalizeTimeZoneName(timeZoneName).
8235 time_zone_name = CanonicalizeTimeZoneName(isolate, time_zone_name);
8236 }
8237 // ii. Let timeZone be ! CreateTemporalTimeZone(timeZoneName).
8238 DirectHandle<JSTemporalTimeZone> time_zone =
8239 temporal::CreateTemporalTimeZone(isolate, time_zone_name)
8240 .ToHandleChecked();
8241 time_zone_obj = time_zone;
8242
8243 // iii. If result.[[TimeZone]].[[Z]] is true, then
8244 if (parsed_result.time_zone.z) {
8245 // 1. Set offsetBehaviour to exact.
8246 offset_behaviour = OffsetBehaviour::kExact;
8247 // iv. Else if offsetString is undefined, then
8248 } else if (IsUndefined(*offset_string_obj)) {
8249 // 1. Set offsetBehaviour to wall.
8250 offset_behaviour = OffsetBehaviour::kWall;
8251 }
8252 // v. Set matchBehaviour to match minutes.
8253 match_behaviour = MatchBehaviour::kMatchMinutes;
8254 }
8255 }
8256 // 8. If timeZone is undefined, then
8257 if (IsUndefined(*time_zone_obj)) {
8258 // a. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
8259 // result.[[Day]], calendar).
8260 return CreateTemporalDate(isolate, result.date, calendar);
8261 }
8262 DCHECK(IsJSReceiver(*time_zone_obj));
8263 DirectHandle<JSReceiver> time_zone = Cast<JSReceiver>(time_zone_obj);
8264 // 9. If offsetBehaviour is option, then
8265 int64_t offset_ns = 0;
8266 if (offset_behaviour == OffsetBehaviour::kOption) {
8267 // a. Set offsetString to ? ToString(offsetString).
8268 DirectHandle<String> offset_string;
8270 Object::ToString(isolate, offset_string_obj));
8271 // b. Let offsetNs be ? ParseTimeZoneOffsetString(offset_string).
8273 isolate, offset_ns, ParseTimeZoneOffsetString(isolate, offset_string),
8274 DirectHandle<Object>());
8275 // 10. Else,
8276 } else {
8277 // a. Let offsetNs be 0.
8278 offset_ns = 0;
8279 }
8280 // 11. Let epochNanoseconds be ? InterpretISODateTimeOffset(result.[[Year]],
8281 // result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]],
8282 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
8283 // result.[[Nanosecond]], offsetBehaviour, offsetNs, timeZone, "compatible",
8284 // "reject", matchBehaviour).
8285 DirectHandle<BigInt> epoch_nanoseconds;
8287 isolate, epoch_nanoseconds,
8288 InterpretISODateTimeOffset(isolate, result, offset_behaviour, offset_ns,
8289 time_zone, Disambiguation::kCompatible,
8290 Offset::kReject, match_behaviour,
8291 method_name));
8292
8293 // 12. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
8294 // calendar).
8295 return CreateTemporalZonedDateTime(isolate, epoch_nanoseconds, time_zone,
8296 calendar);
8297}
8298
8299// #sec-temporal-defaulttemporallargestunit
8300Unit DefaultTemporalLargestUnit(const DurationRecord& dur) {
8301 // 1. If years is not zero, return "year".
8302 if (dur.years != 0) return Unit::kYear;
8303 // 2. If months is not zero, return "month".
8304 if (dur.months != 0) return Unit::kMonth;
8305 // 3. If weeks is not zero, return "week".
8306 if (dur.weeks != 0) return Unit::kWeek;
8307 // 4. If days is not zero, return "day".
8308 if (dur.time_duration.days != 0) return Unit::kDay;
8309 // 5dur.. If hours is not zero, return "hour".
8310 if (dur.time_duration.hours != 0) return Unit::kHour;
8311 // 6. If minutes is not zero, return "minute".
8312 if (dur.time_duration.minutes != 0) return Unit::kMinute;
8313 // 7. If seconds is not zero, return "second".
8314 if (dur.time_duration.seconds != 0) return Unit::kSecond;
8315 // 8. If milliseconds is not zero, return "millisecond".
8316 if (dur.time_duration.milliseconds != 0) return Unit::kMillisecond;
8317 // 9. If microseconds is not zero, return "microsecond".
8318 if (dur.time_duration.microseconds != 0) return Unit::kMicrosecond;
8319 // 10. Return "nanosecond".
8320 return Unit::kNanosecond;
8321}
8322
8323// #sec-temporal-differencezoneddatetime
8324Maybe<DurationRecord> DifferenceZonedDateTime(
8325 Isolate* isolate, DirectHandle<BigInt> ns1, DirectHandle<BigInt> ns2,
8326 DirectHandle<JSReceiver> time_zone, DirectHandle<JSReceiver> calendar,
8327 Unit largest_unit, DirectHandle<JSReceiver> options,
8328 const char* method_name) {
8330
8331 // 1. If ns1 is ns2, then
8333 // a. Return ! CreateDurationRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
8334 return Just(CreateDurationRecord(isolate, {0, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
8335 .ToChecked());
8336 }
8337 // 2. Let startInstant be ! CreateTemporalInstant(ns1).
8338 DirectHandle<JSTemporalInstant> start_instant =
8339 temporal::CreateTemporalInstant(isolate, ns1).ToHandleChecked();
8340 // 3. Let startDateTime be ?
8341 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, startInstant,
8342 // calendar).
8343 DirectHandle<JSTemporalPlainDateTime> start_date_time;
8345 isolate, start_date_time,
8347 isolate, time_zone, start_instant, calendar, method_name),
8349 // 4. Let endInstant be ! CreateTemporalInstant(ns2).
8350 DirectHandle<JSTemporalInstant> end_instant =
8351 temporal::CreateTemporalInstant(isolate, ns2).ToHandleChecked();
8352 // 5. Let endDateTime be ?
8353 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, endInstant,
8354 // calendar).
8355 DirectHandle<JSTemporalPlainDateTime> end_date_time;
8357 isolate, end_date_time,
8359 isolate, time_zone, end_instant, calendar, method_name),
8361 // 6. Let dateDifference be ? DifferenceISODateTime(startDateTime.[[ISOYear]],
8362 // startDateTime.[[ISOMonth]], startDateTime.[[ISODay]],
8363 // startDateTime.[[ISOHour]], startDateTime.[[ISOMinute]],
8364 // startDateTime.[[ISOSecond]], startDateTime.[[ISOMillisecond]],
8365 // startDateTime.[[ISOMicrosecond]], startDateTime.[[ISONanosecond]],
8366 // endDateTime.[[ISOYear]], endDateTime.[[ISOMonth]], endDateTime.[[ISODay]],
8367 // endDateTime.[[ISOHour]], endDateTime.[[ISOMinute]],
8368 // endDateTime.[[ISOSecond]], endDateTime.[[ISOMillisecond]],
8369 // endDateTime.[[ISOMicrosecond]], endDateTime.[[ISONanosecond]], calendar,
8370 // largestUnit, options).
8371 DurationRecord date_difference;
8373 isolate, date_difference,
8374 DifferenceISODateTime(
8375 isolate,
8376 {{start_date_time->iso_year(), start_date_time->iso_month(),
8377 start_date_time->iso_day()},
8378 {start_date_time->iso_hour(), start_date_time->iso_minute(),
8379 start_date_time->iso_second(), start_date_time->iso_millisecond(),
8380 start_date_time->iso_microsecond(),
8381 start_date_time->iso_nanosecond()}},
8382 {{end_date_time->iso_year(), end_date_time->iso_month(),
8383 end_date_time->iso_day()},
8384 {end_date_time->iso_hour(), end_date_time->iso_minute(),
8385 end_date_time->iso_second(), end_date_time->iso_millisecond(),
8386 end_date_time->iso_microsecond(), end_date_time->iso_nanosecond()}},
8387 calendar, largest_unit, options, method_name),
8389
8390 // 7. Let intermediateNs be ? AddZonedDateTime(ns1, timeZone, calendar,
8391 // dateDifference.[[Years]], dateDifference.[[Months]],
8392 // dateDifference.[[Weeks]], 0, 0, 0, 0, 0, 0, 0).
8393 DirectHandle<BigInt> intermediate_ns;
8395 isolate, intermediate_ns,
8396 AddZonedDateTime(isolate, ns1, time_zone, calendar,
8397 {date_difference.years,
8398 date_difference.months,
8399 date_difference.weeks,
8400 {0, 0, 0, 0, 0, 0, 0}},
8401 method_name),
8403 // 8. Let timeRemainderNs be ns2 − intermediateNs.
8404 DirectHandle<BigInt> time_remainder_ns =
8405 BigInt::Subtract(isolate, ns2, intermediate_ns).ToHandleChecked();
8406
8407 // 9. Let intermediate be ? CreateTemporalZonedDateTime(intermediateNs,
8408 // timeZone, calendar).
8409 DirectHandle<JSTemporalZonedDateTime> intermediate =
8410 CreateTemporalZonedDateTime(isolate, intermediate_ns, time_zone, calendar)
8411 .ToHandleChecked();
8412
8413 // 10. Let result be ? NanosecondsToDays(ℝ(timeRemainderNs), intermediate).
8414 NanosecondsToDaysResult result;
8416 isolate, result,
8417 NanosecondsToDays(isolate, time_remainder_ns, intermediate, method_name),
8419
8420 // 11. Let timeDifference be ! BalanceDuration(0, 0, 0, 0, 0, 0,
8421 // result.[[Nanoseconds]], "hour").
8422 TimeDurationRecord time_difference =
8423 BalanceDuration(isolate, Unit::kHour,
8424 {0, 0, 0, 0, 0, 0, result.nanoseconds}, method_name)
8425 .ToChecked();
8426
8427 // 12. Return ! CreateDurationRecord(dateDifference.[[Years]],
8428 // dateDifference.[[Months]], dateDifference.[[Weeks]], result.[[Days]],
8429 // timeDifference.[[Hours]], timeDifference.[[Minutes]],
8430 // timeDifference.[[Seconds]], timeDifference.[[Milliseconds]],
8431 // timeDifference.[[Microseconds]], timeDifference.[[Nanoseconds]]).
8432 time_difference.days = result.days;
8433 return Just(CreateDurationRecord(
8434 isolate, {date_difference.years, date_difference.months,
8435 date_difference.weeks, time_difference})
8436 .ToChecked());
8437}
8438
8439Maybe<DurationRecord> AddDuration(Isolate* isolate, const DurationRecord& dur1,
8440 const DurationRecord& dur2,
8441 DirectHandle<Object> relative_to_obj,
8442 const char* method_name) {
8444
8445 Factory* factory = isolate->factory();
8446 DurationRecord result;
8447 // 1. Let largestUnit1 be ! DefaultTemporalLargestUnit(y1, mon1, w1, d1, h1,
8448 // min1, s1, ms1, mus1).
8449 Unit largest_unit1 = DefaultTemporalLargestUnit(dur1);
8450 // 2. Let largestUnit2 be ! DefaultTemporalLargestUnit(y2, mon2, w2, d2, h2,
8451 // min2, s2, ms2, mus2).
8452 Unit largest_unit2 = DefaultTemporalLargestUnit(dur2);
8453 // 3. Let largestUnit be ! LargerOfTwoTemporalUnits(largestUnit1,
8454 // largestUnit2).
8455 Unit largest_unit = LargerOfTwoTemporalUnits(largest_unit1, largest_unit2);
8456
8457 // 5. If relativeTo is undefined, then
8458 if (IsUndefined(*relative_to_obj)) {
8459 // a. If largestUnit is one of "year", "month", or "week", then
8460 if (largest_unit == Unit::kYear || largest_unit == Unit::kMonth ||
8461 largest_unit == Unit::kWeek) {
8462 // i. Throw a RangeError exception.
8466 }
8467 // b. Let result be ? BalanceDuration(d1 + d2, h1 + h2, min1 + min2, s1 +
8468 // s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit).
8469 // Note: We call a special version of BalanceDuration which add two duration
8470 // internally to avoid overflow the double.
8472 isolate, result.time_duration,
8473 BalanceDuration(isolate, largest_unit, dur1.time_duration,
8474 dur2.time_duration, method_name),
8476
8477 // c. Return ! CreateDurationRecord(0, 0, 0, result.[[Days]],
8478 // result.[[Hours]], result.[[Minutes]], result.[[Seconds]],
8479 // result.[[Milliseconds]], result.[[Microseconds]],
8480 // result.[[Nanoseconds]]).
8481 return Just(CreateDurationRecord(isolate, {0, 0, 0, result.time_duration})
8482 .ToChecked());
8483 // 5. If relativeTo has an [[InitializedTemporalDate]] internal slot, then
8484 } else if (IsJSTemporalPlainDate(*relative_to_obj)) {
8485 // a. Let calendar be relativeTo.[[Calendar]].
8486 DirectHandle<JSTemporalPlainDate> relative_to =
8487 Cast<JSTemporalPlainDate>(relative_to_obj);
8488 DirectHandle<JSReceiver> calendar(relative_to->calendar(), isolate);
8489 // b. Let dateDuration1 be ? CreateTemporalDuration(y1, mon1, w1, d1, 0, 0,
8490 // 0, 0, 0, 0).
8491 DirectHandle<JSTemporalDuration> date_duration1;
8493 isolate, date_duration1,
8494 CreateTemporalDuration(isolate,
8495 {dur1.years,
8496 dur1.months,
8497 dur1.weeks,
8498 {dur1.time_duration.days, 0, 0, 0, 0, 0, 0}}),
8500 // c. Let dateDuration2 be ? CreateTemporalDuration(y2, mon2, w2, d2, 0, 0,
8501 // 0, 0, 0, 0).
8502 DirectHandle<JSTemporalDuration> date_duration2;
8504 isolate, date_duration2,
8505 CreateTemporalDuration(isolate,
8506 {dur2.years,
8507 dur2.months,
8508 dur2.weeks,
8509 {dur2.time_duration.days, 0, 0, 0, 0, 0, 0}}),
8511 // d. Let dateAdd be ? GetMethod(calendar, "dateAdd").
8512 DirectHandle<Object> date_add;
8514 isolate, date_add,
8515 Object::GetMethod(isolate, calendar, factory->dateAdd_string()),
8517 // e. Let intermediate be ? CalendarDateAdd(calendar, relativeTo,
8518 // dateDuration1, undefined, dateAdd).
8519 DirectHandle<JSTemporalPlainDate> intermediate;
8521 isolate, intermediate,
8522 CalendarDateAdd(isolate, calendar, relative_to, date_duration1,
8523 factory->undefined_value(), date_add),
8525 // f. Let end be ? CalendarDateAdd(calendar, intermediate, dateDuration2,
8526 // undefined, dateAdd).
8527 DirectHandle<JSTemporalPlainDate> end;
8529 isolate, end,
8530 CalendarDateAdd(isolate, calendar, intermediate, date_duration2,
8531 factory->undefined_value(), date_add),
8533 // g. Let dateLargestUnit be ! LargerOfTwoTemporalUnits("day", largestUnit).
8534 Unit date_largest_unit = LargerOfTwoTemporalUnits(Unit::kDay, largest_unit);
8535 // h. Let differenceOptions be ! OrdinaryObjectCreate(null).
8536 DirectHandle<JSObject> difference_options =
8537 factory->NewJSObjectWithNullProto();
8538 // i. Perform ! CreateDataPropertyOrThrow(differenceOptions, "largestUnit",
8539 // dateLargestUnit).
8541 isolate, difference_options, factory->largestUnit_string(),
8542 UnitToString(isolate, date_largest_unit), Just(kThrowOnError))
8543 .FromJust());
8544
8545 // j. Let dateDifference be ? CalendarDateUntil(calendar, relativeTo, end,
8546 // differenceOptions).
8547 DirectHandle<JSTemporalDuration> date_difference;
8549 isolate, date_difference,
8550 CalendarDateUntil(isolate, calendar, relative_to, end,
8551 difference_options),
8553 // n. Let result be ? BalanceDuration(dateDifference.[[Days]], h1 + h2, min1
8554 // + min2, s1 + s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit).
8555 // Note: We call a special version of BalanceDuration which add two duration
8556 // internally to avoid overflow the double.
8557 TimeDurationRecord time_dur1 = dur1.time_duration;
8558 time_dur1.days = Object::NumberValue(date_difference->days());
8559 TimeDurationRecord time_dur2 = dur2.time_duration;
8560 time_dur2.days = 0;
8562 isolate, result.time_duration,
8563 BalanceDuration(isolate, largest_unit, time_dur1, time_dur2,
8564 method_name),
8566 // l. Return ! CreateDurationRecord(dateDifference.[[Years]],
8567 // dateDifference.[[Months]], dateDifference.[[Weeks]], result.[[Days]],
8568 // result.[[Hours]], result.[[Minutes]], result.[[Seconds]],
8569 // result.[[Milliseconds]], result.[[Microseconds]],
8570 // result.[[Nanoseconds]]).
8571 return Just(CreateDurationRecord(
8572 isolate, {Object::NumberValue(date_difference->years()),
8573 Object::NumberValue(date_difference->months()),
8574 Object::NumberValue(date_difference->weeks()),
8575 result.time_duration})
8576 .ToChecked());
8577 }
8578 // 6. Assert: relativeTo has an [[InitializedTemporalZonedDateTime]]
8579 // internal slot.
8580 DCHECK(IsJSTemporalZonedDateTime(*relative_to_obj));
8581 auto relative_to = Cast<JSTemporalZonedDateTime>(relative_to_obj);
8582 // 7. Let timeZone be relativeTo.[[TimeZone]].
8583 DirectHandle<JSReceiver> time_zone(relative_to->time_zone(), isolate);
8584 // 8. Let calendar be relativeTo.[[Calendar]].
8585 DirectHandle<JSReceiver> calendar(relative_to->calendar(), isolate);
8586 // 9. Let intermediateNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]],
8587 // timeZone, calendar, y1, mon1, w1, d1, h1, min1, s1, ms1, mus1, ns1).
8588 DirectHandle<BigInt> intermediate_ns;
8590 isolate, intermediate_ns,
8591 AddZonedDateTime(isolate,
8592 direct_handle(relative_to->nanoseconds(), isolate),
8593 time_zone, calendar, dur1, method_name),
8595 // 10. Let endNs be ? AddZonedDateTime(intermediateNs, timeZone, calendar,
8596 // y2, mon2, w2, d2, h2, min2, s2, ms2, mus2, ns2).
8597 DirectHandle<BigInt> end_ns;
8599 isolate, end_ns,
8600 AddZonedDateTime(isolate, intermediate_ns, time_zone, calendar, dur2,
8601 method_name),
8603 // 11. If largestUnit is not one of "year", "month", "week", or "day", then
8604 if (!(largest_unit == Unit::kYear || largest_unit == Unit::kMonth ||
8605 largest_unit == Unit::kWeek || largest_unit == Unit::kDay)) {
8606 // a. Let result be ! DifferenceInstant(relativeTo.[[Nanoseconds]], endNs,
8607 // 1, *"nanosecond"*, largestUnit, *"halfExpand"*).
8608 result.time_duration = DifferenceInstant(
8609 isolate, direct_handle(relative_to->nanoseconds(), isolate), end_ns, 1,
8610 Unit::kNanosecond, largest_unit, RoundingMode::kHalfExpand,
8611 method_name);
8612 // b. Return ! CreateDurationRecord(0, 0, 0, 0, result.[[Hours]],
8613 // result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]],
8614 // result.[[Microseconds]], result.[[Nanoseconds]]).
8615 result.time_duration.days = 0;
8616 return Just(CreateDurationRecord(isolate, {0, 0, 0, result.time_duration})
8617 .ToChecked());
8618 }
8619 // 12. Return ? DifferenceZonedDateTime(relativeTo.[[Nanoseconds]], endNs,
8620 // timeZone, calendar, largestUnit, OrdinaryObjectCreate(null)).
8621 return DifferenceZonedDateTime(
8622 isolate, direct_handle(relative_to->nanoseconds(), isolate), end_ns,
8623 time_zone, calendar, largest_unit, factory->NewJSObjectWithNullProto(),
8624 method_name);
8625}
8626
8627MaybeDirectHandle<JSTemporalDuration>
8628AddDurationToOrSubtractDurationFromDuration(
8629 Isolate* isolate, Arithmetic operation,
8630 DirectHandle<JSTemporalDuration> duration, DirectHandle<Object> other_obj,
8631 DirectHandle<Object> options_obj, const char* method_name) {
8632 // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
8633 double sign = operation == Arithmetic::kSubtract ? -1.0 : 1.0;
8634
8635 // 2. Set other to ? ToTemporalDurationRecord(other).
8636 DurationRecord other;
8638 isolate, other,
8639 temporal::ToTemporalDurationRecord(isolate, other_obj, method_name),
8640 DirectHandle<JSTemporalDuration>());
8641
8642 // 3. Set options to ? GetOptionsObject(options).
8643 DirectHandle<JSReceiver> options;
8645 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
8646
8647 // 4. Let relativeTo be ? ToRelativeTemporalObject(options).
8648 DirectHandle<Object> relative_to;
8650 isolate, relative_to,
8651 ToRelativeTemporalObject(isolate, options, method_name));
8652
8653 // 5. Let result be ? AddDuration(duration.[[Years]], duration.[[Months]],
8654 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
8655 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
8656 // duration.[[Microseconds]], duration.[[Nanoseconds]], sign ×
8657 // other.[[Years]], sign × other.[[Months]], sign × other.[[Weeks]], sign ×
8658 // other.[[Days]], sign × other.[[Hours]], sign × other.[[Minutes]], sign ×
8659 // other.[[Seconds]], sign × other.[[Milliseconds]], sign ×
8660 // other.[[Microseconds]], sign × other.[[Nanoseconds]], relativeTo).
8661 DurationRecord result;
8663 isolate, result,
8664 AddDuration(
8665 isolate,
8666 {Object::NumberValue(duration->years()),
8667 Object::NumberValue(duration->months()),
8668 Object::NumberValue(duration->weeks()),
8669 {Object::NumberValue(duration->days()),
8670 Object::NumberValue(duration->hours()),
8671 Object::NumberValue(duration->minutes()),
8672 Object::NumberValue(duration->seconds()),
8673 Object::NumberValue(duration->milliseconds()),
8674 Object::NumberValue(duration->microseconds()),
8675 Object::NumberValue(duration->nanoseconds())}},
8676 {sign * other.years,
8677 sign * other.months,
8678 sign * other.weeks,
8679 {sign * other.time_duration.days, sign * other.time_duration.hours,
8680 sign * other.time_duration.minutes,
8681 sign * other.time_duration.seconds,
8682 sign * other.time_duration.milliseconds,
8683 sign * other.time_duration.microseconds,
8684 sign * other.time_duration.nanoseconds}},
8685 relative_to, method_name),
8686 DirectHandle<JSTemporalDuration>());
8687
8688 // 6. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]],
8689 // result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]],
8690 // result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]],
8691 // result.[[Nanoseconds]]).
8692 return CreateTemporalDuration(isolate, result).ToHandleChecked();
8693}
8694
8695} // namespace
8696
8697// #sec-temporal.duration.prototype.add
8699 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
8701 return AddDurationToOrSubtractDurationFromDuration(
8702 isolate, Arithmetic::kAdd, duration, other, options,
8703 "Temporal.Duration.prototype.add");
8704}
8705
8706// #sec-temporal.duration.prototype.subtract
8708 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
8710 return AddDurationToOrSubtractDurationFromDuration(
8711 isolate, Arithmetic::kSubtract, duration, other, options,
8712 "Temporal.Duration.prototype.subtract");
8713}
8714
8715// #sec-temporal.duration.prototype.tojson
8717 Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
8718 // 1. Let duration be the this value.
8719 // 2. Perform ? RequireInternalSlot(duration,
8720 // [[InitializedTemporalDuration]]).
8721 // 3. Return ! TemporalDurationToString(duration.[[Years]],
8722 // duration.[[Months]], duration.[[Weeks]], duration.[[Days]],
8723 // duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]],
8724 // duration.[[Milliseconds]], duration.[[Microseconds]],
8725 // duration.[[Nanoseconds]], "auto").
8726 DurationRecord dur = {Object::NumberValue(duration->years()),
8727 Object::NumberValue(duration->months()),
8728 Object::NumberValue(duration->weeks()),
8729 {Object::NumberValue(duration->days()),
8730 Object::NumberValue(duration->hours()),
8731 Object::NumberValue(duration->minutes()),
8732 Object::NumberValue(duration->seconds()),
8733 Object::NumberValue(duration->milliseconds()),
8734 Object::NumberValue(duration->microseconds()),
8735 Object::NumberValue(duration->nanoseconds())}};
8736 return TemporalDurationToString(isolate, dur, Precision::kAuto);
8737}
8738
8739// #sec-temporal.duration.prototype.tolocalestring
8741 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
8742 DirectHandle<Object> locales, DirectHandle<Object> options) {
8743 // 1. Let duration be the this value.
8744 // 2. Perform ? RequireInternalSlot(duration,
8745 // [[InitializedTemporalDuration]]).
8746 // 3. Return ! TemporalDurationToString(duration.[[Years]],
8747 // duration.[[Months]], duration.[[Weeks]], duration.[[Days]],
8748 // duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]],
8749 // duration.[[Milliseconds]], duration.[[Microseconds]],
8750 // duration.[[Nanoseconds]], "auto").
8751 DurationRecord dur = {Object::NumberValue(duration->years()),
8752 Object::NumberValue(duration->months()),
8753 Object::NumberValue(duration->weeks()),
8754 {Object::NumberValue(duration->days()),
8755 Object::NumberValue(duration->hours()),
8756 Object::NumberValue(duration->minutes()),
8757 Object::NumberValue(duration->seconds()),
8758 Object::NumberValue(duration->milliseconds()),
8759 Object::NumberValue(duration->microseconds()),
8760 Object::NumberValue(duration->nanoseconds())}};
8761
8762 // TODO(ftang) Implement #sup-temporal.duration.prototype.tolocalestring
8763 return TemporalDurationToString(isolate, dur, Precision::kAuto);
8764}
8765
8766namespace {
8767// #sec-temporal-moverelativezoneddatetime
8768MaybeDirectHandle<JSTemporalZonedDateTime> MoveRelativeZonedDateTime(
8769 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
8770 const DateDurationRecord& duration, const char* method_name) {
8771 // 1. Let intermediateNs be ? AddZonedDateTime(zonedDateTime.[[Nanoseconds]],
8772 // zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], years, months,
8773 // weeks, days, 0, 0, 0, 0, 0, 0).
8774 DirectHandle<BigInt> intermediate_ns;
8776 isolate, intermediate_ns,
8777 AddZonedDateTime(isolate,
8778 direct_handle(zoned_date_time->nanoseconds(), isolate),
8779 direct_handle(zoned_date_time->time_zone(), isolate),
8780 direct_handle(zoned_date_time->calendar(), isolate),
8781 {duration.years,
8782 duration.months,
8783 duration.weeks,
8784 {duration.days, 0, 0, 0, 0, 0, 0}},
8785 method_name));
8786 // 2. Return ! CreateTemporalZonedDateTime(intermediateNs,
8787 // zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]]).
8788 return CreateTemporalZonedDateTime(
8789 isolate, intermediate_ns,
8790 direct_handle(zoned_date_time->time_zone(), isolate),
8791 direct_handle(zoned_date_time->calendar(), isolate))
8792 .ToHandleChecked();
8793}
8794
8795// #sec-temporal-daysuntil
8796double DaysUntil(Isolate* isolate, DirectHandle<JSTemporalPlainDate> earlier,
8797 DirectHandle<JSTemporalPlainDate> later,
8798 const char* method_name) {
8799 // 1. Let epochDays1 be MakeDay(𝔽(earlier.[[ISOYear]]), 𝔽(earlier.[[ISOMonth]]
8800 // - 1), 𝔽(earlier.[[ISODay]])).
8801 double epoch_days1 = MakeDay(earlier->iso_year(), earlier->iso_month() - 1,
8802 earlier->iso_day());
8803 // 2. Assert: epochDays1 is finite.
8804 // 3. Let epochDays2 be MakeDay(𝔽(later.[[ISOYear]]), 𝔽(later.[[ISOMonth]] -
8805 // 1), 𝔽(later.[[ISODay]])).
8806 double epoch_days2 =
8807 MakeDay(later->iso_year(), later->iso_month() - 1, later->iso_day());
8808 // 4. Assert: epochDays2 is finite.
8809 // 5. Return ℝ(epochDays2) - ℝ(epochDays1).
8810 return epoch_days2 - epoch_days1;
8811}
8812
8813// #sec-temporal-moverelativedate
8814Maybe<MoveRelativeDateResult> MoveRelativeDate(
8815 Isolate* isolate, DirectHandle<JSReceiver> calendar,
8816 DirectHandle<JSTemporalPlainDate> relative_to,
8817 DirectHandle<JSTemporalDuration> duration, const char* method_name) {
8818 // 1. Let newDate be ? CalendarDateAdd(calendar, relativeTo, duration).
8819 DirectHandle<JSTemporalPlainDate> new_date;
8821 isolate, new_date,
8822 CalendarDateAdd(isolate, calendar, relative_to, duration),
8824 // 2. Let days be DaysUntil(relativeTo, newDate).
8825 double days = DaysUntil(isolate, relative_to, new_date, method_name);
8826 // 3. Return the Record { [[RelativeTo]]: newDate, [[Days]]: days }.
8827 return Just(MoveRelativeDateResult({new_date, days}));
8828}
8829
8830// #sec-temporal-roundduration
8831Maybe<DurationRecordWithRemainder> RoundDuration(
8832 Isolate* isolate, const DurationRecord& duration, double increment,
8833 Unit unit, RoundingMode rounding_mode, DirectHandle<Object> relative_to,
8834 const char* method_name) {
8836 // optional argument relativeTo (undefined, a Temporal.PlainDate, or a
8837 // Temporal.ZonedDateTime)
8838 DCHECK(IsUndefined(*relative_to) || IsJSTemporalPlainDate(*relative_to) ||
8839 IsJSTemporalZonedDateTime(*relative_to));
8840
8841 Factory* factory = isolate->factory();
8842 DurationRecordWithRemainder result;
8843 result.record = duration;
8844 // 2. If unit is "year", "month", or "week", and relativeTo is undefined, then
8845 if ((unit == Unit::kYear || unit == Unit::kMonth || unit == Unit::kWeek) &&
8846 IsUndefined(*relative_to)) {
8847 // a. Throw a RangeError exception.
8851 }
8852
8853 // 3. Let zonedRelativeTo be undefined.
8854 DirectHandle<Object> zoned_relative_to =
8855 isolate->factory()->undefined_value();
8856
8857 DirectHandle<JSReceiver> calendar;
8858 // 5. If relativeTo is not undefined, then
8859 if (!IsUndefined(*relative_to)) {
8860 // a. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal
8861 // slot, then
8862 if (IsJSTemporalZonedDateTime(*relative_to)) {
8863 // i. Set zonedRelativeTo to relativeTo.
8864 zoned_relative_to = relative_to;
8865 // ii. Set relativeTo to ? ToTemporalDate(relativeTo).
8866 DirectHandle<JSTemporalPlainDate> date;
8868 isolate, date, ToTemporalDate(isolate, relative_to, method_name),
8870 relative_to = date;
8871 // b. Else,
8872 } else {
8873 // i. Assert: relativeTo has an [[InitializedTemporalDate]] internal
8874 // slot.
8875 DCHECK(IsJSTemporalPlainDate(*relative_to));
8876 }
8877 // c. Let calendar be relativeTo.[[Calendar]].
8878 calendar = DirectHandle<JSReceiver>(
8880 // 5. Else,
8881 } else {
8882 // a. NOTE: calendar will not be used below.
8883 }
8884 double fractional_seconds = 0;
8885 // 6. If unit is one of "year", "month", "week", or "day", then
8886 if (unit == Unit::kYear || unit == Unit::kMonth || unit == Unit::kWeek ||
8887 unit == Unit::kDay) {
8888 // a. Let nanoseconds be ! TotalDurationNanoseconds(0, hours, minutes,
8889 // seconds, milliseconds, microseconds, nanoseconds, 0).
8890 TimeDurationRecord time_duration = duration.time_duration;
8891 time_duration.days = 0;
8892 DirectHandle<BigInt> nanoseconds =
8893 TotalDurationNanoseconds(isolate, time_duration, 0);
8894
8895 // b. Let intermediate be undefined.
8896 DirectHandle<Object> intermediate = isolate->factory()->undefined_value();
8897
8898 // c. If zonedRelativeTo is not undefined, then
8899 if (!IsUndefined(*zoned_relative_to)) {
8900 DCHECK(IsJSTemporalZonedDateTime(*zoned_relative_to));
8901 // i. Let intermediate be ? MoveRelativeZonedDateTime(zonedRelativeTo,
8902 // years, months, weeks, days).
8904 isolate, intermediate,
8905 MoveRelativeZonedDateTime(
8906 isolate, Cast<JSTemporalZonedDateTime>(zoned_relative_to),
8907 {duration.years, duration.months, duration.weeks,
8908 duration.time_duration.days},
8909 method_name),
8911 }
8912
8913 // d. Let result be ? NanosecondsToDays(nanoseconds, intermediate).
8914 NanosecondsToDaysResult to_days_result;
8916 isolate, to_days_result,
8917 NanosecondsToDays(isolate, nanoseconds, intermediate, method_name),
8919
8920 // e. Set days to days + result.[[Days]] + result.[[Nanoseconds]] /
8921 // result.[[DayLength]].
8922 result.record.time_duration.days +=
8923 to_days_result.days +
8924 // https://github.com/tc39/proposal-temporal/issues/2366
8925 std::round(to_days_result.nanoseconds / to_days_result.day_length);
8926
8927 // f. Set hours, minutes, seconds, milliseconds, microseconds, and
8928 // nanoseconds to 0.
8929 result.record.time_duration.hours = result.record.time_duration.minutes =
8930 result.record.time_duration.seconds =
8931 result.record.time_duration.milliseconds =
8932 result.record.time_duration.microseconds =
8933 result.record.time_duration.nanoseconds = 0;
8934
8935 // 7. Else,
8936 } else {
8937 // a. Let fractionalSeconds be nanoseconds × 10^−9 + microseconds × 10^−6 +
8938 // milliseconds × 10^−3 + seconds.
8939 fractional_seconds = result.record.time_duration.nanoseconds * 1e-9 +
8940 result.record.time_duration.microseconds * 1e-6 +
8941 result.record.time_duration.milliseconds * 1e-3 +
8942 result.record.time_duration.seconds;
8943 }
8944 // 8. Let remainder be undefined.
8945 result.remainder = -1; // use -1 for undefined now.
8946
8947 switch (unit) {
8948 // 9. If unit is "year", then
8949 case Unit::kYear: {
8950 // a. Let yearsDuration be ! CreateTemporalDuration(years, 0, 0, 0, 0, 0,
8951 // 0, 0, 0, 0).
8952 DirectHandle<JSTemporalDuration> years_duration =
8953 CreateTemporalDuration(isolate,
8954 {duration.years, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
8955 .ToHandleChecked();
8956
8957 // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
8958 DirectHandle<Object> date_add;
8960 isolate, date_add,
8961 Object::GetMethod(isolate, calendar, factory->dateAdd_string()),
8963
8964 // c. Let yearsLater be ? CalendarDateAdd(calendar, relativeTo,
8965 // yearsDuration, undefined, dateAdd).
8966 DirectHandle<JSTemporalPlainDate> years_later;
8968 isolate, years_later,
8969 CalendarDateAdd(isolate, calendar, relative_to, years_duration,
8970 isolate->factory()->undefined_value(), date_add),
8972
8973 // d. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months,
8974 // weeks, 0, 0, 0, 0, 0, 0, 0).
8975 DirectHandle<JSTemporalDuration> years_months_weeks =
8976 CreateTemporalDuration(isolate, {duration.years,
8977 duration.months,
8978 duration.weeks,
8979 {0, 0, 0, 0, 0, 0, 0}})
8980 .ToHandleChecked();
8981
8982 // e. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo,
8983 // yearsMonthsWeeks, undefined, dateAdd).
8984 DirectHandle<JSTemporalPlainDate> years_months_weeks_later;
8986 isolate, years_months_weeks_later,
8987 CalendarDateAdd(isolate, calendar, relative_to, years_months_weeks,
8988 isolate->factory()->undefined_value(), date_add),
8990
8991 // f. Let monthsWeeksInDays be DaysUntil(yearsLater,
8992 // yearsMonthsWeeksLater).
8993 double months_weeks_in_days = DaysUntil(
8994 isolate, years_later, years_months_weeks_later, method_name);
8995
8996 // g. Set relativeTo to yearsLater.
8997 relative_to = years_later;
8998
8999 // h. Let days be days + monthsWeeksInDays.
9000 result.record.time_duration.days += months_weeks_in_days;
9001
9002 // i. Let daysDuration be ? CreateTemporalDuration(0, 0, 0, days, 0, 0, 0,
9003 // 0, 0, 0).
9004 DirectHandle<JSTemporalDuration> days_duration;
9006 isolate, days_duration,
9007 CreateTemporalDuration(
9008 isolate,
9009 {0, 0, 0, {result.record.time_duration.days, 0, 0, 0, 0, 0, 0}}),
9011
9012 // j. Let daysLater be ? CalendarDateAdd(calendar, relativeTo,
9013 // daysDuration, undefined, dateAdd).
9014 DirectHandle<JSTemporalPlainDate> days_later;
9016 isolate, days_later,
9017 CalendarDateAdd(isolate, calendar, relative_to, days_duration,
9018 isolate->factory()->undefined_value(), date_add),
9020
9021 // k. Let untilOptions be OrdinaryObjectCreate(null).
9022 DirectHandle<JSObject> until_options =
9023 factory->NewJSObjectWithNullProto();
9024
9025 // l. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit",
9026 // "year").
9028 isolate, until_options, factory->largestUnit_string(),
9029 factory->year_string(), Just(kThrowOnError))
9030 .FromJust());
9031
9032 // m. Let timePassed be ? CalendarDateUntil(calendar, relativeTo,
9033 // daysLater, untilOptions).
9034 DirectHandle<JSTemporalDuration> time_passed;
9036 isolate, time_passed,
9037 CalendarDateUntil(isolate, calendar, relative_to, days_later,
9038 until_options),
9040
9041 // n. Let yearsPassed be timePassed.[[Years]].
9042 double years_passed = Object::NumberValue(time_passed->years());
9043
9044 // o. Set years to years + yearsPassed.
9045 result.record.years += years_passed;
9046
9047 // p. Let oldRelativeTo be relativeTo.
9048 DirectHandle<Object> old_relative_to = relative_to;
9049
9050 // q. Let yearsDuration be ? CreateTemporalDuration(yearsPassed, 0, 0, 0,
9051 // 0, 0, 0, 0, 0, 0).
9052 years_duration = CreateTemporalDuration(
9053 isolate, {years_passed, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
9054 .ToHandleChecked();
9055
9056 // r. Set relativeTo to ? CalendarDateAdd(calendar, relativeTo,
9057 // yearsDuration, undefined, dateAdd).
9058 DirectHandle<JSTemporalPlainDate> years_added;
9060 isolate, years_added,
9061 CalendarDateAdd(isolate, calendar, relative_to, years_duration,
9062 isolate->factory()->undefined_value(), date_add),
9064 relative_to = years_added;
9065
9066 // s. Let daysPassed be DaysUntil(oldRelativeTo, relativeTo).
9067 DCHECK(IsJSTemporalPlainDate(*old_relative_to));
9068 DCHECK(IsJSTemporalPlainDate(*relative_to));
9069 double days_passed =
9070 DaysUntil(isolate, Cast<JSTemporalPlainDate>(old_relative_to),
9072
9073 // t. Set days to days - daysPassed.
9074 result.record.time_duration.days -= days_passed;
9075
9076 // u. If days < 0, let sign be -1; else, let sign be 1.
9077 double sign = result.record.time_duration.days < 0 ? -1 : 1;
9078
9079 // v. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0,
9080 // 0, 0).
9081 DirectHandle<JSTemporalDuration> one_year =
9082 CreateTemporalDuration(isolate, {sign, 0, 0, {0, 0, 0, 0, 0, 0, 0}})
9083 .ToHandleChecked();
9084
9085 // w. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
9086 MoveRelativeDateResult move_result;
9087 DCHECK(IsJSTemporalPlainDate(*relative_to));
9089 isolate, move_result,
9090 MoveRelativeDate(isolate, calendar,
9092 method_name),
9094
9095 // x. Let oneYearDays be moveResult.[[Days]].
9096 double one_year_days = move_result.days;
9097 // y. Let fractionalYears be years + days / abs(oneYearDays).
9098 double fractional_years =
9099 result.record.years +
9100 result.record.time_duration.days / std::abs(one_year_days);
9101 // z. Set years to RoundNumberToIncrement(fractionalYears, increment,
9102 // roundingMode).
9103 result.record.years = RoundNumberToIncrement(isolate, fractional_years,
9105 // aa. Set remainder to fractionalYears - years.
9106 result.remainder = fractional_years - result.record.years;
9107 // ab. Set months, weeks, and days to 0.
9108 result.record.months = result.record.weeks =
9109 result.record.time_duration.days = 0;
9110 } break;
9111 // 10. Else if unit is "month", then
9112 case Unit::kMonth: {
9113 // a. Let yearsMonths be ! CreateTemporalDuration(years, months, 0, 0, 0,
9114 // 0, 0, 0, 0, 0).
9115 DirectHandle<JSTemporalDuration> years_months =
9116 CreateTemporalDuration(
9117 isolate,
9118 {duration.years, duration.months, 0, {0, 0, 0, 0, 0, 0, 0}})
9119 .ToHandleChecked();
9120
9121 // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
9122 DirectHandle<Object> date_add;
9124 isolate, date_add,
9125 Object::GetMethod(isolate, calendar, factory->dateAdd_string()),
9127
9128 // c. Let yearsMonthsLater be ? CalendarDateAdd(calendar, relativeTo,
9129 // yearsMonths, undefined, dateAdd).
9130 DirectHandle<JSTemporalPlainDate> years_months_later;
9132 isolate, years_months_later,
9133 CalendarDateAdd(isolate, calendar, relative_to, years_months,
9134 isolate->factory()->undefined_value(), date_add),
9136
9137 // d. Let yearsMonthsWeeks be ! CreateTemporalDuration(years, months,
9138 // weeks, 0, 0, 0, 0, 0, 0, 0).
9139 DirectHandle<JSTemporalDuration> years_months_weeks =
9140 CreateTemporalDuration(isolate, {duration.years,
9141 duration.months,
9142 duration.weeks,
9143 {0, 0, 0, 0, 0, 0, 0}})
9144 .ToHandleChecked();
9145
9146 // e. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo,
9147 // yearsMonthsWeeks, undefined, dateAdd).
9148 DirectHandle<JSTemporalPlainDate> years_months_weeks_later;
9150 isolate, years_months_weeks_later,
9151 CalendarDateAdd(isolate, calendar, relative_to, years_months_weeks,
9152 isolate->factory()->undefined_value(), date_add),
9154
9155 // f. Let weeksInDays be DaysUntil(yearsMonthsLater,
9156 // yearsMonthsWeeksLater).
9157 double weeks_in_days = DaysUntil(isolate, years_months_later,
9158 years_months_weeks_later, method_name);
9159
9160 // g. Set relativeTo to yearsMonthsLater.
9161 relative_to = years_months_later;
9162
9163 // h. Let days be days + weeksInDays.
9164 result.record.time_duration.days += weeks_in_days;
9165
9166 // i. If days < 0, let sign be -1; else, let sign be 1.
9167 double sign = result.record.time_duration.days < 0 ? -1 : 1;
9168
9169 // j. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0,
9170 // 0, 0).
9171 DirectHandle<JSTemporalDuration> one_month =
9172 CreateTemporalDuration(isolate, {0, sign, 0, {0, 0, 0, 0, 0, 0, 0}})
9173 .ToHandleChecked();
9174
9175 // k. Let moveResult be ? MoveRelativeDate(calendar, relativeTo,
9176 // oneMonth).
9177 MoveRelativeDateResult move_result;
9178 DCHECK(IsJSTemporalPlainDate(*relative_to));
9180 isolate, move_result,
9181 MoveRelativeDate(isolate, calendar,
9183 method_name),
9185
9186 // l. Set relativeTo to moveResult.[[RelativeTo]].
9187 relative_to = move_result.relative_to;
9188
9189 // m. Let oneMonthDays be moveResult.[[Days]].
9190 double one_month_days = move_result.days;
9191
9192 // n. Repeat, while abs(days) ≥ abs(oneMonthDays),
9193 while (std::abs(result.record.time_duration.days) >=
9194 std::abs(one_month_days)) {
9195 // i. Set months to months + sign.
9196 result.record.months += sign;
9197 // ii. Set days to days - oneMonthDays.
9198 result.record.time_duration.days -= one_month_days;
9199 // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
9200 // oneMonth).
9201 DCHECK(IsJSTemporalPlainDate(*relative_to));
9203 isolate, move_result,
9204 MoveRelativeDate(isolate, calendar,
9206 method_name),
9208 // iv. Set relativeTo to moveResult.[[RelativeTo]].
9209 relative_to = move_result.relative_to;
9210 // v. Set oneMonthDays to moveResult.[[Days]].
9211 one_month_days = move_result.days;
9212 }
9213 // o. Let fractionalMonths be months + days / abs(oneMonthDays).
9214 double fractional_months =
9215 result.record.months +
9216 result.record.time_duration.days / std::abs(one_month_days);
9217 // p. Set months to RoundNumberToIncrement(fractionalMonths, increment,
9218 // roundingMode).
9219 result.record.months = RoundNumberToIncrement(isolate, fractional_months,
9221 // q. Set remainder to fractionalMonths - months.
9222 result.remainder = fractional_months - result.record.months;
9223 // r. Set weeks and days to 0.
9224 result.record.weeks = result.record.time_duration.days = 0;
9225 } break;
9226 // 11. Else if unit is "week", then
9227 case Unit::kWeek: {
9228 // a. If days < 0, let sign be -1; else, let sign be 1.
9229 double sign = result.record.time_duration.days < 0 ? -1 : 1;
9230 // b. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0,
9231 // 0, 0).
9232 DirectHandle<JSTemporalDuration> one_week =
9233 CreateTemporalDuration(isolate, {0, 0, sign, {0, 0, 0, 0, 0, 0, 0}})
9234 .ToHandleChecked();
9235
9236 // c. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek).
9237 MoveRelativeDateResult move_result;
9238 DCHECK(IsJSTemporalPlainDate(*relative_to));
9240 isolate, move_result,
9241 MoveRelativeDate(isolate, calendar,
9243 method_name),
9245
9246 // d. Set relativeTo to moveResult.[[RelativeTo]].
9247 relative_to = move_result.relative_to;
9248
9249 // e. Let oneWeekDays be moveResult.[[Days]].
9250 double one_week_days = move_result.days;
9251
9252 // f. Repeat, while abs(days) ≥ abs(oneWeekDays),
9253 while (std::abs(result.record.time_duration.days) >=
9254 std::abs(one_week_days)) {
9255 // i. Set weeks to weeks + sign.
9256 result.record.weeks += sign;
9257 // ii. Set days to days - oneWeekDays.
9258 result.record.time_duration.days -= one_week_days;
9259 // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo,
9260 // oneWeek).
9261 DCHECK(IsJSTemporalPlainDate(*relative_to));
9263 isolate, move_result,
9264 MoveRelativeDate(isolate, calendar,
9266 method_name),
9268 // iv. Set relativeTo to moveResult.[[RelativeTo]].
9269 relative_to = move_result.relative_to;
9270 // v. Set oneWeekDays to moveResult.[[Days]].
9271 one_week_days = move_result.days;
9272 }
9273
9274 // g. Let fractionalWeeks be weeks + days / abs(oneWeekDays).
9275 double fractional_weeks =
9276 result.record.weeks +
9277 result.record.time_duration.days / std::abs(one_week_days);
9278 // h. Set weeks to RoundNumberToIncrement(fractionalWeeks, increment,
9279 // roundingMode).
9280 result.record.weeks = RoundNumberToIncrement(isolate, fractional_weeks,
9282 // i. Set remainder to fractionalWeeks - weeks.
9283 result.remainder = fractional_weeks - result.record.weeks;
9284 // j. Set days to 0.
9285 result.record.time_duration.days = 0;
9286 } break;
9287 // 12. Else if unit is "day", then
9288 case Unit::kDay: {
9289 // a. Let fractionalDays be days.
9290 double fractional_days = result.record.time_duration.days;
9291
9292 // b. Set days to ! RoundNumberToIncrement(days, increment, roundingMode).
9293 result.record.time_duration.days = RoundNumberToIncrement(
9294 isolate, result.record.time_duration.days, increment, rounding_mode);
9295
9296 // c. Set remainder to fractionalDays - days.
9297 result.remainder = fractional_days - result.record.time_duration.days;
9298 } break;
9299 // 13. Else if unit is "hour", then
9300 case Unit::kHour: {
9301 // a. Let fractionalHours be (fractionalSeconds / 60 + minutes) / 60 +
9302 // hours.
9303 double fractional_hours =
9304 (fractional_seconds / 60.0 + duration.time_duration.minutes) / 60.0 +
9305 duration.time_duration.hours;
9306
9307 // b. Set hours to ! RoundNumberToIncrement(fractionalHours, increment,
9308 // roundingMode).
9309 result.record.time_duration.hours = RoundNumberToIncrement(
9310 isolate, fractional_hours, increment, rounding_mode);
9311
9312 // c. Set remainder to fractionalHours - hours.
9313 result.remainder = fractional_hours - result.record.time_duration.hours;
9314
9315 // d. Set minutes, seconds, milliseconds, microseconds, and nanoseconds to
9316 // 0.
9317 result.record.time_duration.minutes =
9318 result.record.time_duration.seconds =
9319 result.record.time_duration.milliseconds =
9320 result.record.time_duration.microseconds =
9321 result.record.time_duration.nanoseconds = 0;
9322 } break;
9323 // 14. Else if unit is "minute", then
9324 case Unit::kMinute: {
9325 // a. Let fractionalMinutes be fractionalSeconds / 60 + minutes.
9326 double fractional_minutes =
9327 fractional_seconds / 60.0 + duration.time_duration.minutes;
9328
9329 // b. Set minutes to ! RoundNumberToIncrement(fractionalMinutes,
9330 // increment, roundingMode).
9331 result.record.time_duration.minutes = RoundNumberToIncrement(
9332 isolate, fractional_minutes, increment, rounding_mode);
9333
9334 // c. Set remainder to fractionalMinutes - minutes.
9335 result.remainder =
9336 fractional_minutes - result.record.time_duration.minutes;
9337
9338 // d. Set seconds, milliseconds, microseconds, and nanoseconds to 0.
9339 result.record.time_duration.seconds =
9340 result.record.time_duration.milliseconds =
9341 result.record.time_duration.microseconds =
9342 result.record.time_duration.nanoseconds = 0;
9343 } break;
9344 // 15. Else if unit is "second", then
9345 case Unit::kSecond: {
9346 // a. Set seconds to ! RoundNumberToIncrement(fractionalSeconds,
9347 // increment, roundingMode).
9348 result.record.time_duration.seconds = RoundNumberToIncrement(
9349 isolate, fractional_seconds, increment, rounding_mode);
9350
9351 // b. Set remainder to fractionalSeconds - seconds.
9352 result.remainder =
9353 fractional_seconds - result.record.time_duration.seconds;
9354
9355 // c. Set milliseconds, microseconds, and nanoseconds to 0.
9356 result.record.time_duration.milliseconds =
9357 result.record.time_duration.microseconds =
9358 result.record.time_duration.nanoseconds = 0;
9359 } break;
9360 // 16. Else if unit is "millisecond", then
9361 case Unit::kMillisecond: {
9362 // a. Let fractionalMilliseconds be nanoseconds × 10^−6 + microseconds ×
9363 // 10^−3 + milliseconds.
9364 double fractional_milliseconds =
9365 duration.time_duration.nanoseconds * 1e-6 +
9366 duration.time_duration.microseconds * 1e-3 +
9367 duration.time_duration.milliseconds;
9368
9369 // b. Set milliseconds to ! RoundNumberToIncrement(fractionalMilliseconds,
9370 // increment, roundingMode).
9371 result.record.time_duration.milliseconds = RoundNumberToIncrement(
9372 isolate, fractional_milliseconds, increment, rounding_mode);
9373
9374 // c. Set remainder to fractionalMilliseconds - milliseconds.
9375 result.remainder =
9376 fractional_milliseconds - result.record.time_duration.milliseconds;
9377
9378 // d. Set microseconds and nanoseconds to 0.
9379 result.record.time_duration.microseconds =
9380 result.record.time_duration.nanoseconds = 0;
9381 } break;
9382 // 17. Else if unit is "microsecond", then
9383 case Unit::kMicrosecond: {
9384 // a. Let fractionalMicroseconds be nanoseconds × 10−3 + microseconds.
9385 double fractional_microseconds =
9386 duration.time_duration.nanoseconds * 1e-3 +
9387 duration.time_duration.microseconds;
9388
9389 // b. Set microseconds to ! RoundNumberToIncrement(fractionalMicroseconds,
9390 // increment, roundingMode).
9391 result.record.time_duration.microseconds = RoundNumberToIncrement(
9392 isolate, fractional_microseconds, increment, rounding_mode);
9393
9394 // c. Set remainder to fractionalMicroseconds - microseconds.
9395 result.remainder =
9396 fractional_microseconds - result.record.time_duration.microseconds;
9397
9398 // d. Set nanoseconds to 0.
9399 result.record.time_duration.nanoseconds = 0;
9400 } break;
9401 // 18. Else,
9402 default: {
9403 // a. Assert: unit is "nanosecond".
9404 DCHECK_EQ(unit, Unit::kNanosecond);
9405 // b. Set remainder to nanoseconds.
9406 result.remainder = result.record.time_duration.nanoseconds;
9407
9408 // c. Set nanoseconds to ! RoundNumberToIncrement(nanoseconds, increment,
9409 // roundingMode).
9410 result.record.time_duration.nanoseconds = RoundNumberToIncrement(
9411 isolate, result.record.time_duration.nanoseconds, increment,
9413
9414 // d. Set remainder to remainder − nanoseconds.
9415 result.remainder -= result.record.time_duration.nanoseconds;
9416 } break;
9417 }
9418 // 19. Let duration be ? CreateDurationRecord(years, months, weeks, days,
9419 // hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
9421 isolate, result.record, CreateDurationRecord(isolate, result.record),
9423
9424 return Just(result);
9425}
9426
9427Maybe<DurationRecordWithRemainder> RoundDuration(Isolate* isolate,
9428 const DurationRecord& duration,
9429 double increment, Unit unit,
9431 const char* method_name) {
9432 // 1. If relativeTo is not present, set relativeTo to undefined.
9433 return RoundDuration(isolate, duration, increment, unit, rounding_mode,
9434 isolate->factory()->undefined_value(), method_name);
9435}
9436
9437// #sec-temporal-tosecondsstringprecision
9438struct StringPrecision {
9439 Precision precision;
9440 Unit unit;
9442};
9443
9444// #sec-temporal-tosecondsstringprecision
9445Maybe<StringPrecision> ToSecondsStringPrecision(
9446 Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
9447 const char* method_name);
9448
9449} // namespace
9450
9451// #sec-temporal.duration.prototype.tostring
9453 Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
9454 DirectHandle<Object> options_obj) {
9455 const char* method_name = "Temporal.Duration.prototype.toString";
9456 // 3. Set options to ? GetOptionsObject(options).
9459 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
9460 // 4. Let precision be ? ToSecondsStringPrecision(options).
9461 StringPrecision precision;
9463 isolate, precision,
9464 ToSecondsStringPrecision(isolate, options, method_name),
9466
9467 // 5. If precision.[[Unit]] is "minute", throw a RangeError exception.
9468 if (precision.unit == Unit::kMinute) {
9470 }
9471 // 6. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
9474 isolate, rounding_mode,
9475 ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
9476 method_name),
9478
9479 // 7. Let result be ? RoundDuration(duration.[[Years]], duration.[[Months]],
9480 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
9481 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
9482 // duration.[[Microseconds]], duration.[[Nanoseconds]],
9483 // precision.[[Increment]], precision.[[Unit]], roundingMode).
9484 DurationRecord dur = {Object::NumberValue(duration->years()),
9485 Object::NumberValue(duration->months()),
9486 Object::NumberValue(duration->weeks()),
9487 {Object::NumberValue(duration->days()),
9488 Object::NumberValue(duration->hours()),
9489 Object::NumberValue(duration->minutes()),
9490 Object::NumberValue(duration->seconds()),
9491 Object::NumberValue(duration->milliseconds()),
9492 Object::NumberValue(duration->microseconds()),
9493 Object::NumberValue(duration->nanoseconds())}};
9494 DurationRecordWithRemainder result;
9496 isolate, result,
9497 RoundDuration(isolate, dur, precision.increment, precision.unit,
9498 rounding_mode, method_name),
9500
9501 // 8. Return ! TemporalDurationToString(result.[[Years]], result.[[Months]],
9502 // result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]],
9503 // result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]],
9504 // result.[[Nanoseconds]], precision.[[Precision]]).
9505
9506 return TemporalDurationToString(isolate, result.record, precision.precision);
9507}
9508
9509// #sec-temporal.calendar
9511 Isolate* isolate, DirectHandle<JSFunction> target,
9513 // 1. If NewTarget is undefined, then
9514 if (IsUndefined(*new_target, isolate)) {
9515 // a. Throw a TypeError exception.
9516 THROW_NEW_ERROR(isolate,
9517 NewTypeError(MessageTemplate::kConstructorNotFunction,
9518 isolate->factory()->NewStringFromStaticChars(
9519 "Temporal.Calendar")));
9520 }
9521 // 2. Set identifier to ? ToString(identifier).
9524 Object::ToString(isolate, identifier_obj));
9525 // 3. If ! IsBuiltinCalendar(id) is false, then
9526 if (!IsBuiltinCalendar(isolate, identifier)) {
9527 // a. Throw a RangeError exception.
9529 isolate, NewRangeError(MessageTemplate::kInvalidCalendar, identifier));
9530 }
9531 return CreateTemporalCalendar(isolate, target, new_target, identifier);
9532}
9533
9534namespace {
9535
9536// #sec-temporal-toisodayofyear
9537int32_t ToISODayOfYear(Isolate* isolate, const DateRecord& date) {
9539 // 1. Assert: IsValidISODate(year, month, day) is *true*.
9540 DCHECK(IsValidISODate(isolate, date));
9541 // 2. Let _epochDays_ be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
9542 // 3. Assert: _epochDays_ is finite.
9543 // 4. Return ℝ(DayWithinYear(MakeDate(_epochDays_, *+0*<sub>𝔽</sub>))) + 1.
9544 // Note: In ISO 8601, Jan: month=1, Dec: month=12,
9545 // In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
9546 return date.day +
9547 isolate->date_cache()->DaysFromYearMonth(date.year, date.month - 1) -
9548 isolate->date_cache()->DaysFromYearMonth(date.year, 0);
9549}
9550
9551bool IsPlainDatePlainDateTimeOrPlainYearMonth(
9552 DirectHandle<Object> temporal_date_like) {
9553 return IsJSTemporalPlainDate(*temporal_date_like) ||
9554 IsJSTemporalPlainDateTime(*temporal_date_like) ||
9555 IsJSTemporalPlainYearMonth(*temporal_date_like);
9556}
9557
9558// #sec-temporal-toisodayofweek
9559int32_t ToISODayOfWeek(Isolate* isolate, const DateRecord& date) {
9561
9562 // 1. Assert: IsValidISODate(year, month, day) is *true*.
9563 DCHECK(IsValidISODate(isolate, date));
9564 // 2. Let _epochDays_ be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
9565 // Note: "- 1" after "date.day" came from the MakeyDay AO in
9566 // "9. Return Day(t) + dt - 1𝔽."
9567 int32_t epoch_days =
9568 isolate->date_cache()->DaysFromYearMonth(date.year, date.month - 1) +
9569 date.day - 1;
9570 // 3. Assert: _epochDays_ is finite.
9571 // 4. Let _dayOfWeek_ be WeekDay(MakeDate(_epochDays_, *+0*<sub>𝔽</sub>)).
9572 int32_t weekday = isolate->date_cache()->Weekday(epoch_days);
9573 // 5. If _dayOfWeek_ = *+0*<sub>𝔽</sub>, return 7.
9574
9575 // Note: In ISO 8601, Jan: month=1, Dec: month=12.
9576 // In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
9577 // Weekday() expect "the number of days since the epoch" as input and the
9578 // value of day is 1-based so we need to minus 1 to calculate "the number of
9579 // days" because the number of days on the epoch (1970/1/1) should be 0,
9580 // not 1
9581 // Note: In ISO 8601, Sun: weekday=7 Mon: weekday=1
9582 // In DateCache API, Sun: weekday=0 Mon: weekday=1
9583 // 6. Return ℝ(_dayOfWeek_).
9584 return weekday == 0 ? 7 : weekday;
9585}
9586
9587// #sec-temporal-regulateisodate
9588Maybe<DateRecord> RegulateISODate(Isolate* isolate, ShowOverflow overflow,
9589 const DateRecord& date) {
9591
9592 // 1. Assert: year, month, and day are integers.
9593 // 2. Assert: overflow is either "constrain" or "reject".
9594 switch (overflow) {
9595 // 3. If overflow is "reject", then
9596 case ShowOverflow::kReject:
9597 // a. If ! IsValidISODate(year, month, day) is false, throw a RangeError
9598 // exception.
9599 if (!IsValidISODate(isolate, date)) {
9603 }
9604 // b. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day
9605 // }.
9606 return Just(date);
9607 // 4. If overflow is "constrain", then
9608 case ShowOverflow::kConstrain:
9609 DateRecord result(date);
9610 // a. Set month to ! ConstrainToRange(month, 1, 12).
9611 result.month = std::max(std::min(result.month, 12), 1);
9612 // b. Set day to ! ConstrainToRange(day, 1, ! ISODaysInMonth(year,
9613 // month)).
9614 result.day =
9615 std::max(std::min(result.day,
9616 ISODaysInMonth(isolate, result.year, result.month)),
9617 1);
9618 // c. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day
9619 // }.
9620 return Just(result);
9621 }
9622}
9623
9624// #sec-temporal-regulateisoyearmonth
9625Maybe<int32_t> RegulateISOYearMonth(Isolate* isolate, ShowOverflow overflow,
9626 int32_t month) {
9627 // 1. Assert: year and month are integers.
9628 // 2. Assert: overflow is either "constrain" or "reject".
9629 switch (overflow) {
9630 // 3. If overflow is "constrain", then
9631 case ShowOverflow::kConstrain:
9632 // a. Return ! ConstrainISOYearMonth(year, month).
9633 return Just(std::max(std::min(month, 12), 1));
9634 // 4. If overflow is "reject", then
9635 case ShowOverflow::kReject:
9636 // a. If ! IsValidISOMonth(month) is false, throw a RangeError exception.
9637 if (month < 1 || 12 < month) {
9641 }
9642 // b. Return the new Record { [[Year]]: year, [[Month]]: month }.
9643 return Just(month);
9644 default:
9645 UNREACHABLE();
9646 }
9647}
9648
9649// #sec-temporal-resolveisomonth
9650Maybe<int32_t> ResolveISOMonth(Isolate* isolate,
9651 DirectHandle<JSReceiver> fields) {
9652 Factory* factory = isolate->factory();
9653 // 1. Let month be ! Get(fields, "month").
9654 DirectHandle<Object> month_obj =
9655 JSReceiver::GetProperty(isolate, fields, factory->month_string())
9656 .ToHandleChecked();
9657 // 2. Let monthCode be ! Get(fields, "monthCode").
9658 DirectHandle<Object> month_code_obj =
9659 JSReceiver::GetProperty(isolate, fields, factory->monthCode_string())
9660 .ToHandleChecked();
9661 // 3. If monthCode is undefined, then
9662 if (IsUndefined(*month_code_obj, isolate)) {
9663 // a. If month is undefined, throw a TypeError exception.
9664 if (IsUndefined(*month_obj, isolate)) {
9667 }
9668 // b. Return month.
9669 // Note: In Temporal spec, "month" in fields is always converted by
9670 // ToPositiveInteger inside PrepareTemporalFields before calling
9671 // ResolveISOMonth. Therefore the month_obj is always a positive integer.
9672 DCHECK(IsSmi(*month_obj) || IsHeapNumber(*month_obj));
9673 return Just(FastD2I(Object::NumberValue(Cast<Number>(*month_obj))));
9674 }
9675 // 4. Assert: Type(monthCode) is String.
9676 DCHECK(IsString(*month_code_obj));
9677 DirectHandle<String> month_code;
9678 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, month_code,
9679 Object::ToString(isolate, month_code_obj),
9681 // 5. Let monthLength be the length of monthCode.
9682 // 6. If monthLength is not 3, throw a RangeError exception.
9683 if (month_code->length() != 3) {
9685 isolate,
9686 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
9687 factory->monthCode_string()),
9689 }
9690 // 7. Let numberPart be the substring of monthCode from 1.
9691 // 8. Set numberPart to ! ToIntegerOrInfinity(numberPart).
9692 // 9. If numberPart < 1 or numberPart > 12, throw a RangeError exception.
9693 uint16_t m0 = month_code->Get(0);
9694 uint16_t m1 = month_code->Get(1);
9695 uint16_t m2 = month_code->Get(2);
9696 if (!((m0 == 'M') && ((m1 == '0' && '1' <= m2 && m2 <= '9') ||
9697 (m1 == '1' && '0' <= m2 && m2 <= '2')))) {
9699 isolate,
9700 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
9701 factory->monthCode_string()),
9703 }
9704 int32_t number_part =
9705 10 * static_cast<int32_t>(m1 - '0') + static_cast<int32_t>(m2 - '0');
9706 // 10. If month is not undefined, and month ≠ numberPart, then
9707 // 11. If ! SameValueNonNumeric(monthCode, ! BuildISOMonthCode(numberPart)) is
9708 // false, then a. Throw a RangeError exception.
9709 // Note: In Temporal spec, "month" in fields is always converted by
9710 // ToPositiveInteger inside PrepareTemporalFields before calling
9711 // ResolveISOMonth. Therefore the month_obj is always a positive integer.
9712 if (!IsUndefined(*month_obj) &&
9713 FastD2I(Object::NumberValue(Cast<Number>(*month_obj))) != number_part) {
9714 // a. Throw a RangeError exception.
9716 isolate,
9717 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
9718 factory->month_string()),
9720 }
9721
9722 // 12. Return numberPart.
9723 return Just(number_part);
9724}
9725
9726// #sec-temporal-isodatefromfields
9727Maybe<DateRecord> ISODateFromFields(Isolate* isolate,
9728 DirectHandle<JSReceiver> fields,
9729 DirectHandle<JSReceiver> options,
9730 const char* method_name) {
9731 Factory* factory = isolate->factory();
9732
9733 // 1. Assert: Type(fields) is Object.
9734 // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month",
9735 // "monthCode", "year" », «"year", "day"»).
9736 DirectHandle<FixedArray> field_names =
9737 DayMonthMonthCodeYearInFixedArray(isolate);
9739 isolate, fields,
9740 PrepareTemporalFields(isolate, fields, field_names,
9741 RequiredFields::kYearAndDay),
9743 // 3. Let overflow be ? ToTemporalOverflow(options).
9744 ShowOverflow overflow;
9746 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
9748
9749 // 4. Let year be ! Get(fields, "year").
9750 DirectHandle<Object> year_obj =
9751 JSReceiver::GetProperty(isolate, fields, factory->year_string())
9752 .ToHandleChecked();
9753 // 5. Assert: Type(year) is Number.
9754 // Note: "year" in fields is always converted by
9755 // ToIntegerThrowOnInfinity inside the PrepareTemporalFields above.
9756 // Therefore the year_obj is always an integer.
9757 DCHECK(IsSmi(*year_obj) || IsHeapNumber(*year_obj));
9758
9759 // 6. Let month be ? ResolveISOMonth(fields).
9760 int32_t month;
9762 isolate, month, ResolveISOMonth(isolate, fields), Nothing<DateRecord>());
9763
9764 // 7. Let day be ! Get(fields, "day").
9765 DirectHandle<Object> day_obj =
9766 JSReceiver::GetProperty(isolate, fields, factory->day_string())
9767 .ToHandleChecked();
9768 // 8. Assert: Type(day) is Number.
9769 // Note: "day" in fields is always converted by
9770 // ToIntegerThrowOnInfinity inside the PrepareTemporalFields above.
9771 // Therefore the day_obj is always an integer.
9772 DCHECK(IsSmi(*day_obj) || IsHeapNumber(*day_obj));
9773 // 9. Return ? RegulateISODate(year, month, day, overflow).
9774 return RegulateISODate(
9775 isolate, overflow,
9776 {FastD2I(Object::NumberValue(Cast<Number>(*year_obj))), month,
9778}
9779
9780// #sec-temporal-addisodate
9781Maybe<DateRecord> AddISODate(Isolate* isolate, const DateRecord& date,
9782 const DateDurationRecord& duration,
9783 ShowOverflow overflow) {
9785
9786 // 1. Assert: year, month, day, years, months, weeks, and days are integers.
9787 // 2. Assert: overflow is either "constrain" or "reject".
9788 DCHECK(overflow == ShowOverflow::kConstrain ||
9789 overflow == ShowOverflow::kReject);
9790 // 3. Let intermediate be ! BalanceISOYearMonth(year + years, month + months).
9791 DateRecord intermediate = date;
9792 intermediate.year += static_cast<int32_t>(duration.years);
9793 intermediate.month += static_cast<int32_t>(duration.months);
9794 BalanceISOYearMonth(isolate, &intermediate.year, &intermediate.month);
9795 // 4. Let intermediate be ? RegulateISODate(intermediate.[[Year]],
9796 // intermediate.[[Month]], day, overflow).
9798 isolate, intermediate, RegulateISODate(isolate, overflow, intermediate),
9800
9801 // 5. Set days to days + 7 × weeks.
9802 // 6. Let d be intermediate.[[Day]] + days.
9803 intermediate.day += duration.days + 7 * duration.weeks;
9804 // 7. Return BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], d).
9805 return Just(BalanceISODate(isolate, intermediate));
9806}
9807
9808// #sec-temporal-differenceisodate
9809Maybe<DateDurationRecord> DifferenceISODate(Isolate* isolate,
9810 const DateRecord& date1,
9811 const DateRecord& date2,
9812 Unit largest_unit,
9813 const char* method_name) {
9815
9816 // 1. Assert: largestUnit is one of "year", "month", "week", or "day".
9817 DCHECK(largest_unit == Unit::kYear || largest_unit == Unit::kMonth ||
9818 largest_unit == Unit::kWeek || largest_unit == Unit::kDay);
9819 // 2. If largestUnit is "year" or "month", then
9820 switch (largest_unit) {
9821 case Unit::kYear:
9822 case Unit::kMonth: {
9823 // a. Let sign be -(! CompareISODate(y1, m1, d1, y2, m2, d2)).
9824 int32_t sign = -CompareISODate(date1, date2);
9825 // b. If sign is 0, return ! CreateDateDurationRecord(0, 0, 0, 0).
9826 if (sign == 0) {
9827 return DateDurationRecord::Create(isolate, 0, 0, 0, 0);
9828 }
9829
9830 // c. Let start be the new Record { [[Year]]: y1, [[Month]]: m1, [[Day]]:
9831 // d1
9832 // }.
9833 DateRecord start = date1;
9834 // d. Let end be the new Record { [[Year]]: y2, [[Month]]: m2, [[Day]]:
9835 // d2 }.
9836 DateRecord end = date2;
9837 // e. Let years be end.[[Year]] − start.[[Year]].
9838 double years = end.year - start.year;
9839 // f. Let mid be ! AddISODate(y1, m1, d1, years, 0, 0, 0, "constrain").
9840 DateRecord mid;
9842 isolate, mid,
9843 AddISODate(isolate, date1, {years, 0, 0, 0},
9844 ShowOverflow::kConstrain),
9846
9847 // g. Let midSign be -(! CompareISODate(mid.[[Year]], mid.[[Month]],
9848 // mid.[[Day]], y2, m2, d2)).
9849 int32_t mid_sign = -CompareISODate(mid, date2);
9850
9851 // h. If midSign is 0, then
9852 if (mid_sign == 0) {
9853 // i. If largestUnit is "year", return ! CreateDateDurationRecord(years,
9854 // 0, 0, 0).
9855 if (largest_unit == Unit::kYear) {
9856 return DateDurationRecord::Create(isolate, years, 0, 0, 0);
9857 }
9858 // ii. Return ! CreateDateDurationRecord(0, years × 12, 0, 0).
9859 return DateDurationRecord::Create(isolate, 0, years * 12, 0, 0);
9860 }
9861 // i. Let months be end.[[Month]] − start.[[Month]].
9862 double months = end.month - start.month;
9863 // j. If midSign is not equal to sign, then
9864 if (mid_sign != sign) {
9865 // i. Set years to years - sign.
9866 years -= sign;
9867 // ii. Set months to months + sign × 12.
9868 months += sign * 12;
9869 }
9870 // k. Set mid be ! AddISODate(y1, m1, d1, years, months, 0, 0,
9871 // "constrain").
9873 isolate, mid,
9874 AddISODate(isolate, date1, {years, months, 0, 0},
9875 ShowOverflow::kConstrain),
9877 // l. Let midSign be -(! CompareISODate(mid.[[Year]], mid.[[Month]],
9878 // mid.[[Day]], y2, m2, d2)).
9879 mid_sign = -CompareISODate(mid, date2);
9880 // m. If midSign is 0, then
9881 if (mid_sign == 0) {
9882 // 1. i. If largestUnit is "year", return !
9883 // CreateDateDurationRecord(years, months, 0, 0).
9884 if (largest_unit == Unit::kYear) {
9885 return DateDurationRecord::Create(isolate, years, months, 0, 0);
9886 }
9887 // ii. Return ! CreateDateDurationRecord(0, months + years × 12, 0, 0).
9888 return DateDurationRecord::Create(isolate, 0, months + years * 12, 0,
9889 0);
9890 }
9891 // n. If midSign is not equal to sign, then
9892 if (mid_sign != sign) {
9893 // i. Set months to months - sign.
9894 months -= sign;
9895 // ii. If months is equal to -sign, then
9896 if (months == -sign) {
9897 // 1. Set years to years - sign.
9898 years -= sign;
9899 // 2. Set months to 11 × sign.
9900 months = 11 * sign;
9901 }
9902 // iii. Set mid be ! AddISODate(y1, m1, d1, years, months, 0, 0,
9903 // "constrain").
9905 isolate, mid,
9906 AddISODate(isolate, date1, {years, months, 0, 0},
9907 ShowOverflow::kConstrain),
9909 // iv. Let midSign be -(! CompareISODate(mid.[[Year]], mid.[[Month]],
9910 // mid.[[Day]], y2, m2, d2)).
9911 mid_sign = -CompareISODate(mid, date2);
9912 }
9913 // o. Let days be 0.
9914 double days = 0;
9915 // p. If mid.[[Month]] = end.[[Month]], then
9916 if (mid.month == end.month) {
9917 // i. Assert: mid.[[Year]] = end.[[Year]].
9918 DCHECK_EQ(mid.year, end.year);
9919 // ii. Set days to end.[[Day]] - mid.[[Day]].
9920 days = end.day - mid.day;
9921 } else if (sign < 0) {
9922 // q. Else if sign < 0, set days to -mid.[[Day]] - (!
9923 // ISODaysInMonth(end.[[Year]], end.[[Month]]) - end.[[Day]]).
9924 days =
9925 -mid.day - (ISODaysInMonth(isolate, end.year, end.month) - end.day);
9926 } else {
9927 // r. Else, set days to end.[[Day]] + (! ISODaysInMonth(mid.[[Year]],
9928 // mid.[[Month]]) - mid.[[Day]]).
9929 days =
9930 end.day + (ISODaysInMonth(isolate, mid.year, mid.month) - mid.day);
9931 }
9932 // s. If largestUnit is "month", then
9933 if (largest_unit == Unit::kMonth) {
9934 // i. Set months to months + years × 12.
9935 months += years * 12;
9936 // ii. Set years to 0.
9937 years = 0;
9938 }
9939 // t. Return ! CreateDateDurationRecord(years, months, 0, days).
9940 return DateDurationRecord::Create(isolate, years, months, 0, days);
9941 }
9942 // 3. If largestUnit is "day" or "week", then
9943 case Unit::kDay:
9944 case Unit::kWeek: {
9945 DateRecord smaller, greater;
9946 // a. If ! CompareISODate(y1, m1, d1, y2, m2, d2) < 0, then
9947 int32_t sign;
9948 if (CompareISODate(date1, date2) < 0) {
9949 // i. Let smaller be the Record { [[Year]]: y1, [[Month]]: m1, [[Day]]:
9950 // d1
9951 // }.
9952 smaller = date1;
9953 // ii. Let greater be the Record { [[Year]]: y2, [[Month]]: m2, [[Day]]:
9954 // d2
9955 // }.
9956 greater = date2;
9957 // iii. Let sign be 1.
9958 sign = 1;
9959 } else {
9960 // b. Else,
9961 // i. Let smaller be the new Record { [[Year]]: y2, [[Month]]: m2,
9962 // [[Day]]: d2 }.
9963 smaller = date2;
9964 // ii. Let greater be the new Record { [[Year]]: y1, [[Month]]: m1,
9965 // [[Day]]: d1 }.
9966 greater = date1;
9967 // iii. Let sign be −1.
9968 sign = -1;
9969 }
9970 // c. Let days be ! ToISODayOfYear(greater.[[Year]], greater.[[Month]],
9971 // greater.[[Day]]) − ! ToISODayOfYear(smaller.[[Year]],
9972 // smaller.[[Month]], smaller.[[Day]]).
9973 int32_t days =
9974 ToISODayOfYear(isolate, greater) - ToISODayOfYear(isolate, smaller);
9975 // d. Let year be smaller.[[Year]].
9976 // e. Repeat, while year < greater.[[Year]],
9977 for (int32_t year = smaller.year; year < greater.year; year++) {
9978 // i. Set days to days + ! ISODaysInYear(year).
9979 // ii. Set year to year + 1.
9980 days += ISODaysInYear(isolate, year);
9981 }
9982 // f. Let weeks be 0.
9983 int32_t weeks = 0;
9984 // g. If largestUnit is "week", then
9985 if (largest_unit == Unit::kWeek) {
9986 // i. Set weeks to floor(days / 7).
9987 weeks = days / 7;
9988 // ii. Set days to days mod 7.
9989 days = days % 7;
9990 }
9991 // h. Return ! CreateDateDurationRecord(0, 0, weeks × sign, days × sign).
9992 return DateDurationRecord::Create(isolate, 0, 0, weeks * sign,
9993 days * sign);
9994 }
9995 default:
9996 UNREACHABLE();
9997 }
9998}
9999
10000// #sec-temporal-isoyearmonthfromfields
10001Maybe<DateRecord> ISOYearMonthFromFields(Isolate* isolate,
10002 DirectHandle<JSReceiver> fields,
10003 DirectHandle<JSReceiver> options,
10004 const char* method_name) {
10005 Factory* factory = isolate->factory();
10006 // 1. Assert: Type(fields) is Object.
10007 // 2. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode",
10008 // "year" », «»).
10009 DirectHandle<FixedArray> field_names = factory->NewFixedArray(3);
10010 field_names->set(0, ReadOnlyRoots(isolate).month_string());
10011 field_names->set(1, ReadOnlyRoots(isolate).monthCode_string());
10012 field_names->set(2, ReadOnlyRoots(isolate).year_string());
10014 isolate, fields,
10015 PrepareTemporalFields(isolate, fields, field_names,
10016 RequiredFields::kNone),
10018 // 3. Let overflow be ? ToTemporalOverflow(options).
10019 ShowOverflow overflow;
10021 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
10023
10024 // 4. Let year be ! Get(fields, "year").
10025 DirectHandle<Object> year_obj =
10026 JSReceiver::GetProperty(isolate, fields, factory->year_string())
10027 .ToHandleChecked();
10028 // 5. If year is undefined, throw a TypeError exception.
10029 if (IsUndefined(*year_obj, isolate)) {
10032 }
10033 DateRecord result;
10034 result.year = FastD2I(floor(Object::NumberValue(Cast<Number>(*year_obj))));
10035 // 6. Let month be ? ResolveISOMonth(fields).
10036 int32_t month;
10038 isolate, month, ResolveISOMonth(isolate, fields), Nothing<DateRecord>());
10039 // 7. Let result be ? RegulateISOYearMonth(year, month, overflow).
10041 isolate, result.month, RegulateISOYearMonth(isolate, overflow, month),
10043 // 8. Return the new Record { [[Year]]: result.[[Year]], [[Month]]:
10044 // result.[[Month]], [[ReferenceISODay]]: 1 }.
10045 result.day = 1;
10046 return Just(result);
10047}
10048
10049// #sec-temporal-toisoweekofyear
10050int32_t ToISOWeekOfYear(Isolate* isolate, const DateRecord& date) {
10052 // 1. Assert: IsValidISODate(year, month, day) is *true*.
10053 DCHECK(IsValidISODate(isolate, date));
10054
10055 // 2. Let wednesday be 3.
10056 constexpr int32_t kWednesday = 3;
10057 // 3. Let thursday_ be 4.
10058 constexpr int32_t kThursday = 4;
10059 // 4. Let friday be 5.
10060 constexpr int32_t kFriday = 5;
10061 // 5. Let saturday be 6.
10062 constexpr int32_t kSaturday = 6;
10063 // 6. Let daysInWeek be 7.
10064 constexpr int32_t kDaysInWeek = 7;
10065 // 7. Let maxWeekNumber be 53.
10066 constexpr int32_t kMaxWeekNumber = 53;
10067 // 8. Let dayOfYear be ToISODayOfYear(year, month, day).
10068 int32_t day_of_year = ToISODayOfYear(isolate, date);
10069 // 9. Let dayOfWeek be ToISODayOfWeek(year, month, day).
10070 int32_t day_of_week = ToISODayOfWeek(isolate, date);
10071 // 10. Let week be floor((dayOfYear + daysInWeek - dayOfWeek + wednesday ) /
10072 // daysInWeek).
10073 int32_t week =
10074 (day_of_year + kDaysInWeek - day_of_week + kWednesday) / kDaysInWeek;
10075 // 11. If week < 1, then
10076 if (week < 1) {
10077 // a. NOTE: This is the last week of the previous year.
10078 // b. Let dayOfJan1st be ToISODayOfWeek(year, 1, 1).
10079 int32_t day_of_jan_1st = ToISODayOfWeek(isolate, {date.year, 1, 1});
10080 // c. If dayOfJan1st is friday, then
10081 if (day_of_jan_1st == kFriday) {
10082 // a. Return maxWeekNumber.
10083 return kMaxWeekNumber;
10084 }
10085 // d. If dayOfJan1st is saturday, and InLeapYear(TimeFromYear(𝔽(year - 1)))
10086 // is *1*<sub>𝔽</sub>, then
10087 if (day_of_jan_1st == kSaturday && IsISOLeapYear(isolate, date.year - 1)) {
10088 // i. Return maxWeekNumber.
10089 return kMaxWeekNumber;
10090 }
10091 // e. Return maxWeekNumber - 1.
10092 return kMaxWeekNumber - 1;
10093 }
10094 // 12. If week is maxWeekNumber, then
10095 if (week == kMaxWeekNumber) {
10096 // a. Let daysInYear be DaysInYear(𝔽(year)).
10097 int32_t days_in_year = ISODaysInYear(isolate, date.year);
10098 // b. Let daysLaterInYear be daysInYear - dayOfYear.
10099 int32_t days_later_in_year = days_in_year - day_of_year;
10100 // c. Let daysAfterThursday be thursday - dayOfWeek.
10101 int32_t days_after_thursday = kThursday - day_of_week;
10102 // d. If daysLaterInYear &lt; daysAfterThursday, then
10103 if (days_later_in_year < days_after_thursday) {
10104 // 1. Return 1.
10105 return 1;
10106 }
10107 }
10108 // 13. Return week.
10109 return week;
10110}
10111
10112} // namespace
10113
10114// #sec-temporal.calendar.prototype.dateadd
10117 DirectHandle<Object> date_obj, DirectHandle<Object> duration_obj,
10118 DirectHandle<Object> options_obj) {
10119 const char* method_name = "Temporal.Calendar.prototype.dateAdd";
10120 // 1. Let calendar be the this value.
10121 // 2. Perform ? RequireInternalSlot(calendar,
10122 // [[InitializedTemporalCalendar]]).
10123 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10124 // 4. Set date to ? ToTemporalDate(date).
10127 ToTemporalDate(isolate, date_obj, method_name));
10128
10129 // 5. Set duration to ? ToTemporalDuration(duration).
10132 isolate, duration,
10133 temporal::ToTemporalDuration(isolate, duration_obj, method_name));
10134
10135 // 6. Set options to ? GetOptionsObject(options).
10138 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10139
10140 // 7. Let overflow be ? ToTemporalOverflow(options).
10141 ShowOverflow overflow;
10143 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
10145
10146 // 8. Let balanceResult be ? BalanceDuration(duration.[[Days]],
10147 // duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]],
10148 // duration.[[Milliseconds]], duration.[[Microseconds]],
10149 // duration.[[Nanoseconds]], "day").
10150 TimeDurationRecord balance_result;
10152 isolate, balance_result,
10153 BalanceDuration(isolate, Unit::kDay,
10154 {Object::NumberValue(duration->days()),
10155 Object::NumberValue(duration->hours()),
10156 Object::NumberValue(duration->minutes()),
10157 Object::NumberValue(duration->seconds()),
10158 Object::NumberValue(duration->milliseconds()),
10159 Object::NumberValue(duration->microseconds()),
10160 Object::NumberValue(duration->nanoseconds())},
10161 method_name),
10163
10164 DateRecord result;
10165 // If calendar.[[Identifier]] is "iso8601", then
10166 if (calendar->calendar_index() == 0) {
10167 // 9. Let result be ? AddISODate(date.[[ISOYear]], date.[[ISOMonth]],
10168 // date.[[ISODay]], duration.[[Years]], duration.[[Months]],
10169 // duration.[[Weeks]], balanceResult.[[Days]], overflow).
10171 isolate, result,
10172 AddISODate(
10173 isolate, {date->iso_year(), date->iso_month(), date->iso_day()},
10174 {Object::NumberValue(duration->years()),
10175 Object::NumberValue(duration->months()),
10176 Object::NumberValue(duration->weeks()), balance_result.days},
10177 overflow),
10179 } else {
10180#ifdef V8_INTL_SUPPORT
10181 // TODO(ftang) add code for other calendar.
10182 UNIMPLEMENTED();
10183#else // V8_INTL_SUPPORT
10184 UNREACHABLE();
10185#endif // V8_INTL_SUPPORT
10186 }
10187 // 10. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
10188 // result.[[Day]], calendar).
10189 return CreateTemporalDate(isolate, result, calendar);
10190}
10191
10192// #sec-temporal.calendar.prototype.daysinyear
10195 DirectHandle<Object> temporal_date_like) {
10196 // 1. Let calendar be the this value.
10197 // 2. Perform ? RequireInternalSlot(calendar,
10198 // [[InitializedTemporalCalendar]]).
10199 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10200 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10201 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]] or
10202 // [[InitializedTemporalYearMonth]] internal slot, then
10203 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10204 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10206 isolate, temporal_date_like,
10207 ToTemporalDate(isolate, temporal_date_like,
10208 "Temporal.Calendar.prototype.daysInYear"));
10209 }
10210
10211 // a. Let daysInYear be ! ISODaysInYear(temporalDateLike.[[ISOYear]]).
10212 int32_t year;
10213 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10214 year = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_year();
10215 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10216 year = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_year();
10217 } else {
10218 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10219 year = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_year();
10220 }
10221 int32_t days_in_year = ISODaysInYear(isolate, year);
10222 // 6. Return 𝔽(daysInYear).
10223 return direct_handle(Smi::FromInt(days_in_year), isolate);
10224}
10225
10226// #sec-temporal.calendar.prototype.daysinmonth
10229 DirectHandle<Object> temporal_date_like) {
10230 // 1 Let calendar be the this value.
10231 // 2. Perform ? RequireInternalSlot(calendar,
10232 // [[InitializedTemporalCalendar]]).
10233 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10234 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10235 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]] or
10236 // [[InitializedTemporalYearMonth]] internal slot, then
10237 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10238 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10240 isolate, temporal_date_like,
10241 ToTemporalDate(isolate, temporal_date_like,
10242 "Temporal.Calendar.prototype.daysInMonth"));
10243 }
10244
10245 // 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]],
10246 // temporalDateLike.[[ISOMonth]])).
10247 int32_t year;
10248 int32_t month;
10249 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10250 year = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_year();
10251 month = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_month();
10252 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10253 year = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_year();
10254 month = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_month();
10255 } else {
10256 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10257 year = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_year();
10258 month = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_month();
10259 }
10260 return direct_handle(Smi::FromInt(ISODaysInMonth(isolate, year, month)),
10261 isolate);
10262}
10263
10264// #sec-temporal.calendar.prototype.year
10267 DirectHandle<Object> temporal_date_like) {
10268 // 1. Let calendar be the this value.
10269 // 2. Perform ? RequireInternalSlot(calendar,
10270 // [[InitializedTemporalCalendar]]).
10271 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10272 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10273 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
10274 // or [[InitializedTemporalYearMonth]]
10275 // internal slot, then
10276 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10277 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10279 isolate, temporal_date_like,
10280 ToTemporalDate(isolate, temporal_date_like,
10281 "Temporal.Calendar.prototype.year"));
10282 }
10283
10284 // a. Let year be ! ISOYear(temporalDateLike).
10285 int32_t year;
10286 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10287 year = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_year();
10288 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10289 year = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_year();
10290 } else {
10291 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10292 year = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_year();
10293 }
10294
10295 // 6. Return 𝔽(year).
10296 return direct_handle(Smi::FromInt(year), isolate);
10297}
10298
10299// #sec-temporal.calendar.prototype.dayofyear
10302 DirectHandle<Object> temporal_date_like) {
10303 // 1. Let calendar be the this value.
10304 // 2. Perform ? RequireInternalSlot(calendar,
10305 // [[InitializedTemporalCalendar]]).
10306 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10307 // 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
10310 isolate, temporal_date,
10311 ToTemporalDate(isolate, temporal_date_like,
10312 "Temporal.Calendar.prototype.dayOfYear"));
10313 // a. Let value be ! ToISODayOfYear(temporalDate.[[ISOYear]],
10314 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
10315 int32_t value = ToISODayOfYear(
10316 isolate, {temporal_date->iso_year(), temporal_date->iso_month(),
10317 temporal_date->iso_day()});
10318 return direct_handle(Smi::FromInt(value), isolate);
10319}
10320
10321// #sec-temporal.calendar.prototype.dayofweek
10324 DirectHandle<Object> temporal_date_like) {
10325 // 1. Let calendar be the this value.
10326 // 2. Perform ? RequireInternalSlot(calendar,
10327 // [[InitializedTemporalCalendar]]).
10328 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10329 // 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
10332 isolate, temporal_date,
10333 ToTemporalDate(isolate, temporal_date_like,
10334 "Temporal.Calendar.prototype.dayOfWeek"));
10335 // a. Let value be ! ToISODayOfWeek(temporalDate.[[ISOYear]],
10336 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
10337 int32_t value = ToISODayOfWeek(
10338 isolate, {temporal_date->iso_year(), temporal_date->iso_month(),
10339 temporal_date->iso_day()});
10340 return direct_handle(Smi::FromInt(value), isolate);
10341}
10342
10343// #sec-temporal.calendar.prototype.monthsinyear
10346 DirectHandle<Object> temporal_date_like) {
10347 // 1. Let calendar be the this value.
10348 // 2. Perform ? RequireInternalSlot(calendar,
10349 // [[InitializedTemporalCalendar]]).
10350 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10351 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10352 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], or
10353 // [[InitializedTemporalYearMonth]] internal slot, then
10354 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10355 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10357 isolate, temporal_date_like,
10358 ToTemporalDate(isolate, temporal_date_like,
10359 "Temporal.Calendar.prototype.monthsInYear"));
10360 }
10361
10362 // a. a. Let monthsInYear be 12.
10363 int32_t months_in_year = 12;
10364 // 6. Return 𝔽(monthsInYear).
10365 return direct_handle(Smi::FromInt(months_in_year), isolate);
10366}
10367
10368// #sec-temporal.calendar.prototype.inleapyear
10371 DirectHandle<Object> temporal_date_like) {
10372 // 1. Let calendar be the this value.
10373 // 2. Perform ? RequireInternalSlot(calendar,
10374 // [[InitializedTemporalCalendar]]).
10375 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10376 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10377 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], or
10378 // [[InitializedTemporalYearMonth]] internal slot, then
10379 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10380 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10382 isolate, temporal_date_like,
10383 ToTemporalDate(isolate, temporal_date_like,
10384 "Temporal.Calendar.prototype.inLeapYear"));
10385 }
10386
10387 // a. Let inLeapYear be ! IsISOLeapYear(temporalDateLike.[[ISOYear]]).
10388 int32_t year;
10389 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10390 year = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_year();
10391 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10392 year = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_year();
10393 } else {
10394 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10395 year = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_year();
10396 }
10397 return isolate->factory()->ToBoolean(IsISOLeapYear(isolate, year));
10398}
10399
10400// #sec-temporal.calendar.prototype.daysinweek
10403 DirectHandle<Object> temporal_date_like) {
10404 // 1. Let calendar be the this value.
10405 // 2. Perform ? RequireInternalSlot(calendar,
10406 // [[InitializedTemporalCalendar]]).
10407 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10408 // 4. Perform ? ToTemporalDate(temporalDateLike).
10411 isolate, date,
10412 ToTemporalDate(isolate, temporal_date_like,
10413 "Temporal.Calendar.prototype.daysInWeek"));
10414 // 5. Return 7𝔽.
10415 return direct_handle(Smi::FromInt(7), isolate);
10416}
10417
10418// #sec-temporal.calendar.prototype.datefromfields
10421 DirectHandle<Object> fields_obj, DirectHandle<Object> options_obj) {
10422 // 1. Let calendar be the this value.
10423 // 2. Perform ? RequireInternalSlot(calendar,
10424 // [[InitializedTemporalCalendar]]).
10425 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10426 // 4. If Type(fields) is not Object, throw a TypeError exception.
10427 const char* method_name = "Temporal.Calendar.prototype.dateFromFields";
10428 if (!IsJSReceiver(*fields_obj)) {
10429 THROW_NEW_ERROR(isolate,
10430 NewTypeError(MessageTemplate::kCalledOnNonObject,
10431 isolate->factory()->NewStringFromAsciiChecked(
10432 method_name)));
10433 }
10434 DirectHandle<JSReceiver> fields = Cast<JSReceiver>(fields_obj);
10435
10436 // 5. Set options to ? GetOptionsObject(options).
10439 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10440 if (calendar->calendar_index() == 0) {
10441 // 6. Let result be ? ISODateFromFields(fields, options).
10442 DateRecord result;
10444 isolate, result,
10445 ISODateFromFields(isolate, fields, options, method_name),
10447 // 7. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
10448 // result.[[Day]], calendar).
10449 return CreateTemporalDate(isolate, result, calendar);
10450 }
10451 // TODO(ftang) add intl implementation inside #ifdef V8_INTL_SUPPORT
10452 UNREACHABLE();
10453}
10454
10455// #sec-temporal.calendar.prototype.mergefields
10458 DirectHandle<Object> fields_obj,
10459 DirectHandle<Object> additional_fields_obj) {
10460 // 1. Let calendar be the this value.
10461 // 2. Perform ? RequireInternalSlot(calendar,
10462 // [[InitializedTemporalCalendar]]).
10463 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10464 // 4. Set fields to ? ToObject(fields).
10466 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
10467 Object::ToObject(isolate, fields_obj));
10468
10469 // 5. Set additionalFields to ? ToObject(additionalFields).
10470 DirectHandle<JSReceiver> additional_fields;
10471 ASSIGN_RETURN_ON_EXCEPTION(isolate, additional_fields,
10472 Object::ToObject(isolate, additional_fields_obj));
10473 // 5. If calendar.[[Identifier]] is "iso8601", then
10474 if (calendar->calendar_index() == 0) {
10475 // a. Return ? DefaultMergeFields(fields, additionalFields).
10476 return DefaultMergeFields(isolate, fields, additional_fields);
10477 }
10478#ifdef V8_INTL_SUPPORT
10479 // TODO(ftang) add Intl code.
10480#endif // V8_INTL_SUPPORT
10481 UNREACHABLE();
10482}
10483
10484// #sec-temporal.calendar.prototype.dateuntil
10488 DirectHandle<Object> options_obj) {
10489 const char* method_name = "Temporal.Calendar.prototype.dateUntil";
10490 // 1. Let calendar be the this value.
10491 // 2. Perform ? RequireInternalSlot(calendar,
10492 // [[InitializedTemporalCalendar]]).
10493 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10494 // 4. Set one to ? ToTemporalDate(one).
10497 ToTemporalDate(isolate, one_obj, method_name));
10498 // 5. Set two to ? ToTemporalDate(two).
10500 ASSIGN_RETURN_ON_EXCEPTION(isolate, two,
10501 ToTemporalDate(isolate, two_obj, method_name));
10502 // 6. Set options to ? GetOptionsObject(options).
10505 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10506
10507 // 7. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", date,
10508 // "auto").
10509 Unit largest_unit;
10511 isolate, largest_unit,
10512 GetTemporalUnit(isolate, options, "largestUnit", UnitGroup::kDate,
10513 Unit::kAuto, false, method_name),
10515 // 8. If largestUnit is "auto", set largestUnit to "day".
10516 if (largest_unit == Unit::kAuto) largest_unit = Unit::kDay;
10517
10518 // 9. Let result be ! DifferenceISODate(one.[[ISOYear]], one.[[ISOMonth]],
10519 // one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]],
10520 // largestUnit).
10521 DateDurationRecord result;
10523 isolate, result,
10524 DifferenceISODate(isolate,
10525 {one->iso_year(), one->iso_month(), one->iso_day()},
10526 {two->iso_year(), two->iso_month(), two->iso_day()},
10527 largest_unit, method_name),
10529
10530 // 10. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]],
10531 // result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0).
10532 return CreateTemporalDuration(isolate, {result.years,
10533 result.months,
10534 result.weeks,
10535 {result.days, 0, 0, 0, 0, 0, 0}})
10536 .ToHandleChecked();
10537}
10538
10539// #sec-temporal.calendar.prototype.day
10542 DirectHandle<Object> temporal_date_like) {
10543 // 1. Let calendar be the this value.
10544 // 2. Perform ? RequireInternalSlot(calendar,
10545 // [[InitializedTemporalCalendar]]).
10546 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10547 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10548 // have an [[InitializedTemporalDate]] or [[InitializedTemporalMonthDay]]
10549 // internal slot, then
10550 if (!(IsJSTemporalPlainDate(*temporal_date_like) ||
10551 IsJSTemporalPlainDateTime(*temporal_date_like) ||
10552 IsJSTemporalPlainMonthDay(*temporal_date_like))) {
10553 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10555 isolate, temporal_date_like,
10556 ToTemporalDate(isolate, temporal_date_like,
10557 "Temporal.Calendar.prototype.day"));
10558 }
10559
10560 // 5. Let day be ! ISODay(temporalDateLike).
10561 int32_t day;
10562 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10563 day = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_day();
10564 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10565 day = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_day();
10566 } else {
10567 DCHECK(IsJSTemporalPlainMonthDay(*temporal_date_like));
10568 day = Cast<JSTemporalPlainMonthDay>(temporal_date_like)->iso_day();
10569 }
10570
10571 // 6. Return 𝔽(day).
10572 return direct_handle(Smi::FromInt(day), isolate);
10573}
10574
10575// #sec-temporal.calendar.prototype.monthcode
10578 DirectHandle<Object> temporal_date_like) {
10579 // 1. Let calendar be the this value.
10580 // 2. Perform ? RequireInternalSlot(calendar,
10581 // [[InitializedTemporalCalendar]]).
10582 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10583 // 4. If Type(temporalDateLike) is not Object or temporalDateLike does not
10584 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
10585 // [[InitializedTemporalMonthDay]], or
10586 // [[InitializedTemporalYearMonth]] internal slot, then
10587 if (!(IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like) ||
10588 IsJSTemporalPlainMonthDay(*temporal_date_like))) {
10589 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10591 isolate, temporal_date_like,
10592 ToTemporalDate(isolate, temporal_date_like,
10593 "Temporal.Calendar.prototype.monthCode"));
10594 }
10595
10596 // 5. Return ! ISOMonthCode(temporalDateLike).
10597 int32_t month;
10598 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10599 month = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_month();
10600 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10601 month = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_month();
10602 } else if (IsJSTemporalPlainMonthDay(*temporal_date_like)) {
10603 month = Cast<JSTemporalPlainMonthDay>(temporal_date_like)->iso_month();
10604 } else {
10605 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10606 month = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_month();
10607 }
10608 IncrementalStringBuilder builder(isolate);
10609 builder.AppendCharacter('M');
10610 if (month < 10) {
10611 builder.AppendCharacter('0');
10612 }
10613 builder.AppendInt(month);
10614
10615 return builder.Finish();
10616}
10617
10618// #sec-temporal.calendar.prototype.month
10621 DirectHandle<Object> temporal_date_like) {
10622 // 4. If Type(temporalDateLike) is Object and temporalDateLike has an
10623 // [[InitializedTemporalMonthDay]] internal slot, then
10624 if (IsJSTemporalPlainMonthDay(*temporal_date_like)) {
10625 // a. Throw a TypeError exception.
10627 }
10628 // 5. If Type(temporalDateLike) is not Object or temporalDateLike does not
10629 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
10630 // or [[InitializedTemporalYearMonth]]
10631 // internal slot, then
10632 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10633 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10635 isolate, temporal_date_like,
10636 ToTemporalDate(isolate, temporal_date_like,
10637 "Temporal.Calendar.prototype.month"));
10638 }
10639
10640 // 6. Return ! ISOMonth(temporalDateLike).
10641 int32_t month;
10642 if (IsJSTemporalPlainDate(*temporal_date_like)) {
10643 month = Cast<JSTemporalPlainDate>(temporal_date_like)->iso_month();
10644 } else if (IsJSTemporalPlainDateTime(*temporal_date_like)) {
10645 month = Cast<JSTemporalPlainDateTime>(temporal_date_like)->iso_month();
10646 } else {
10647 DCHECK(IsJSTemporalPlainYearMonth(*temporal_date_like));
10648 month = Cast<JSTemporalPlainYearMonth>(temporal_date_like)->iso_month();
10649 }
10650
10651 // 7. Return 𝔽(month).
10652 return direct_handle(Smi::FromInt(month), isolate);
10653}
10654
10655// #sec-temporal.calendar.prototype.monthdayfromfields
10659 DirectHandle<Object> fields_obj, DirectHandle<Object> options_obj) {
10660 // 1. Let calendar be the this value.
10661 // 2. Perform ? RequireInternalSlot(calendar,
10662 // [[InitializedTemporalCalendar]]).
10663 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10664 const char* method_name = "Temporal.Calendar.prototype.monthDayFromFields";
10665 // 4. If Type(fields) is not Object, throw a TypeError exception.
10666 if (!IsJSReceiver(*fields_obj)) {
10667 THROW_NEW_ERROR(isolate,
10668 NewTypeError(MessageTemplate::kCalledOnNonObject,
10669 isolate->factory()->NewStringFromAsciiChecked(
10670 method_name)));
10671 }
10672 DirectHandle<JSReceiver> fields = Cast<JSReceiver>(fields_obj);
10673 // 5. Set options to ? GetOptionsObject(options).
10676 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10677 // 6. Let result be ? ISOMonthDayFromFields(fields, options).
10678 if (calendar->calendar_index() == 0) {
10679 DateRecord result;
10681 isolate, result,
10682 ISOMonthDayFromFields(isolate, fields, options, method_name),
10684 // 7. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]],
10685 // calendar, result.[[ReferenceISOYear]]).
10686 return CreateTemporalMonthDay(isolate, result.month, result.day, calendar,
10687 result.year);
10688 }
10689 // TODO(ftang) add intl code inside #ifdef V8_INTL_SUPPORT
10690 UNREACHABLE();
10691}
10692
10693// #sec-temporal.calendar.prototype.yearmonthfromfields
10697 DirectHandle<Object> fields_obj, DirectHandle<Object> options_obj) {
10698 // 1. Let calendar be the this value.
10699 // 2. Perform ? RequireInternalSlot(calendar,
10700 // [[InitializedTemporalCalendar]]).
10701 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10702 const char* method_name = "Temporal.Calendar.prototype.yearMonthFromFields";
10703 // 4. If Type(fields) is not Object, throw a TypeError exception.
10704 if (!IsJSReceiver(*fields_obj)) {
10705 THROW_NEW_ERROR(isolate,
10706 NewTypeError(MessageTemplate::kCalledOnNonObject,
10707 isolate->factory()->NewStringFromAsciiChecked(
10708 method_name)));
10709 }
10710 DirectHandle<JSReceiver> fields = Cast<JSReceiver>(fields_obj);
10711 // 5. Set options to ? GetOptionsObject(options).
10714 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10715 // 6. Let result be ? ISOYearMonthFromFields(fields, options).
10716 if (calendar->calendar_index() == 0) {
10717 DateRecord result;
10719 isolate, result,
10720 ISOYearMonthFromFields(isolate, fields, options, method_name),
10722 // 7. Return ? CreateTemporalYearMonth(result.[[Year]], result.[[Month]],
10723 // calendar, result.[[ReferenceISODay]]).
10724 return CreateTemporalYearMonth(isolate, result.year, result.month, calendar,
10725 result.day);
10726 }
10727 // TODO(ftang) add intl code inside #ifdef V8_INTL_SUPPORT
10728 UNREACHABLE();
10729}
10730
10731#ifdef V8_INTL_SUPPORT
10732// #sup-temporal.calendar.prototype.era
10733MaybeDirectHandle<Object> JSTemporalCalendar::Era(
10735 DirectHandle<Object> temporal_date_like) {
10736 // 1. Let calendar be the this value.
10737 // 2. Perform ? RequireInternalSlot(calendar,
10738 // [[InitializedTemporalCalendar]]).
10739 // 3. If Type(temporalDateLike) is not Object or temporalDateLike does not
10740 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
10741 // or [[InitializedTemporalYearMonth]]
10742 // internal slot, then
10743 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10744 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10746 isolate, temporal_date_like,
10747 ToTemporalDate(isolate, temporal_date_like,
10748 "Temporal.Calendar.prototype.era"));
10749 }
10750 // 4. If calendar.[[Identifier]] is "iso8601", then
10751 if (calendar->calendar_index() == 0) {
10752 // a. Return undefined.
10753 return isolate->factory()->undefined_value();
10754 }
10755 UNIMPLEMENTED();
10756 // TODO(ftang) implement other calendars
10757 // 5. Return ! CalendarDateEra(calendar.[[Identifier]], temporalDateLike).
10758}
10759
10760// #sup-temporal.calendar.prototype.erayear
10761MaybeDirectHandle<Object> JSTemporalCalendar::EraYear(
10762 Isolate* isolate, DirectHandle<JSTemporalCalendar> calendar,
10763 DirectHandle<Object> temporal_date_like) {
10764 // 1. Let calendar be the this value.
10765 // 2. Perform ? RequireInternalSlot(calendar,
10766 // [[InitializedTemporalCalendar]]).
10767 // 3. If Type(temporalDateLike) is not Object or temporalDateLike does not
10768 // have an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]],
10769 // or [[InitializedTemporalYearMonth]]
10770 // internal slot, then
10771 if (!IsPlainDatePlainDateTimeOrPlainYearMonth(temporal_date_like)) {
10772 // a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
10774 isolate, temporal_date_like,
10775 ToTemporalDate(isolate, temporal_date_like,
10776 "Temporal.Calendar.prototype.eraYear"));
10777 }
10778 // 4. If calendar.[[Identifier]] is "iso8601", then
10779 if (calendar->calendar_index() == 0) {
10780 // a. Return undefined.
10781 return isolate->factory()->undefined_value();
10782 }
10783 UNIMPLEMENTED();
10784 // TODO(ftang) implement other calendars
10785 // 5. Let eraYear be ! CalendarDateEraYear(calendar.[[Identifier]],
10786 // temporalDateLike).
10787 // 6. If eraYear is undefined, then
10788 // a. Return undefined.
10789 // 7. Return 𝔽(eraYear).
10790}
10791
10792#endif // V8_INTL_SUPPORT
10793
10794// #sec-temporal.calendar.prototype.weekofyear
10797 DirectHandle<Object> temporal_date_like) {
10798 // 1. Let calendar be the this value.
10799 // 2. Perform ? RequireInternalSlot(calendar,
10800 // [[InitializedTemporalCalendar]]).
10801 // 3. Assert: calendar.[[Identifier]] is "iso8601".
10802 // 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
10805 isolate, temporal_date,
10806 ToTemporalDate(isolate, temporal_date_like,
10807 "Temporal.Calendar.prototype.weekOfYear"));
10808 // a. Let value be ! ToISOWeekOfYear(temporalDate.[[ISOYear]],
10809 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
10810 int32_t value = ToISOWeekOfYear(
10811 isolate, {temporal_date->iso_year(), temporal_date->iso_month(),
10812 temporal_date->iso_day()});
10813 return direct_handle(Smi::FromInt(value), isolate);
10814}
10815
10816// #sec-temporal.calendar.prototype.tostring
10819 const char* method_name) {
10820 return CalendarIdentifier(isolate, calendar->calendar_index());
10821}
10822
10823// #sec-temporal.now.timezone
10825 Isolate* isolate) {
10826 return SystemTimeZone(isolate);
10827}
10828
10829// #sec-temporal.timezone
10831 Isolate* isolate, DirectHandle<JSFunction> target,
10833 // 1. If NewTarget is undefined, then
10834 if (IsUndefined(*new_target, isolate)) {
10835 // a. Throw a TypeError exception.
10836 THROW_NEW_ERROR(isolate,
10837 NewTypeError(MessageTemplate::kConstructorNotFunction,
10838 isolate->factory()->NewStringFromAsciiChecked(
10839 "Temporal.TimeZone")));
10840 }
10841 // 2. Set identifier to ? ToString(identifier).
10844 Object::ToString(isolate, identifier_obj));
10845 DirectHandle<String> canonical;
10846 // 3. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset
10847 // (see 13.33), then
10848 if (IsValidTimeZoneNumericUTCOffsetString(isolate, identifier)) {
10849 // a. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(identifier).
10850 int64_t offset_nanoseconds;
10852 isolate, offset_nanoseconds,
10853 ParseTimeZoneOffsetString(isolate, identifier),
10855
10856 // b. Let canonical be ! FormatTimeZoneOffsetString(offsetNanoseconds).
10857 canonical = FormatTimeZoneOffsetString(isolate, offset_nanoseconds);
10858 } else {
10859 // 4. Else,
10860 // a. If ! IsValidTimeZoneName(identifier) is false, then
10861 if (!IsValidTimeZoneName(isolate, identifier)) {
10862 // i. Throw a RangeError exception.
10863 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeZone,
10864 identifier));
10865 }
10866 // b. Let canonical be ! CanonicalizeTimeZoneName(identifier).
10867 canonical = CanonicalizeTimeZoneName(isolate, identifier);
10868 }
10869 // 5. Return ? CreateTemporalTimeZone(canonical, NewTarget).
10870 return CreateTemporalTimeZone(isolate, target, new_target, canonical);
10871}
10872
10873namespace {
10874
10876 Isolate* isolate, DirectHandle<Object> item_obj,
10877 DirectHandle<Object> options, const char* method_name);
10878
10880 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name) {
10881 // 1. If options is not present, set options to undefined.
10882 return ToTemporalDateTime(isolate, item_obj,
10883 isolate->factory()->undefined_value(), method_name);
10884}
10885
10886} // namespace
10887
10888// #sec-temporal.timezone.prototype.getinstantfor
10891 DirectHandle<Object> date_time_obj, DirectHandle<Object> options_obj) {
10892 const char* method_name = "Temporal.TimeZone.prototype.getInstantFor";
10893 // 1. Let timeZone be the this value.
10894 // 2. Perform ? RequireInternalSlot(timeZone,
10895 // [[InitializedTemporalTimeZone]]).
10896 // 3. Set dateTime to ? ToTemporalDateTime(dateTime).
10899 isolate, date_time,
10900 ToTemporalDateTime(isolate, date_time_obj, method_name));
10901
10902 // 4. Set options to ? GetOptionsObject(options).
10905 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
10906
10907 // 5. Let disambiguation be ? ToTemporalDisambiguation(options).
10908 Disambiguation disambiguation;
10910 isolate, disambiguation,
10911 ToTemporalDisambiguation(isolate, options, method_name),
10913
10914 // 6. Return ? BuiltinTimeZoneGetInstantFor(timeZone, dateTime,
10915 // disambiguation).
10916 return BuiltinTimeZoneGetInstantFor(isolate, time_zone, date_time,
10917 disambiguation, method_name);
10918}
10919
10920namespace {
10921
10922#ifdef V8_INTL_SUPPORT
10923DirectHandle<Object> GetIANATimeZoneTransition(Isolate* isolate,
10925 int32_t time_zone_index,
10926 Intl::Transition transition) {
10927 if (time_zone_index == JSTemporalTimeZone::kUTCTimeZoneIndex) {
10928 return isolate->factory()->null_value();
10929 }
10930 return Intl::GetTimeZoneOffsetTransitionNanoseconds(isolate, time_zone_index,
10931 nanoseconds, transition);
10932}
10933// #sec-temporal-getianatimezonenexttransition
10934DirectHandle<Object> GetIANATimeZoneNextTransition(
10935 Isolate* isolate, DirectHandle<BigInt> nanoseconds,
10936 int32_t time_zone_index) {
10937 return GetIANATimeZoneTransition(isolate, nanoseconds, time_zone_index,
10939}
10940// #sec-temporal-getianatimezoneprevioustransition
10941DirectHandle<Object> GetIANATimeZonePreviousTransition(
10942 Isolate* isolate, DirectHandle<BigInt> nanoseconds,
10943 int32_t time_zone_index) {
10944 return GetIANATimeZoneTransition(isolate, nanoseconds, time_zone_index,
10946}
10947
10948DirectHandle<Object> GetIANATimeZoneOffsetNanoseconds(
10949 Isolate* isolate, DirectHandle<BigInt> nanoseconds,
10950 int32_t time_zone_index) {
10951 if (time_zone_index == JSTemporalTimeZone::kUTCTimeZoneIndex) {
10952 return direct_handle(Smi::zero(), isolate);
10953 }
10954
10955 return isolate->factory()->NewNumberFromInt64(
10956 Intl::GetTimeZoneOffsetNanoseconds(isolate, time_zone_index,
10957 nanoseconds));
10958}
10959#else // V8_INTL_SUPPORT
10960// #sec-temporal-getianatimezonenexttransition
10961DirectHandle<Object> GetIANATimeZoneNextTransition(Isolate* isolate,
10962 DirectHandle<BigInt>,
10963 int32_t) {
10964 return isolate->factory()->null_value();
10965}
10966// #sec-temporal-getianatimezoneprevioustransition
10967DirectHandle<Object> GetIANATimeZonePreviousTransition(Isolate* isolate,
10968 DirectHandle<BigInt>,
10969 int32_t) {
10970 return isolate->factory()->null_value();
10971}
10972DirectHandle<Object> GetIANATimeZoneOffsetNanoseconds(Isolate* isolate,
10973 DirectHandle<BigInt>,
10974 int32_t time_zone_index) {
10976 return handle(Smi::zero(), isolate);
10977}
10978#endif // V8_INTL_SUPPORT
10979
10980} // namespace
10981
10982// #sec-temporal.timezone.prototype.getplaindatetimefor
10983MaybeDirectHandle<JSTemporalPlainDateTime>
10986 DirectHandle<Object> instant_obj, DirectHandle<Object> calendar_like) {
10988 const char* method_name = "Temporal.TimeZone.prototype.getPlainDateTimeFor";
10989 // 1. 1. Let timeZone be the this value.
10990 // 2. Perform ? RequireInternalSlot(timeZone,
10991 // [[InitializedTemporalTimeZone]]).
10992 // 3. Set instant to ? ToTemporalInstant(instant).
10995 isolate, instant, ToTemporalInstant(isolate, instant_obj, method_name));
10996 // 4. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
10999 isolate, calendar,
11000 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
11001
11002 // 5. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
11003 // calendar).
11005 isolate, time_zone, instant, calendar, method_name);
11006}
11007
11008// template for shared code of Temporal.TimeZone.prototype.getNextTransition and
11009// Temporal.TimeZone.prototype.getPreviousTransition
11010template <DirectHandle<Object> (*iana_func)(Isolate*, DirectHandle<BigInt>,
11011 int32_t)>
11014 DirectHandle<Object> starting_point_obj, const char* method_name) {
11016 // 1. Let timeZone be the this value.
11017 // 2. Perform ? RequireInternalSlot(timeZone,
11018 // [[InitializedTemporalTimeZone]]).
11019 // 3. Set startingPoint to ? ToTemporalInstant(startingPoint).
11020 DirectHandle<JSTemporalInstant> starting_point;
11022 isolate, starting_point,
11023 ToTemporalInstant(isolate, starting_point_obj, method_name));
11024 // 4. If timeZone.[[OffsetNanoseconds]] is not undefined, return null.
11025 if (time_zone->is_offset()) {
11026 return isolate->factory()->null_value();
11027 }
11028 // 5. Let transition be ?
11029 // GetIANATimeZoneNextTransition(startingPoint.[[Nanoseconds]],
11030 // timeZone.[[Identifier]]).
11031 DirectHandle<Object> transition_obj =
11032 iana_func(isolate, direct_handle(starting_point->nanoseconds(), isolate),
11033 time_zone->time_zone_index());
11034 // 6. If transition is null, return null.
11035 if (IsNull(*transition_obj)) {
11036 return isolate->factory()->null_value();
11037 }
11038 DCHECK(IsBigInt(*transition_obj));
11039 DirectHandle<BigInt> transition = Cast<BigInt>(transition_obj);
11040 // 7. Return ! CreateTemporalInstant(transition).
11041 return temporal::CreateTemporalInstant(isolate, transition).ToHandleChecked();
11042}
11043
11044// #sec-temporal.timezone.prototype.getnexttransition
11047 DirectHandle<Object> starting_point_obj) {
11049 isolate, time_zone, starting_point_obj,
11050 "Temporal.TimeZone.prototype.getNextTransition");
11051}
11052// #sec-temporal.timezone.prototype.getprevioustransition
11055 DirectHandle<Object> starting_point_obj) {
11057 isolate, time_zone, starting_point_obj,
11058 "Temporal.TimeZone.prototype.getPreviousTransition");
11059}
11060
11061// #sec-temporal.timezone.prototype.getpossibleinstantsfor
11062// #sec-temporal-getianatimezoneepochvalue
11064 Isolate* isolate, const DateTimeRecord& date_time) {
11065 Factory* factory = isolate->factory();
11066 // 6. Let possibleInstants be a new empty List.
11067 DirectHandle<BigInt> epoch_nanoseconds =
11068 GetEpochFromISOParts(isolate, date_time);
11069 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1);
11070 // 7. For each value epochNanoseconds in possibleEpochNanoseconds, do
11071 // a. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
11072 // RangeError exception.
11073 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
11075 }
11076 // b. Let instant be ! CreateTemporalInstant(epochNanoseconds).
11078 temporal::CreateTemporalInstant(isolate, epoch_nanoseconds)
11079 .ToHandleChecked();
11080 // c. Append instant to possibleInstants.
11081 fixed_array->set(0, *instant);
11082 // 8. Return ! CreateArrayFromList(possibleInstants).
11083 return factory->NewJSArrayWithElements(fixed_array);
11084}
11085
11086#ifdef V8_INTL_SUPPORT
11087MaybeDirectHandle<JSArray> GetIANATimeZoneEpochValueAsArrayOfInstant(
11088 Isolate* isolate, int32_t time_zone_index,
11089 const DateTimeRecord& date_time) {
11090 Factory* factory = isolate->factory();
11091 if (time_zone_index == JSTemporalTimeZone::kUTCTimeZoneIndex) {
11092 return GetIANATimeZoneEpochValueAsArrayOfInstantForUTC(isolate, date_time);
11093 }
11094
11095 // For TimeZone other than UTC, call ICU indirectly from Intl
11096 DirectHandle<BigInt> nanoseconds_in_local_time =
11097 GetEpochFromISOParts(isolate, date_time);
11098
11099 DirectHandleVector<BigInt> possible_offset =
11100 Intl::GetTimeZonePossibleOffsetNanoseconds(isolate, time_zone_index,
11101 nanoseconds_in_local_time);
11102
11103 int32_t array_length = static_cast<int32_t>(possible_offset.size());
11104 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(array_length);
11105
11106 for (int32_t i = 0; i < array_length; i++) {
11107 DirectHandle<BigInt> epoch_nanoseconds =
11108 BigInt::Subtract(isolate, nanoseconds_in_local_time, possible_offset[i])
11109 .ToHandleChecked();
11110 // a. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
11111 // RangeError exception.
11112 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
11114 }
11115 // b. Let instant be ! CreateTemporalInstant(epochNanoseconds).
11116 DirectHandle<JSTemporalInstant> instant =
11117 temporal::CreateTemporalInstant(isolate, epoch_nanoseconds)
11118 .ToHandleChecked();
11119 // b. Append instant to possibleInstants.
11120 fixed_array->set(i, *(instant));
11121 }
11122
11123 // 8. Return ! CreateArrayFromList(possibleInstants).
11124 return factory->NewJSArrayWithElements(fixed_array);
11125}
11126
11127#else // V8_INTL_SUPPORT
11128
11130 Isolate* isolate, int32_t time_zone_index,
11131 const DateTimeRecord& date_time) {
11133 return GetIANATimeZoneEpochValueAsArrayOfInstantForUTC(isolate, date_time);
11134}
11135#endif // V8_INTL_SUPPORT
11136
11137// #sec-temporal.timezone.prototype.getpossibleinstantsfor
11140 DirectHandle<Object> date_time_obj) {
11141 Factory* factory = isolate->factory();
11142 // 1. Let timeZone be the this value.
11143 // 2. Perform ? RequireInternalSlot(timeZone,
11144 // [[InitializedTemporalTimezone]]).
11145 // 3. Set dateTime to ? ToTemporalDateTime(dateTime).
11148 isolate, date_time,
11149 ToTemporalDateTime(isolate, date_time_obj,
11150 "Temporal.TimeZone.prototype.getPossibleInstantsFor"));
11151 DateTimeRecord date_time_record = {
11152 {date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
11153 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
11154 date_time->iso_millisecond(), date_time->iso_microsecond(),
11155 date_time->iso_nanosecond()}};
11156 // 4. If timeZone.[[OffsetNanoseconds]] is not undefined, then
11157 if (time_zone->is_offset()) {
11158 // a. Let epochNanoseconds be ! GetEpochFromISOParts(dateTime.[[ISOYear]],
11159 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
11160 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
11161 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
11162 // dateTime.[[ISONanosecond]]).
11163 DirectHandle<BigInt> epoch_nanoseconds =
11164 GetEpochFromISOParts(isolate, date_time_record);
11165 // b. Let possibleEpochNanoseconds be « epochNanoseconds -
11166 // ℤ(timeZone.[[OffsetNanoseconds]]) ».
11167 epoch_nanoseconds =
11169 isolate, epoch_nanoseconds,
11170 BigInt::FromInt64(isolate, time_zone->offset_nanoseconds()))
11171 .ToHandleChecked();
11172
11173 // The following is the step 7 and 8 for the case of step 4 under the if
11174 // block.
11175
11176 // a. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
11177 // RangeError exception.
11178 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
11180 }
11181
11182 // b. Let instant be ! CreateTemporalInstant(epochNanoseconds).
11183
11185 temporal::CreateTemporalInstant(isolate, epoch_nanoseconds)
11186 .ToHandleChecked();
11187 // c. Return ! CreateArrayFromList(« instant »).
11188 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1);
11189 fixed_array->set(0, *instant);
11190 return factory->NewJSArrayWithElements(fixed_array);
11191 }
11192
11193 // 5. Let possibleEpochNanoseconds be ?
11194 // GetIANATimeZoneEpochValue(timeZone.[[Identifier]], dateTime.[[ISOYear]],
11195 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
11196 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
11197 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
11198 // dateTime.[[ISONanosecond]]).
11199
11200 // ... Step 5-8 put into GetIANATimeZoneEpochValueAsArrayOfInstant
11201 // 8. Return ! CreateArrayFromList(possibleInstants).
11203 isolate, time_zone->time_zone_index(), date_time_record);
11204}
11205
11206// #sec-temporal.timezone.prototype.getoffsetnanosecondsfor
11209 DirectHandle<Object> instant_obj) {
11211 // 1. Let timeZone be the this value.
11212 // 2. Perform ? RequireInternalSlot(timeZone,
11213 // [[InitializedTemporalTimeZone]]).
11214 // 3. Set instant to ? ToTemporalInstant(instant).
11217 isolate, instant,
11218 ToTemporalInstant(isolate, instant_obj,
11219 "Temporal.TimeZone.prototype.getOffsetNanosecondsFor"));
11220 // 4. If timeZone.[[OffsetNanoseconds]] is not undefined, return
11221 // timeZone.[[OffsetNanoseconds]].
11222 if (time_zone->is_offset()) {
11223 return isolate->factory()->NewNumberFromInt64(
11224 time_zone->offset_nanoseconds());
11225 }
11226 // 5. Return ! GetIANATimeZoneOffsetNanoseconds(instant.[[Nanoseconds]],
11227 // timeZone.[[Identifier]]).
11228 return GetIANATimeZoneOffsetNanoseconds(
11229 isolate, direct_handle(instant->nanoseconds(), isolate),
11230 time_zone->time_zone_index());
11231}
11232
11233// #sec-temporal.timezone.prototype.getoffsetstringfor
11236 DirectHandle<Object> instant_obj) {
11238 const char* method_name = "Temporal.TimeZone.prototype.getOffsetStringFor";
11239 // 1. Let timeZone be the this value.
11240 // 2. Perform ? RequireInternalSlot(timeZone,
11241 // [[InitializedTemporalTimeZone]]).
11242 // 3. Set instant to ? ToTemporalInstant(instant).
11245 isolate, instant, ToTemporalInstant(isolate, instant_obj, method_name));
11246 // 4. Return ? BuiltinTimeZoneGetOffsetStringFor(timeZone, instant).
11247 return BuiltinTimeZoneGetOffsetStringFor(isolate, time_zone, instant,
11248 method_name);
11249}
11250
11251// #sec-temporal.timezone.prototype.tostring
11254 const char* method_name) {
11255 return time_zone->id(isolate);
11256}
11257
11259 DCHECK(is_offset() == false);
11261}
11262
11265 DCHECK(is_offset());
11266 return static_cast<int64_t>(offset_milliseconds()) * 1000000 +
11267 static_cast<int64_t>(offset_sub_milliseconds());
11268}
11269
11271 this->set_offset_milliseconds(static_cast<int32_t>(ns / 1000000));
11272 this->set_offset_sub_milliseconds(static_cast<int32_t>(ns % 1000000));
11273}
11274
11276 if (is_offset()) {
11277 return FormatTimeZoneOffsetString(isolate, offset_nanoseconds());
11278 }
11279#ifdef V8_INTL_SUPPORT
11280 std::string id =
11282 return isolate->factory()->NewStringFromAsciiChecked(id.c_str());
11283#else // V8_INTL_SUPPORT
11285 return isolate->factory()->UTC_string();
11286#endif // V8_INTL_SUPPORT
11287}
11288
11290 Isolate* isolate, DirectHandle<JSFunction> target,
11292 DirectHandle<Object> iso_month_obj, DirectHandle<Object> iso_day_obj,
11293 DirectHandle<Object> calendar_like) {
11294 const char* method_name = "Temporal.PlainDate";
11295 // 1. If NewTarget is undefined, throw a TypeError exception.
11296 if (IsUndefined(*new_target)) {
11297 THROW_NEW_ERROR(isolate,
11298 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
11299 isolate->factory()->NewStringFromAsciiChecked(
11300 method_name)));
11301 }
11302#define TO_INT_THROW_ON_INFTY(name, T) \
11303 int32_t name; \
11304 { \
11305 DirectHandle<Object> number_##name; \
11306 /* x. Let name be ? ToIntegerThrowOnInfinity(name). */ \
11307 ASSIGN_RETURN_ON_EXCEPTION(isolate, number_##name, \
11308 ToIntegerThrowOnInfinity(isolate, name##_obj)); \
11309 name = NumberToInt32(*number_##name); \
11310 }
11311
11315
11316 // 8. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
11319 isolate, calendar,
11320 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
11321
11322 // 9. Return ? CreateTemporalDate(y, m, d, calendar, NewTarget).
11323 return CreateTemporalDate(isolate, target, new_target,
11324 {iso_year, iso_month, iso_day}, calendar);
11325}
11326
11327// #sec-temporal.plaindate.compare
11329 Isolate* isolate, DirectHandle<Object> one_obj,
11330 DirectHandle<Object> two_obj) {
11331 const char* method_name = "Temporal.PlainDate.compare";
11332 // 1. Set one to ? ToTemporalDate(one).
11335 ToTemporalDate(isolate, one_obj, method_name));
11336 // 2. Set two to ? ToTemporalDate(two).
11338 ASSIGN_RETURN_ON_EXCEPTION(isolate, two,
11339 ToTemporalDate(isolate, two_obj, method_name));
11340 // 3. Return 𝔽(! CompareISODate(one.[[ISOYear]], one.[[ISOMonth]],
11341 // one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]])).
11342 return DirectHandle<Smi>(
11344 CompareISODate({one->iso_year(), one->iso_month(), one->iso_day()},
11345 {two->iso_year(), two->iso_month(), two->iso_day()})),
11346 isolate);
11347}
11348
11349// #sec-temporal.plaindate.prototype.equals
11351 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11352 DirectHandle<Object> other_obj) {
11353 Factory* factory = isolate->factory();
11354 // 1. Let temporalDate be the this value.
11355 // 2. Perform ? RequireInternalSlot(temporalDate,
11356 // [[InitializedTemporalDate]]).
11357 // 3. Set other to ? ToTemporalDate(other).
11360 isolate, other,
11361 ToTemporalDate(isolate, other_obj,
11362 "Temporal.PlainDate.prototype.equals"));
11363 // 4. If temporalDate.[[ISOYear]] ≠ other.[[ISOYear]], return false.
11364 if (temporal_date->iso_year() != other->iso_year()) {
11365 return factory->false_value();
11366 }
11367 // 5. If temporalDate.[[ISOMonth]] ≠ other.[[ISOMonth]], return false.
11368 if (temporal_date->iso_month() != other->iso_month()) {
11369 return factory->false_value();
11370 }
11371 // 6. If temporalDate.[[ISODay]] ≠ other.[[ISODay]], return false.
11372 if (temporal_date->iso_day() != other->iso_day()) {
11373 return factory->false_value();
11374 }
11375 // 7. Return ? CalendarEquals(temporalDate.[[Calendar]], other.[[Calendar]]).
11376 return CalendarEquals(isolate,
11377 direct_handle(temporal_date->calendar(), isolate),
11378 direct_handle(other->calendar(), isolate));
11379}
11380
11381// #sec-temporal.plaindate.prototype.withcalendar
11383 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11384 DirectHandle<Object> calendar_like) {
11385 const char* method_name = "Temporal.PlainDate.prototype.withCalendar";
11386 // 1. Let temporalDate be the this value.
11387 // 2. Perform ? RequireInternalSlot(temporalDate,
11388 // [[InitializedTemporalDate]]).
11389 // 3. Let calendar be ? ToTemporalCalendar(calendar).
11392 isolate, calendar,
11393 temporal::ToTemporalCalendar(isolate, calendar_like, method_name));
11394 // 4. Return ? CreateTemporalDate(temporalDate.[[ISOYear]],
11395 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], calendar).
11396 return CreateTemporalDate(
11397 isolate,
11398 {temporal_date->iso_year(), temporal_date->iso_month(),
11399 temporal_date->iso_day()},
11400 calendar);
11401}
11402
11403// Template for common code shared by
11404// Temporal.PlainDate(Time)?.prototype.toPlain(YearMonth|MonthDay)
11405// #sec-temporal.plaindate.prototype.toplainmonthday
11406// #sec-temporal.plaindate.prototype.toplainyearmonth
11407// #sec-temporal.plaindatetime.prototype.toplainmonthday
11408// #sec-temporal.plaindatetime.prototype.toplainyearmonth
11409template <typename T, typename R,
11410 MaybeDirectHandle<R> (*from_fields)(
11415 Factory* factory = isolate->factory();
11416 // 1. Let temporalDate be the this value.
11417 // 2. Perform ? RequireInternalSlot(t, [[InitializedTemporalDate]]).
11418 // 3. Let calendar be t.[[Calendar]].
11419 DirectHandle<JSReceiver> calendar(t->calendar(), isolate);
11420 // 4. Let fieldNames be ? CalendarFields(calendar, « f1 , f2 »).
11421 DirectHandle<FixedArray> field_names = factory->NewFixedArray(2);
11422 field_names->set(0, *f1);
11423 field_names->set(1, *f2);
11424 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
11425 CalendarFields(isolate, calendar, field_names));
11426 // 5. Let fields be ? PrepareTemporalFields(t, fieldNames, «»).
11429 isolate, fields,
11430 PrepareTemporalFields(isolate, t, field_names, RequiredFields::kNone));
11431 // 6. Return ? FromFields(calendar, fields).
11432 return from_fields(isolate, calendar, fields,
11433 isolate->factory()->undefined_value());
11434}
11435
11436// #sec-temporal.plaindate.prototype.toplainyearmonth
11437MaybeDirectHandle<JSTemporalPlainYearMonth>
11439 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
11441 YearMonthFromFields>(isolate, temporal_date,
11442 isolate->factory()->monthCode_string(),
11443 isolate->factory()->year_string());
11444}
11445
11446// #sec-temporal.plaindate.prototype.toplainmonthday
11448 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
11450 MonthDayFromFields>(isolate, temporal_date,
11451 isolate->factory()->day_string(),
11452 isolate->factory()->monthCode_string());
11453}
11454
11455// #sec-temporal.plaindate.prototype.toplaindatetime
11457 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11458 DirectHandle<Object> temporal_time_obj) {
11459 // 1. Let temporalDate be the this value.
11460 // 2. Perform ? RequireInternalSlot(temporalDate,
11461 // [[InitializedTemporalDate]]).
11462 // 3. If temporalTime is undefined, then
11463 if (IsUndefined(*temporal_time_obj)) {
11464 // a. Return ? CreateTemporalDateTime(temporalDate.[[ISOYear]],
11465 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], 0, 0, 0, 0, 0, 0,
11466 // temporalDate.[[Calendar]]).
11468 isolate,
11469 {{temporal_date->iso_year(), temporal_date->iso_month(),
11470 temporal_date->iso_day()},
11471 {0, 0, 0, 0, 0, 0}},
11472 DirectHandle<JSReceiver>(temporal_date->calendar(), isolate));
11473 }
11474 // 4. Set temporalTime to ? ToTemporalTime(temporalTime).
11477 isolate, temporal_time,
11478 temporal::ToTemporalTime(isolate, temporal_time_obj,
11479 "Temporal.PlainDate.prototype.toPlainDateTime"));
11480 // 5. Return ? CreateTemporalDateTime(temporalDate.[[ISOYear]],
11481 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]],
11482 // temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]],
11483 // temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]],
11484 // temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]],
11485 // temporalDate.[[Calendar]]).
11487 isolate,
11488 {{temporal_date->iso_year(), temporal_date->iso_month(),
11489 temporal_date->iso_day()},
11490 {temporal_time->iso_hour(), temporal_time->iso_minute(),
11491 temporal_time->iso_second(), temporal_time->iso_millisecond(),
11492 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()}},
11493 DirectHandle<JSReceiver>(temporal_date->calendar(), isolate));
11494}
11495
11496namespace {
11497
11498// #sec-temporal-rejectobjectwithcalendarortimezone
11499Maybe<bool> RejectObjectWithCalendarOrTimeZone(
11500 Isolate* isolate, DirectHandle<JSReceiver> object) {
11502
11503 Factory* factory = isolate->factory();
11504 // 1. Assert: Type(object) is Object.
11505 // 2. If object has an [[InitializedTemporalDate]],
11506 // [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
11507 // [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
11508 // [[InitializedTemporalZonedDateTime]] internal slot, then
11509 if (IsJSTemporalPlainDate(*object) || IsJSTemporalPlainDateTime(*object) ||
11510 IsJSTemporalPlainMonthDay(*object) || IsJSTemporalPlainTime(*object) ||
11511 IsJSTemporalPlainYearMonth(*object) ||
11512 IsJSTemporalZonedDateTime(*object)) {
11513 // a. Throw a TypeError exception.
11515 Nothing<bool>());
11516 }
11517 // 3. Let calendarProperty be ? Get(object, "calendar").
11518 DirectHandle<Object> calendar_property;
11520 isolate, calendar_property,
11521 JSReceiver::GetProperty(isolate, object, factory->calendar_string()),
11522 Nothing<bool>());
11523 // 4. If calendarProperty is not undefined, then
11524 if (!IsUndefined(*calendar_property)) {
11525 // a. Throw a TypeError exception.
11527 Nothing<bool>());
11528 }
11529 // 5. Let timeZoneProperty be ? Get(object, "timeZone").
11530 DirectHandle<Object> time_zone_property;
11532 isolate, time_zone_property,
11533 JSReceiver::GetProperty(isolate, object, factory->timeZone_string()),
11534 Nothing<bool>());
11535 // 6. If timeZoneProperty is not undefined, then
11536 if (!IsUndefined(*time_zone_property)) {
11537 // a. Throw a TypeError exception.
11539 Nothing<bool>());
11540 }
11541 return Just(true);
11542}
11543
11544// #sec-temporal-calendarmergefields
11545MaybeDirectHandle<JSReceiver> CalendarMergeFields(
11546 Isolate* isolate, DirectHandle<JSReceiver> calendar,
11547 DirectHandle<JSReceiver> fields,
11548 DirectHandle<JSReceiver> additional_fields) {
11549 // 1. Let mergeFields be ? GetMethod(calendar, "mergeFields").
11550 DirectHandle<Object> merge_fields;
11552 isolate, merge_fields,
11553 Object::GetMethod(isolate, calendar,
11554 isolate->factory()->mergeFields_string()));
11555 // 2. If mergeFields is undefined, then
11556 if (IsUndefined(*merge_fields)) {
11557 // a. Return ? DefaultMergeFields(fields, additionalFields).
11558 return DefaultMergeFields(isolate, fields, additional_fields);
11559 }
11560 // 3. Return ? Call(mergeFields, calendar, « fields, additionalFields »).
11561 DirectHandle<Object> args[] = {fields, additional_fields};
11562 DirectHandle<Object> result;
11564 isolate, result,
11565 Execution::Call(isolate, merge_fields, calendar, base::VectorOf(args)));
11566 // 4. If Type(result) is not Object, throw a TypeError exception.
11567 if (!IsJSReceiver(*result)) {
11569 }
11570 return Cast<JSReceiver>(result);
11571}
11572
11573// Common code shared by Temporal.Plain(Date|YearMonth|MonthDay).prototype.with
11574template <typename T, MaybeDirectHandle<T> (*from_fields_func)(
11575 Isolate*, DirectHandle<JSReceiver>,
11576 DirectHandle<JSReceiver>, DirectHandle<Object>)>
11577MaybeDirectHandle<T> PlainDateOrYearMonthOrMonthDayWith(
11578 Isolate* isolate, DirectHandle<T> temporal,
11579 DirectHandle<Object> temporal_like_obj, DirectHandle<Object> options_obj,
11580 DirectHandle<FixedArray> field_names, const char* method_name) {
11581 // 1. Let temporalDate be the this value.
11582 // 2. Perform ? RequireInternalSlot(temporalDate,
11583 // [[InitializedTemporalXXX]]).
11584 // 3. If Type(temporalXXXLike) is not Object, then
11585 if (!IsJSReceiver(*temporal_like_obj)) {
11586 // a. Throw a TypeError exception.
11588 }
11589 DirectHandle<JSReceiver> temporal_like = Cast<JSReceiver>(temporal_like_obj);
11590 // 4. Perform ? RejectObjectWithCalendarOrTimeZone(temporalXXXLike).
11591 MAYBE_RETURN(RejectObjectWithCalendarOrTimeZone(isolate, temporal_like),
11592 DirectHandle<T>());
11593
11594 // 5. Let calendar be temporalXXX.[[Calendar]].
11595 DirectHandle<JSReceiver> calendar(temporal->calendar(), isolate);
11596
11597 // 6. Let fieldNames be ? CalendarFields(calendar, fieldNames).
11598 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
11599 CalendarFields(isolate, calendar, field_names));
11600 // 7. Let partialDate be ? PreparePartialTemporalFields(temporalXXXLike,
11601 // fieldNames).
11602 DirectHandle<JSReceiver> partial_date;
11604 isolate, partial_date,
11605 PreparePartialTemporalFields(isolate, temporal_like, field_names));
11606 // 8. Set options to ? GetOptionsObject(options).
11607 DirectHandle<JSReceiver> options;
11609 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
11610 // 9. Let fields be ? PrepareTemporalFields(temporalXXX, fieldNames, «»).
11611 DirectHandle<JSReceiver> fields;
11613 isolate, fields,
11614 PrepareTemporalFields(isolate, temporal, field_names,
11615 RequiredFields::kNone));
11616 // 10. Set fields to ? CalendarMergeFields(calendar, fields, partialDate).
11618 isolate, fields,
11619 CalendarMergeFields(isolate, calendar, fields, partial_date));
11620 // 11. Set fields to ? PrepareTemporalFields(fields, fieldNames, «»).
11621 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
11622 PrepareTemporalFields(isolate, fields, field_names,
11623 RequiredFields::kNone));
11624 // 12. Return ? XxxFromFields(calendar, fields, options).
11625 return from_fields_func(isolate, calendar, fields, options);
11626}
11627
11628} // namespace
11629
11630// #sec-temporal.plaindate.prototype.with
11632 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11633 DirectHandle<Object> temporal_date_like_obj,
11634 DirectHandle<Object> options_obj) {
11635 // 6. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
11636 // "monthCode", "year" »).
11637 DirectHandle<FixedArray> field_names =
11638 DayMonthMonthCodeYearInFixedArray(isolate);
11639 return PlainDateOrYearMonthOrMonthDayWith<JSTemporalPlainDate,
11640 DateFromFields>(
11641 isolate, temporal_date, temporal_date_like_obj, options_obj, field_names,
11642 "Temporal.PlainDate.prototype.with");
11643}
11644
11645// #sec-temporal.plaindate.prototype.tozoneddatetime
11647 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11648 DirectHandle<Object> item_obj) {
11649 const char* method_name = "Temporal.PlainDate.prototype.toZonedDateTime";
11650 Factory* factory = isolate->factory();
11651 // 1. Let temporalDate be the this value.
11652 // 2. Perform ? RequireInternalSlot(temporalDate,
11653 // [[InitializedTemporalDate]]).
11654 // 3. If Type(item) is Object, then
11656 DirectHandle<Object> temporal_time_obj;
11657 if (IsJSReceiver(*item_obj)) {
11659 // a. Let timeZoneLike be ? Get(item, "timeZone").
11660 DirectHandle<Object> time_zone_like;
11662 isolate, time_zone_like,
11663 JSReceiver::GetProperty(isolate, item, factory->timeZone_string()));
11664 // b. If timeZoneLike is undefined, then
11665 if (IsUndefined(*time_zone_like)) {
11666 // i. Let timeZone be ? ToTemporalTimeZone(item).
11668 isolate, time_zone,
11669 temporal::ToTemporalTimeZone(isolate, item, method_name));
11670 // ii. Let temporalTime be undefined.
11671 temporal_time_obj = factory->undefined_value();
11672 // c. Else,
11673 } else {
11674 // i. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
11676 isolate, time_zone,
11677 temporal::ToTemporalTimeZone(isolate, time_zone_like, method_name));
11678 // ii. Let temporalTime be ? Get(item, "plainTime").
11680 isolate, temporal_time_obj,
11681 JSReceiver::GetProperty(isolate, item, factory->plainTime_string()));
11682 }
11683 // 4. Else,
11684 } else {
11685 // a. Let timeZone be ? ToTemporalTimeZone(item).
11687 isolate, time_zone,
11688 temporal::ToTemporalTimeZone(isolate, item_obj, method_name));
11689 // b. Let temporalTime be undefined.
11690 temporal_time_obj = factory->undefined_value();
11691 }
11692 // 5. If temporalTime is undefined, then
11693 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
11694 DirectHandle<JSReceiver> calendar(temporal_date->calendar(), isolate);
11695 if (IsUndefined(*temporal_time_obj)) {
11696 // a. Let temporalDateTime be ?
11697 // CreateTemporalDateTime(temporalDate.[[ISOYear]],
11698 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], 0, 0, 0, 0, 0, 0,
11699 // temporalDate.[[Calendar]]).
11701 isolate, temporal_date_time,
11703 isolate,
11704 {{temporal_date->iso_year(), temporal_date->iso_month(),
11705 temporal_date->iso_day()},
11706 {0, 0, 0, 0, 0, 0}},
11707 calendar));
11708 // 6. Else,
11709 } else {
11711 // a. Set temporalTime to ? ToTemporalTime(temporalTime).
11713 isolate, temporal_time,
11714 temporal::ToTemporalTime(isolate, temporal_time_obj, method_name));
11715 // b. Let temporalDateTime be ?
11716 // CreateTemporalDateTime(temporalDate.[[ISOYear]],
11717 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]],
11718 // temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]],
11719 // temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]],
11720 // temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]],
11721 // temporalDate.[[Calendar]]).
11723 isolate, temporal_date_time,
11725 isolate,
11726 {{temporal_date->iso_year(), temporal_date->iso_month(),
11727 temporal_date->iso_day()},
11728 {temporal_time->iso_hour(), temporal_time->iso_minute(),
11729 temporal_time->iso_second(), temporal_time->iso_millisecond(),
11730 temporal_time->iso_microsecond(),
11731 temporal_time->iso_nanosecond()}},
11732 calendar));
11733 }
11734 // 7. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone,
11735 // temporalDateTime, "compatible").
11738 isolate, instant,
11739 BuiltinTimeZoneGetInstantFor(isolate, time_zone, temporal_date_time,
11740 Disambiguation::kCompatible, method_name));
11741 // 8. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
11742 // temporalDate.[[Calendar]]).
11743 return CreateTemporalZonedDateTime(
11744 isolate, direct_handle(instant->nanoseconds(), isolate), time_zone,
11745 calendar);
11746}
11747
11748// #sec-temporal.plaindate.prototype.add
11750 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11751 DirectHandle<Object> temporal_duration_like,
11752 DirectHandle<Object> options_obj) {
11753 const char* method_name = "Temporal.PlainDate.prototype.add";
11754 // 1. Let temporalDate be the this value.
11755 // 2. Perform ? RequireInternalSlot(temporalDate,
11756 // [[InitializedTemporalDate]]).
11757 // 3. Let duration be ? ToTemporalDuration(temporalDurationLike).
11759 ASSIGN_RETURN_ON_EXCEPTION(isolate, duration,
11761 isolate, temporal_duration_like, method_name));
11762
11763 // 4. Set options to ? GetOptionsObject(options).
11766 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
11767 // 5. Return ? CalendarDateAdd(temporalDate.[[Calendar]], temporalDate,
11768 // duration, options).
11769 return CalendarDateAdd(isolate,
11770 direct_handle(temporal_date->calendar(), isolate),
11771 temporal_date, duration, options);
11772}
11773
11774// #sec-temporal.plaindate.prototype.subtract
11776 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
11777 DirectHandle<Object> temporal_duration_like,
11778 DirectHandle<Object> options_obj) {
11779 const char* method_name = "Temporal.PlainDate.prototype.subtract";
11780 // 1. Let temporalDate be the this value.
11781 // 2. Perform ? RequireInternalSlot(temporalDate,
11782 // [[InitializedTemporalDate]]).
11783 // 3. Let duration be ? ToTemporalDuration(temporalDurationLike).
11785 ASSIGN_RETURN_ON_EXCEPTION(isolate, duration,
11787 isolate, temporal_duration_like, method_name));
11788
11789 // 4. Set options to ? GetOptionsObject(options).
11792 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
11793
11794 // 5. Let negatedDuration be ! CreateNegatedTemporalDuration(duration).
11795 DirectHandle<JSTemporalDuration> negated_duration =
11796 CreateNegatedTemporalDuration(isolate, duration).ToHandleChecked();
11797
11798 // 6. Return ? CalendarDateAdd(temporalDate.[[Calendar]], temporalDate,
11799 // negatedDuration, options).
11800 return CalendarDateAdd(isolate,
11801 direct_handle(temporal_date->calendar(), isolate),
11802 temporal_date, negated_duration, options);
11803}
11804
11805namespace {
11806// #sec-temporal-differencetemporalplandate
11807MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalPlainDate(
11808 Isolate* isolate, TimePreposition operation,
11810 DirectHandle<Object> other_obj, DirectHandle<Object> options,
11811 const char* method_name) {
11813 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
11814 double sign = operation == TimePreposition::kSince ? -1 : 1;
11815 // 2. Set other to ? ToTemporalDate(other).
11817 ASSIGN_RETURN_ON_EXCEPTION(isolate, other,
11818 ToTemporalDate(isolate, other_obj, method_name));
11819 // 3. If ? CalendarEquals(temporalDate.[[Calendar]], other.[[Calendar]]) is
11820 // false, throw a RangeError exception.
11821 bool calendar_equals;
11823 isolate, calendar_equals,
11824 CalendarEqualsBool(isolate,
11825 direct_handle(temporal_date->calendar(), isolate),
11826 direct_handle(other->calendar(), isolate)),
11828 if (!calendar_equals) {
11830 }
11831
11832 // 4. Let settings be ? GetDifferenceSettings(operation, options, date, « »,
11833 // "day", "day").
11834 DifferenceSettings settings;
11836 isolate, settings,
11837 GetDifferenceSettings(isolate, operation, options, UnitGroup::kDate,
11838 DisallowedUnitsInDifferenceSettings::kNone,
11839 Unit::kDay, Unit::kDay, method_name),
11840 DirectHandle<JSTemporalDuration>());
11841 // 5. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]],
11842 // settings.[[LargestUnit]]).
11843 DirectHandle<JSReceiver> until_options;
11845 isolate, until_options,
11846 MergeLargestUnitOption(isolate, settings.options, settings.largest_unit),
11847 DirectHandle<JSTemporalDuration>());
11848 // 6. Let result be ? CalendarDateUntil(temporalDate.[[Calendar]],
11849 // temporalDate, other, untilOptions).
11850 DirectHandle<JSTemporalDuration> result;
11852 isolate, result,
11853 CalendarDateUntil(isolate,
11854 direct_handle(temporal_date->calendar(), isolate),
11855 temporal_date, other, until_options),
11856 DirectHandle<JSTemporalDuration>());
11857 // 7. If settings.[[SmallestUnit]] is not "day" or
11858 // settings.[[RoundingIncrement]] ≠ 1, then
11859 if (settings.smallest_unit != Unit::kDay ||
11860 settings.rounding_increment != 1) {
11861 // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]],
11862 // result.[[Weeks]], result.[[Days]], 0, 0, 0, 0, 0, 0,
11863 // settings.[[RoundingIncrement]], settings.[[SmallestUnit]],
11864 // settings.[[RoundingMode]], temporalDate)).[[DurationRecord]].
11865 DurationRecordWithRemainder round_result;
11867 isolate, round_result,
11868 RoundDuration(isolate,
11869 {Object::NumberValue(result->years()),
11870 Object::NumberValue(result->months()),
11871 Object::NumberValue(result->weeks()),
11872 {Object::NumberValue(result->days()), 0, 0, 0, 0, 0, 0}},
11873 settings.rounding_increment, settings.smallest_unit,
11874 settings.rounding_mode, temporal_date, method_name),
11875 DirectHandle<JSTemporalDuration>());
11876 // 8. Return ! CreateTemporalDuration(sign × result.[[Years]], sign ×
11877 // result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], 0, 0,
11878 // 0, 0, 0, 0).
11879 round_result.record.years *= sign;
11880 round_result.record.months *= sign;
11881 round_result.record.weeks *= sign;
11882 round_result.record.time_duration.days *= sign;
11883 round_result.record.time_duration.hours =
11884 round_result.record.time_duration.minutes =
11885 round_result.record.time_duration.seconds =
11886 round_result.record.time_duration.milliseconds =
11887 round_result.record.time_duration.microseconds =
11888 round_result.record.time_duration.nanoseconds = 0;
11889 return CreateTemporalDuration(isolate, round_result.record)
11890 .ToHandleChecked();
11891 }
11892 // 8. Return ! CreateTemporalDuration(sign × result.[[Years]], sign ×
11893 // result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], 0, 0,
11894 // 0, 0, 0, 0).
11895 return CreateTemporalDuration(
11896 isolate,
11897 {sign * Object::NumberValue(result->years()),
11898 sign * Object::NumberValue(result->months()),
11899 sign * Object::NumberValue(result->weeks()),
11900 {sign * Object::NumberValue(result->days()), 0, 0, 0, 0, 0, 0}})
11901 .ToHandleChecked();
11902}
11903
11904} // namespace
11905
11906// #sec-temporal.plaindate.prototype.until
11911 return DifferenceTemporalPlainDate(isolate, TimePreposition::kUntil, handle,
11912 other, options,
11913 "Temporal.PlainDate.prototype.until");
11914}
11915
11916// #sec-temporal.plaindate.prototype.since
11921 return DifferenceTemporalPlainDate(isolate, TimePreposition::kSince, handle,
11922 other, options,
11923 "Temporal.PlainDate.prototype.since");
11924}
11925
11926// #sec-temporal.now.plaindate
11928 Isolate* isolate, DirectHandle<Object> calendar_like,
11929 DirectHandle<Object> temporal_time_zone_like) {
11930 const char* method_name = "Temporal.Now.plainDate";
11931 // 1. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendarLike).
11933 ASSIGN_RETURN_ON_EXCEPTION(isolate, date_time,
11934 SystemDateTime(isolate, temporal_time_zone_like,
11935 calendar_like, method_name));
11936 // 2. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
11937 // dateTime.[[ISODay]], dateTime.[[Calendar]]).
11938 return CreateTemporalDate(
11939 isolate,
11940 {date_time->iso_year(), date_time->iso_month(),
11941 date_time->iso_day()},
11942 DirectHandle<JSReceiver>(date_time->calendar(), isolate))
11943 .ToHandleChecked();
11944}
11945
11946// #sec-temporal.now.plaindateiso
11948 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
11949 const char* method_name = "Temporal.Now.plainDateISO";
11950 // 1. Let calendar be ! GetISO8601Calendar().
11952 // 2. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendar).
11955 isolate, date_time,
11956 SystemDateTime(isolate, temporal_time_zone_like, calendar, method_name));
11957 // 3. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
11958 // dateTime.[[ISODay]], dateTime.[[Calendar]]).
11959 return CreateTemporalDate(
11960 isolate,
11961 {date_time->iso_year(), date_time->iso_month(),
11962 date_time->iso_day()},
11963 DirectHandle<JSReceiver>(date_time->calendar(), isolate))
11964 .ToHandleChecked();
11965}
11966
11967// #sec-temporal.plaindate.from
11969 Isolate* isolate, DirectHandle<Object> item,
11970 DirectHandle<Object> options_obj) {
11971 const char* method_name = "Temporal.PlainDate.from";
11972 // 1. Set options to ? GetOptionsObject(options).
11975 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
11976 // 2. If Type(item) is Object and item has an [[InitializedTemporalDate]]
11977 // internal slot, then
11978 if (IsJSTemporalPlainDate(*item)) {
11979 // a. Perform ? ToTemporalOverflow(options).
11981 isolate, ToTemporalOverflow(isolate, options, method_name),
11983 // b. Return ? CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
11984 // item.[[ISODay]], item.[[Calendar]]).
11985 auto date = Cast<JSTemporalPlainDate>(item);
11986 return CreateTemporalDate(
11987 isolate, {date->iso_year(), date->iso_month(), date->iso_day()},
11988 DirectHandle<JSReceiver>(date->calendar(), isolate));
11989 }
11990 // 3. Return ? ToTemporalDate(item, options).
11991 return ToTemporalDate(isolate, item, options, method_name);
11992}
11993
11994#define DEFINE_INT_FIELD(obj, str, field, item) \
11995 CHECK(JSReceiver::CreateDataProperty( \
11996 isolate, obj, factory->str##_string(), \
11997 DirectHandle<Smi>(Smi::FromInt(item->field()), isolate), \
11998 Just(kThrowOnError)) \
11999 .FromJust());
12000
12001// #sec-temporal.plaindate.prototype.getisofields
12003 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
12004 Factory* factory = isolate->factory();
12005 // 1. Let temporalDate be the this value.
12006 // 2. Perform ? RequireInternalSlot(temporalDate,
12007 // [[InitializedTemporalDate]]).
12008 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
12009 DirectHandle<JSObject> fields =
12010 isolate->factory()->NewJSObject(isolate->object_function());
12011 // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
12012 // temporalDate.[[Calendar]]).
12014 isolate, fields, factory->calendar_string(),
12015 DirectHandle<JSReceiver>(temporal_date->calendar(), isolate),
12017 .FromJust());
12018 // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
12019 // 𝔽(temporalDate.[[ISODay]])).
12020 // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
12021 // 𝔽(temporalDate.[[ISOMonth]])).
12022 // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
12023 // 𝔽(temporalDate.[[ISOYear]])).
12024 DEFINE_INT_FIELD(fields, isoDay, iso_day, temporal_date)
12025 DEFINE_INT_FIELD(fields, isoMonth, iso_month, temporal_date)
12026 DEFINE_INT_FIELD(fields, isoYear, iso_year, temporal_date)
12027 // 8. Return fields.
12028 return fields;
12029}
12030
12031// #sec-temporal.plaindate.prototype.tojson
12033 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
12034 // 1. Let temporalDate be the this value.
12035 // 2. Perform ? RequireInternalSlot(temporalDate,
12036 // [[InitializedTemporalDate]]).
12037 // 3. Return ? TemporalDateToString(temporalDate, "auto").
12038 return TemporalDateToString(isolate, temporal_date, ShowCalendar::kAuto);
12039}
12040
12041namespace {
12042
12043// #sec-temporal-toshowcalendaroption
12044Maybe<ShowCalendar> ToShowCalendarOption(Isolate* isolate,
12046 const char* method_name) {
12047 // 1. Return ? GetOption(normalizedOptions, "calendarName", « String », «
12048 // "auto", "always", "never" », "auto").
12050 isolate, options, "calendarName", method_name,
12051 {"auto", "always", "never"},
12052 {ShowCalendar::kAuto, ShowCalendar::kAlways, ShowCalendar::kNever},
12053 ShowCalendar::kAuto);
12054}
12055
12056template <typename T, MaybeDirectHandle<String> (*F)(Isolate*, DirectHandle<T>,
12057 ShowCalendar)>
12058MaybeDirectHandle<String> TemporalToString(Isolate* isolate,
12059 DirectHandle<T> temporal,
12060 DirectHandle<Object> options_obj,
12061 const char* method_name) {
12062 // 1. Let temporalDate be the this value.
12063 // 2. Perform ? RequireInternalSlot(temporalDate,
12064 // [[InitializedTemporalDate]]).
12065 // 3. Set options to ? GetOptionsObject(options).
12066 DirectHandle<JSReceiver> options;
12068 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
12069 // 4. Let showCalendar be ? ToShowCalendarOption(options).
12070 ShowCalendar show_calendar;
12072 isolate, show_calendar,
12073 ToShowCalendarOption(isolate, options, method_name),
12074 DirectHandle<String>());
12075 // 5. Return ? TemporalDateToString(temporalDate, showCalendar).
12076 return F(isolate, temporal, show_calendar);
12077}
12078} // namespace
12079
12080// #sec-temporal.plaindate.prototype.tostring
12082 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
12083 DirectHandle<Object> options) {
12084 return TemporalToString<JSTemporalPlainDate, TemporalDateToString>(
12085 isolate, temporal_date, options, "Temporal.PlainDate.prototype.toString");
12086}
12087
12088// #sup-temporal.plaindate.prototype.tolocalestring
12090 Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
12091 DirectHandle<Object> locales, DirectHandle<Object> options) {
12092#ifdef V8_INTL_SUPPORT
12094 isolate, temporal_date, locales, options,
12095 "Temporal.PlainDate.prototype.toLocaleString");
12096#else // V8_INTL_SUPPORT
12097 return TemporalDateToString(isolate, temporal_date, ShowCalendar::kAuto);
12098#endif // V8_INTL_SUPPORT
12099}
12100
12101// #sec-temporal-createtemporaldatetime
12103 Isolate* isolate, DirectHandle<JSFunction> target,
12105 DirectHandle<Object> iso_month_obj, DirectHandle<Object> iso_day_obj,
12106 DirectHandle<Object> hour_obj, DirectHandle<Object> minute_obj,
12107 DirectHandle<Object> second_obj, DirectHandle<Object> millisecond_obj,
12108 DirectHandle<Object> microsecond_obj, DirectHandle<Object> nanosecond_obj,
12109 DirectHandle<Object> calendar_like) {
12110 const char* method_name = "Temporal.PlainDateTime";
12111 // 1. If NewTarget is undefined, throw a TypeError exception.
12112 if (IsUndefined(*new_target)) {
12113 THROW_NEW_ERROR(isolate,
12114 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
12115 isolate->factory()->NewStringFromAsciiChecked(
12116 method_name)));
12117 }
12118
12128
12129 // 20. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
12132 isolate, calendar,
12133 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
12134
12135 // 21. Return ? CreateTemporalDateTime(isoYear, isoMonth, isoDay, hour,
12136 // minute, second, millisecond, microsecond, nanosecond, calendar, NewTarget).
12137 return CreateTemporalDateTime(
12138 isolate, target, new_target,
12139 {{iso_year, iso_month, iso_day},
12141 calendar);
12142}
12143
12144namespace {
12145
12146// #sec-temporal-interprettemporaldatetimefields
12147Maybe<temporal::DateTimeRecord> InterpretTemporalDateTimeFields(
12150 const char* method_name) {
12152
12153 // 1. Let timeResult be ? ToTemporalTimeRecord(fields).
12154 TimeRecord time_result;
12156 isolate, time_result, ToTemporalTimeRecord(isolate, fields, method_name),
12158
12159 // 2. Let temporalDate be ? DateFromFields(calendar, fields, options).
12162 isolate, temporal_date,
12163 DateFromFields(isolate, calendar, fields, options),
12165
12166 // 3. Let overflow be ? ToTemporalOverflow(options).
12167 ShowOverflow overflow;
12169 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
12171
12172 // 4. Let timeResult be ? RegulateTime(timeResult.[[Hour]],
12173 // timeResult.[[Minute]], timeResult.[[Second]], timeResult.[[Millisecond]],
12174 // timeResult.[[Microsecond]], timeResult.[[Nanosecond]], overflow).
12176 isolate, time_result,
12177 temporal::RegulateTime(isolate, time_result, overflow),
12179 // 5. Return the new Record { [[Year]]: temporalDate.[[ISOYear]], [[Month]]:
12180 // temporalDate.[[ISOMonth]], [[Day]]: temporalDate.[[ISODay]], [[Hour]]:
12181 // timeResult.[[Hour]], [[Minute]]: timeResult.[[Minute]], [[Second]]:
12182 // timeResult.[[Second]], [[Millisecond]]: timeResult.[[Millisecond]],
12183 // [[Microsecond]]: timeResult.[[Microsecond]], [[Nanosecond]]:
12184 // timeResult.[[Nanosecond]] }.
12185
12187 {temporal_date->iso_year(), temporal_date->iso_month(),
12188 temporal_date->iso_day()},
12189 time_result};
12190 return Just(result);
12191}
12192
12193// #sec-temporal-parsetemporaldatetimestring
12194Maybe<DateTimeRecordWithCalendar> ParseTemporalDateTimeString(
12195 Isolate* isolate, DirectHandle<String> iso_string) {
12197 // 1. Assert: Type(isoString) is String.
12198 // 2. If isoString does not satisfy the syntax of a TemporalDateTimeString
12199 // (see 13.33), then
12200 std::optional<ParsedISO8601Result> parsed =
12201 TemporalParser::ParseTemporalDateTimeString(isolate, iso_string);
12202 if (!parsed.has_value()) {
12203 // a. Throw a *RangeError* exception.
12207 }
12208
12209 // 3. If _isoString_ contains a |UTCDesignator|, then
12210 if (parsed->utc_designator) {
12211 // a. Throw a *RangeError* exception.
12215 }
12216
12217 // 3. Let result be ? ParseISODateTime(isoString).
12218 // 4. Return result.
12219 return ParseISODateTime(isolate, iso_string, *parsed);
12220}
12221
12222// #sec-temporal-totemporaldatetime
12223MaybeDirectHandle<JSTemporalPlainDateTime> ToTemporalDateTime(
12224 Isolate* isolate, DirectHandle<Object> item_obj,
12225 DirectHandle<Object> options, const char* method_name) {
12227 // 2. Assert: Type(options) is Object or Undefined.
12228 DCHECK(IsJSReceiver(*options) || IsUndefined(*options));
12229
12230 DirectHandle<JSReceiver> calendar;
12231 temporal::DateTimeRecord result;
12232 // 2. If Type(item) is Object, then
12233 if (IsJSReceiver(*item_obj)) {
12234 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
12235 // a. If item has an [[InitializedTemporalDateTime]] internal slot, then
12236 // i. Return item.
12237 if (IsJSTemporalPlainDateTime(*item)) {
12238 return Cast<JSTemporalPlainDateTime>(item);
12239 }
12240 // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
12241 // then
12242 if (IsJSTemporalZonedDateTime(*item)) {
12243 // i. Perform ? ToTemporalOverflow(options).
12245 isolate, ToTemporalOverflow(isolate, options, method_name),
12246 DirectHandle<JSTemporalPlainDateTime>());
12247 // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
12248 auto zoned_date_time = Cast<JSTemporalZonedDateTime>(item);
12249 DirectHandle<JSTemporalInstant> instant =
12251 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
12252 .ToHandleChecked();
12253 // iii. Return ?
12254 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
12255 // instant, item.[[Calendar]]).
12257 isolate, direct_handle(zoned_date_time->time_zone(), isolate),
12258 instant, direct_handle(zoned_date_time->calendar(), isolate),
12259 method_name);
12260 }
12261 // c. If item has an [[InitializedTemporalDate]] internal slot, then
12262 if (IsJSTemporalPlainDate(*item)) {
12263 // i. Perform ? ToTemporalOverflow(options).
12265 isolate, ToTemporalOverflow(isolate, options, method_name),
12266 DirectHandle<JSTemporalPlainDateTime>());
12267 // ii. Return ? CreateTemporalDateTime(item.[[ISOYear]],
12268 // item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0,
12269 // item.[[Calendar]]).
12270 auto date = Cast<JSTemporalPlainDate>(item);
12272 isolate,
12273 {{date->iso_year(), date->iso_month(), date->iso_day()},
12274 {0, 0, 0, 0, 0, 0}},
12275 direct_handle(date->calendar(), isolate));
12276 }
12277 // d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
12279 isolate, calendar,
12280 GetTemporalCalendarWithISODefault(isolate, item, method_name));
12281 // e. Let fieldNames be ? CalendarFields(calendar, « "day", "hour",
12282 // "microsecond", "millisecond", "minute", "month", "monthCode",
12283 // "nanosecond", "second", "year" »).
12284 DirectHandle<FixedArray> field_names = All10UnitsInFixedArray(isolate);
12285 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
12286 CalendarFields(isolate, calendar, field_names));
12287 // f. Let fields be ? PrepareTemporalFields(item,
12288 // PrepareTemporalFields(item, fieldNames, «»).
12289 DirectHandle<JSReceiver> fields;
12290 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
12291 PrepareTemporalFields(isolate, item, field_names,
12292 RequiredFields::kNone));
12293 // g. Let result be ?
12294 // InterpretTemporalDateTimeFields(calendar, fields, options).
12296 isolate, result,
12297 InterpretTemporalDateTimeFields(isolate, calendar, fields, options,
12298 method_name),
12299 DirectHandle<JSTemporalPlainDateTime>());
12300 } else {
12301 // 3. Else,
12302 // a. Perform ? ToTemporalOverflow(options).
12304 isolate, ToTemporalOverflow(isolate, options, method_name),
12305 DirectHandle<JSTemporalPlainDateTime>());
12306
12307 // b. Let string be ? ToString(item).
12308 DirectHandle<String> string;
12309 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
12310 Object::ToString(isolate, item_obj));
12311 // c. Let result be ? ParseTemporalDateTimeString(string).
12312 DateTimeRecordWithCalendar parsed_result;
12314 isolate, parsed_result, ParseTemporalDateTimeString(isolate, string),
12315 DirectHandle<JSTemporalPlainDateTime>());
12316 result = {parsed_result.date, parsed_result.time};
12317 // d. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
12318 // result.[[Day]]) is true.
12319 DCHECK(IsValidISODate(isolate, result.date));
12320 // e. Assert: ! IsValidTime(result.[[Hour]],
12321 // result.[[Minute]], result.[[Second]], result.[[Millisecond]],
12322 // result.[[Microsecond]], result.[[Nanosecond]]) is true.
12323 DCHECK(IsValidTime(isolate, result.time));
12324 // f. Let calendar
12325 // be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
12327 isolate, calendar,
12328 ToTemporalCalendarWithISODefault(isolate, parsed_result.calendar,
12329 method_name));
12330 }
12331 // 4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
12332 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
12333 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
12334 // calendar).
12335 return temporal::CreateTemporalDateTime(isolate, {result.date, result.time},
12336 calendar);
12337}
12338
12339} // namespace
12340
12341// #sec-temporal.plaindatetime.from
12343 Isolate* isolate, DirectHandle<Object> item,
12344 DirectHandle<Object> options_obj) {
12345 const char* method_name = "Temporal.PlainDateTime.from";
12346 // 1. Set options to ? GetOptionsObject(options).
12349 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
12350 // 2. If Type(item) is Object and item has an [[InitializedTemporalDateTime]]
12351 // internal slot, then
12352 if (IsJSTemporalPlainDateTime(*item)) {
12353 // a. Perform ? ToTemporalOverflow(options).
12355 isolate, ToTemporalOverflow(isolate, options, method_name),
12357 // b. Return ? CreateTemporalDateTime(item.[[ISYear]], item.[[ISOMonth]],
12358 // item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]],
12359 // item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]],
12360 // item.[[ISONanosecond]], item.[[Calendar]]).
12361 auto date_time = Cast<JSTemporalPlainDateTime>(item);
12363 isolate,
12364 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12365 {date_time->iso_hour(), date_time->iso_minute(),
12366 date_time->iso_second(), date_time->iso_millisecond(),
12367 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
12368 direct_handle(date_time->calendar(), isolate));
12369 }
12370 // 3. Return ? ToTemporalDateTime(item, options).
12371 return ToTemporalDateTime(isolate, item, options, method_name);
12372}
12373
12374// #sec-temporal.plaindatetime.compare
12376 Isolate* isolate, DirectHandle<Object> one_obj,
12377 DirectHandle<Object> two_obj) {
12378 const char* method_name = "Temporal.PlainDateTime.compare";
12379 // 1. Set one to ? ToTemporalDateTime(one).
12382 ToTemporalDateTime(isolate, one_obj, method_name));
12383 // 2. Set two to ? ToTemporalDateTime(two).
12385 ASSIGN_RETURN_ON_EXCEPTION(isolate, two,
12386 ToTemporalDateTime(isolate, two_obj, method_name));
12387 // 3. Return 𝔽(! CompareISODateTime(one.[[ISOYear]], one.[[ISOMonth]],
12388 // one.[[ISODay]], one.[[ISOHour]], one.[[ISOMinute]], one.[[ISOSecond]],
12389 // one.[[ISOMillisecond]], one.[[ISOMicrosecond]], one.[[ISONanosecond]],
12390 // two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], two.[[ISOHour]],
12391 // two.[[ISOMinute]], two.[[ISOSecond]], two.[[ISOMillisecond]],
12392 // two.[[ISOMicrosecond]], two.[[ISONanosecond]])).
12393 return DirectHandle<Smi>(
12394 Smi::FromInt(CompareISODateTime(
12395 {
12396 {one->iso_year(), one->iso_month(), one->iso_day()},
12397 {one->iso_hour(), one->iso_minute(), one->iso_second(),
12398 one->iso_millisecond(), one->iso_microsecond(),
12399 one->iso_nanosecond()},
12400 },
12401 {
12402 {two->iso_year(), two->iso_month(), two->iso_day()},
12403 {two->iso_hour(), two->iso_minute(), two->iso_second(),
12404 two->iso_millisecond(), two->iso_microsecond(),
12405 two->iso_nanosecond()},
12406 })),
12407 isolate);
12408}
12409
12410// #sec-temporal.plaindatetime.prototype.equals
12413 DirectHandle<Object> other_obj) {
12414 // 1. Let dateTime be the this value.
12415 // 2. Perform ? RequireInternalSlot(dateTime,
12416 // [[InitializedTemporalDateTime]]).
12417 // 3. Set other to ? ToTemporalDateTime(other).
12420 isolate, other,
12421 ToTemporalDateTime(isolate, other_obj,
12422 "Temporal.PlainDateTime.prototype.equals"));
12423 // 4. Let result be ! CompareISODateTime(dateTime.[[ISOYear]],
12424 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
12425 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
12426 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
12427 // dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]],
12428 // other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]],
12429 // other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]],
12430 // other.[[ISONanosecond]]).
12431 int32_t result = CompareISODateTime(
12432 {
12433 {date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12434 {date_time->iso_hour(), date_time->iso_minute(),
12435 date_time->iso_second(), date_time->iso_millisecond(),
12436 date_time->iso_microsecond(), date_time->iso_nanosecond()},
12437 },
12438 {
12439 {other->iso_year(), other->iso_month(), other->iso_day()},
12440 {other->iso_hour(), other->iso_minute(), other->iso_second(),
12441 other->iso_millisecond(), other->iso_microsecond(),
12442 other->iso_nanosecond()},
12443 });
12444 // 5. If result is not 0, return false.
12445 if (result != 0) return isolate->factory()->false_value();
12446 // 6. Return ? CalendarEquals(dateTime.[[Calendar]], other.[[Calendar]]).
12447 return CalendarEquals(isolate, direct_handle(date_time->calendar(), isolate),
12448 direct_handle(other->calendar(), isolate));
12449}
12450
12451// #sec-temporal.plaindatetime.prototype.with
12454 DirectHandle<Object> temporal_date_time_like_obj,
12455 DirectHandle<Object> options_obj) {
12456 const char* method_name = "Temporal.PlainDateTime.prototype.with";
12457 // 1. Let dateTime be the this value.
12458 // 2. Perform ? RequireInternalSlot(dateTime,
12459 // [[InitializedTemporalDateTime]]).
12460 // 3. If Type(temporalDateTimeLike) is not Object, then
12461 if (!IsJSReceiver(*temporal_date_time_like_obj)) {
12462 // a. Throw a TypeError exception.
12464 }
12465 DirectHandle<JSReceiver> temporal_date_time_like =
12466 Cast<JSReceiver>(temporal_date_time_like_obj);
12467 // 4. Perform ? RejectObjectWithCalendarOrTimeZone(temporalTimeLike).
12469 RejectObjectWithCalendarOrTimeZone(isolate, temporal_date_time_like),
12471 // 5. Let calendar be dateTime.[[Calendar]].
12472 DirectHandle<JSReceiver> calendar(date_time->calendar(), isolate);
12473 // 6. Let fieldNames be ? CalendarFields(calendar, « "day", "hour",
12474 // "microsecond", "millisecond", "minute", "month", "monthCode", "nanosecond",
12475 // "second", "year" »).
12476 DirectHandle<FixedArray> field_names = All10UnitsInFixedArray(isolate);
12477 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
12478 CalendarFields(isolate, calendar, field_names));
12479
12480 // 7. Let partialDateTime be ?
12481 // PreparePartialTemporalFields(temporalDateTimeLike, fieldNames).
12482 DirectHandle<JSReceiver> partial_date_time;
12484 isolate, partial_date_time,
12485 PreparePartialTemporalFields(isolate, temporal_date_time_like,
12486 field_names));
12487
12488 // 8. Set options to ? GetOptionsObject(options).
12491 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
12492 // 9. Let fields be ? PrepareTemporalFields(dateTime, fieldNames, «»).
12495 isolate, fields,
12496 PrepareTemporalFields(isolate, date_time, field_names,
12497 RequiredFields::kNone));
12498
12499 // 10. Set fields to ? CalendarMergeFields(calendar, fields, partialDateTime).
12501 isolate, fields,
12502 CalendarMergeFields(isolate, calendar, fields, partial_date_time));
12503 // 11. Set fields to ? PrepareTemporalFields(fields, fieldNames, «»).
12504 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
12505 PrepareTemporalFields(isolate, fields, field_names,
12506 RequiredFields::kNone));
12507 // 12. Let result be ? InterpretTemporalDateTimeFields(calendar, fields,
12508 // options).
12511 isolate, result,
12512 InterpretTemporalDateTimeFields(isolate, calendar, fields, options,
12513 method_name),
12515 // 13. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
12516 // result.[[Day]]) is true.
12517 DCHECK(IsValidISODate(isolate, result.date));
12518 // 14. Assert: ! IsValidTime(result.[[Hour]], result.[[Minute]],
12519 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
12520 // result.[[Nanosecond]]) is true.
12521 DCHECK(IsValidTime(isolate, result.time));
12522 // 15. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
12523 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
12524 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
12525 // calendar).
12526 return temporal::CreateTemporalDateTime(isolate, {result.date, result.time},
12527 calendar);
12528}
12529
12530// #sec-temporal.plaindatetime.prototype.withplaintime
12534 DirectHandle<Object> plain_time_like) {
12535 // 1. Let temporalDateTime be the this value.
12536 // 2. Perform ? RequireInternalSlot(temporalDateTime,
12537 // [[InitializedTemporalDateTime]]).
12538 // 3. If plainTimeLike is undefined, then
12539 if (IsUndefined(*plain_time_like)) {
12540 // a. Return ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
12541 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0,
12542 // 0, 0, temporalDateTime.[[Calendar]]).
12544 isolate,
12545 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12546 {0, 0, 0, 0, 0, 0}},
12547 direct_handle(date_time->calendar(), isolate));
12548 }
12550 // 4. Let plainTime be ? ToTemporalTime(plainTimeLike).
12552 isolate, plain_time,
12554 isolate, plain_time_like,
12555 "Temporal.PlainDateTime.prototype.withPlainTime"));
12556 // 5. Return ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
12557 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]],
12558 // plainTime.[[ISOHour]], plainTime.[[ISOMinute]], plainTime.[[ISOSecond]],
12559 // plainTime.[[ISOMillisecond]], plainTime.[[ISOMicrosecond]],
12560 // plainTime.[[ISONanosecond]], temporalDateTime.[[Calendar]]).
12562 isolate,
12563 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12564 {plain_time->iso_hour(), plain_time->iso_minute(),
12565 plain_time->iso_second(), plain_time->iso_millisecond(),
12566 plain_time->iso_microsecond(), plain_time->iso_nanosecond()}},
12567 direct_handle(date_time->calendar(), isolate));
12568}
12569
12570// #sec-temporal.plaindatetime.prototype.withcalendar
12574 DirectHandle<Object> calendar_like) {
12575 // 1. Let temporalDateTime be the this value.
12576 // 2. Perform ? RequireInternalSlot(temporalDateTime,
12577 // [[InitializedTemporalDateTime]]).
12578 // 3. Let calendar be ? ToTemporalCalendar(calendar).
12581 isolate, calendar,
12583 isolate, calendar_like,
12584 "Temporal.PlainDateTime.prototype.withCalendar"));
12585 // 4. Return ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
12586 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]],
12587 // temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]],
12588 // temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]],
12589 // temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]],
12590 // calendar).
12592 isolate,
12593 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12594 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
12595 date_time->iso_millisecond(), date_time->iso_microsecond(),
12596 date_time->iso_nanosecond()}},
12597 calendar);
12598}
12599
12600// #sec-temporal.plaindatetime.prototype.toplainyearmonth
12603 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
12605 YearMonthFromFields>(isolate, date_time,
12606 isolate->factory()->monthCode_string(),
12607 isolate->factory()->year_string());
12608}
12609
12610// #sec-temporal.plaindatetime.prototype.toplainmonthday
12613 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
12615 MonthDayFromFields>(isolate, date_time,
12616 isolate->factory()->day_string(),
12617 isolate->factory()->monthCode_string());
12618}
12619
12620// #sec-temporal.plaindatetime.prototype.tozoneddatetime
12624 DirectHandle<Object> temporal_time_zone_like,
12625 DirectHandle<Object> options_obj) {
12626 const char* method_name = "Temporal.PlainDateTime.prototype.toZonedDateTime";
12627 // 1. Let dateTime be the this value.
12628 // 2. Perform ? RequireInternalSlot(dateTime,
12629 // [[InitializedTemporalDateTime]]).
12630 // 3. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
12633 isolate, time_zone,
12634 temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
12635 method_name));
12636 // 4. Set options to ? GetOptionsObject(options).
12639 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
12640 // 5. Let disambiguation be ? ToTemporalDisambiguation(options).
12641 Disambiguation disambiguation;
12643 isolate, disambiguation,
12644 ToTemporalDisambiguation(isolate, options, method_name),
12646
12647 // 6. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone, dateTime,
12648 // disambiguation).
12651 isolate, instant,
12652 BuiltinTimeZoneGetInstantFor(isolate, time_zone, date_time,
12653 disambiguation, method_name));
12654
12655 // 7. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]],
12656 // timeZone, dateTime.[[Calendar]]).
12657 return CreateTemporalZonedDateTime(
12658 isolate, direct_handle(instant->nanoseconds(), isolate), time_zone,
12659 DirectHandle<JSReceiver>(date_time->calendar(), isolate));
12660}
12661
12662namespace {
12663
12664// #sec-temporal-consolidatecalendars
12665MaybeDirectHandle<JSReceiver> ConsolidateCalendars(
12668 Factory* factory = isolate->factory();
12669 // 1. If one and two are the same Object value, return two.
12670 if (one.is_identical_to(two)) return two;
12671
12672 // 2. Let calendarOne be ? ToString(one).
12673 DirectHandle<String> calendar_one;
12674 ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar_one,
12675 Object::ToString(isolate, one));
12676 // 3. Let calendarTwo be ? ToString(two).
12677 DirectHandle<String> calendar_two;
12678 ASSIGN_RETURN_ON_EXCEPTION(isolate, calendar_two,
12679 Object::ToString(isolate, two));
12680 // 4. If calendarOne is calendarTwo, return two.
12681 if (String::Equals(isolate, calendar_one, calendar_two)) {
12682 return two;
12683 }
12684 // 5. If calendarOne is "iso8601", return two.
12685 if (String::Equals(isolate, calendar_one, factory->iso8601_string())) {
12686 return two;
12687 }
12688 // 6. If calendarTwo is "iso8601", return one.
12689 if (String::Equals(isolate, calendar_two, factory->iso8601_string())) {
12690 return one;
12691 }
12692 // 7. Throw a RangeError exception.
12694}
12695
12696} // namespace
12697
12698// #sec-temporal.plaindatetime.prototype.withplaindate
12699MaybeDirectHandle<JSTemporalPlainDateTime>
12702 DirectHandle<Object> temporal_date_like) {
12703 // 1. Let temporalDateTime be the this value.
12704 // 2. Perform ? RequireInternalSlot(temporalDateTime,
12705 // [[InitializedTemporalDateTime]]).
12706 // 3. Let plainDate be ? ToTemporalDate(plainDateLike).
12709 isolate, plain_date,
12710 ToTemporalDate(isolate, temporal_date_like,
12711 "Temporal.PlainDateTime.prototype.withPlainDate"));
12712 // 4. Let calendar be ? ConsolidateCalendars(temporalDateTime.[[Calendar]],
12713 // plainDate.[[Calendar]]).
12716 isolate, calendar,
12717 ConsolidateCalendars(isolate,
12718 direct_handle(date_time->calendar(), isolate),
12719 direct_handle(plain_date->calendar(), isolate)));
12720 // 5. Return ? CreateTemporalDateTime(plainDate.[[ISOYear]],
12721 // plainDate.[[ISOMonth]], plainDate.[[ISODay]], temporalDateTime.[[ISOHour]],
12722 // temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
12723 // temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
12724 // temporalDateTime.[[ISONanosecond]], calendar).
12726 isolate,
12727 {{plain_date->iso_year(), plain_date->iso_month(), plain_date->iso_day()},
12728 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
12729 date_time->iso_millisecond(), date_time->iso_microsecond(),
12730 date_time->iso_nanosecond()}},
12731 calendar);
12732}
12733
12734namespace {
12735MaybeDirectHandle<String> TemporalDateTimeToString(
12736 Isolate* isolate, const DateTimeRecord& date_time,
12738 ShowCalendar show_calendar) {
12739 IncrementalStringBuilder builder(isolate);
12740 // 1. Assert: isoYear, isoMonth, isoDay, hour, minute, second, millisecond,
12741 // microsecond, and nanosecond are integers.
12742 // 2. Let year be ! PadISOYear(isoYear).
12743 PadISOYear(&builder, date_time.date.year);
12744
12745 // 3. Let month be ToZeroPaddedDecimalString(isoMonth, 2).
12746 builder.AppendCharacter('-');
12747 ToZeroPaddedDecimalString(&builder, date_time.date.month, 2);
12748
12749 // 4. Let day be ToZeroPaddedDecimalString(isoDay, 2).
12750 builder.AppendCharacter('-');
12751 ToZeroPaddedDecimalString(&builder, date_time.date.day, 2);
12752 // 5. Let hour be ToZeroPaddedDecimalString(hour, 2).
12753 builder.AppendCharacter('T');
12754 ToZeroPaddedDecimalString(&builder, date_time.time.hour, 2);
12755
12756 // 6. Let minute be ToZeroPaddedDecimalString(minute, 2).
12757 builder.AppendCharacter(':');
12758 ToZeroPaddedDecimalString(&builder, date_time.time.minute, 2);
12759
12760 // 7. Let seconds be ! FormatSecondsStringPart(second, millisecond,
12761 // microsecond, nanosecond, precision).
12762 FormatSecondsStringPart(
12763 &builder, date_time.time.second, date_time.time.millisecond,
12764 date_time.time.microsecond, date_time.time.nanosecond, precision);
12765 // 8. Let calendarString be ? MaybeFormatCalendarAnnotation(calendar,
12766 // showCalendar).
12767 DirectHandle<String> calendar_string;
12769 isolate, calendar_string,
12770 MaybeFormatCalendarAnnotation(isolate, calendar, show_calendar));
12771
12772 // 9. Return the string-concatenation of year, the code unit 0x002D
12773 // (HYPHEN-MINUS), month, the code unit 0x002D (HYPHEN-MINUS), day, 0x0054
12774 // (LATIN CAPITAL LETTER T), hour, the code unit 0x003A (COLON), minute,
12775 builder.AppendString(calendar_string);
12776 return builder.Finish().ToHandleChecked();
12777}
12778} // namespace
12779
12780// #sec-temporal.plaindatetime.prototype.tojson
12782 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
12783 return TemporalDateTimeToString(
12784 isolate,
12785 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12786 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
12787 date_time->iso_millisecond(), date_time->iso_microsecond(),
12788 date_time->iso_nanosecond()}},
12789 DirectHandle<JSReceiver>(date_time->calendar(), isolate),
12790 Precision::kAuto, ShowCalendar::kAuto);
12791}
12792
12793// #sec-temporal.plaindatetime.prototype.tolocalestring
12796 DirectHandle<Object> locales, DirectHandle<Object> options) {
12797#ifdef V8_INTL_SUPPORT
12799 isolate, date_time, locales, options,
12800 "Temporal.PlainDateTime.prototype.toLocaleString");
12801#else // V8_INTL_SUPPORT
12802 return TemporalDateTimeToString(
12803 isolate,
12804 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12805 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
12806 date_time->iso_millisecond(), date_time->iso_microsecond(),
12807 date_time->iso_nanosecond()}},
12808 DirectHandle<JSReceiver>(date_time->calendar(), isolate),
12809 Precision::kAuto, ShowCalendar::kAuto);
12810#endif // V8_INTL_SUPPORT
12811}
12812
12813namespace {
12814
12815constexpr double kNsPerDay = 8.64e13;
12816
12817DateTimeRecord RoundTime(
12818 Isolate* isolate, const TimeRecord& time, double increment, Unit unit,
12820 // 3.a a. If dayLengthNs is not present, set dayLengthNs to nsPerDay.
12821 double day_length_ns = kNsPerDay);
12822
12823// #sec-temporal-roundisodatetime
12824DateTimeRecord RoundISODateTime(
12825 Isolate* isolate, const DateTimeRecord& date_time, double increment,
12827 // 3. If dayLength is not present, set dayLength to nsPerDay.
12828 double day_length_ns = kNsPerDay) {
12829 // 1. Assert: year, month, day, hour, minute, second, millisecond,
12830 // microsecond, and nanosecond are integers.
12832 // 2. Assert: ISODateTimeWithinLimits(year, month, day, hour, minute, second,
12833 // millisecond, microsecond, nanosecond) is true.
12834 DCHECK(ISODateTimeWithinLimits(isolate, date_time));
12835
12836 // 4. Let roundedTime be ! RoundTime(hour, minute, second, millisecond,
12837 // microsecond, nanosecond, increment, unit, roundingMode, dayLength).
12838 DateTimeRecord rounded_time = RoundTime(isolate, date_time.time, increment,
12839 unit, rounding_mode, day_length_ns);
12840 // 5. Let balanceResult be ! BalanceISODate(year, month, day +
12841 // roundedTime.[[Days]]).
12842 rounded_time.date.year = date_time.date.year;
12843 rounded_time.date.month = date_time.date.month;
12844 rounded_time.date.day += date_time.date.day;
12845 DateRecord balance_result = BalanceISODate(isolate, rounded_time.date);
12846
12847 // 6. Return the Record { [[Year]]: balanceResult.[[Year]], [[Month]]:
12848 // balanceResult.[[Month]], [[Day]]: balanceResult.[[Day]], [[Hour]]:
12849 // roundedTime.[[Hour]], [[Minute]]: roundedTime.[[Minute]], [[Second]]:
12850 // roundedTime.[[Second]], [[Millisecond]]: roundedTime.[[Millisecond]],
12851 // [[Microsecond]]: roundedTime.[[Microsecond]], [[Nanosecond]]:
12852 // roundedTime.[[Nanosecond]] }.
12853 return {balance_result, rounded_time.time};
12854}
12855
12856} // namespace
12857
12858// #sec-temporal.plaindatetime.prototype.tostring
12861 DirectHandle<Object> options_obj) {
12862 const char* method_name = "Temporal.PlainDateTime.prototype.toString";
12863 // 1. Let dateTime be the this value.
12864 // 2. Perform ? RequireInternalSlot(dateTime,
12865 // [[InitializedTemporalDateTime]]).
12866 // 3. Set options to ? GetOptionsObject(options).
12869 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
12870
12871 // 4. Let precision be ? ToSecondsStringPrecision(options).
12872 StringPrecision precision;
12874 isolate, precision,
12875 ToSecondsStringPrecision(isolate, options, method_name),
12877
12878 // 5. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
12881 isolate, rounding_mode,
12882 ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
12883 method_name),
12885
12886 // 6. Let showCalendar be ? ToShowCalendarOption(options).
12887 ShowCalendar show_calendar;
12889 isolate, show_calendar,
12890 ToShowCalendarOption(isolate, options, method_name),
12892
12893 // 7. Let result be ! RoundISODateTime(dateTime.[[ISOYear]],
12894 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
12895 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
12896 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
12897 // dateTime.[[ISONanosecond]], precision.[[Increment]], precision.[[Unit]],
12898 // roundingMode).
12899 DateTimeRecord result = RoundISODateTime(
12900 isolate,
12901 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
12902 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
12903 date_time->iso_millisecond(), date_time->iso_microsecond(),
12904 date_time->iso_nanosecond()}},
12905 precision.increment, precision.unit, rounding_mode);
12906 // 8. Return ? TemporalDateTimeToString(result.[[Year]], result.[[Month]],
12907 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
12908 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
12909 // dateTime.[[Calendar]], precision.[[Precision]], showCalendar).
12910 return TemporalDateTimeToString(isolate, result,
12911 direct_handle(date_time->calendar(), isolate),
12912 precision.precision, show_calendar);
12913}
12914
12915// #sec-temporal.now.plaindatetime
12917 Isolate* isolate, DirectHandle<Object> calendar_like,
12918 DirectHandle<Object> temporal_time_zone_like) {
12919 const char* method_name = "Temporal.Now.plainDateTime";
12920 // 1. Return ? SystemDateTime(temporalTimeZoneLike, calendarLike).
12921 return SystemDateTime(isolate, temporal_time_zone_like, calendar_like,
12922 method_name);
12923}
12924
12925// #sec-temporal.now.plaindatetimeiso
12927 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
12928 const char* method_name = "Temporal.Now.plainDateTimeISO";
12929 // 1. Let calendar be ! GetISO8601Calendar().
12931 // 2. Return ? SystemDateTime(temporalTimeZoneLike, calendar).
12932 return SystemDateTime(isolate, temporal_time_zone_like, calendar,
12933 method_name);
12934}
12935
12936namespace {
12937
12938// #sec-temporal-totemporaldatetimeroundingincrement
12939Maybe<double> ToTemporalDateTimeRoundingIncrement(
12940 Isolate* isolate, DirectHandle<JSReceiver> normalized_option,
12941 Unit smallest_unit) {
12942 Maximum maximum;
12943 // 1. If smallestUnit is "day", then
12944 if (smallest_unit == Unit::kDay) {
12945 // a. Let maximum be 1.
12946 maximum.value = 1;
12947 maximum.defined = true;
12948 // 2. Else,
12949 } else {
12950 // a. Let maximum be !
12951 // MaximumTemporalDurationRoundingIncrement(smallestUnit).
12952 maximum = MaximumTemporalDurationRoundingIncrement(smallest_unit);
12953 // b. Assert: maximum is not undefined.
12954 DCHECK(maximum.defined);
12955 }
12956 // 3. Return ? ToTemporalRoundingIncrement(normalizedOptions, maximum, false).
12957 return ToTemporalRoundingIncrement(isolate, normalized_option, maximum.value,
12958 maximum.defined, false);
12959}
12960
12961} // namespace
12962
12963// #sec-temporal.plaindatetime.prototype.round
12966 DirectHandle<Object> round_to_obj) {
12967 const char* method_name = "Temporal.PlainDateTime.prototype.round";
12968 Factory* factory = isolate->factory();
12969 // 1. Let temporalTime be the this value.
12970 // 2. Perform ? RequireInternalSlot(dateTime,
12971 // [[InitializedTemporalDateTime]]).
12972 // 3. If roundTo is undefined, then
12973 if (IsUndefined(*round_to_obj)) {
12974 // a. Throw a TypeError exception.
12976 }
12977
12978 DirectHandle<JSReceiver> round_to;
12979 // 4. If Type(roundTo) is String, then
12980 if (IsString(*round_to_obj)) {
12981 // a. Let paramString be roundTo.
12982 DirectHandle<String> param_string = Cast<String>(round_to_obj);
12983 // b. Set roundTo to ! OrdinaryObjectCreate(null).
12984 round_to = factory->NewJSObjectWithNullProto();
12985 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit",
12986 // paramString).
12987 CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
12988 factory->smallestUnit_string(),
12989 param_string, Just(kThrowOnError))
12990 .FromJust());
12991 // 5. Else
12992 } else {
12993 // a. Set roundTo to ? GetOptionsObject(roundTo).
12995 isolate, round_to,
12996 GetOptionsObject(isolate, round_to_obj, method_name));
12997 }
12998
12999 // 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time,
13000 // required).
13001 Unit smallest_unit;
13003 isolate, smallest_unit,
13004 GetTemporalUnit(isolate, round_to, "smallestUnit", UnitGroup::kTime,
13005 Unit::kDay, true, method_name),
13007
13008 // 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
13011 isolate, rounding_mode,
13012 ToTemporalRoundingMode(isolate, round_to, RoundingMode::kHalfExpand,
13013 method_name),
13015
13016 // 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(roundTo,
13017 // smallestUnit).
13018 double rounding_increment;
13020 isolate, rounding_increment,
13021 ToTemporalDateTimeRoundingIncrement(isolate, round_to, smallest_unit),
13023
13024 // 9. Let result be ! RoundISODateTime(dateTime.[[ISOYear]],
13025 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
13026 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
13027 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
13028 // dateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
13029 DateTimeRecord result = RoundISODateTime(
13030 isolate,
13031 {{date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
13032 {date_time->iso_hour(), date_time->iso_minute(), date_time->iso_second(),
13033 date_time->iso_millisecond(), date_time->iso_microsecond(),
13034 date_time->iso_nanosecond()}},
13036
13037 // 10. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
13038 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
13039 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
13040 // dateTime.[[Calendar]]).
13042 isolate, result, direct_handle(date_time->calendar(), isolate));
13043}
13044
13045namespace {
13046
13048AddDurationToOrSubtractDurationFromPlainDateTime(
13049 Isolate* isolate, Arithmetic operation,
13051 DirectHandle<Object> temporal_duration_like,
13052 DirectHandle<Object> options_obj, const char* method_name) {
13053 // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
13054 double sign = operation == Arithmetic::kSubtract ? -1.0 : 1.0;
13055 // 2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
13056 DurationRecord duration;
13058 isolate, duration,
13059 temporal::ToTemporalDurationRecord(isolate, temporal_duration_like,
13060 method_name),
13062
13063 TimeDurationRecord& time_duration = duration.time_duration;
13064
13065 // 3. Set options to ? GetOptionsObject(options).
13068 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
13069 // 4. Let result be ? AddDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
13070 // dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]],
13071 // dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]],
13072 // dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]],
13073 // dateTime.[[Calendar]], duration.[[Years]], duration.[[Months]],
13074 // duration.[[Weeks]], duration.[[Days]], duration.[[Hours]],
13075 // duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]],
13076 // duration.[[Microseconds]], duration.[[Nanoseconds]], options).
13077 DateTimeRecord result;
13079 isolate, result,
13080 AddDateTime(isolate,
13081 {{date_time->iso_year(), date_time->iso_month(),
13082 date_time->iso_day()},
13083 {date_time->iso_hour(), date_time->iso_minute(),
13084 date_time->iso_second(), date_time->iso_millisecond(),
13085 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
13086 direct_handle(date_time->calendar(), isolate),
13087 {sign * duration.years,
13088 sign * duration.months,
13089 sign * duration.weeks,
13090 {sign * time_duration.days, sign * time_duration.hours,
13091 sign * time_duration.minutes, sign * time_duration.seconds,
13092 sign * time_duration.milliseconds,
13093 sign * time_duration.microseconds,
13094 sign * time_duration.nanoseconds}},
13095 options),
13096 DirectHandle<JSTemporalPlainDateTime>());
13097
13098 // 5. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
13099 // result.[[Day]]) is true.
13100 DCHECK(IsValidISODate(isolate, result.date));
13101 // 6. Assert: ! IsValidTime(result.[[Hour]], result.[[Minute]],
13102 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
13103 // result.[[Nanosecond]]) is true.
13104 DCHECK(IsValidTime(isolate, result.time));
13105 // 7. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]],
13106 // result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]],
13107 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]],
13108 // dateTime.[[Calendar]]).
13110 isolate, result, direct_handle(date_time->calendar(), isolate));
13111}
13112
13113} // namespace
13114
13115// #sec-temporal.plaindatetime.prototype.add
13118 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
13119 return AddDurationToOrSubtractDurationFromPlainDateTime(
13120 isolate, Arithmetic::kAdd, date_time, temporal_duration_like, options,
13121 "Temporal.PlainDateTime.prototype.add");
13122}
13123
13124// #sec-temporal.plaindatetime.prototype.subtract
13127 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
13128 return AddDurationToOrSubtractDurationFromPlainDateTime(
13129 isolate, Arithmetic::kSubtract, date_time, temporal_duration_like,
13130 options, "Temporal.PlainDateTime.prototype.subtract");
13131}
13132
13133namespace {
13134
13135// #sec-temporal-differencetemporalplaindatetime
13136MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalPlainDateTime(
13137 Isolate* isolate, TimePreposition operation,
13139 DirectHandle<Object> other_obj, DirectHandle<Object> options,
13140 const char* method_name) {
13142 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
13143 double sign = operation == TimePreposition::kSince ? -1 : 1;
13144 // 2. Set other to ? ToTemporalDateTime(other).
13147 isolate, other, ToTemporalDateTime(isolate, other_obj, method_name));
13148 // 3. If ? CalendarEquals(dateTime.[[Calendar]], other.[[Calendar]]) is false,
13149 // throw a RangeError exception.
13150 bool calendar_equals;
13152 isolate, calendar_equals,
13153 CalendarEqualsBool(isolate, direct_handle(date_time->calendar(), isolate),
13154 direct_handle(other->calendar(), isolate)),
13156 if (!calendar_equals) {
13158 }
13159 // 4. Let settings be ? GetDifferenceSettings(operation, options, datetime, «
13160 // », "nanosecond", "day").
13161 DifferenceSettings settings;
13163 isolate, settings,
13164 GetDifferenceSettings(isolate, operation, options, UnitGroup::kDateTime,
13165 DisallowedUnitsInDifferenceSettings::kNone,
13166 Unit::kNanosecond, Unit::kDay, method_name),
13167 DirectHandle<JSTemporalDuration>());
13168 // 5. Let diff be ? DifferenceISODateTime(dateTime.[[ISOYear]],
13169 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
13170 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
13171 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
13172 // dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]],
13173 // other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]],
13174 // other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]],
13175 // other.[[ISONanosecond]], dateTime.[[Calendar]], settings.[[LargestUnit]],
13176 // settings.[[Options]]).
13177 DurationRecord diff;
13179 isolate, diff,
13180 DifferenceISODateTime(
13181 isolate,
13182 {{date_time->iso_year(), date_time->iso_month(),
13183 date_time->iso_day()},
13184 {date_time->iso_hour(), date_time->iso_minute(),
13185 date_time->iso_second(), date_time->iso_millisecond(),
13186 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
13187 {{other->iso_year(), other->iso_month(), other->iso_day()},
13188 {other->iso_hour(), other->iso_minute(), other->iso_second(),
13189 other->iso_millisecond(), other->iso_microsecond(),
13190 other->iso_nanosecond()}},
13191 direct_handle(date_time->calendar(), isolate), settings.largest_unit,
13192 settings.options, method_name),
13193 DirectHandle<JSTemporalDuration>());
13194 // 6. Let relativeTo be ! CreateTemporalDate(dateTime.[[ISOYear]],
13195 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]).
13196 DirectHandle<JSTemporalPlainDate> relative_to;
13198 isolate, relative_to,
13199 CreateTemporalDate(
13200 isolate,
13201 {date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
13202 direct_handle(date_time->calendar(), isolate)),
13203 DirectHandle<JSTemporalDuration>());
13204 // 7. Let roundResult be (? RoundDuration(diff.[[Years]], diff.[[Months]],
13205 // diff.[[Weeks]], diff.[[Days]], diff.[[Hours]], diff.[[Minutes]],
13206 // diff.[[Seconds]], diff.[[Milliseconds]], diff.[[Microseconds]],
13207 // diff.[[Nanoseconds]], settings.[[RoundingIncrement]],
13208 // settings.[[SmallestUnit]], settings.[[RoundingMode]],
13209 // relativeTo)).[[DurationRecord]].
13210 DurationRecordWithRemainder round_result;
13212 isolate, round_result,
13213 RoundDuration(isolate, diff, settings.rounding_increment,
13214 settings.smallest_unit, settings.rounding_mode, relative_to,
13215 method_name),
13216 DirectHandle<JSTemporalDuration>());
13217 // 8. Let result be ? BalanceDuration(roundResult.[[Days]],
13218 // roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]],
13219 // roundResult.[[Milliseconds]], roundResult.[[Microseconds]],
13220 // roundResult.[[Nanoseconds]], settings.[[LargestUnit]]).
13222 isolate, round_result.record.time_duration,
13223 BalanceDuration(isolate, settings.largest_unit,
13224 round_result.record.time_duration, method_name),
13225 DirectHandle<JSTemporalDuration>());
13226 // 9. Return ! CreateTemporalDuration(sign × roundResult.[[Years]], sign ×
13227 // roundResult.[[Months]], sign × roundResult.[[Weeks]], sign ×
13228 // result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign ×
13229 // result.[[Seconds]], sign × result.[[Milliseconds]], sign ×
13230 // result.[[Microseconds]], sign × result.[[Nanoseconds]]).
13231 return CreateTemporalDuration(
13232 isolate, {sign * round_result.record.years,
13233 sign * round_result.record.months,
13234 sign * round_result.record.weeks,
13235 {sign * round_result.record.time_duration.days,
13236 sign * round_result.record.time_duration.hours,
13237 sign * round_result.record.time_duration.minutes,
13238 sign * round_result.record.time_duration.seconds,
13239 sign * round_result.record.time_duration.milliseconds,
13240 sign * round_result.record.time_duration.microseconds,
13241 sign * round_result.record.time_duration.nanoseconds}})
13242 .ToHandleChecked();
13243}
13244
13245} // namespace
13246
13247// #sec-temporal.plaindatetime.prototype.until
13252 return DifferenceTemporalPlainDateTime(
13253 isolate, TimePreposition::kUntil, handle, other, options,
13254 "Temporal.PlainDateTime.prototype.until");
13255}
13256
13257// #sec-temporal.plaindatetime.prototype.since
13262 return DifferenceTemporalPlainDateTime(
13263 isolate, TimePreposition::kSince, handle, other, options,
13264 "Temporal.PlainDateTime.prototype.since");
13265}
13266
13267// #sec-temporal.plaindatetime.prototype.getisofields
13269 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
13270 Factory* factory = isolate->factory();
13271 // 1. Let dateTime be the this value.
13272 // 2. Perform ? RequireInternalSlot(temporalDateTime,
13273 // [[InitializedTemporalDateTime]]).
13274 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
13275 DirectHandle<JSObject> fields =
13276 isolate->factory()->NewJSObject(isolate->object_function());
13277 // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
13278 // temporalTime.[[Calendar]]).
13280 isolate, fields, factory->calendar_string(),
13281 DirectHandle<JSReceiver>(date_time->calendar(), isolate),
13283 .FromJust());
13284 // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
13285 // 𝔽(dateTime.[[ISODay]])).
13286 // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
13287 // 𝔽(temporalTime.[[ISOHour]])).
13288 // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
13289 // 𝔽(temporalTime.[[ISOMicrosecond]])).
13290 // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
13291 // 𝔽(temporalTime.[[ISOMillisecond]])).
13292 // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
13293 // 𝔽(temporalTime.[[ISOMinute]])).
13294 // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
13295 // 𝔽(temporalTime.[[ISOMonth]])).
13296 // 11. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
13297 // 𝔽(temporalTime.[[ISONanosecond]])).
13298 // 12. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
13299 // 𝔽(temporalTime.[[ISOSecond]])).
13300 // 13. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
13301 // 𝔽(temporalTime.[[ISOYear]])).
13302 DEFINE_INT_FIELD(fields, isoDay, iso_day, date_time)
13303 DEFINE_INT_FIELD(fields, isoHour, iso_hour, date_time)
13304 DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, date_time)
13305 DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, date_time)
13306 DEFINE_INT_FIELD(fields, isoMinute, iso_minute, date_time)
13307 DEFINE_INT_FIELD(fields, isoMonth, iso_month, date_time)
13308 DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, date_time)
13309 DEFINE_INT_FIELD(fields, isoSecond, iso_second, date_time)
13310 DEFINE_INT_FIELD(fields, isoYear, iso_year, date_time)
13311 // 14. Return fields.
13312 return fields;
13313}
13314
13315// #sec-temporal.plaindatetime.prototype.toplaindate
13317 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
13318 // 1. Let dateTime be the this value.
13319 // 2. Perform ? RequireInternalSlot(dateTime,
13320 // [[InitializedTemporalDateTime]]).
13321 // 3. Return ? CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
13322 // dateTime.[[ISODay]], dateTime.[[Calendar]]).
13323 return CreateTemporalDate(
13324 isolate,
13325 {date_time->iso_year(), date_time->iso_month(), date_time->iso_day()},
13326 DirectHandle<JSReceiver>(date_time->calendar(), isolate));
13327}
13328
13329// #sec-temporal.plaindatetime.prototype.toplaintime
13331 Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
13332 // 1. Let dateTime be the this value.
13333 // 2. Perform ? RequireInternalSlot(dateTime,
13334 // [[InitializedTemporalDateTime]]).
13335 // 3. Return ? CreateTemporalTime(dateTime.[[ISOHour]],
13336 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
13337 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
13338 // dateTime.[[ISONanosecond]]).
13339 return CreateTemporalTime(
13340 isolate, {date_time->iso_hour(), date_time->iso_minute(),
13341 date_time->iso_second(), date_time->iso_millisecond(),
13342 date_time->iso_microsecond(), date_time->iso_nanosecond()});
13343}
13344
13345// #sec-temporal.plainmonthday
13347 Isolate* isolate, DirectHandle<JSFunction> target,
13349 DirectHandle<Object> iso_day_obj, DirectHandle<Object> calendar_like,
13350 DirectHandle<Object> reference_iso_year_obj) {
13351 const char* method_name = "Temporal.PlainMonthDay";
13352 // 1. If NewTarget is undefined, throw a TypeError exception.
13353 if (IsUndefined(*new_target)) {
13354 THROW_NEW_ERROR(isolate,
13355 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
13356 isolate->factory()->NewStringFromAsciiChecked(
13357 method_name)));
13358 }
13359
13360 // 3. Let m be ? ToIntegerThrowOnInfinity(isoMonth).
13362 // 5. Let d be ? ToIntegerThrowOnInfinity(isoDay).
13364 // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
13367 isolate, calendar,
13368 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
13369
13370 // 2. If referenceISOYear is undefined, then
13371 // a. Set referenceISOYear to 1972𝔽.
13372 // ...
13373 // 8. Let ref be ? ToIntegerThrowOnInfinity(referenceISOYear).
13374 int32_t ref = 1972;
13375 if (!IsUndefined(*reference_iso_year_obj)) {
13377 ref = reference_iso_year;
13378 }
13379
13380 // 10. Return ? CreateTemporalMonthDay(y, m, calendar, ref, NewTarget).
13381 return CreateTemporalMonthDay(isolate, target, new_target, iso_month, iso_day,
13382 calendar, ref);
13383}
13384
13385namespace {
13386
13387// #sec-temporal-parsetemporalmonthdaystring
13388Maybe<DateRecordWithCalendar> ParseTemporalMonthDayString(
13389 Isolate* isolate, DirectHandle<String> iso_string) {
13391
13392 // 1. Assert: Type(isoString) is String.
13393 // 2. If isoString does not satisfy the syntax of a TemporalMonthDayString
13394 // (see 13.33), then
13395 std::optional<ParsedISO8601Result> parsed =
13396 TemporalParser::ParseTemporalMonthDayString(isolate, iso_string);
13397 if (!parsed.has_value()) {
13398 // a. Throw a *RangeError* exception.
13402 }
13403 // 3. If isoString contains a UTCDesignator, then
13404 if (parsed->utc_designator) {
13405 // a. Throw a *RangeError* exception.
13409 }
13410
13411 // 3. Let result be ? ParseISODateTime(isoString).
13412 DateTimeRecordWithCalendar result;
13414 isolate, result, ParseISODateTime(isolate, iso_string, *parsed),
13416 // 5. Let year be result.[[Year]].
13417 // 6. If no part of isoString is produced by the DateYear production, then
13418 // a. Set year to undefined.
13419
13420 // 7. Return the Record { [[Year]]: year, [[Month]]: result.[[Month]],
13421 // [[Day]]: result.[[Day]], [[Calendar]]: result.[[Calendar]] }.
13422 DateRecordWithCalendar ret({result.date, result.calendar});
13423 return Just(ret);
13424}
13425
13426// #sec-temporal-totemporalmonthday
13427MaybeDirectHandle<JSTemporalPlainMonthDay> ToTemporalMonthDay(
13428 Isolate* isolate, DirectHandle<Object> item_obj,
13429 DirectHandle<Object> options, const char* method_name) {
13431
13432 Factory* factory = isolate->factory();
13433 // 2. Assert: Type(options) is Object or Undefined.
13434 DCHECK(IsJSReceiver(*options) || IsUndefined(*options));
13435
13436 // 3. Let referenceISOYear be 1972 (the first leap year after the Unix epoch).
13437 constexpr int32_t kReferenceIsoYear = 1972;
13438 // 4. If Type(item) is Object, then
13439 if (IsJSReceiver(*item_obj)) {
13440 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
13441 // a. If item has an [[InitializedTemporalMonthDay]] internal slot, then
13442 // i. Return item.
13443 if (IsJSTemporalPlainMonthDay(*item_obj)) {
13444 return Cast<JSTemporalPlainMonthDay>(item_obj);
13445 }
13446 bool calendar_absent = false;
13447 // b. If item has an [[InitializedTemporalDate]],
13448 // [[InitializedTemporalDateTime]], [[InitializedTemporalTime]],
13449 // [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]]
13450 // internal slot, then
13451 // i. Let calendar be item.[[Calendar]].
13452 // ii. Let calendarAbsent be false.
13453 DirectHandle<JSReceiver> calendar;
13454 if (IsJSTemporalPlainDate(*item_obj)) {
13456 isolate);
13457 } else if (IsJSTemporalPlainDateTime(*item_obj)) {
13459 Cast<JSTemporalPlainDateTime>(item_obj)->calendar(), isolate);
13460 } else if (IsJSTemporalPlainTime(*item_obj)) {
13462 isolate);
13463 } else if (IsJSTemporalPlainYearMonth(*item_obj)) {
13465 Cast<JSTemporalPlainYearMonth>(item_obj)->calendar(), isolate);
13466 } else if (IsJSTemporalZonedDateTime(*item_obj)) {
13468 Cast<JSTemporalZonedDateTime>(item_obj)->calendar(), isolate);
13469 // c. Else,
13470 } else {
13471 // i. Let calendar be ? Get(item, "calendar").
13472 DirectHandle<Object> calendar_obj;
13474 isolate, calendar_obj,
13475 JSReceiver::GetProperty(isolate, item, factory->calendar_string()));
13476 // ii. If calendar is undefined, then
13477 if (IsUndefined(*calendar_obj)) {
13478 // 1. Let calendarAbsent be true.
13479 calendar_absent = true;
13480 }
13481 // iv. Set calendar to ? ToTemporalCalendarWithISODefault(calendar).
13483 isolate, calendar,
13484 ToTemporalCalendarWithISODefault(isolate, calendar_obj, method_name));
13485 }
13486 // d. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
13487 // "monthCode", "year" »).
13488 DirectHandle<FixedArray> field_names =
13489 DayMonthMonthCodeYearInFixedArray(isolate);
13490 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
13491 CalendarFields(isolate, calendar, field_names));
13492 // e. Let fields be ? PrepareTemporalFields(item, fieldNames, «»).
13493 DirectHandle<JSReceiver> fields;
13494 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
13495 PrepareTemporalFields(isolate, item, field_names,
13496 RequiredFields::kNone));
13497 // f. Let month be ? Get(fields, "month").
13498 DirectHandle<Object> month;
13500 isolate, month,
13501 JSReceiver::GetProperty(isolate, fields, factory->month_string()),
13502 DirectHandle<JSTemporalPlainMonthDay>());
13503 // g. Let monthCode be ? Get(fields, "monthCode").
13504 DirectHandle<Object> month_code;
13506 isolate, month_code,
13507 JSReceiver::GetProperty(isolate, fields, factory->monthCode_string()),
13508 DirectHandle<JSTemporalPlainMonthDay>());
13509 // h. Let year be ? Get(fields, "year").
13510 DirectHandle<Object> year;
13512 isolate, year,
13513 JSReceiver::GetProperty(isolate, fields, factory->year_string()),
13514 DirectHandle<JSTemporalPlainMonthDay>());
13515 // i. If calendarAbsent is true, and month is not undefined, and monthCode
13516 // is undefined and year is undefined, then
13517 if (calendar_absent && !IsUndefined(*month) && IsUndefined(*month_code) &&
13518 IsUndefined(*year)) {
13519 // i. Perform ! CreateDataPropertyOrThrow(fields, "year",
13520 // 𝔽(referenceISOYear)).
13522 isolate, fields, factory->year_string(),
13523 direct_handle(Smi::FromInt(kReferenceIsoYear), isolate),
13525 .FromJust());
13526 }
13527 // j. Return ? MonthDayFromFields(calendar, fields, options).
13528 return MonthDayFromFields(isolate, calendar, fields, options);
13529 }
13530 // 5. Perform ? ToTemporalOverflow(options).
13532 isolate, ToTemporalOverflow(isolate, options, method_name),
13533 DirectHandle<JSTemporalPlainMonthDay>());
13534
13535 // 6. Let string be ? ToString(item).
13536 DirectHandle<String> string;
13537 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
13538 Object::ToString(isolate, item_obj));
13539
13540 // 7. Let result be ? ParseTemporalMonthDayString(string).
13541 DateRecordWithCalendar result;
13543 isolate, result, ParseTemporalMonthDayString(isolate, string),
13544 DirectHandle<JSTemporalPlainMonthDay>());
13545
13546 // 8. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
13547 DirectHandle<JSReceiver> calendar;
13549 isolate, calendar,
13550 ToTemporalCalendarWithISODefault(isolate, result.calendar, method_name));
13551
13552 // 9. If result.[[Year]] is undefined, then
13553 // We use kMintInt31 to represent undefined
13554 if (result.date.year == kMinInt31) {
13555 // a. Return ? CreateTemporalMonthDay(result.[[Month]], result.[[Day]],
13556 // calendar, referenceISOYear).
13557 return CreateTemporalMonthDay(isolate, result.date.month, result.date.day,
13558 calendar, kReferenceIsoYear);
13559 }
13560
13561 DirectHandle<JSTemporalPlainMonthDay> created_result;
13562 // 10. Set result to ? CreateTemporalMonthDay(result.[[Month]],
13563 // result.[[Day]], calendar, referenceISOYear).
13565 isolate, created_result,
13566 CreateTemporalMonthDay(isolate, result.date.month, result.date.day,
13567 calendar, kReferenceIsoYear));
13568 // 11. NOTE: The following operation is called without options, in order for
13569 // the calendar to store a canonical value in the [[ISOYear]] internal slot of
13570 // the result.
13571 // 12. Return ? CalendarMonthDayFromFields(calendar, result).
13572 return MonthDayFromFields(isolate, calendar, created_result);
13573}
13574
13575MaybeDirectHandle<JSTemporalPlainMonthDay> ToTemporalMonthDay(
13576 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name) {
13577 // 1. If options is not present, set options to undefined.
13578 return ToTemporalMonthDay(isolate, item_obj,
13579 isolate->factory()->undefined_value(), method_name);
13580}
13581
13582} // namespace
13583
13584// #sec-temporal.plainmonthday.from
13586 Isolate* isolate, DirectHandle<Object> item,
13587 DirectHandle<Object> options_obj) {
13588 const char* method_name = "Temporal.PlainMonthDay.from";
13589 // 1. Set options to ? GetOptionsObject(options).
13592 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
13593 // 2. If Type(item) is Object and item has an [[InitializedTemporalMonthDay]]
13594 // internal slot, then
13595 if (IsJSTemporalPlainMonthDay(*item)) {
13596 // a. Perform ? ToTemporalOverflow(options).
13598 isolate, ToTemporalOverflow(isolate, options, method_name),
13600 // b. Return ? CreateTemporalMonthDay(item.[[ISOMonth]], item.[[ISODay]],
13601 // item.[[Calendar]], item.[[ISOYear]]).
13602 auto month_day = Cast<JSTemporalPlainMonthDay>(item);
13603 return CreateTemporalMonthDay(
13604 isolate, month_day->iso_month(), month_day->iso_day(),
13605 direct_handle(month_day->calendar(), isolate), month_day->iso_year());
13606 }
13607 // 3. Return ? ToTemporalMonthDay(item, options).
13608 return ToTemporalMonthDay(isolate, item, options, method_name);
13609}
13610
13611// #sec-temporal.plainyearmonth.prototype.equals
13614 DirectHandle<Object> other_obj) {
13615 // 1. Let monthDay be the this value.
13616 // 2. Perform ? RequireInternalSlot(monthDay,
13617 // [[InitializedTemporalMonthDay]]).
13618 // 3. Set other to ? ToTemporalMonthDay(other).
13621 isolate, other,
13622 ToTemporalMonthDay(isolate, other_obj,
13623 "Temporal.PlainMonthDay.prototype.equals"));
13624 // 4. If monthDay.[[ISOMonth]] ≠ other.[[ISOMonth]], return false.
13625 if (month_day->iso_month() != other->iso_month())
13626 return isolate->factory()->false_value();
13627 // 5. If monthDay.[[ISODay]] ≠ other.[[ISODay]], return false.
13628 if (month_day->iso_day() != other->iso_day())
13629 return isolate->factory()->false_value();
13630 // 6. If monthDay.[[ISOYear]] ≠ other.[[ISOYear]], return false.
13631 if (month_day->iso_year() != other->iso_year())
13632 return isolate->factory()->false_value();
13633 // 7. Return ? CalendarEquals(monthDay.[[Calendar]], other.[[Calendar]]).
13634 return CalendarEquals(
13635 isolate, DirectHandle<JSReceiver>(month_day->calendar(), isolate),
13636 DirectHandle<JSReceiver>(other->calendar(), isolate));
13637}
13638
13639// #sec-temporal.plainmonthday.prototype.with
13641 Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> temporal_month_day,
13642 DirectHandle<Object> temporal_month_day_like_obj,
13643 DirectHandle<Object> options_obj) {
13644 // 6. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
13645 // "monthCode", "year" »).
13646 DirectHandle<FixedArray> field_names =
13647 DayMonthMonthCodeYearInFixedArray(isolate);
13648 return PlainDateOrYearMonthOrMonthDayWith<JSTemporalPlainMonthDay,
13649 MonthDayFromFields>(
13650 isolate, temporal_month_day, temporal_month_day_like_obj, options_obj,
13651 field_names, "Temporal.PlainMonthDay.prototype.with");
13652}
13653
13654namespace {
13655
13656// Common code shared by PlainMonthDay and PlainYearMonth.prototype.toPlainDate
13657template <typename T>
13658MaybeDirectHandle<JSTemporalPlainDate> PlainMonthDayOrYearMonthToPlainDate(
13659 Isolate* isolate, DirectHandle<T> temporal, DirectHandle<Object> item_obj,
13660 DirectHandle<String> receiver_field_name_1,
13661 DirectHandle<String> receiver_field_name_2,
13662 DirectHandle<String> input_field_name) {
13663 Factory* factory = isolate->factory();
13664 // 1. Let monthDay be the this value.
13665 // 2. Perform ? RequireInternalSlot(monthDay,
13666 // [[InitializedTemporalXXX]]).
13667 // 3. If Type(item) is not Object, then
13668 if (!IsJSReceiver(*item_obj)) {
13669 // a. Throw a TypeError exception.
13671 }
13672 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
13673 // 4. Let calendar be Xxx.[[Calendar]].
13674 DirectHandle<JSReceiver> calendar(temporal->calendar(), isolate);
13675 // 5. Let receiverFieldNames be ? CalendarFields(calendar, «
13676 // receiverFieldName1, receiverFieldName2 »).
13677 DirectHandle<FixedArray> receiver_field_names = factory->NewFixedArray(2);
13678 receiver_field_names->set(0, *receiver_field_name_1);
13679 receiver_field_names->set(1, *receiver_field_name_2);
13681 isolate, receiver_field_names,
13682 CalendarFields(isolate, calendar, receiver_field_names));
13683 // 6. Let fields be ? PrepareTemporalFields(temporal, receiverFieldNames, «»).
13684 DirectHandle<JSReceiver> fields;
13686 isolate, fields,
13687 PrepareTemporalFields(isolate, temporal, receiver_field_names,
13688 RequiredFields::kNone));
13689 // 7. Let inputFieldNames be ? CalendarFields(calendar, « inputFieldName »).
13690 DirectHandle<FixedArray> input_field_names = factory->NewFixedArray(1);
13691 input_field_names->set(0, *input_field_name);
13693 isolate, input_field_names,
13694 CalendarFields(isolate, calendar, input_field_names));
13695 // 8. Let inputFields be ? PrepareTemporalFields(item, inputFieldNames, «»).
13696 DirectHandle<JSReceiver> input_fields;
13698 isolate, input_fields,
13699 PrepareTemporalFields(isolate, item, input_field_names,
13700 RequiredFields::kNone));
13701 // 9. Let mergedFields be ? CalendarMergeFields(calendar, fields,
13702 // inputFields).
13703 DirectHandle<JSReceiver> merged_fields;
13705 isolate, merged_fields,
13706 CalendarMergeFields(isolate, calendar, fields, input_fields));
13707 // 10. Let mergedFieldNames be the List containing all the elements of
13708 // receiverFieldNames followed by all the elements of inputFieldNames, with
13709 // duplicate elements removed.
13710 DirectHandle<FixedArray> merged_field_names = factory->NewFixedArray(
13711 receiver_field_names->length() + input_field_names->length());
13712 Handle<StringSet> added = StringSet::New(isolate);
13713 for (int i = 0; i < receiver_field_names->length(); i++) {
13714 DirectHandle<Object> field(receiver_field_names->get(i), isolate);
13715 DCHECK(IsString(*field));
13716 auto string = Cast<String>(field);
13717 if (!added->Has(isolate, string)) {
13718 merged_field_names->set(added->NumberOfElements(), *field);
13719 added = StringSet::Add(isolate, added, string);
13720 }
13721 }
13722 for (int i = 0; i < input_field_names->length(); i++) {
13723 DirectHandle<Object> field(input_field_names->get(i), isolate);
13724 DCHECK(IsString(*field));
13725 auto string = Cast<String>(field);
13726 if (!added->Has(isolate, string)) {
13727 merged_field_names->set(added->NumberOfElements(), *field);
13728 added = StringSet::Add(isolate, added, string);
13729 }
13730 }
13731 merged_field_names = FixedArray::RightTrimOrEmpty(isolate, merged_field_names,
13732 added->NumberOfElements());
13733
13734 // 11. Set mergedFields to ? PrepareTemporalFields(mergedFields,
13735 // mergedFieldNames, «»).
13737 isolate, merged_fields,
13738 PrepareTemporalFields(isolate, merged_fields, merged_field_names,
13739 RequiredFields::kNone));
13740 // 12. Let options be ! OrdinaryObjectCreate(null).
13741 DirectHandle<JSObject> options = factory->NewJSObjectWithNullProto();
13742 // 13. Perform ! CreateDataPropertyOrThrow(options, "overflow", "reject").
13744 isolate, options, factory->overflow_string(),
13745 factory->reject_string(), Just(kThrowOnError))
13746 .FromJust());
13747 // 14. Return ? DateFromFields(calendar, mergedFields, options).
13748 return DateFromFields(isolate, calendar, merged_fields, options);
13749}
13750
13751} // namespace
13752
13753// #sec-temporal.plainmonthday.prototype.toplaindate
13756 DirectHandle<Object> item_obj) {
13757 Factory* factory = isolate->factory();
13758 // 5. Let receiverFieldNames be ? CalendarFields(calendar, « "day",
13759 // "monthCode" »).
13760 // 7. Let inputFieldNames be ? CalendarFields(calendar, « "year" »).
13761 return PlainMonthDayOrYearMonthToPlainDate<JSTemporalPlainMonthDay>(
13762 isolate, month_day, item_obj, factory->day_string(),
13763 factory->monthCode_string(), factory->year_string());
13764}
13765
13766// #sec-temporal.plainmonthday.prototype.getisofields
13768 Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day) {
13769 Factory* factory = isolate->factory();
13770 // 1. Let monthDay be the this value.
13771 // 2. Perform ? RequireInternalSlot(monthDay,
13772 // [[InitializedTemporalMonthDay]]).
13773 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
13774 DirectHandle<JSObject> fields =
13775 factory->NewJSObject(isolate->object_function());
13776 // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
13777 // montyDay.[[Calendar]]).
13779 isolate, fields, factory->calendar_string(),
13780 DirectHandle<JSReceiver>(month_day->calendar(), isolate),
13782 .FromJust());
13783
13784 // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
13785 // 𝔽(montyDay.[[ISODay]])).
13786 // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
13787 // 𝔽(montyDay.[[ISOMonth]])).
13788 // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
13789 // 𝔽(montyDay.[[ISOYear]])).
13790 DEFINE_INT_FIELD(fields, isoDay, iso_day, month_day)
13791 DEFINE_INT_FIELD(fields, isoMonth, iso_month, month_day)
13792 DEFINE_INT_FIELD(fields, isoYear, iso_year, month_day)
13793 // 8. Return fields.
13794 return fields;
13795}
13796
13797// #sec-temporal.plainmonthday.prototype.tojson
13799 Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day) {
13800 return TemporalMonthDayToString(isolate, month_day, ShowCalendar::kAuto);
13801}
13802
13803// #sec-temporal.plainmonthday.prototype.tostring
13806 DirectHandle<Object> options) {
13807 return TemporalToString<JSTemporalPlainMonthDay, TemporalMonthDayToString>(
13808 isolate, month_day, options, "Temporal.PlainMonthDay.prototype.toString");
13809}
13810
13811// #sec-temporal.plainmonthday.prototype.tolocalestring
13814 DirectHandle<Object> locales, DirectHandle<Object> options) {
13815#ifdef V8_INTL_SUPPORT
13817 isolate, month_day, locales, options,
13818 "Temporal.PlainMonthDay.prototype.toLocaleString");
13819#else // V8_INTL_SUPPORT
13820 return TemporalMonthDayToString(isolate, month_day, ShowCalendar::kAuto);
13821#endif // V8_INTL_SUPPORT
13822}
13823
13826 Isolate* isolate, DirectHandle<JSFunction> target,
13828 DirectHandle<Object> iso_month_obj, DirectHandle<Object> calendar_like,
13829 DirectHandle<Object> reference_iso_day_obj) {
13830 const char* method_name = "Temporal.PlainYearMonth";
13831 // 1. If NewTarget is undefined, throw a TypeError exception.
13832 if (IsUndefined(*new_target)) {
13833 THROW_NEW_ERROR(isolate,
13834 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
13835 isolate->factory()->NewStringFromAsciiChecked(
13836 method_name)));
13837 }
13838 // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
13839 // 10. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget).
13840
13841 // 3. Let y be ? ToIntegerThrowOnInfinity(isoYear).
13843 // 5. Let m be ? ToIntegerThrowOnInfinity(isoMonth).
13845 // 7. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
13848 isolate, calendar,
13849 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
13850
13851 // 2. If referenceISODay is undefined, then
13852 // a. Set referenceISODay to 1𝔽.
13853 // ...
13854 // 8. Let ref be ? ToIntegerThrowOnInfinity(referenceISODay).
13855 int32_t ref = 1;
13856 if (!IsUndefined(*reference_iso_day_obj)) {
13858 ref = reference_iso_day;
13859 }
13860
13861 // 10. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget).
13862 return CreateTemporalYearMonth(isolate, target, new_target, iso_year,
13863 iso_month, calendar, ref);
13864}
13865
13866namespace {
13867
13868// #sec-temporal-parsetemporalyearmonthstring
13869Maybe<DateRecordWithCalendar> ParseTemporalYearMonthString(
13870 Isolate* isolate, DirectHandle<String> iso_string) {
13872
13873 // 1. Assert: Type(isoString) is String.
13874 // 2. If isoString does not satisfy the syntax of a TemporalYearMonthString
13875 // (see 13.33), then
13876 std::optional<ParsedISO8601Result> parsed =
13877 TemporalParser::ParseTemporalYearMonthString(isolate, iso_string);
13878 if (!parsed.has_value()) {
13882 }
13883
13884 // 3. If _isoString_ contains a |UTCDesignator|, then
13885 if (parsed->utc_designator) {
13886 // a. Throw a *RangeError* exception.
13890 }
13891
13892 // 3. Let result be ? ParseISODateTime(isoString).
13893 DateTimeRecordWithCalendar result;
13895 isolate, result, ParseISODateTime(isolate, iso_string, *parsed),
13897
13898 // 4. Return the Record { [[Year]]: result.[[Year]], [[Month]]:
13899 // result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]:
13900 // result.[[Calendar]] }.
13901 DateRecordWithCalendar ret = {
13902 {result.date.year, result.date.month, result.date.day}, result.calendar};
13903 return Just(ret);
13904}
13905
13906// #sec-temporal-totemporalyearmonth
13907MaybeDirectHandle<JSTemporalPlainYearMonth> ToTemporalYearMonth(
13908 Isolate* isolate, DirectHandle<Object> item_obj,
13909 DirectHandle<Object> options, const char* method_name) {
13911
13912 // 2. Assert: Type(options) is Object or Undefined.
13913 DCHECK(IsJSReceiver(*options) || IsUndefined(*options));
13914 // 3. If Type(item) is Object, then
13915 if (IsJSReceiver(*item_obj)) {
13916 DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
13917 // a. If item has an [[InitializedTemporalYearMonth]] internal slot, then
13918 // i. Return item.
13919 if (IsJSTemporalPlainYearMonth(*item_obj)) {
13920 return Cast<JSTemporalPlainYearMonth>(item_obj);
13921 }
13922
13923 // b. Let calendar be ? GetTemporalCalendarWithISODefault(item).
13924 DirectHandle<JSReceiver> calendar;
13926 isolate, calendar,
13927 GetTemporalCalendarWithISODefault(isolate, item, method_name));
13928 // c. Let fieldNames be ? CalendarFields(calendar, « "month", "monthCode",
13929 // "year" »).
13930 DirectHandle<FixedArray> field_names =
13931 MonthMonthCodeYearInFixedArray(isolate);
13932 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
13933 CalendarFields(isolate, calendar, field_names));
13934 // d. Let fields be ? PrepareTemporalFields(item, fieldNames, «»).
13935 DirectHandle<JSReceiver> fields;
13936 ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
13937 PrepareTemporalFields(isolate, item, field_names,
13938 RequiredFields::kNone));
13939 // e. Return ? YearMonthFromFields(calendar, fields, options).
13940 return YearMonthFromFields(isolate, calendar, fields, options);
13941 }
13942 // 4. Perform ? ToTemporalOverflow(options).
13944 isolate, ToTemporalOverflow(isolate, options, method_name),
13945 DirectHandle<JSTemporalPlainYearMonth>());
13946 // 5. Let string be ? ToString(item).
13947 DirectHandle<String> string;
13948 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
13949 Object::ToString(isolate, item_obj));
13950 // 6. Let result be ? ParseTemporalYearMonthString(string).
13951 DateRecordWithCalendar result;
13953 isolate, result, ParseTemporalYearMonthString(isolate, string),
13954 DirectHandle<JSTemporalPlainYearMonth>());
13955 // 7. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
13956 DirectHandle<JSReceiver> calendar;
13958 isolate, calendar,
13959 ToTemporalCalendarWithISODefault(isolate, result.calendar, method_name));
13960 // 8. Set result to ? CreateTemporalYearMonth(result.[[Year]],
13961 // result.[[Month]], calendar, result.[[Day]]).
13962 DirectHandle<JSTemporalPlainYearMonth> created_result;
13964 isolate, created_result,
13965 CreateTemporalYearMonth(isolate, result.date.year, result.date.month,
13966 calendar, result.date.day));
13967 // 9. NOTE: The following operation is called without options, in order for
13968 // the calendar to store a canonical value in the [[ISODay]] internal slot of
13969 // the result.
13970 // 10. Return ? CalendarYearMonthFromFields(calendar, result).
13971 return YearMonthFromFields(isolate, calendar, created_result);
13972}
13973
13974MaybeDirectHandle<JSTemporalPlainYearMonth> ToTemporalYearMonth(
13975 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name) {
13976 // 1. If options is not present, set options to undefined.
13977 return ToTemporalYearMonth(
13978 isolate, item_obj, isolate->factory()->undefined_value(), method_name);
13979}
13980
13981} // namespace
13982
13983// #sec-temporal.plainyearmonth.from
13985 Isolate* isolate, DirectHandle<Object> item,
13986 DirectHandle<Object> options_obj) {
13987 const char* method_name = "Temporal.PlainYearMonth.from";
13988 // 1. Set options to ? GetOptionsObject(options).
13991 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
13992 // 2. If Type(item) is Object and item has an [[InitializedTemporalYearMonth]]
13993 // internal slot, then
13994 if (IsJSTemporalPlainYearMonth(*item)) {
13995 // a. Perform ? ToTemporalOverflow(options).
13997 isolate, ToTemporalOverflow(isolate, options, method_name),
13999 // b. Return ? CreateTemporalYearMonth(item.[[ISOYear]], item.[[ISOMonth]],
14000 // item.[[Calendar]], item.[[ISODay]]).
14001 auto year_month = Cast<JSTemporalPlainYearMonth>(item);
14002 return CreateTemporalYearMonth(
14003 isolate, year_month->iso_year(), year_month->iso_month(),
14004 direct_handle(year_month->calendar(), isolate), year_month->iso_day());
14005 }
14006 // 3. Return ? ToTemporalYearMonth(item, options).
14007 return ToTemporalYearMonth(isolate, item, options, method_name);
14008}
14009
14010// #sec-temporal.plainyearmonth.compare
14012 Isolate* isolate, DirectHandle<Object> one_obj,
14013 DirectHandle<Object> two_obj) {
14014 const char* method_name = "Temporal.PlainYearMonth.compare";
14015 // 1. Set one to ? ToTemporalYearMonth(one).
14018 isolate, one, ToTemporalYearMonth(isolate, one_obj, method_name));
14019 // 2. Set two to ? ToTemporalYearMonth(two).
14022 isolate, two, ToTemporalYearMonth(isolate, two_obj, method_name));
14023 // 3. Return 𝔽(! CompareISODate(one.[[ISOYear]], one.[[ISOMonth]],
14024 // one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]])).
14025 return direct_handle(
14027 CompareISODate({one->iso_year(), one->iso_month(), one->iso_day()},
14028 {two->iso_year(), two->iso_month(), two->iso_day()})),
14029 isolate);
14030}
14031
14032// #sec-temporal.plainyearmonth.prototype.equals
14035 DirectHandle<Object> other_obj) {
14036 // 1. Let yearMonth be the this value.
14037 // 2. Perform ? RequireInternalSlot(yearMonth,
14038 // [[InitializedTemporalYearMonth]]).
14039 // 3. Set other to ? ToTemporalYearMonth(other).
14042 isolate, other,
14043 ToTemporalYearMonth(isolate, other_obj,
14044 "Temporal.PlainYearMonth.prototype.equals"));
14045 // 4. If yearMonth.[[ISOYear]] ≠ other.[[ISOYear]], return false.
14046 if (year_month->iso_year() != other->iso_year())
14047 return isolate->factory()->false_value();
14048 // 5. If yearMonth.[[ISOMonth]] ≠ other.[[ISOMonth]], return false.
14049 if (year_month->iso_month() != other->iso_month())
14050 return isolate->factory()->false_value();
14051 // 6. If yearMonth.[[ISODay]] ≠ other.[[ISODay]], return false.
14052 if (year_month->iso_day() != other->iso_day())
14053 return isolate->factory()->false_value();
14054 // 7. Return ? CalendarEquals(yearMonth.[[Calendar]], other.[[Calendar]]).
14055 return CalendarEquals(
14056 isolate, DirectHandle<JSReceiver>(year_month->calendar(), isolate),
14057 DirectHandle<JSReceiver>(other->calendar(), isolate));
14058}
14059
14060namespace {
14061
14063AddDurationToOrSubtractDurationFromPlainYearMonth(
14064 Isolate* isolate, Arithmetic operation,
14066 DirectHandle<Object> temporal_duration_like,
14067 DirectHandle<Object> options_obj, const char* method_name) {
14068 // 1. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
14069 DurationRecord duration;
14071 isolate, duration,
14072 temporal::ToTemporalDurationRecord(isolate, temporal_duration_like,
14073 method_name),
14075
14076 // 2. If operation is subtract, then
14077 if (operation == Arithmetic::kSubtract) {
14078 // a. Set duration to ! CreateNegatedDurationRecord(duration).
14079 duration = CreateNegatedDurationRecord(isolate, duration).ToChecked();
14080 }
14081 // 3. Let balanceResult be ? BalanceDuration(duration.[[Days]],
14082 // duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]],
14083 // duration.[[Milliseconds]], duration.[[Microseconds]],
14084 // duration.[[Nanoseconds]], "day").
14085 TimeDurationRecord balance_result;
14087 isolate, balance_result,
14088 BalanceDuration(isolate, Unit::kDay, duration.time_duration, method_name),
14089 DirectHandle<JSTemporalPlainYearMonth>());
14090 // 4. Set options to ? GetOptionsObject(options).
14091 DirectHandle<JSReceiver> options;
14093 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
14094 // 5. Let calendar be yearMonth.[[Calendar]].
14095 DirectHandle<JSReceiver> calendar(year_month->calendar(), isolate);
14096
14097 // 6. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
14098 Factory* factory = isolate->factory();
14099 DirectHandle<FixedArray> field_names = MonthCodeYearInFixedArray(isolate);
14100 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
14101 CalendarFields(isolate, calendar, field_names));
14102
14103 // 7. Let fields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
14104 DirectHandle<JSReceiver> fields;
14106 isolate, fields,
14107 PrepareTemporalFields(isolate, year_month, field_names,
14108 RequiredFields::kNone));
14109
14110 // 8. Set sign to ! DurationSign(duration.[[Years]], duration.[[Months]],
14111 // duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0, 0, 0, 0).
14112 int32_t sign =
14113 DurationRecord::Sign({duration.years,
14114 duration.months,
14115 duration.weeks,
14116 {balance_result.days, 0, 0, 0, 0, 0, 0}});
14117
14118 // 9. If sign < 0, then
14119 DirectHandle<Object> day;
14120 if (sign < 0) {
14121 // a. Let dayFromCalendar be ? CalendarDaysInMonth(calendar, yearMonth).
14122 DirectHandle<Object> day_from_calendar;
14124 isolate, day_from_calendar,
14125 temporal::CalendarDaysInMonth(isolate, calendar, year_month));
14126
14127 // b. Let day be ? ToPositiveInteger(dayFromCalendar).
14128 ASSIGN_RETURN_ON_EXCEPTION(isolate, day,
14129 ToPositiveInteger(isolate, day_from_calendar));
14130 // 10. Else,
14131 } else {
14132 // a. Let day be 1.
14133 day = direct_handle(Smi::FromInt(1), isolate);
14134 }
14135 // 11. Perform ! CreateDataPropertyOrThrow(fields, "day", day).
14136 CHECK(JSReceiver::CreateDataProperty(isolate, fields, factory->day_string(),
14137 day, Just(kThrowOnError))
14138 .FromJust());
14139
14140 // 12. Let date be ? CalendarDateFromFields(calendar, fields).
14141 DirectHandle<JSTemporalPlainDate> date;
14143 isolate, date,
14144 FromFields<JSTemporalPlainDate>(
14145 isolate, calendar, fields, isolate->factory()->undefined_value(),
14146 isolate->factory()->dateFromFields_string(),
14147 JS_TEMPORAL_PLAIN_DATE_TYPE));
14148
14149 // 13. Let durationToAdd be ! CreateTemporalDuration(duration.[[Years]],
14150 // duration.[[Months]], duration.[[Weeks]], balanceResult.[[Days]], 0, 0, 0,
14151 // 0, 0, 0).
14152 DirectHandle<JSTemporalDuration> duration_to_add =
14153 CreateTemporalDuration(isolate, {duration.years,
14154 duration.months,
14155 duration.weeks,
14156 {balance_result.days, 0, 0, 0, 0, 0, 0}})
14157 .ToHandleChecked();
14158 // 14. Let optionsCopy be OrdinaryObjectCreate(null).
14159 DirectHandle<JSReceiver> options_copy =
14160 isolate->factory()->NewJSObjectWithNullProto();
14161
14162 // 15. Let entries be ? EnumerableOwnPropertyNames(options, key+value).
14163 // 16. For each element nextEntry of entries, do
14164 // a. Perform ! CreateDataPropertyOrThrow(optionsCopy, nextEntry[0],
14165 // nextEntry[1]).
14166 bool set;
14168 isolate, set,
14170 isolate, options_copy, options,
14172 DirectHandle<JSTemporalPlainYearMonth>());
14173
14174 // 17. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd,
14175 // options).
14176 DirectHandle<JSTemporalPlainDate> added_date;
14178 isolate, added_date,
14179 CalendarDateAdd(isolate, calendar, date, duration_to_add, options));
14180 // 18. Let addedDateFields be ? PrepareTemporalFields(addedDate, fieldNames,
14181 // «»).
14182 DirectHandle<JSReceiver> added_date_fields;
14184 isolate, added_date_fields,
14185 PrepareTemporalFields(isolate, added_date, field_names,
14186 RequiredFields::kNone));
14187 // 19. Return ? CalendarYearMonthFromFields(calendar, addedDateFields,
14188 // optionsCopy).
14189 return FromFields<JSTemporalPlainYearMonth>(
14190 isolate, calendar, added_date_fields, options_copy,
14191 isolate->factory()->yearMonthFromFields_string(),
14192 JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE);
14193}
14194
14195} // namespace
14196
14197// #sec-temporal.plainyearmonth.prototype.add
14200 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
14201 return AddDurationToOrSubtractDurationFromPlainYearMonth(
14202 isolate, Arithmetic::kAdd, year_month, temporal_duration_like, options,
14203 "Temporal.PlainYearMonth.prototype.add");
14204}
14205
14206// #sec-temporal.plainyearmonth.prototype.subtract
14209 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
14210 return AddDurationToOrSubtractDurationFromPlainYearMonth(
14211 isolate, Arithmetic::kSubtract, year_month, temporal_duration_like,
14212 options, "Temporal.PlainYearMonth.prototype.subtract");
14213}
14214
14215namespace {
14216// #sec-temporal-differencetemporalplandyearmonth
14217MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalPlainYearMonth(
14218 Isolate* isolate, TimePreposition operation,
14220 DirectHandle<Object> other_obj, DirectHandle<Object> options,
14221 const char* method_name) {
14223 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
14224 double sign = operation == TimePreposition::kSince ? -1 : 1;
14225 // 2. Set other to ? ToTemporalDateTime(other).
14228 isolate, other, ToTemporalYearMonth(isolate, other_obj, method_name));
14229 // 3. Let calendar be yearMonth.[[Calendar]].
14230 DirectHandle<JSReceiver> calendar(year_month->calendar(), isolate);
14231
14232 // 4. If ? CalendarEquals(calendar, other.[[Calendar]]) is false, throw a
14233 // RangeError exception.
14234 bool calendar_equals;
14236 isolate, calendar_equals,
14237 CalendarEqualsBool(isolate, calendar,
14238 direct_handle(other->calendar(), isolate)),
14240 if (!calendar_equals) {
14242 }
14243
14244 // 5. Let settings be ? GetDifferenceSettings(operation, options, date, «
14245 // "week", "day" », "month", "year").
14246 DifferenceSettings settings;
14248 isolate, settings,
14249 GetDifferenceSettings(isolate, operation, options, UnitGroup::kDate,
14250 DisallowedUnitsInDifferenceSettings::kWeekAndDay,
14251 Unit::kMonth, Unit::kYear, method_name),
14252 DirectHandle<JSTemporalDuration>());
14253 // 6. Let fieldNames be ? CalendarFields(calendar, « "monthCode", "year" »).
14254 Factory* factory = isolate->factory();
14255 DirectHandle<FixedArray> field_names = MonthCodeYearInFixedArray(isolate);
14256 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
14257 CalendarFields(isolate, calendar, field_names));
14258
14259 // 7. Let otherFields be ? PrepareTemporalFields(other, fieldNames, «»).
14260 DirectHandle<JSReceiver> other_fields;
14261 ASSIGN_RETURN_ON_EXCEPTION(isolate, other_fields,
14262 PrepareTemporalFields(isolate, other, field_names,
14263 RequiredFields::kNone));
14264 // 8. Perform ! CreateDataPropertyOrThrow(otherFields, "day", 1𝔽).
14265 DirectHandle<Object> one(Smi::FromInt(1), isolate);
14266 CHECK(JSReceiver::CreateDataProperty(isolate, other_fields,
14267 factory->day_string(), one,
14269 .FromJust());
14270 // 9. Let otherDate be ? CalendarDateFromFields(calendar, otherFields).
14271 // DateFromFields(Isolate* isolate,
14272 DirectHandle<JSTemporalPlainDate> other_date;
14274 isolate, other_date,
14275 DateFromFields(isolate, calendar, other_fields,
14276 isolate->factory()->undefined_value()));
14277 // 10. Let thisFields be ? PrepareTemporalFields(yearMonth, fieldNames, «»).
14278 DirectHandle<JSReceiver> this_fields;
14280 isolate, this_fields,
14281 PrepareTemporalFields(isolate, year_month, field_names,
14282 RequiredFields::kNone));
14283 // 11. Perform ! CreateDataPropertyOrThrow(thisFields, "day", 1𝔽).
14284 CHECK(JSReceiver::CreateDataProperty(isolate, this_fields,
14285 factory->day_string(), one,
14287 .FromJust());
14288 // 12. Let thisDate be ? CalendarDateFromFields(calendar, thisFields).
14289 DirectHandle<JSTemporalPlainDate> this_date;
14291 isolate, this_date,
14292 DateFromFields(isolate, calendar, this_fields,
14293 isolate->factory()->undefined_value()));
14294 // 13. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]],
14295 // settings.[[LargestUnit]]).
14296 DirectHandle<JSReceiver> until_options;
14298 isolate, until_options,
14299 MergeLargestUnitOption(isolate, settings.options, settings.largest_unit));
14300 // 14. Let result be ? CalendarDateUntil(calendar, thisDate, otherDate,
14301 // untilOptions).
14302 DirectHandle<JSTemporalDuration> result;
14304 CalendarDateUntil(isolate, calendar, this_date,
14305 other_date, until_options));
14306
14307 // 15. If settings.[[SmallestUnit]] is not "month" or
14308 // settings.[[RoundingIncrement]] ≠ 1, then
14309 if (settings.smallest_unit != Unit::kMonth ||
14310 settings.rounding_increment != 1) {
14311 // a. Set result to (? RoundDuration(result.[[Years]], result.[[Months]], 0,
14312 // 0, 0, 0, 0, 0, 0, 0, settings.[[RoundingIncrement]],
14313 // settings.[[SmallestUnit]], settings.[[RoundingMode]],
14314 // thisDate)).[[DurationRecord]].
14315 DurationRecordWithRemainder round_result;
14317 isolate, round_result,
14318 RoundDuration(isolate,
14319 {Object::NumberValue(result->years()),
14320 Object::NumberValue(result->months()),
14321 0,
14322 {0, 0, 0, 0, 0, 0, 0}},
14323 settings.rounding_increment, settings.smallest_unit,
14324 settings.rounding_mode, this_date, method_name),
14325 DirectHandle<JSTemporalDuration>());
14326 // 16. Return ! CreateTemporalDuration(sign × result.[[Years]], sign ×
14327 // result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0).
14328 return CreateTemporalDuration(isolate, {round_result.record.years * sign,
14329 round_result.record.months * sign,
14330 0,
14331 {0, 0, 0, 0, 0, 0, 0}})
14332 .ToHandleChecked();
14333 }
14334 // 16. Return ! CreateTemporalDuration(sign × result.[[Years]], sign ×
14335 // result.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0).
14336 return CreateTemporalDuration(isolate,
14337 {Object::NumberValue(result->years()) * sign,
14338 Object::NumberValue(result->months()) * sign,
14339 0,
14340 {0, 0, 0, 0, 0, 0, 0}})
14341 .ToHandleChecked();
14342}
14343
14344} // namespace
14345
14346// #sec-temporal.plainyearmonth.prototype.until
14351 return DifferenceTemporalPlainYearMonth(
14352 isolate, TimePreposition::kUntil, handle, other, options,
14353 "Temporal.PlainYearMonth.prototype.until");
14354}
14355
14356// #sec-temporal.plainyearmonth.prototype.since
14361 return DifferenceTemporalPlainYearMonth(
14362 isolate, TimePreposition::kSince, handle, other, options,
14363 "Temporal.PlainYearMonth.prototype.since");
14364}
14365
14366// #sec-temporal.plainyearmonth.prototype.with
14368 Isolate* isolate,
14369 DirectHandle<JSTemporalPlainYearMonth> temporal_year_month,
14370 DirectHandle<Object> temporal_year_month_like_obj,
14371 DirectHandle<Object> options_obj) {
14372 // 6. Let fieldNames be ? CalendarFields(calendar, « "month", "monthCode",
14373 // "year" »).
14374 DirectHandle<FixedArray> field_names =
14375 MonthMonthCodeYearInFixedArray(isolate);
14376 return PlainDateOrYearMonthOrMonthDayWith<JSTemporalPlainYearMonth,
14377 YearMonthFromFields>(
14378 isolate, temporal_year_month, temporal_year_month_like_obj, options_obj,
14379 field_names, "Temporal.PlainYearMonth.prototype.with");
14380}
14381
14382// #sec-temporal.plainyearmonth.prototype.toplaindate
14385 DirectHandle<Object> item_obj) {
14386 Factory* factory = isolate->factory();
14387 // 5. Let receiverFieldNames be ? CalendarFields(calendar, « "monthCode",
14388 // "year" »).
14389 // 7. Let inputFieldNames be ? CalendarFields(calendar, « "day" »).
14390 return PlainMonthDayOrYearMonthToPlainDate<JSTemporalPlainYearMonth>(
14391 isolate, year_month, item_obj, factory->monthCode_string(),
14392 factory->year_string(), factory->day_string());
14393}
14394
14395// #sec-temporal.plainyearmonth.prototype.getisofields
14397 Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month) {
14398 Factory* factory = isolate->factory();
14399 // 1. Let yearMonth be the this value.
14400 // 2. Perform ? RequireInternalSlot(yearMonth,
14401 // [[InitializedTemporalYearMonth]]).
14402 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
14403 DirectHandle<JSObject> fields =
14404 isolate->factory()->NewJSObject(isolate->object_function());
14405 // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
14406 // yearMonth.[[Calendar]]).
14408 isolate, fields, factory->calendar_string(),
14409 DirectHandle<JSReceiver>(year_month->calendar(), isolate),
14411 .FromJust());
14412 // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
14413 // 𝔽(yearMonth.[[ISODay]])).
14414 // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
14415 // 𝔽(yearMonth.[[ISOMonth]])).
14416 // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
14417 // 𝔽(yearMonth.[[ISOYear]])).
14418 DEFINE_INT_FIELD(fields, isoDay, iso_day, year_month)
14419 DEFINE_INT_FIELD(fields, isoMonth, iso_month, year_month)
14420 DEFINE_INT_FIELD(fields, isoYear, iso_year, year_month)
14421 // 8. Return fields.
14422 return fields;
14423}
14424
14425// #sec-temporal.plainyearmonth.prototype.tojson
14427 Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month) {
14428 return TemporalYearMonthToString(isolate, year_month, ShowCalendar::kAuto);
14429}
14430
14431// #sec-temporal.plainyearmonth.prototype.tostring
14434 DirectHandle<Object> options) {
14435 return TemporalToString<JSTemporalPlainYearMonth, TemporalYearMonthToString>(
14436 isolate, year_month, options,
14437 "Temporal.PlainYearMonth.prototype.toString");
14438}
14439
14440// #sec-temporal.plainyearmonth.prototype.tolocalestring
14443 DirectHandle<Object> locales, DirectHandle<Object> options) {
14444#ifdef V8_INTL_SUPPORT
14446 isolate, year_month, locales, options,
14447 "Temporal.PlainYearMonth.prototype.toLocaleString");
14448#else // V8_INTL_SUPPORT
14449 return TemporalYearMonthToString(isolate, year_month, ShowCalendar::kAuto);
14450#endif // V8_INTL_SUPPORT
14451}
14452
14453// #sec-temporal-plaintime-constructor
14455 Isolate* isolate, DirectHandle<JSFunction> target,
14457 DirectHandle<Object> minute_obj, DirectHandle<Object> second_obj,
14458 DirectHandle<Object> millisecond_obj, DirectHandle<Object> microsecond_obj,
14459 DirectHandle<Object> nanosecond_obj) {
14460 const char* method_name = "Temporal.PlainTime";
14461 // 1. If NewTarget is undefined, then
14462 // a. Throw a TypeError exception.
14463 if (IsUndefined(*new_target)) {
14464 // a. Throw a TypeError exception.
14465 THROW_NEW_ERROR(isolate,
14466 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
14467 isolate->factory()->NewStringFromAsciiChecked(
14468 method_name)));
14469 }
14470
14477
14478 // 14. Return ? CreateTemporalTime(hour, minute, second, millisecond,
14479 // microsecond, nanosecond, NewTarget).
14480 return CreateTemporalTime(
14481 isolate, target, new_target,
14483}
14484
14485// #sec-temporal.plaintime.prototype.tozoneddatetime
14487 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14488 DirectHandle<Object> item_obj) {
14489 const char* method_name = "Temporal.PlainTime.prototype.toZonedDateTime";
14490 Factory* factory = isolate->factory();
14491 // 1. Let temporalTime be the this value.
14492 // 2. Perform ? RequireInternalSlot(temporalTime,
14493 // [[InitializedTemporalTime]]).
14494 // 3. If Type(item) is not Object, then
14495 if (!IsJSReceiver(*item_obj)) {
14496 // a. Throw a TypeError exception.
14498 }
14500 // 4. Let temporalDateLike be ? Get(item, "plainDate").
14501 DirectHandle<Object> temporal_date_like;
14503 isolate, temporal_date_like,
14504 JSReceiver::GetProperty(isolate, item, factory->plainDate_string()));
14505 // 5. If temporalDateLike is undefined, then
14506 if (IsUndefined(*temporal_date_like)) {
14507 // a. Throw a TypeError exception.
14509 }
14510 // 6. Let temporalDate be ? ToTemporalDate(temporalDateLike).
14513 isolate, temporal_date,
14514 ToTemporalDate(isolate, temporal_date_like, method_name));
14515 // 7. Let temporalTimeZoneLike be ? Get(item, "timeZone").
14516 DirectHandle<Object> temporal_time_zone_like;
14518 isolate, temporal_time_zone_like,
14519 JSReceiver::GetProperty(isolate, item, factory->timeZone_string()));
14520 // 8. If temporalTimeZoneLike is undefined, then
14521 if (IsUndefined(*temporal_time_zone_like)) {
14522 // a. Throw a TypeError exception.
14524 }
14525 // 9. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
14528 isolate, time_zone,
14529 temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
14530 method_name));
14531 // 10. Let temporalDateTime be ?
14532 // CreateTemporalDateTime(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]],
14533 // temporalDate.[[ISODay]], temporalTime.[[ISOHour]],
14534 // temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]],
14535 // temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
14536 // temporalTime.[[ISONanosecond]], temporalDate.[[Calendar]]).
14537 DirectHandle<JSReceiver> calendar(temporal_date->calendar(), isolate);
14538 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
14540 isolate, temporal_date_time,
14542 isolate,
14543 {{temporal_date->iso_year(), temporal_date->iso_month(),
14544 temporal_date->iso_day()},
14545 {temporal_time->iso_hour(), temporal_time->iso_minute(),
14546 temporal_time->iso_second(), temporal_time->iso_millisecond(),
14547 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()}},
14548 calendar));
14549 // 11. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone,
14550 // temporalDateTime, "compatible").
14553 isolate, instant,
14554 BuiltinTimeZoneGetInstantFor(isolate, time_zone, temporal_date_time,
14555 Disambiguation::kCompatible, method_name));
14556 // 12. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
14557 // temporalDate.[[Calendar]]).
14558 return CreateTemporalZonedDateTime(
14559 isolate, direct_handle(instant->nanoseconds(), isolate), time_zone,
14560 calendar);
14561}
14562
14563namespace {
14564// #sec-temporal-comparetemporaltime
14565int32_t CompareTemporalTime(const TimeRecord& time1, const TimeRecord& time2) {
14567
14568 // 1. Assert: h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, and ns2
14569 // are integers.
14570 // 2. If h1 > h2, return 1.
14571 if (time1.hour > time2.hour) return 1;
14572 // 3. If h1 < h2, return -1.
14573 if (time1.hour < time2.hour) return -1;
14574 // 4. If min1 > min2, return 1.
14575 if (time1.minute > time2.minute) return 1;
14576 // 5. If min1 < min2, return -1.
14577 if (time1.minute < time2.minute) return -1;
14578 // 6. If s1 > s2, return 1.
14579 if (time1.second > time2.second) return 1;
14580 // 7. If s1 < s2, return -1.
14581 if (time1.second < time2.second) return -1;
14582 // 8. If ms1 > ms2, return 1.
14583 if (time1.millisecond > time2.millisecond) return 1;
14584 // 9. If ms1 < ms2, return -1.
14585 if (time1.millisecond < time2.millisecond) return -1;
14586 // 10. If mus1 > mus2, return 1.
14587 if (time1.microsecond > time2.microsecond) return 1;
14588 // 11. If mus1 < mus2, return -1.
14589 if (time1.microsecond < time2.microsecond) return -1;
14590 // 12. If ns1 > ns2, return 1.
14591 if (time1.nanosecond > time2.nanosecond) return 1;
14592 // 13. If ns1 < ns2, return -1.
14593 if (time1.nanosecond < time2.nanosecond) return -1;
14594 // 14. Return 0.
14595 return 0;
14596}
14597} // namespace
14598
14599// #sec-temporal.plaintime.compare
14601 Isolate* isolate, DirectHandle<Object> one_obj,
14602 DirectHandle<Object> two_obj) {
14603 const char* method_name = "Temporal.PainTime.compare";
14604 // 1. Set one to ? ToTemporalTime(one).
14607 isolate, one, temporal::ToTemporalTime(isolate, one_obj, method_name));
14608 // 2. Set two to ? ToTemporalTime(two).
14611 isolate, two, temporal::ToTemporalTime(isolate, two_obj, method_name));
14612 // 3. Return 𝔽(! CompareTemporalTime(one.[[ISOHour]], one.[[ISOMinute]],
14613 // one.[[ISOSecond]], one.[[ISOMillisecond]], one.[[ISOMicrosecond]],
14614 // one.[[ISONanosecond]], two.[[ISOHour]], two.[[ISOMinute]],
14615 // two.[[ISOSecond]], two.[[ISOMillisecond]], two.[[ISOMicrosecond]],
14616 // two.[[ISONanosecond]])).
14617 return direct_handle(Smi::FromInt(CompareTemporalTime(
14618 {one->iso_hour(), one->iso_minute(),
14619 one->iso_second(), one->iso_millisecond(),
14620 one->iso_microsecond(), one->iso_nanosecond()},
14621 {two->iso_hour(), two->iso_minute(),
14622 two->iso_second(), two->iso_millisecond(),
14623 two->iso_microsecond(), two->iso_nanosecond()})),
14624 isolate);
14625}
14626
14627// #sec-temporal.plaintime.prototype.equals
14629 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14630 DirectHandle<Object> other_obj) {
14631 // 1. Let temporalTime be the this value.
14632 // 2. Perform ? RequireInternalSlot(temporalTime,
14633 // [[InitializedTemporalTime]]).
14634 // 3. Set other to ? ToTemporalTime(other).
14637 isolate, other,
14638 temporal::ToTemporalTime(isolate, other_obj,
14639 "Temporal.PlainTime.prototype.equals"));
14640 // 4. If temporalTime.[[ISOHour]] ≠ other.[[ISOHour]], return false.
14641 if (temporal_time->iso_hour() != other->iso_hour())
14642 return isolate->factory()->false_value();
14643 // 5. If temporalTime.[[ISOMinute]] ≠ other.[[ISOMinute]], return false.
14644 if (temporal_time->iso_minute() != other->iso_minute())
14645 return isolate->factory()->false_value();
14646 // 6. If temporalTime.[[ISOSecond]] ≠ other.[[ISOSecond]], return false.
14647 if (temporal_time->iso_second() != other->iso_second())
14648 return isolate->factory()->false_value();
14649 // 7. If temporalTime.[[ISOMillisecond]] ≠ other.[[ISOMillisecond]], return
14650 // false.
14651 if (temporal_time->iso_millisecond() != other->iso_millisecond())
14652 return isolate->factory()->false_value();
14653 // 8. If temporalTime.[[ISOMicrosecond]] ≠ other.[[ISOMicrosecond]], return
14654 // false.
14655 if (temporal_time->iso_microsecond() != other->iso_microsecond())
14656 return isolate->factory()->false_value();
14657 // 9. If temporalTime.[[ISONanosecond]] ≠ other.[[ISONanosecond]], return
14658 // false.
14659 if (temporal_time->iso_nanosecond() != other->iso_nanosecond())
14660 return isolate->factory()->false_value();
14661 // 10. Return true.
14662 return isolate->factory()->true_value();
14663}
14664
14665namespace {
14666
14667// #sec-temporal-maximumtemporaldurationroundingincrement
14668Maximum MaximumTemporalDurationRoundingIncrement(Unit unit) {
14669 switch (unit) {
14670 // 1. If unit is "year", "month", "week", or "day", then
14671 case Unit::kYear:
14672 case Unit::kMonth:
14673 case Unit::kWeek:
14674 case Unit::kDay:
14675 // a. Return undefined.
14676 return {false, 0};
14677 // 2. If unit is "hour", then
14678 case Unit::kHour:
14679 // a. Return 24.
14680 return {true, 24};
14681 // 3. If unit is "minute" or "second", then
14682 case Unit::kMinute:
14683 case Unit::kSecond:
14684 // a. Return 60.
14685 return {true, 60};
14686 // 4. Assert: unit is one of "millisecond", "microsecond", or "nanosecond".
14687 case Unit::kMillisecond:
14688 case Unit::kMicrosecond:
14689 case Unit::kNanosecond:
14690 // 5. Return 1000.
14691 return {true, 1000};
14692 default:
14693 UNREACHABLE();
14694 }
14695}
14696
14697} // namespace
14698
14699// #sec-temporal.plaintime.prototype.round
14701 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14702 DirectHandle<Object> round_to_obj) {
14703 const char* method_name = "Temporal.PlainTime.prototype.round";
14704 Factory* factory = isolate->factory();
14705 // 1. Let temporalTime be the this value.
14706 // 2. Perform ? RequireInternalSlot(temporalTime,
14707 // [[InitializedTemporalTime]]).
14708 // 3. If roundTo is undefined, then
14709 if (IsUndefined(*round_to_obj)) {
14710 // a. Throw a TypeError exception.
14712 }
14713
14714 DirectHandle<JSReceiver> round_to;
14715 // 4. If Type(roundTo) is String, then
14716 if (IsString(*round_to_obj)) {
14717 // a. Let paramString be roundTo.
14718 DirectHandle<String> param_string = Cast<String>(round_to_obj);
14719 // b. Set roundTo to ! OrdinaryObjectCreate(null).
14720 round_to = factory->NewJSObjectWithNullProto();
14721 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit",
14722 // paramString).
14723 CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
14724 factory->smallestUnit_string(),
14725 param_string, Just(kThrowOnError))
14726 .FromJust());
14727 } else {
14728 // 5. Set roundTo to ? GetOptionsObject(roundTo).
14730 isolate, round_to,
14731 GetOptionsObject(isolate, round_to_obj, method_name));
14732 }
14733
14734 // 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time,
14735 // required).
14736 Unit smallest_unit;
14738 isolate, smallest_unit,
14739 GetTemporalUnit(isolate, round_to, "smallestUnit", UnitGroup::kTime,
14740 Unit::kNotPresent, true, method_name),
14742
14743 // 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
14746 isolate, rounding_mode,
14747 ToTemporalRoundingMode(isolate, round_to, RoundingMode::kHalfExpand,
14748 method_name),
14750
14751 // 8. Let maximum be ! MaximumTemporalDurationRoundingIncrement(smallestUnit).
14752 Maximum maximum = MaximumTemporalDurationRoundingIncrement(smallest_unit);
14753
14754 // 9. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo,
14755 // maximum, false).
14756 double rounding_increment;
14758 isolate, rounding_increment,
14759 ToTemporalRoundingIncrement(isolate, round_to, maximum.value,
14760 maximum.defined, false),
14762
14763 // 12. Let result be ! RoundTime(temporalTime.[[ISOHour]],
14764 // temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]],
14765 // temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
14766 // temporalTime.[[ISONanosecond]], roundingIncrement, smallestUnit,
14767 // roundingMode).
14768 DateTimeRecord result = RoundTime(
14769 isolate,
14770 {temporal_time->iso_hour(), temporal_time->iso_minute(),
14771 temporal_time->iso_second(), temporal_time->iso_millisecond(),
14772 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
14774 // 13. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]],
14775 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
14776 // result.[[Nanosecond]]).
14777 return CreateTemporalTime(isolate, result.time);
14778}
14779
14780// #sec-temporal.plaintime.prototype.with
14782 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14783 DirectHandle<Object> temporal_time_like_obj,
14784 DirectHandle<Object> options_obj) {
14785 const char* method_name = "Temporal.PlainTime.prototype.with";
14786 // 1. Let temporalTime be the this value.
14787 // 2. Perform ? RequireInternalSlot(temporalTime,
14788 // [[InitializedTemporalTime]]).
14789 // 3. If Type(temporalTimeLike) is not Object, then
14790 if (!IsJSReceiver(*temporal_time_like_obj)) {
14791 // a. Throw a TypeError exception.
14793 }
14794 DirectHandle<JSReceiver> temporal_time_like =
14795 Cast<JSReceiver>(temporal_time_like_obj);
14796 // 4. Perform ? RejectObjectWithCalendarOrTimeZone(temporalTimeLike).
14797 MAYBE_RETURN(RejectObjectWithCalendarOrTimeZone(isolate, temporal_time_like),
14799 // 5. Let partialTime be ? ToPartialTime(temporalTimeLike).
14800 TimeRecord result;
14802 isolate, result,
14803 ToPartialTime(
14804 isolate, temporal_time_like,
14805 {temporal_time->iso_hour(), temporal_time->iso_minute(),
14806 temporal_time->iso_second(), temporal_time->iso_millisecond(),
14807 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
14808 method_name),
14810
14811 // 6. Set options to ? GetOptionsObject(options).
14814 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
14815 // 7. Let overflow be ? ToTemporalOverflow(options).
14816 ShowOverflow overflow;
14818 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
14820
14821 // 20. Let result be ? RegulateTime(hour, minute, second, millisecond,
14822 // microsecond, nanosecond, overflow).
14824 isolate, result, temporal::RegulateTime(isolate, result, overflow),
14826 // 25. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]],
14827 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
14828 // result.[[Nanosecond]]).
14829 return CreateTemporalTime(isolate, result);
14830}
14831
14832// #sec-temporal.now.plaintimeiso
14834 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
14835 const char* method_name = "Temporal.Now.plainTimeISO";
14836 // 1. Let calendar be ! GetISO8601Calendar().
14838 // 2. Let dateTime be ? SystemDateTime(temporalTimeZoneLike, calendar).
14841 isolate, date_time,
14842 SystemDateTime(isolate, temporal_time_zone_like, calendar, method_name));
14843 // 3. Return ! CreateTemporalTime(dateTime.[[ISOHour]],
14844 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
14845 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
14846 // dateTime.[[ISONanosecond]]).
14847 return CreateTemporalTime(
14848 isolate,
14849 {date_time->iso_hour(), date_time->iso_minute(),
14850 date_time->iso_second(), date_time->iso_millisecond(),
14851 date_time->iso_microsecond(), date_time->iso_nanosecond()})
14852 .ToHandleChecked();
14853}
14854
14855// #sec-temporal.plaintime.from
14857 Isolate* isolate, DirectHandle<Object> item_obj,
14858 DirectHandle<Object> options_obj) {
14859 const char* method_name = "Temporal.PlainTime.from";
14860 // 1. Set options to ? GetOptionsObject(options).
14863 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
14864 // 2. Let overflow be ? ToTemporalOverflow(options).
14865 ShowOverflow overflow;
14867 isolate, overflow, ToTemporalOverflow(isolate, options, method_name),
14869 // 3. If Type(item) is Object and item has an [[InitializedTemporalTime]]
14870 // internal slot, then
14871 if (IsJSTemporalPlainTime(*item_obj)) {
14872 // a. Return ? CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]],
14873 // item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]],
14874 // item.[[ISONanosecond]]).
14875 auto item = Cast<JSTemporalPlainTime>(item_obj);
14876 return CreateTemporalTime(
14877 isolate, {item->iso_hour(), item->iso_minute(), item->iso_second(),
14878 item->iso_millisecond(), item->iso_microsecond(),
14879 item->iso_nanosecond()});
14880 }
14881 // 4. Return ? ToTemporalTime(item, overflow).
14882 return temporal::ToTemporalTime(isolate, item_obj, method_name, overflow);
14883}
14884
14885// #sec-temporal.plaintime.prototype.toplaindatetime
14887 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14888 DirectHandle<Object> temporal_date_like) {
14889 // 1. Let temporalTime be the this value.
14890 // 2. Perform ? RequireInternalSlot(temporalTime,
14891 // [[InitializedTemporalTime]]).
14892 // 3. Set temporalDate to ? ToTemporalDate(temporalDate).
14895 isolate, temporal_date,
14896 ToTemporalDate(isolate, temporal_date_like,
14897 "Temporal.PlainTime.prototype.toPlainDateTime"));
14898 // 4. Return ? CreateTemporalDateTime(temporalDate.[[ISOYear]],
14899 // temporalDate.[[ISOMonth]], temporalDate.[[ISODay]],
14900 // temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]],
14901 // temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]],
14902 // temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]],
14903 // temporalDate.[[Calendar]]).
14905 isolate,
14906 {{temporal_date->iso_year(), temporal_date->iso_month(),
14907 temporal_date->iso_day()},
14908 {temporal_time->iso_hour(), temporal_time->iso_minute(),
14909 temporal_time->iso_second(), temporal_time->iso_millisecond(),
14910 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()}},
14911 direct_handle(temporal_date->calendar(), isolate));
14912}
14913
14914namespace {
14915
14916// #sec-temporal-adddurationtoorsubtractdurationfromplaintime
14918AddDurationToOrSubtractDurationFromPlainTime(
14919 Isolate* isolate, Arithmetic operation,
14921 DirectHandle<Object> temporal_duration_like, const char* method_name) {
14922 // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
14923 double sign = operation == Arithmetic::kSubtract ? -1.0 : 1.0;
14924 // 2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
14925 DurationRecord duration;
14927 isolate, duration,
14928 temporal::ToTemporalDurationRecord(isolate, temporal_duration_like,
14929 method_name),
14931 TimeDurationRecord& time_duration = duration.time_duration;
14932
14933 // 3. Let result be ! AddTime(temporalTime.[[ISOHour]],
14934 // temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]],
14935 // temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
14936 // temporalTime.[[ISONanosecond]], sign x duration.[[Hours]], sign x
14937 // duration.[[Minutes]], sign x duration.[[Seconds]], sign x
14938 // duration.[[Milliseconds]], sign x duration.[[Microseconds]], sign x
14939 // duration.[[Nanoseconds]]).
14940 DateTimeRecord result = AddTime(
14941 isolate,
14942 {temporal_time->iso_hour(), temporal_time->iso_minute(),
14943 temporal_time->iso_second(), temporal_time->iso_millisecond(),
14944 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
14945 {0, sign * time_duration.hours, sign * time_duration.minutes,
14946 sign * time_duration.seconds, sign * time_duration.milliseconds,
14947 sign * time_duration.microseconds, sign * time_duration.nanoseconds});
14948 // 4. Assert: ! IsValidTime(result.[[Hour]], result.[[Minute]],
14949 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
14950 // result.[[Nanosecond]]) is true.
14951 DCHECK(IsValidTime(isolate, result.time));
14952 // 5. Return ? CreateTemporalTime(result.[[Hour]], result.[[Minute]],
14953 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
14954 // result.[[Nanosecond]]).
14955 return CreateTemporalTime(isolate, result.time);
14956}
14957
14958} // namespace
14959
14960// #sec-temporal.plaintime.prototype.add
14962 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14963 DirectHandle<Object> temporal_duration_like) {
14964 return AddDurationToOrSubtractDurationFromPlainTime(
14965 isolate, Arithmetic::kAdd, temporal_time, temporal_duration_like,
14966 "Temporal.PlainTime.prototype.add");
14967}
14968
14969// #sec-temporal.plaintime.prototype.subtract
14971 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
14972 DirectHandle<Object> temporal_duration_like) {
14973 return AddDurationToOrSubtractDurationFromPlainTime(
14974 isolate, Arithmetic::kSubtract, temporal_time, temporal_duration_like,
14975 "Temporal.PlainTime.prototype.subtract");
14976}
14977
14978namespace {
14979// #sec-temporal-differencetemporalplantime
14980MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalPlainTime(
14981 Isolate* isolate, TimePreposition operation,
14983 DirectHandle<Object> other_obj, DirectHandle<Object> options,
14984 const char* method_name) {
14986 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
14987 double sign = operation == TimePreposition::kSince ? -1 : 1;
14988 // 2. Set other to ? ToTemporalDate(other).
14991 isolate, other,
14992 temporal::ToTemporalTime(isolate, other_obj, method_name));
14993
14994 // 3. Let settings be ? GetDifferenceSettings(operation, options, time, « »,
14995 // "nanosecond", "hour").
14996 DifferenceSettings settings;
14998 isolate, settings,
14999 GetDifferenceSettings(isolate, operation, options, UnitGroup::kTime,
15000 DisallowedUnitsInDifferenceSettings::kNone,
15001 Unit::kNanosecond, Unit::kHour, method_name),
15003 // 4. Let result be ! DifferenceTime(temporalTime.[[ISOHour]],
15004 // temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]],
15005 // temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
15006 // temporalTime.[[ISONanosecond]], other.[[ISOHour]], other.[[ISOMinute]],
15007 // other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]],
15008 // other.[[ISONanosecond]]).
15009 DurationRecordWithRemainder result;
15010 result.record.time_duration =
15011 DifferenceTime(
15012 isolate,
15013 {temporal_time->iso_hour(), temporal_time->iso_minute(),
15014 temporal_time->iso_second(), temporal_time->iso_millisecond(),
15015 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
15016 {other->iso_hour(), other->iso_minute(), other->iso_second(),
15017 other->iso_millisecond(), other->iso_microsecond(),
15018 other->iso_nanosecond()})
15019 .ToChecked();
15020 // 5. Set result to (! RoundDuration(0, 0, 0, 0, result.[[Hours]],
15021 // result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]],
15022 // result.[[Microseconds]], result.[[Nanoseconds]],
15023 // settings.[[RoundingIncrement]], settings.[[SmallestUnit]],
15024 // settings.[[RoundingMode]])).[[DurationRecord]].
15025 result.record.years = result.record.months = result.record.weeks =
15026 result.record.time_duration.days = 0;
15027 result =
15028 RoundDuration(isolate, result.record, settings.rounding_increment,
15029 settings.smallest_unit, settings.rounding_mode, method_name)
15030 .ToChecked();
15031 // 6. Set result to ! BalanceDuration(0, result.[[Hours]], result.[[Minutes]],
15032 // result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]],
15033 // result.[[Nanoseconds]], settings.[[LargestUnit]]).
15034 result.record.time_duration.days = 0;
15035 result.record.time_duration =
15036 BalanceDuration(isolate, settings.largest_unit,
15037 result.record.time_duration, method_name)
15038 .ToChecked();
15039
15040 // 7. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]],
15041 // sign × result.[[Minutes]], sign × result.[[Seconds]], sign ×
15042 // result.[[Milliseconds]], sign × result.[[Microseconds]], sign ×
15043 // result.[[Nanoseconds]]).
15044 result.record.years = result.record.months = result.record.weeks =
15045 result.record.time_duration.days = 0;
15046 result.record.time_duration.hours *= sign;
15047 result.record.time_duration.minutes *= sign;
15048 result.record.time_duration.seconds *= sign;
15049 result.record.time_duration.milliseconds *= sign;
15050 result.record.time_duration.microseconds *= sign;
15051 result.record.time_duration.nanoseconds *= sign;
15052 return CreateTemporalDuration(isolate, result.record).ToHandleChecked();
15053}
15054
15055} // namespace
15056
15057// #sec-temporal.plaintime.prototype.until
15062 return DifferenceTemporalPlainTime(isolate, TimePreposition::kUntil, handle,
15063 other, options,
15064 "Temporal.PlainTime.prototype.until");
15065}
15066
15067// #sec-temporal.plaintime.prototype.since
15072 return DifferenceTemporalPlainTime(isolate, TimePreposition::kSince, handle,
15073 other, options,
15074 "Temporal.PlainTime.prototype.since");
15075}
15076
15077// #sec-temporal.plaintime.prototype.getisofields
15079 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time) {
15080 Factory* factory = isolate->factory();
15081 // 1. Let temporalTime be the this value.
15082 // 2. Perform ? RequireInternalSlot(temporalTime,
15083 // [[InitializedTemporalTime]]).
15084 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
15085 DirectHandle<JSObject> fields =
15086 isolate->factory()->NewJSObject(isolate->object_function());
15087 // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar",
15088 // temporalTime.[[Calendar]]).
15089 DirectHandle<JSTemporalCalendar> iso8601_calendar =
15091 CHECK(JSReceiver::CreateDataProperty(isolate, fields,
15092 factory->calendar_string(),
15093 iso8601_calendar, Just(kThrowOnError))
15094 .FromJust());
15095
15096 // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
15097 // 𝔽(temporalTime.[[ISOHour]])).
15098 // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
15099 // 𝔽(temporalTime.[[ISOMicrosecond]])).
15100 // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
15101 // 𝔽(temporalTime.[[ISOMillisecond]])).
15102 // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
15103 // 𝔽(temporalTime.[[ISOMinute]])).
15104 // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
15105 // 𝔽(temporalTime.[[ISONanosecond]])).
15106 // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
15107 // 𝔽(temporalTime.[[ISOSecond]])).
15108 DEFINE_INT_FIELD(fields, isoHour, iso_hour, temporal_time)
15109 DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, temporal_time)
15110 DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, temporal_time)
15111 DEFINE_INT_FIELD(fields, isoMinute, iso_minute, temporal_time)
15112 DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, temporal_time)
15113 DEFINE_INT_FIELD(fields, isoSecond, iso_second, temporal_time)
15114 // 11. Return fields.
15115 return fields;
15116}
15117
15118// #sec-temporal.plaintime.prototype.tojson
15120 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time) {
15121 return TemporalTimeToString(isolate, temporal_time, Precision::kAuto);
15122}
15123
15124// #sup-temporal.plaintime.prototype.tolocalestring
15126 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
15127 DirectHandle<Object> locales, DirectHandle<Object> options) {
15128#ifdef V8_INTL_SUPPORT
15130 isolate, temporal_time, locales, options,
15131 "Temporal.PlainTime.prototype.toLocaleString");
15132#else // V8_INTL_SUPPORT
15133 return TemporalTimeToString(isolate, temporal_time, Precision::kAuto);
15134#endif // V8_INTL_SUPPORT
15135}
15136
15137namespace {
15138
15139// #sec-temporal-getunsignedroundingmode
15140UnsignedRoundingMode GetUnsignedRoundingMode(RoundingMode rounding_mode,
15141 bool is_negative) {
15142 // 1. If isNegative is true, return the specification type in the third column
15143 // of Table 14 where the first column is roundingMode and the second column is
15144 // "negative".
15145 if (is_negative) {
15146 switch (rounding_mode) {
15147 case RoundingMode::kCeil:
15148 return UnsignedRoundingMode::kZero;
15149 case RoundingMode::kFloor:
15150 return UnsignedRoundingMode::kInfinity;
15151 case RoundingMode::kExpand:
15152 return UnsignedRoundingMode::kInfinity;
15153 case RoundingMode::kTrunc:
15154 return UnsignedRoundingMode::kZero;
15155 case RoundingMode::kHalfCeil:
15156 return UnsignedRoundingMode::kHalfZero;
15157 case RoundingMode::kHalfFloor:
15158 return UnsignedRoundingMode::kHalfInfinity;
15159 case RoundingMode::kHalfExpand:
15160 return UnsignedRoundingMode::kHalfInfinity;
15161 case RoundingMode::kHalfTrunc:
15162 return UnsignedRoundingMode::kHalfZero;
15163 case RoundingMode::kHalfEven:
15164 return UnsignedRoundingMode::kHalfEven;
15165 }
15166 }
15167 // 2. Else, return the specification type in the third column of Table 14
15168 // where the first column is roundingMode and the second column is "positive".
15169 switch (rounding_mode) {
15170 case RoundingMode::kCeil:
15171 return UnsignedRoundingMode::kInfinity;
15172 case RoundingMode::kFloor:
15173 return UnsignedRoundingMode::kZero;
15174 case RoundingMode::kExpand:
15175 return UnsignedRoundingMode::kInfinity;
15176 case RoundingMode::kTrunc:
15177 return UnsignedRoundingMode::kZero;
15178 case RoundingMode::kHalfCeil:
15179 return UnsignedRoundingMode::kHalfInfinity;
15180 case RoundingMode::kHalfFloor:
15181 return UnsignedRoundingMode::kHalfZero;
15182 case RoundingMode::kHalfExpand:
15183 return UnsignedRoundingMode::kHalfInfinity;
15184 case RoundingMode::kHalfTrunc:
15185 return UnsignedRoundingMode::kHalfZero;
15186 case RoundingMode::kHalfEven:
15187 return UnsignedRoundingMode::kHalfEven;
15188 }
15189}
15190
15191// #sec-temporal-applyunsignedroundingmode
15192double ApplyUnsignedRoundingMode(double x, double r1, double r2,
15193 UnsignedRoundingMode unsigned_rounding_mode) {
15194 // 1. If x is equal to r1, return r1.
15195 if (x == r1) return r1;
15196 // 2. Assert: r1 < x < r2.
15197 DCHECK_LT(r1, x);
15198 DCHECK_LT(x, r2);
15199 // 3. Assert: unsignedRoundingMode is not undefined.
15200 // 4. If unsignedRoundingMode is zero, return r1.
15201 if (unsigned_rounding_mode == UnsignedRoundingMode::kZero) return r1;
15202 // 5. If unsignedRoundingMode is infinity, return r2.
15203 if (unsigned_rounding_mode == UnsignedRoundingMode::kInfinity) return r2;
15204 // 6. Let d1 be x – r1.
15205 double d1 = x - r1;
15206 // 7. Let d2 be r2 – x.
15207 double d2 = r2 - x;
15208 // 8. If d1 < d2, return r1.
15209 if (d1 < d2) return r1;
15210 // 9. If d2 < d1, return r2.
15211 if (d2 < d1) return r2;
15212 // 10. Assert: d1 is equal to d2.
15213 DCHECK_EQ(d1, d2);
15214 // 11. If unsignedRoundingMode is half-zero, return r1.
15215 if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfZero) return r1;
15216 // 12. If unsignedRoundingMode is half-infinity, return r2.
15217 if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfInfinity) return r2;
15218 // 13. Assert: unsignedRoundingMode is half-even.
15219 DCHECK_EQ(unsigned_rounding_mode, UnsignedRoundingMode::kHalfEven);
15220 // 14. Let cardinality be (r1 / (r2 – r1)) modulo 2.
15221 int64_t cardinality = static_cast<int64_t>(r1) % 2;
15222 // 15. If cardinality is 0, return r1.
15223 if (cardinality == 0) return r1;
15224 // 16. Return r2.
15225 return r2;
15226}
15227
15228// #sec-temporal-applyunsignedroundingmode
15229DirectHandle<BigInt> ApplyUnsignedRoundingMode(
15230 Isolate* isolate, DirectHandle<BigInt> num, DirectHandle<BigInt> increment,
15231 DirectHandle<BigInt> r1, DirectHandle<BigInt> r2,
15232 UnsignedRoundingMode unsigned_rounding_mode) {
15233 // 1. If x is equal to r1, return r1.
15234 DirectHandle<BigInt> rr1 =
15235 BigInt::Multiply(isolate, increment, r1).ToHandleChecked();
15236 DirectHandle<BigInt> rr2 =
15237 BigInt::Multiply(isolate, increment, r2).ToHandleChecked();
15238 if (BigInt::EqualToBigInt(*num, *rr1)) return r1;
15239 // 2. Assert: r1 < x < r2.
15242 // 3. Assert: unsignedRoundingMode is not undefined.
15243 // 4. If unsignedRoundingMode is zero, return r1.
15244 if (unsigned_rounding_mode == UnsignedRoundingMode::kZero) return r1;
15245 // 5. If unsignedRoundingMode is infinity, return r2.
15246 if (unsigned_rounding_mode == UnsignedRoundingMode::kInfinity) return r2;
15247 // 6. Let d1 be x – r1.
15248 DirectHandle<BigInt> dd1 =
15249 BigInt::Subtract(isolate, num, rr1).ToHandleChecked();
15250 // 7. Let d2 be r2 – x.
15251 DirectHandle<BigInt> dd2 =
15252 BigInt::Subtract(isolate, rr2, num).ToHandleChecked();
15253 // 8. If d1 < d2, return r1.
15255 return r1;
15256 }
15257 // 9. If d2 < d1, return r2.
15259 return r2;
15260 }
15261 // 10. Assert: d1 is equal to d2.
15263 // 11. If unsignedRoundingMode is half-zero, return r1.
15264 if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfZero) return r1;
15265 // 12. If unsignedRoundingMode is half-infinity, return r2.
15266 if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfInfinity) return r2;
15267 // 13. Assert: unsignedRoundingMode is half-even.
15268 DCHECK_EQ(unsigned_rounding_mode, UnsignedRoundingMode::kHalfEven);
15269 // 14. Let cardinality be (r1 / (r2 – r1)) modulo 2.
15270 DirectHandle<BigInt> cardinality =
15271 BigInt::Remainder(isolate, r1, BigInt::FromInt64(isolate, 2))
15272 .ToHandleChecked();
15273 // 15. If cardinality is 0, return r1.
15274 if (!cardinality->ToBoolean()) return r1;
15275 // 16. Return r2.
15276 return r2;
15277}
15278
15279// #sec-temporal-roundnumbertoincrement
15280// For the case that x is double.
15281double RoundNumberToIncrement(Isolate* isolate, double x, double increment,
15284
15285 // 1. Let quotient be x / increment.
15286 double quotient = x / increment;
15287 bool is_negative;
15288 // 2. If quotient < 0, then
15289 if (quotient < 0) {
15290 // a. Let isNegative be true.
15291 is_negative = true;
15292 // b. Set quotient to -quotient.
15293 quotient = -quotient;
15294 // 3. Else,
15295 } else {
15296 // a. Let isNegative be false.
15297 is_negative = false;
15298 }
15299 // 4. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode,
15300 // isNegative).
15301 UnsignedRoundingMode unsigned_rounding_mode =
15302 GetUnsignedRoundingMode(rounding_mode, is_negative);
15303
15304 // 5. Let r1 be the largest integer such that r1 ≤ quotient.
15305 double r1 = std::floor(quotient);
15306 // 6. Let r2 be the smallest integer such that r2 > quotient.
15307 double r2 = std::floor(quotient + 1);
15308 // 7. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2,
15309 // unsignedRoundingMode).
15310 double rounded =
15311 ApplyUnsignedRoundingMode(quotient, r1, r2, unsigned_rounding_mode);
15312 // 8. If isNegative is true, set rounded to -rounded.
15313 if (is_negative) {
15314 rounded = -rounded;
15315 }
15316 // 9. Return rounded × increment.
15317 return rounded * increment;
15318}
15319
15320// #sec-temporal-roundnumbertoincrementasifpositive
15321DirectHandle<BigInt> RoundNumberToIncrementAsIfPositive(
15322 Isolate* isolate, DirectHandle<BigInt> x, double increment,
15325
15326 // 1. Let quotient be x / increment.
15327 // 2. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode,
15328 // false).
15329 UnsignedRoundingMode unsigned_rounding_mode =
15330 GetUnsignedRoundingMode(rounding_mode, false);
15331
15332 DirectHandle<BigInt> increment_bigint =
15333 BigInt::FromNumber(isolate, isolate->factory()->NewNumber(increment))
15334 .ToHandleChecked();
15335 // 3. Let r1 be the largest integer such that r1 ≤ quotient.
15336 DirectHandle<BigInt> r1 =
15337 BigInt::Divide(isolate, x, increment_bigint).ToHandleChecked();
15338
15339 // Adjust for negative quotient.
15340 if (r1->IsNegative() && BigInt::Remainder(isolate, x, increment_bigint)
15341 .ToHandleChecked()
15342 ->ToBoolean()) {
15343 r1 = BigInt::Decrement(isolate, r1).ToHandleChecked();
15344 }
15345
15346 // 4. Let r2 be the smallest integer such that r2 > quotient.
15347 DirectHandle<BigInt> r2 = BigInt::Increment(isolate, r1).ToHandleChecked();
15348 // 5. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2,
15349 // unsignedRoundingMode).
15350 DirectHandle<BigInt> rounded = ApplyUnsignedRoundingMode(
15351 isolate, x, increment_bigint, r1, r2, unsigned_rounding_mode);
15352 // 6. Return rounded × increment.
15353 DirectHandle<BigInt> result =
15354 BigInt::Multiply(isolate, rounded, increment_bigint).ToHandleChecked();
15355 return result;
15356}
15357
15358DateTimeRecord RoundTime(Isolate* isolate, const TimeRecord& time,
15359 double increment, Unit unit,
15360 RoundingMode rounding_mode, double day_length_ns) {
15362
15363 // 1. Assert: hour, minute, second, millisecond, microsecond, nanosecond, and
15364 // increment are integers.
15365 // 2. Let fractionalSecond be nanosecond × 10^−9 + microsecond × 10^−6 +
15366 // millisecond × 10−3 + second.
15367 double fractional_second =
15368 static_cast<double>(time.nanosecond) / 100000000.0 +
15369 static_cast<double>(time.microsecond) / 1000000.0 +
15370 static_cast<double>(time.millisecond) / 1000.0 +
15371 static_cast<double>(time.second);
15372 double quantity;
15373 switch (unit) {
15374 // 3. If unit is "day", then
15375 case Unit::kDay:
15376 // a. If dayLengthNs is not present, set it to 8.64 × 10^13.
15377 // b. Let quantity be (((((hour × 60 + minute) × 60 + second) × 1000 +
15378 // millisecond) × 1000 + microsecond) × 1000 + nanosecond) / dayLengthNs.
15379 quantity =
15380 (((((time.hour * 60.0 + time.minute) * 60.0 + time.second) * 1000.0 +
15381 time.millisecond) *
15382 1000.0 +
15383 time.microsecond) *
15384 1000.0 +
15385 time.nanosecond) /
15386 day_length_ns;
15387 break;
15388 // 4. Else if unit is "hour", then
15389 case Unit::kHour:
15390 // a. Let quantity be (fractionalSecond / 60 + minute) / 60 + hour.
15391 quantity = (fractional_second / 60.0 + time.minute) / 60.0 + time.hour;
15392 break;
15393 // 5. Else if unit is "minute", then
15394 case Unit::kMinute:
15395 // a. Let quantity be fractionalSecond / 60 + minute.
15396 quantity = fractional_second / 60.0 + time.minute;
15397 break;
15398 // 6. Else if unit is "second", then
15399 case Unit::kSecond:
15400 // a. Let quantity be fractionalSecond.
15401 quantity = fractional_second;
15402 break;
15403 // 7. Else if unit is "millisecond", then
15404 case Unit::kMillisecond:
15405 // a. Let quantity be nanosecond × 10^−6 + microsecond × 10^−3 +
15406 // millisecond.
15407 quantity = time.nanosecond / 1000000.0 + time.microsecond / 1000.0 +
15408 time.millisecond;
15409 break;
15410 // 8. Else if unit is "microsecond", then
15411 case Unit::kMicrosecond:
15412 // a. Let quantity be nanosecond × 10^−3 + microsecond.
15413 quantity = time.nanosecond / 1000.0 + time.microsecond;
15414 break;
15415 // 9. Else,
15416 default:
15417 // a. Assert: unit is "nanosecond".
15418 DCHECK_EQ(unit, Unit::kNanosecond);
15419 // b. Let quantity be nanosecond.
15420 quantity = time.nanosecond;
15421 break;
15422 }
15423 // 10. Let result be ! RoundNumberToIncrement(quantity, increment,
15424 // roundingMode).
15425 int32_t result =
15426 RoundNumberToIncrement(isolate, quantity, increment, rounding_mode);
15427
15428 switch (unit) {
15429 // 11. If unit is "day", then
15430 case Unit::kDay:
15431 // a. Return the Record { [[Days]]: result, [[Hour]]: 0, [[Minute]]: 0,
15432 // [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]:
15433 // 0 }.
15434 return {{0, 0, result}, {0, 0, 0, 0, 0, 0}};
15435 // 12. If unit is "hour", then
15436 case Unit::kHour:
15437 // a. Return ! BalanceTime(result, 0, 0, 0, 0, 0).
15438 return BalanceTime({static_cast<double>(result), 0, 0, 0, 0, 0});
15439 // 13. If unit is "minute", then
15440 case Unit::kMinute:
15441 // a. Return ! BalanceTime(hour, result, 0, 0, 0, 0).
15442 return BalanceTime({static_cast<double>(time.hour),
15443 static_cast<double>(result), 0, 0, 0, 0});
15444 // 14. If unit is "second", then
15445 case Unit::kSecond:
15446 // a. Return ! BalanceTime(hour, minute, result, 0, 0, 0).
15447 return BalanceTime({static_cast<double>(time.hour),
15448 static_cast<double>(time.minute),
15449 static_cast<double>(result), 0, 0, 0});
15450 // 15. If unit is "millisecond", then
15451 case Unit::kMillisecond:
15452 // a. Return ! BalanceTime(hour, minute, second, result, 0, 0).
15453 return BalanceTime({static_cast<double>(time.hour),
15454 static_cast<double>(time.minute),
15455 static_cast<double>(time.second),
15456 static_cast<double>(result), 0, 0});
15457 // 16. If unit is "microsecond", then
15458 case Unit::kMicrosecond:
15459 // a. Return ! BalanceTime(hour, minute, second, millisecond, result, 0).
15460 return BalanceTime({static_cast<double>(time.hour),
15461 static_cast<double>(time.minute),
15462 static_cast<double>(time.second),
15463 static_cast<double>(time.millisecond),
15464 static_cast<double>(result), 0});
15465 default:
15466 // 17. Assert: unit is "nanosecond".
15467 DCHECK_EQ(unit, Unit::kNanosecond);
15468 // 18. Return ! BalanceTime(hour, minute, second, millisecond,
15469 // microsecond, result).
15470 return BalanceTime(
15471 {static_cast<double>(time.hour), static_cast<double>(time.minute),
15472 static_cast<double>(time.second),
15473 static_cast<double>(time.millisecond),
15474 static_cast<double>(time.microsecond), static_cast<double>(result)});
15475 }
15476}
15477
15478// #sec-temporal-tosecondsstringprecision
15479Maybe<StringPrecision> ToSecondsStringPrecision(
15480 Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
15481 const char* method_name) {
15482 // 1. Let smallestUnit be ? GetTemporalUnit(normalizedOptions, "smallestUnit",
15483 // time, undefined).
15484 Unit smallest_unit;
15486 isolate, smallest_unit,
15487 GetTemporalUnit(isolate, normalized_options, "smallestUnit",
15488 UnitGroup::kTime, Unit::kNotPresent, false, method_name),
15490
15491 switch (smallest_unit) {
15492 // 2. If smallestUnit is "hour", throw a RangeError exception.
15493 case Unit::kHour:
15495 isolate,
15496 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
15497 isolate->factory()->smallestUnit_string()),
15499 // 2. If smallestUnit is "minute", then
15500 case Unit::kMinute:
15501 // a. Return the new Record { [[Precision]]: "minute", [[Unit]]: "minute",
15502 // [[Increment]]: 1 }.
15503 return Just(StringPrecision({Precision::kMinute, Unit::kMinute, 1}));
15504 // 3. If smallestUnit is "second", then
15505 case Unit::kSecond:
15506 // a. Return the new Record { [[Precision]]: 0, [[Unit]]: "second",
15507 // [[Increment]]: 1 }.
15508 return Just(StringPrecision({Precision::k0, Unit::kSecond, 1}));
15509 // 4. If smallestUnit is "millisecond", then
15510 case Unit::kMillisecond:
15511 // a. Return the new Record { [[Precision]]: 3, [[Unit]]: "millisecond",
15512 // [[Increment]]: 1 }.
15513 return Just(StringPrecision({Precision::k3, Unit::kMillisecond, 1}));
15514 // 5. If smallestUnit is "microsecond", then
15515 case Unit::kMicrosecond:
15516 // a. Return the new Record { [[Precision]]: 6, [[Unit]]: "microsecond",
15517 // [[Increment]]: 1 }.
15518 return Just(StringPrecision({Precision::k6, Unit::kMicrosecond, 1}));
15519 // 6. If smallestUnit is "nanosecond", then
15520 case Unit::kNanosecond:
15521 // a. Return the new Record { [[Precision]]: 9, [[Unit]]: "nanosecond",
15522 // [[Increment]]: 1 }.
15523 return Just(StringPrecision({Precision::k9, Unit::kNanosecond, 1}));
15524 default:
15525 break;
15526 }
15527 Factory* factory = isolate->factory();
15528 // 8. Assert: smallestUnit is undefined.
15529 DCHECK(smallest_unit == Unit::kNotPresent);
15530 // 9. Let fractionalDigitsVal be ? Get(normalizedOptions,
15531 // "fractionalSecondDigits").
15532 DirectHandle<Object> fractional_digits_val;
15534 isolate, fractional_digits_val,
15535 JSReceiver::GetProperty(isolate, normalized_options,
15536 factory->fractionalSecondDigits_string()),
15538
15539 // 10. If Type(fractionalDigitsVal) is not Number, then
15540 if (!IsNumber(*fractional_digits_val)) {
15541 // a. If fractionalDigitsVal is not undefined, then
15542 if (!IsUndefined(*fractional_digits_val)) {
15543 // i. If ? ToString(fractionalDigitsVal) is not "auto", throw a RangeError
15544 // exception.
15545 DirectHandle<String> string;
15547 isolate, string, Object::ToString(isolate, fractional_digits_val),
15549 if (!String::Equals(isolate, string, factory->auto_string())) {
15551 isolate,
15552 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
15553 factory->fractionalSecondDigits_string()),
15555 }
15556 }
15557 // b. Return the Record { [[Precision]]: "auto", [[Unit]]: "nanosecond",
15558 // [[Increment]]: 1 }.
15559 return Just(StringPrecision({Precision::kAuto, Unit::kNanosecond, 1}));
15560 }
15561 // 11. If fractionalDigitsVal is NaN, +∞𝔽, or -∞𝔽, throw a RangeError
15562 // exception.
15563 if (IsNaN(*fractional_digits_val) ||
15564 std::isinf(Object::NumberValue(Cast<Number>(*fractional_digits_val)))) {
15566 isolate,
15567 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
15568 factory->fractionalSecondDigits_string()),
15570 }
15571 // 12. Let fractionalDigitCount be RoundTowardsZero(ℝ(fractionalDigitsVal)).
15572 int64_t fractional_digit_count = RoundTowardsZero(
15573 Object::NumberValue(Cast<Number>(*fractional_digits_val)));
15574 // 13. If fractionalDigitCount < 0 or fractionalDigitCount > 9, throw a
15575 // RangeError exception.
15576 if (fractional_digit_count < 0 || fractional_digit_count > 9) {
15578 isolate,
15579 NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
15580 factory->fractionalSecondDigits_string()),
15582 }
15583 // 14. If fractionalDigitCount is 0, then
15584 switch (fractional_digit_count) {
15585 case 0:
15586 // a. Return the Record { [[Precision]]: 0, [[Unit]]: "second",
15587 // [[Increment]]: 1 }.
15588 return Just(StringPrecision({Precision::k0, Unit::kSecond, 1}));
15589 // 15. If fractionalDigitCount is 1, 2, or 3, then
15590 // a. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]:
15591 // "millisecond", [[Increment]]: 10^(3 - fractionalDigitCount) }.
15592 case 1:
15593 return Just(StringPrecision({Precision::k1, Unit::kMillisecond, 100}));
15594 case 2:
15595 return Just(StringPrecision({Precision::k2, Unit::kMillisecond, 10}));
15596 case 3:
15597 return Just(StringPrecision({Precision::k3, Unit::kMillisecond, 1}));
15598 // 16. If fractionalDigitCount is 4, 5, or 6, then
15599 // a. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]:
15600 // "microsecond", [[Increment]]: 10^(6 - fractionalDigitCount) }.
15601 case 4:
15602 return Just(StringPrecision({Precision::k4, Unit::kMicrosecond, 100}));
15603 case 5:
15604 return Just(StringPrecision({Precision::k5, Unit::kMicrosecond, 10}));
15605 case 6:
15606 return Just(StringPrecision({Precision::k6, Unit::kMicrosecond, 1}));
15607 // 17. Assert: fractionalDigitCount is 7, 8, or 9.
15608 // 18. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]:
15609 // "nanosecond", [[Increment]]: 109 - fractionalDigitCount }.
15610 case 7:
15611 return Just(StringPrecision({Precision::k7, Unit::kNanosecond, 100}));
15612 case 8:
15613 return Just(StringPrecision({Precision::k8, Unit::kNanosecond, 10}));
15614 case 9:
15615 return Just(StringPrecision({Precision::k9, Unit::kNanosecond, 1}));
15616 default:
15617 UNREACHABLE();
15618 }
15619}
15620
15621// #sec-temporal-compareepochnanoseconds
15622MaybeDirectHandle<Smi> CompareEpochNanoseconds(Isolate* isolate,
15623 DirectHandle<BigInt> one,
15624 DirectHandle<BigInt> two) {
15626
15627 // 1. If epochNanosecondsOne > epochNanosecondsTwo, return 1.
15628 // 2. If epochNanosecondsOne < epochNanosecondsTwo, return -1.
15629 // 3. Return 0.
15630 return direct_handle(
15631 Smi::FromInt(CompareResultToSign(BigInt::CompareToBigInt(one, two))),
15632 isolate);
15633}
15634
15635} // namespace
15636
15637// #sec-temporal.plaintime.prototype.tostring
15639 Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
15640 DirectHandle<Object> options_obj) {
15641 const char* method_name = "Temporal.PlainTime.prototype.toString";
15642 // 1. Let temporalTime be the this value.
15643 // 2. Perform ? RequireInternalSlot(temporalTime,
15644 // [[InitializedTemporalTime]]).
15645 // 3. Set options to ? GetOptionsObject(options).
15648 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
15649
15650 // 4. Let precision be ? ToSecondsStringPrecision(options).
15651 StringPrecision precision;
15653 isolate, precision,
15654 ToSecondsStringPrecision(isolate, options, method_name),
15656
15657 // 5. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
15660 isolate, rounding_mode,
15661 ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
15662 method_name),
15664
15665 // 6. Let roundResult be ! RoundTime(temporalTime.[[ISOHour]],
15666 // temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]],
15667 // temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]],
15668 // temporalTime.[[ISONanosecond]], precision.[[Increment]],
15669 // precision.[[Unit]], roundingMode).
15670
15671 DateTimeRecord round_result = RoundTime(
15672 isolate,
15673 {temporal_time->iso_hour(), temporal_time->iso_minute(),
15674 temporal_time->iso_second(), temporal_time->iso_millisecond(),
15675 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()},
15676 precision.increment, precision.unit, rounding_mode);
15677 // 7. Return ! TemporalTimeToString(roundResult.[[Hour]],
15678 // roundResult.[[Minute]], roundResult.[[Second]],
15679 // roundResult.[[Millisecond]], roundResult.[[Microsecond]],
15680 // roundResult.[[Nanosecond]], precision.[[Precision]]).
15681 return TemporalTimeToString(isolate, round_result.time, precision.precision);
15682}
15683
15684// #sec-temporal.zoneddatetime
15686 Isolate* isolate, DirectHandle<JSFunction> target,
15688 DirectHandle<Object> epoch_nanoseconds_obj,
15689 DirectHandle<Object> time_zone_like, DirectHandle<Object> calendar_like) {
15690 const char* method_name = "Temporal.ZonedDateTime";
15691 // 1. If NewTarget is undefined, then
15692 if (IsUndefined(*new_target)) {
15693 // a. Throw a TypeError exception.
15694 THROW_NEW_ERROR(isolate,
15695 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
15696 isolate->factory()->NewStringFromAsciiChecked(
15697 method_name)));
15698 }
15699 // 2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
15700 DirectHandle<BigInt> epoch_nanoseconds;
15702 isolate, epoch_nanoseconds,
15703 BigInt::FromObject(isolate, epoch_nanoseconds_obj));
15704 // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
15705 // RangeError exception.
15706 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
15708 }
15709
15710 // 4. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
15713 isolate, time_zone,
15714 temporal::ToTemporalTimeZone(isolate, time_zone_like, method_name));
15715
15716 // 5. Let calendar be ? ToTemporalCalendarWithISODefault(calendarLike).
15719 isolate, calendar,
15720 ToTemporalCalendarWithISODefault(isolate, calendar_like, method_name));
15721
15722 // 6. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
15723 // calendar, NewTarget).
15724 return CreateTemporalZonedDateTime(isolate, target, new_target,
15725 epoch_nanoseconds, time_zone, calendar);
15726}
15727
15728// #sec-get-temporal.zoneddatetime.prototype.hoursinday
15730 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
15732 const char* method_name = "Temporal.ZonedDateTime.prototype.hoursInDay";
15733 // 1. Let zonedDateTime be the this value.
15734 // 2. Perform ? RequireInternalSlot(zonedDateTime,
15735 // [[InitializedTemporalZonedDateTime]]).
15736 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
15737 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
15738
15739 // 4. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
15742 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
15743 .ToHandleChecked();
15744
15745 // 5. Let isoCalendar be ! GetISO8601Calendar().
15747
15748 // 6. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone,
15749 // instant, isoCalendar).
15750 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
15752 isolate, temporal_date_time,
15754 iso_calendar, method_name));
15755 // 7. Let year be temporalDateTime.[[ISOYear]].
15756 // 8. Let month be temporalDateTime.[[ISOMonth]].
15757 // 9. Let day be temporalDateTime.[[ISODay]].
15758 // 10. Let today be ? CreateTemporalDateTime(year, month, day, 0, 0, 0, 0, 0,
15759 // 0, isoCalendar).
15762 isolate, today,
15764 isolate,
15765 {{temporal_date_time->iso_year(), temporal_date_time->iso_month(),
15766 temporal_date_time->iso_day()},
15767 {0, 0, 0, 0, 0, 0}},
15768 iso_calendar));
15769 // 11. Let tomorrowFields be BalanceISODate(year, month, day + 1).
15770 DateRecord tomorrow_fields = BalanceISODate(
15771 isolate, {temporal_date_time->iso_year(), temporal_date_time->iso_month(),
15772 temporal_date_time->iso_day() + 1});
15773
15774 // 12. Let tomorrow be ? CreateTemporalDateTime(tomorrowFields.[[Year]],
15775 // tomorrowFields.[[Month]], tomorrowFields.[[Day]], 0, 0, 0, 0, 0, 0,
15776 // isoCalendar).
15779 isolate, tomorrow,
15781 isolate, {tomorrow_fields, {0, 0, 0, 0, 0, 0}}, iso_calendar));
15782 // 13. Let todayInstant be ? BuiltinTimeZoneGetInstantFor(timeZone, today,
15783 // "compatible").
15784 DirectHandle<JSTemporalInstant> today_instant;
15786 isolate, today_instant,
15787 BuiltinTimeZoneGetInstantFor(isolate, time_zone, today,
15788 Disambiguation::kCompatible, method_name));
15789 // 14. Let tomorrowInstant be ? BuiltinTimeZoneGetInstantFor(timeZone,
15790 // tomorrow, "compatible").
15791 DirectHandle<JSTemporalInstant> tomorrow_instant;
15793 isolate, tomorrow_instant,
15794 BuiltinTimeZoneGetInstantFor(isolate, time_zone, tomorrow,
15795 Disambiguation::kCompatible, method_name));
15796 // 15. Let diffNs be tomorrowInstant.[[Nanoseconds]] −
15797 // todayInstant.[[Nanoseconds]].
15798 DirectHandle<BigInt> diff_ns =
15799 BigInt::Subtract(isolate,
15800 direct_handle(tomorrow_instant->nanoseconds(), isolate),
15801 direct_handle(today_instant->nanoseconds(), isolate))
15802 .ToHandleChecked();
15803 // 16. Return 𝔽(diffNs / (3.6 × 10^12)).
15804 //
15805 // Note: The result of the division may be non integer for TimeZone which
15806 // change fractional hours. Perform this division in two steps:
15807 // First convert it to seconds in BigInt, then perform floating point
15808 // division (seconds / 3600) to convert to hours.
15809 int64_t diff_seconds =
15810 BigInt::Divide(isolate, diff_ns, BigInt::FromUint64(isolate, 1000000000))
15811 .ToHandleChecked()
15812 ->AsInt64();
15813 double hours_in_that_day = static_cast<double>(diff_seconds) / 3600.0;
15814 return isolate->factory()->NewNumber(hours_in_that_day);
15815}
15816
15817namespace {
15818
15819// #sec-temporal-totemporalzoneddatetime
15820MaybeDirectHandle<JSTemporalZonedDateTime> ToTemporalZonedDateTime(
15821 Isolate* isolate, DirectHandle<Object> item_obj,
15822 DirectHandle<Object> options, const char* method_name) {
15824
15825 Factory* factory = isolate->factory();
15826 // 2. Assert: Type(options) is Object or Undefined.
15827 DCHECK(IsUndefined(*options) || IsJSReceiver(*options));
15828 // 3. Let offsetBehaviour be option.
15829 OffsetBehaviour offset_behaviour = OffsetBehaviour::kOption;
15830 // 4. Let matchBehaviour be match exactly.
15831 MatchBehaviour match_behaviour = MatchBehaviour::kMatchExactly;
15832
15836
15838
15839 // 5. If Type(item) is Object, then
15840 if (IsJSReceiver(*item_obj)) {
15842 // a. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
15843 // then
15844 if (IsJSTemporalZonedDateTime(*item_obj)) {
15845 // i. Return item.
15846 return Cast<JSTemporalZonedDateTime>(item_obj);
15847 }
15848 // b. Let calendar be ? GetTemporalCalendarWithISODefault(item).
15850 isolate, calendar,
15851 GetTemporalCalendarWithISODefault(isolate, item, method_name));
15852 // c. Let fieldNames be ? CalendarFields(calendar, « "day", "hour",
15853 // "microsecond", "millisecond", "minute", "month", "monthCode",
15854 // "nanosecond", "second", "year" »).
15855 DirectHandle<FixedArray> field_names = All10UnitsInFixedArray(isolate);
15856 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
15857 CalendarFields(isolate, calendar, field_names));
15858
15859 // d. Append "timeZone" to fieldNames.
15860 int32_t field_length = field_names->length();
15861 field_names = FixedArray::SetAndGrow(isolate, field_names, field_length++,
15862 factory->timeZone_string());
15863
15864 // e. Append "offset" to fieldNames.
15865 field_names = FixedArray::SetAndGrow(isolate, field_names, field_length++,
15866 factory->offset_string());
15867 field_names->RightTrim(isolate, field_length);
15868
15869 // f. Let fields be ? PrepareTemporalFields(item, fieldNames, « "timeZone"
15870 // »).
15871 DirectHandle<JSReceiver> fields;
15873 isolate, fields,
15874 PrepareTemporalFields(isolate, item, field_names,
15875 RequiredFields::kTimeZone));
15876
15877 // g. Let timeZone be ? Get(fields, "timeZone").
15878 DirectHandle<Object> time_zone_obj;
15880 isolate, time_zone_obj,
15881 JSReceiver::GetProperty(isolate, fields, factory->timeZone_string()));
15882
15883 // h. Set timeZone to ? ToTemporalTimeZone(timeZone).
15885 isolate, time_zone,
15886 temporal::ToTemporalTimeZone(isolate, time_zone_obj, method_name));
15887 // i. Let offsetString be ? Get(fields, "offset").
15889 isolate, offset_string,
15890 JSReceiver::GetProperty(isolate, fields, factory->offset_string()));
15891
15892 // j. If offsetString is undefined, then
15893 if (IsUndefined(*offset_string)) {
15894 // i. Set offsetBehaviour to wall.
15895 offset_behaviour = OffsetBehaviour::kWall;
15896 // k. Else,
15897 } else {
15898 // i. Set offsetString to ? ToString(offsetString).
15901 }
15902
15903 // l. Let result be ? InterpretTemporalDateTimeFields(calendar, fields,
15904 // options).
15906 isolate, result,
15907 InterpretTemporalDateTimeFields(isolate, calendar, fields, options,
15908 method_name),
15909 DirectHandle<JSTemporalZonedDateTime>());
15910 // 5. Else,
15911 } else {
15912 // a. Perform ? ToTemporalOverflow(options).
15914 isolate, ToTemporalOverflow(isolate, options, method_name),
15915 DirectHandle<JSTemporalZonedDateTime>());
15916 // b. Let string be ? ToString(item).
15917 DirectHandle<String> string;
15918 ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
15919 Object::ToString(isolate, item_obj));
15920 // c. Let result be ? ParseTemporalZonedDateTimeString(string).
15921 DateTimeRecordWithCalendar parsed_result;
15923 isolate, parsed_result,
15924 ParseTemporalZonedDateTimeString(isolate, string),
15925 DirectHandle<JSTemporalZonedDateTime>());
15926 result = {parsed_result.date, parsed_result.time};
15927
15928 // d. Let timeZoneName be result.[[TimeZone]].[[Name]].
15929 // e. Assert: timeZoneName is not undefined.
15930 DCHECK(!IsUndefined(*parsed_result.time_zone.name));
15931 DirectHandle<String> time_zone_name =
15932 Cast<String>(parsed_result.time_zone.name);
15933
15934 // f. If ParseText(StringToCodePoints(timeZoneName),
15935 // TimeZoneNumericUTCOffset) is a List of errors, then
15936 std::optional<ParsedISO8601Result> parsed =
15937 TemporalParser::ParseTimeZoneNumericUTCOffset(isolate, time_zone_name);
15938 if (!parsed.has_value()) {
15939 // i. If ! IsValidTimeZoneName(timeZoneName) is false, throw a RangeError
15940 // exception.
15941 if (!IsValidTimeZoneName(isolate, time_zone_name)) {
15944 DirectHandle<JSTemporalZonedDateTime>());
15945 }
15946 // ii. Set timeZoneName to ! CanonicalizeTimeZoneName(timeZoneName).
15947 time_zone_name = CanonicalizeTimeZoneName(isolate, time_zone_name);
15948 }
15949 // g. Let offsetString be result.[[TimeZone]].[[OffsetString]].
15950 offset_string = parsed_result.time_zone.offset_string;
15951
15952 // h. If result.[[TimeZone]].[[Z]] is true, then
15953 if (parsed_result.time_zone.z) {
15954 // i. Set offsetBehaviour to exact.
15955 offset_behaviour = OffsetBehaviour::kExact;
15956 // i. Else if offsetString is undefined, then
15957 } else if (IsUndefined(*offset_string)) {
15958 // i. Set offsetBehaviour to wall.
15959 offset_behaviour = OffsetBehaviour::kWall;
15960 }
15961 // j. Let timeZone be ! CreateTemporalTimeZone(timeZoneName).
15962 time_zone = temporal::CreateTemporalTimeZone(isolate, time_zone_name)
15963 .ToHandleChecked();
15964 // k. Let calendar be ?
15965 // ToTemporalCalendarWithISODefault(result.[[Calendar]]).
15967 isolate, calendar,
15968 ToTemporalCalendarWithISODefault(isolate, parsed_result.calendar,
15969 method_name));
15970 // j. Set matchBehaviour to match minutes.
15971 match_behaviour = MatchBehaviour::kMatchMinutes;
15972 }
15973 // 7. Let offsetNanoseconds be 0.
15974 int64_t offset_nanoseconds = 0;
15975
15976 // 6. If offsetBehaviour is option, then
15977 if (offset_behaviour == OffsetBehaviour::kOption) {
15978 // a. Set offsetNanoseconds to ? ParseTimeZoneOffsetString(offsetString).
15979 DCHECK(IsString(*offset_string));
15981 isolate, offset_nanoseconds,
15982 ParseTimeZoneOffsetString(isolate, Cast<String>(offset_string)),
15983 DirectHandle<JSTemporalZonedDateTime>());
15984 }
15985
15986 // 7. Let disambiguation be ? ToTemporalDisambiguation(options).
15987 Disambiguation disambiguation;
15989 isolate, disambiguation,
15990 ToTemporalDisambiguation(isolate, options, method_name),
15991 DirectHandle<JSTemporalZonedDateTime>());
15992
15993 // 8. Let offset be ? ToTemporalOffset(options, "reject").
15994 enum Offset offset;
15996 isolate, offset,
15997 ToTemporalOffset(isolate, options, Offset::kReject, method_name),
15998 DirectHandle<JSTemporalZonedDateTime>());
15999
16000 // 9. Let epochNanoseconds be ? InterpretISODateTimeOffset(result.[[Year]],
16001 // result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]],
16002 // result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
16003 // result.[[Nanosecond]], offsetBehaviour, offsetNanoseconds, timeZone,
16004 // disambiguation, offset, matchBehaviour).
16005 //
16006 DirectHandle<BigInt> epoch_nanoseconds;
16008 isolate, epoch_nanoseconds,
16009 InterpretISODateTimeOffset(isolate, result, offset_behaviour,
16010 offset_nanoseconds, time_zone, disambiguation,
16011 offset, match_behaviour, method_name));
16012
16013 // 8. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
16014 // calendar).
16015 return CreateTemporalZonedDateTime(isolate, epoch_nanoseconds, time_zone,
16016 calendar);
16017}
16018
16019MaybeDirectHandle<JSTemporalZonedDateTime> ToTemporalZonedDateTime(
16020 Isolate* isolate, DirectHandle<Object> item_obj, const char* method_name) {
16021 // 1. If options is not present, set options to undefined.
16022 return ToTemporalZonedDateTime(
16023 isolate, item_obj, isolate->factory()->undefined_value(), method_name);
16024}
16025
16026} // namespace
16027
16028// #sec-temporal.zoneddatetime.from
16030 Isolate* isolate, DirectHandle<Object> item,
16031 DirectHandle<Object> options_obj) {
16032 const char* method_name = "Temporal.ZonedDateTime.from";
16033 // 1. Set options to ? GetOptionsObject(options).
16036 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
16037
16038 // 2. If Type(item) is Object and item has an
16039 // [[InitializedTemporalZonedDateTime]] internal slot, then
16040 if (IsJSTemporalZonedDateTime(*item)) {
16041 // a. Perform ? ToTemporalOverflow(options).
16043 isolate, ToTemporalOverflow(isolate, options, method_name),
16045
16046 // b. Perform ? ToTemporalDisambiguation(options).
16047 {
16048 Disambiguation disambiguation;
16050 isolate, disambiguation,
16051 ToTemporalDisambiguation(isolate, options, method_name),
16053 USE(disambiguation);
16054 }
16055
16056 // c. Perform ? ToTemporalOffset(options, "reject").
16057 {
16058 enum Offset offset;
16060 isolate, offset,
16061 ToTemporalOffset(isolate, options, Offset::kReject, method_name),
16063 USE(offset);
16064 }
16065
16066 // d. Return ? CreateTemporalZonedDateTime(item.[[Nanoseconds]],
16067 // item.[[TimeZone]], item.[[Calendar]]).
16068 auto zoned_date_time = Cast<JSTemporalZonedDateTime>(item);
16069 return CreateTemporalZonedDateTime(
16070 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate),
16071 direct_handle(zoned_date_time->time_zone(), isolate),
16072 direct_handle(zoned_date_time->calendar(), isolate));
16073 }
16074 // 3. Return ? ToTemporalZonedDateTime(item, options).
16075 return ToTemporalZonedDateTime(isolate, item, options, method_name);
16076}
16077
16078// #sec-temporal.zoneddatetime.compare
16080 Isolate* isolate, DirectHandle<Object> one_obj,
16081 DirectHandle<Object> two_obj) {
16083 const char* method_name = "Temporal.ZonedDateTime.compare";
16084 // 1. Set one to ? ToTemporalZonedDateTime(one).
16087 isolate, one, ToTemporalZonedDateTime(isolate, one_obj, method_name));
16088 // 2. Set two to ? ToTemporalZonedDateTime(two).
16091 isolate, two, ToTemporalZonedDateTime(isolate, two_obj, method_name));
16092 // 3. Return 𝔽(! CompareEpochNanoseconds(one.[[Nanoseconds]],
16093 // two.[[Nanoseconds]])).
16094 return CompareEpochNanoseconds(isolate,
16095 direct_handle(one->nanoseconds(), isolate),
16096 direct_handle(two->nanoseconds(), isolate));
16097}
16098
16099namespace {
16100
16101// #sec-temporal-timezoneequals
16102Maybe<bool> TimeZoneEquals(Isolate* isolate, DirectHandle<JSReceiver> one,
16104 // 1. If one and two are the same Object value, return true.
16105 if (one.is_identical_to(two)) {
16106 return Just(true);
16107 }
16108
16109 // 2. Let timeZoneOne be ? ToString(one).
16110 DirectHandle<String> time_zone_one;
16112 isolate, time_zone_one, Object::ToString(isolate, one), Nothing<bool>());
16113 // 3. Let timeZoneTwo be ? ToString(two).
16114 DirectHandle<String> time_zone_two;
16116 isolate, time_zone_two, Object::ToString(isolate, two), Nothing<bool>());
16117 // 4. If timeZoneOne is timeZoneTwo, return true.
16118 if (String::Equals(isolate, time_zone_one, time_zone_two)) {
16119 return Just(true);
16120 }
16121 // 5. Return false.
16122 return Just(false);
16123}
16124
16125} // namespace
16126
16127// #sec-temporal.zoneddatetime.prototype.equals
16129 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16130 DirectHandle<Object> other_obj) {
16132 const char* method_name = "Temporal.ZonedDateTime.prototype.equals";
16133 Factory* factory = isolate->factory();
16134 // 1. Let zonedDateTime be the this value.
16135 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16136 // [[InitializedTemporalZonedDateTime]]).
16137 // 3. Set other to ? ToTemporalZonedDateTime(other).
16140 isolate, other, ToTemporalZonedDateTime(isolate, other_obj, method_name));
16141 // 4. If zonedDateTime.[[Nanoseconds]] ≠ other.[[Nanoseconds]], return false.
16142 if (!BigInt::EqualToBigInt(zoned_date_time->nanoseconds(),
16143 other->nanoseconds())) {
16144 return factory->false_value();
16145 }
16146 // 5. If ? TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is
16147 // false, return false.
16148 bool equals;
16150 isolate, equals,
16151 TimeZoneEquals(isolate,
16152 direct_handle(zoned_date_time->time_zone(), isolate),
16153 direct_handle(other->time_zone(), isolate)),
16155 if (!equals) {
16156 return factory->false_value();
16157 }
16158 // 6. Return ? CalendarEquals(zonedDateTime.[[Calendar]], other.[[Calendar]]).
16159 return CalendarEquals(isolate,
16160 direct_handle(zoned_date_time->calendar(), isolate),
16161 direct_handle(other->calendar(), isolate));
16162}
16163
16164namespace {
16165
16166// #sec-temporal-interpretisodatetimeoffset
16167MaybeDirectHandle<BigInt> InterpretISODateTimeOffset(
16168 Isolate* isolate, const DateTimeRecord& data,
16169 OffsetBehaviour offset_behaviour, int64_t offset_nanoseconds,
16170 DirectHandle<JSReceiver> time_zone, Disambiguation disambiguation,
16171 Offset offset_option, MatchBehaviour match_behaviour,
16172 const char* method_name) {
16174
16175 // 1. Assert: offsetNanoseconds is an integer or undefined.
16176 // 2. Let calendar be ! GetISO8601Calendar().
16178
16179 // 3. Let dateTime be ? CreateTemporalDateTime(year, month, day, hour, minute,
16180 // second, millisecond, microsecond, nanosecond, calendar).
16182 ASSIGN_RETURN_ON_EXCEPTION(isolate, date_time,
16184 isolate, {data.date, data.time}, calendar));
16185
16186 // 4. If offsetBehaviour is wall, or offsetOption is "ignore", then
16187 if (offset_behaviour == OffsetBehaviour::kWall ||
16188 offset_option == Offset::kIgnore) {
16189 // a. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone, dateTime,
16190 // disambiguation).
16191 DirectHandle<JSTemporalInstant> instant;
16193 isolate, instant,
16194 BuiltinTimeZoneGetInstantFor(isolate, time_zone, date_time,
16195 disambiguation, method_name));
16196 // b. Return instant.[[Nanoseconds]].
16197 return direct_handle(instant->nanoseconds(), isolate);
16198 }
16199 // 5. If offsetBehaviour is exact, or offsetOption is "use", then
16200 if (offset_behaviour == OffsetBehaviour::kExact ||
16201 offset_option == Offset::kUse) {
16202 // a. Let epochNanoseconds be ? GetEpochFromISOParts(year, month, day, hour,
16203 // minute, second, millisecond, microsecond, nanosecond).
16204 DirectHandle<BigInt> epoch_nanoseconds =
16205 GetEpochFromISOParts(isolate, {data.date, data.time});
16206
16207 // b. Set epochNanoseconds to epochNanoseconds - ℤ(offsetNanoseconds).
16208 epoch_nanoseconds =
16209 BigInt::Subtract(isolate, epoch_nanoseconds,
16210 BigInt::FromInt64(isolate, offset_nanoseconds))
16211 .ToHandleChecked();
16212 // c. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
16213 // RangeError exception.
16214 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
16216 }
16217 // d. Return epochNanoseconds.
16218 return epoch_nanoseconds;
16219 }
16220 // 6. Assert: offsetBehaviour is option.
16221 DCHECK_EQ(offset_behaviour, OffsetBehaviour::kOption);
16222 // 7. Assert: offsetOption is "prefer" or "reject".
16223 DCHECK(offset_option == Offset::kPrefer || offset_option == Offset::kReject);
16224 // 8. Let possibleInstants be ? GetPossibleInstantsFor(timeZone, dateTime).
16225 DirectHandle<FixedArray> possible_instants;
16227 isolate, possible_instants,
16228 GetPossibleInstantsFor(isolate, time_zone, date_time));
16229
16230 // 9. For each element candidate of possibleInstants, do
16231 for (int i = 0; i < possible_instants->length(); i++) {
16232 DCHECK(IsJSTemporalInstant(possible_instants->get(i)));
16233 DirectHandle<JSTemporalInstant> candidate(
16234 Cast<JSTemporalInstant>(possible_instants->get(i)), isolate);
16235 // a. Let candidateNanoseconds be ? GetOffsetNanosecondsFor(timeZone,
16236 // candidate).
16237 int64_t candidate_nanoseconds;
16239 isolate, candidate_nanoseconds,
16240 GetOffsetNanosecondsFor(isolate, time_zone, candidate, method_name),
16241 DirectHandle<BigInt>());
16242 // b. If candidateNanoseconds = offsetNanoseconds, then
16243 if (candidate_nanoseconds == offset_nanoseconds) {
16244 // i. Return candidate.[[Nanoseconds]].
16245 return DirectHandle<BigInt>(candidate->nanoseconds(), isolate);
16246 }
16247 // c. If matchBehaviour is match minutes, then
16248 if (match_behaviour == MatchBehaviour::kMatchMinutes) {
16249 // i. Let roundedCandidateNanoseconds be !
16250 // RoundNumberToIncrement(candidateNanoseconds, 60 × 10^9, "halfExpand").
16251 double rounded_candidate_nanoseconds = RoundNumberToIncrement(
16252 isolate, candidate_nanoseconds, 6e10, RoundingMode::kHalfExpand);
16253 // ii. If roundedCandidateNanoseconds = offsetNanoseconds, then
16254 if (rounded_candidate_nanoseconds == offset_nanoseconds) {
16255 // 1. Return candidate.[[Nanoseconds]].
16256 return DirectHandle<BigInt>(candidate->nanoseconds(), isolate);
16257 }
16258 }
16259 }
16260 // 10. If offsetOption is "reject", throw a RangeError exception.
16261 if (offset_option == Offset::kReject) {
16263 }
16264 // 11. Let instant be ? DisambiguatePossibleInstants(possibleInstants,
16265 // timeZone, dateTime, disambiguation).
16266 DirectHandle<JSTemporalInstant> instant;
16268 isolate, instant,
16269 DisambiguatePossibleInstants(isolate, possible_instants, time_zone,
16270 date_time, disambiguation, method_name));
16271 // 12. Return instant.[[Nanoseconds]].
16272 return DirectHandle<BigInt>(instant->nanoseconds(), isolate);
16273}
16274
16275} // namespace
16276
16277// #sec-temporal.zoneddatetime.prototype.with
16279 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16280 DirectHandle<Object> temporal_zoned_date_time_like_obj,
16281 DirectHandle<Object> options_obj) {
16283 const char* method_name = "Temporal.ZonedDateTime.prototype.with";
16284 Factory* factory = isolate->factory();
16285 // 1. Let zonedDateTime be the this value.
16286 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16287 // [[InitializedTemporalZonedDateTime]]).
16288 // 3. If Type(temporalZonedDateTimeLike) is not Object, then
16289 if (!IsJSReceiver(*temporal_zoned_date_time_like_obj)) {
16290 // a. Throw a TypeError exception.
16292 }
16293 DirectHandle<JSReceiver> temporal_zoned_date_time_like =
16294 Cast<JSReceiver>(temporal_zoned_date_time_like_obj);
16295 // 4. Perform ? RejectObjectWithCalendarOrTimeZone(temporalZonedDateTimeLike).
16296 MAYBE_RETURN(RejectObjectWithCalendarOrTimeZone(
16297 isolate, temporal_zoned_date_time_like),
16299
16300 // 5. Let calendar be zonedDateTime.[[Calendar]].
16301 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
16302
16303 // 6. Let fieldNames be ? CalendarFields(calendar, « "day", "hour",
16304 // "microsecond", "millisecond", "minute", "month", "monthCode", "nanosecond",
16305 // "second", "year" »).
16306 DirectHandle<FixedArray> field_names;
16308 isolate, field_names,
16309 CalendarFields(isolate, calendar, All10UnitsInFixedArray(isolate)));
16310
16311 // 7. Append "offset" to fieldNames.
16312 int32_t field_length = field_names->length();
16313 field_names = FixedArray::SetAndGrow(isolate, field_names, field_length++,
16314 factory->offset_string());
16315 field_names->RightTrim(isolate, field_length);
16316
16317 // 8. Let partialZonedDateTime be ?
16318 // PreparePartialTemporalFields(temporalZonedDateTimeLike, fieldNames).
16319 DirectHandle<JSReceiver> partial_zoned_date_time;
16321 isolate, partial_zoned_date_time,
16322 PreparePartialTemporalFields(isolate, temporal_zoned_date_time_like,
16323 field_names));
16324 // 9. Set options to ? GetOptionsObject(options).
16327 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
16328
16329 // 10. Let disambiguation be ? ToTemporalDisambiguation(options).
16330 Disambiguation disambiguation;
16332 isolate, disambiguation,
16333 ToTemporalDisambiguation(isolate, options, method_name),
16335
16336 // 11. Let offset be ? ToTemporalOffset(options, "prefer").
16337 enum Offset offset;
16339 isolate, offset,
16340 ToTemporalOffset(isolate, options, Offset::kPrefer, method_name),
16342
16343 // 12. Let timeZone be zonedDateTime.[[TimeZone]].
16344 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16345
16346 // 13. Append "timeZone" to fieldNames.
16347 field_length = field_names->length();
16348 field_names = FixedArray::SetAndGrow(isolate, field_names, field_length++,
16349 factory->timeZone_string());
16350 field_names->RightTrim(isolate, field_length);
16351
16352 // 14. Let fields be ? PrepareTemporalFields(zonedDateTime, fieldNames, «
16353 // "timeZone", "offset"»).
16356 isolate, fields,
16357 PrepareTemporalFields(isolate, zoned_date_time, field_names,
16358 RequiredFields::kTimeZoneAndOffset));
16359 // 15. Set fields to ? CalendarMergeFields(calendar, fields,
16360 // partialZonedDateTime).
16362 isolate, fields,
16363 CalendarMergeFields(isolate, calendar, fields, partial_zoned_date_time));
16364
16365 // 16. Set fields to ? PrepareTemporalFields(fields, fieldNames, « "timeZone"
16366 // , "offset"»).
16368 isolate, fields,
16369 PrepareTemporalFields(isolate, fields, field_names,
16370 RequiredFields::kTimeZoneAndOffset));
16371
16372 // 17. Let offsetString be ? Get(fields, "offset").
16375 isolate, offset_string,
16376 JSReceiver::GetProperty(isolate, fields, factory->offset_string()));
16377
16378 // 18. Assert: Type(offsetString) is String.
16379 DCHECK(IsString(*offset_string));
16380
16381 // 19. Let dateTimeResult be ? InterpretTemporalDateTimeFields(calendar,
16382 // fields, options).
16383 temporal::DateTimeRecord date_time_result;
16385 isolate, date_time_result,
16386 InterpretTemporalDateTimeFields(isolate, calendar, fields, options,
16387 method_name),
16389
16390 // 20. Let offsetNanoseconds be ? ParseTimeZoneOffsetString(offsetString).
16391 int64_t offset_nanoseconds;
16393 isolate, offset_nanoseconds,
16394 ParseTimeZoneOffsetString(isolate, Cast<String>(offset_string)),
16396
16397 // 21. Let epochNanoseconds be ?
16398 // InterpretISODateTimeOffset(dateTimeResult.[[Year]],
16399 // dateTimeResult.[[Month]], dateTimeResult.[[Day]], dateTimeResult.[[Hour]],
16400 // dateTimeResult.[[Minute]], dateTimeResult.[[Second]],
16401 // dateTimeResult.[[Millisecond]], dateTimeResult.[[Microsecond]],
16402 // dateTimeResult.[[Nanosecond]], option, offsetNanoseconds, timeZone,
16403 // disambiguation, offset, match exactly).
16404 DirectHandle<BigInt> epoch_nanoseconds;
16406 isolate, epoch_nanoseconds,
16407 InterpretISODateTimeOffset(
16408 isolate, {date_time_result.date, date_time_result.time},
16409 OffsetBehaviour::kOption, offset_nanoseconds, time_zone,
16410 disambiguation, offset, MatchBehaviour::kMatchExactly, method_name));
16411
16412 // 27. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
16413 // calendar).
16414 return CreateTemporalZonedDateTime(isolate, epoch_nanoseconds, time_zone,
16415 calendar);
16416}
16417
16418// #sec-temporal.zoneddatetime.prototype.withcalendar
16421 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16422 DirectHandle<Object> calendar_like) {
16424 const char* method_name = "Temporal.ZonedDateTime.prototype.withCalendar";
16425 // 1. Let zonedDateTime be the this value.
16426 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16427 // [[InitializedTemporalZonedDateTime]]).
16428 // 3. Let calendar be ? ToTemporalCalendar(calendarLike).
16431 isolate, calendar,
16432 temporal::ToTemporalCalendar(isolate, calendar_like, method_name));
16433
16434 // 4. Return ? CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]],
16435 // zonedDateTime.[[TimeZone]], calendar).
16436 DirectHandle<BigInt> nanoseconds(zoned_date_time->nanoseconds(), isolate);
16437 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16438 return CreateTemporalZonedDateTime(isolate, nanoseconds, time_zone, calendar);
16439}
16440
16441// #sec-temporal.zoneddatetime.prototype.withplaindate
16444 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16445 DirectHandle<Object> plain_date_like) {
16447 const char* method_name = "Temporal.ZonedDateTime.prototype.withPlainDate";
16448 // 1. Let zonedDateTime be the this value.
16449 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16450 // [[InitializedTemporalZonedDateTime]]).
16451 // 3. Let plainDate be ? ToTemporalDate(plainDateLike).
16454 isolate, plain_date,
16455 ToTemporalDate(isolate, plain_date_like, method_name));
16456
16457 // 4. Let timeZone be zonedDateTime.[[TimeZone]].
16458 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16459 // 5. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
16462 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
16463 .ToHandleChecked();
16464
16465 // 6. Let plainDateTime be ?
16466 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
16467 // zonedDateTime.[[Calendar]]).
16470 isolate, plain_date_time,
16472 isolate, time_zone, instant,
16473 direct_handle(zoned_date_time->calendar(), isolate), method_name));
16474 // 7. Let calendar be ? ConsolidateCalendars(zonedDateTime.[[Calendar]],
16475 // plainDate.[[Calendar]]).
16478 isolate, calendar,
16479 ConsolidateCalendars(isolate,
16480 direct_handle(zoned_date_time->calendar(), isolate),
16481 direct_handle(plain_date->calendar(), isolate)));
16482
16483 // 8. Let resultPlainDateTime be ?
16484 // CreateTemporalDateTime(plainDate.[[ISOYear]], plainDate.[[ISOMonth]],
16485 // plainDate.[[ISODay]], plainDateTime.[[ISOHour]],
16486 // plainDateTime.[[ISOMinute]], plainDateTime.[[ISOSecond]],
16487 // plainDateTime.[[ISOMillisecond]], plainDateTime.[[ISOMicrosecond]],
16488 // plainDateTime.[[ISONanosecond]], calendar).
16489 DirectHandle<JSTemporalPlainDateTime> result_plain_date_time;
16491 isolate, result_plain_date_time,
16493 isolate,
16494 {{plain_date->iso_year(), plain_date->iso_month(),
16495 plain_date->iso_day()},
16496 {plain_date_time->iso_hour(), plain_date_time->iso_minute(),
16497 plain_date_time->iso_second(), plain_date_time->iso_millisecond(),
16498 plain_date_time->iso_microsecond(),
16499 plain_date_time->iso_nanosecond()}},
16500 calendar));
16501 // 9. Set instant to ? BuiltinTimeZoneGetInstantFor(timeZone,
16502 // resultPlainDateTime, "compatible").
16504 isolate, instant,
16505 BuiltinTimeZoneGetInstantFor(isolate, time_zone, result_plain_date_time,
16506 Disambiguation::kCompatible, method_name));
16507 // 10. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
16508 // calendar).
16509 return CreateTemporalZonedDateTime(
16510 isolate, direct_handle(instant->nanoseconds(), isolate), time_zone,
16511 calendar);
16512}
16513
16514// #sec-temporal.zoneddatetime.prototype.withplaintime
16517 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16518 DirectHandle<Object> plain_time_like) {
16520 const char* method_name = "Temporal.ZonedDateTime.prototype.withPlainTime";
16521 // 1. Let zonedDateTime be the this value.
16522 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16523 // [[InitializedTemporalZonedDateTime]]).
16524 // 3. If plainTimeLike is undefined, then
16526 if (IsUndefined(*plain_time_like)) {
16527 // a. Let plainTime be ? CreateTemporalTime(0, 0, 0, 0, 0, 0).
16528 ASSIGN_RETURN_ON_EXCEPTION(isolate, plain_time,
16529 CreateTemporalTime(isolate, {0, 0, 0, 0, 0, 0}));
16530 // 4. Else,
16531 } else {
16532 // a. Let plainTime be ? ToTemporalTime(plainTimeLike).
16534 isolate, plain_time,
16535 temporal::ToTemporalTime(isolate, plain_time_like, method_name));
16536 }
16537 // 5. Let timeZone be zonedDateTime.[[TimeZone]].
16538 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16539 // 6. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
16542 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
16543 .ToHandleChecked();
16544 // 7. Let calendar be zonedDateTime.[[Calendar]].
16545 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
16546 // 8. Let plainDateTime be ?
16547 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
16550 isolate, plain_date_time,
16552 calendar, method_name));
16553 // 9. Let resultPlainDateTime be ?
16554 // CreateTemporalDateTime(plainDateTime.[[ISOYear]],
16555 // plainDateTime.[[ISOMonth]], plainDateTime.[[ISODay]],
16556 // plainTime.[[ISOHour]], plainTime.[[ISOMinute]], plainTime.[[ISOSecond]],
16557 // plainTime.[[ISOMillisecond]], plainTime.[[ISOMicrosecond]],
16558 // plainTime.[[ISONanosecond]], calendar).
16559 DirectHandle<JSTemporalPlainDateTime> result_plain_date_time;
16561 isolate, result_plain_date_time,
16563 isolate,
16564 {{plain_date_time->iso_year(), plain_date_time->iso_month(),
16565 plain_date_time->iso_day()},
16566 {plain_time->iso_hour(), plain_time->iso_minute(),
16567 plain_time->iso_second(), plain_time->iso_millisecond(),
16568 plain_time->iso_microsecond(), plain_time->iso_nanosecond()}},
16569 calendar));
16570 // 10. Let instant be ? BuiltinTimeZoneGetInstantFor(timeZone,
16571 // resultPlainDateTime, "compatible").
16573 isolate, instant,
16574 BuiltinTimeZoneGetInstantFor(isolate, time_zone, result_plain_date_time,
16575 Disambiguation::kCompatible, method_name));
16576 // 11. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
16577 // calendar).
16578 return CreateTemporalZonedDateTime(
16579 isolate, direct_handle(instant->nanoseconds(), isolate), time_zone,
16580 calendar);
16581}
16582
16583// #sec-temporal.zoneddatetime.prototype.withtimezone
16586 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16587 DirectHandle<Object> time_zone_like) {
16589 const char* method_name = "Temporal.ZonedDateTime.prototype.withTimeZone";
16590 // 1. Let zonedDateTime be the this value.
16591 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16592 // [[InitializedTemporalZonedDateTime]]).
16593 // 3. Let timeZone be ? ToTemporalTimeZone(timeZoneLike).
16596 isolate, time_zone,
16597 temporal::ToTemporalTimeZone(isolate, time_zone_like, method_name));
16598
16599 // 4. Return ? CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]],
16600 // timeZone, zonedDateTime.[[Calendar]]).
16601 DirectHandle<BigInt> nanoseconds(zoned_date_time->nanoseconds(), isolate);
16602 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
16603 return CreateTemporalZonedDateTime(isolate, nanoseconds, time_zone, calendar);
16604}
16605
16606// Common code shared by ZonedDateTime.prototype.toPlainYearMonth and
16607// toPlainMonthDay
16608template <typename T, MaybeDirectHandle<T> (*from_fields_func)(
16612 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16613 DirectHandle<String> field_name_1, DirectHandle<String> field_name_2,
16614 const char* method_name) {
16616 Factory* factory = isolate->factory();
16617 // 1. Let zonedDateTime be the this value.
16618 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16619 // [[InitializedTemporalZonedDateTime]]).
16620 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
16621 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16622 // 4. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
16625 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
16626 .ToHandleChecked();
16627 // 5. Let calendar be zonedDateTime.[[Calendar]].
16628 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
16629 // 6. Let temporalDateTime be ?
16630 // temporal::BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
16631 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
16633 isolate, temporal_date_time,
16635 calendar, method_name));
16636 // 7. Let fieldNames be ? CalendarFields(calendar, « field_name_1,
16637 // field_name_2 »).
16638 DirectHandle<FixedArray> field_names = factory->NewFixedArray(2);
16639 field_names->set(0, *field_name_1);
16640 field_names->set(1, *field_name_2);
16641 ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
16642 CalendarFields(isolate, calendar, field_names));
16643 // 8. Let fields be ? PrepareTemporalFields(temporalDateTime, fieldNames, «»).
16646 isolate, fields,
16647 PrepareTemporalFields(isolate, temporal_date_time, field_names,
16648 RequiredFields::kNone));
16649 // 9. Return ? XxxFromFields(calendar, fields).
16650 return from_fields_func(isolate, calendar, fields,
16651 factory->undefined_value());
16652}
16653
16654// #sec-temporal.zoneddatetime.prototype.toplainyearmonth
16655MaybeDirectHandle<JSTemporalPlainYearMonth>
16657 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
16659 YearMonthFromFields>(
16660 isolate, zoned_date_time, isolate->factory()->monthCode_string(),
16661 isolate->factory()->year_string(),
16662 "Temporal.ZonedDateTime.prototype.toPlainYearMonth");
16663}
16664
16665// #sec-temporal.zoneddatetime.prototype.toplainmonthday
16668 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
16670 MonthDayFromFields>(
16671 isolate, zoned_date_time, isolate->factory()->day_string(),
16672 isolate->factory()->monthCode_string(),
16673 "Temporal.ZonedDateTime.prototype.toPlainMonthDay");
16674}
16675
16676namespace {
16677
16678// #sec-temporal-temporalzoneddatetimetostring
16679MaybeDirectHandle<String> TemporalZonedDateTimeToString(
16680 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16681 Precision precision, ShowCalendar show_calendar,
16682 ShowTimeZone show_time_zone, ShowOffset show_offset, double increment,
16683 Unit unit, RoundingMode rounding_mode, const char* method_name) {
16684 // 4. Let ns be ! RoundTemporalInstant(zonedDateTime.[[Nanoseconds]],
16685 // increment, unit, roundingMode).
16686 DirectHandle<BigInt> ns = RoundTemporalInstant(
16687 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate),
16689
16690 // 5. Let timeZone be zonedDateTime.[[TimeZone]].
16691 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16692 // 6. Let instant be ! CreateTemporalInstant(ns).
16694 temporal::CreateTemporalInstant(isolate, ns).ToHandleChecked();
16695
16696 // 7. Let isoCalendar be ! GetISO8601Calendar().
16699
16700 // 8. Let temporalDateTime be ?
16701 // BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
16702 // isoCalendar).
16703 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
16705 isolate, temporal_date_time,
16707 iso_calendar, method_name));
16708 // 9. Let dateTimeString be ?
16709 // TemporalDateTimeToString(temporalDateTime.[[ISOYear]],
16710 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]],
16711 // temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]],
16712 // temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]],
16713 // temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]],
16714 // isoCalendar, precision, "never").
16715 DirectHandle<String> date_time_string;
16717 isolate, date_time_string,
16718 TemporalDateTimeToString(
16719 isolate,
16720 {{temporal_date_time->iso_year(), temporal_date_time->iso_month(),
16721 temporal_date_time->iso_day()},
16722 {temporal_date_time->iso_hour(), temporal_date_time->iso_minute(),
16723 temporal_date_time->iso_second(),
16724 temporal_date_time->iso_millisecond(),
16725 temporal_date_time->iso_microsecond(),
16726 temporal_date_time->iso_nanosecond()}},
16727 iso_calendar, precision, ShowCalendar::kNever));
16728
16729 IncrementalStringBuilder builder(isolate);
16730 builder.AppendString(date_time_string);
16731
16732 // 10. If showOffset is "never", then
16733 if (show_offset == ShowOffset::kNever) {
16734 // a. Let offsetString be the empty String.
16735 // 11. Else,
16736 } else {
16737 // a. Let offsetNs be ? GetOffsetNanosecondsFor(timeZone, instant).
16738 int64_t offset_ns;
16740 isolate, offset_ns,
16741 GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
16742 DirectHandle<String>());
16743 // b. Let offsetString be ! FormatISOTimeZoneOffsetString(offsetNs).
16744 builder.AppendString(FormatISOTimeZoneOffsetString(isolate, offset_ns));
16745 }
16746
16747 // 12. If showTimeZone is "never", then
16748 if (show_time_zone == ShowTimeZone::kNever) {
16749 // a. Let timeZoneString be the empty String.
16750 // 13. Else,
16751 } else {
16752 // a. Let timeZoneID be ? ToString(timeZone).
16753 DirectHandle<String> time_zone_id;
16754 ASSIGN_RETURN_ON_EXCEPTION(isolate, time_zone_id,
16755 Object::ToString(isolate, time_zone));
16756 // b. Let timeZoneString be the string-concatenation of the code unit 0x005B
16757 // (LEFT SQUARE BRACKET), timeZoneID, and the code unit 0x005D (RIGHT SQUARE
16758 // BRACKET).
16759 builder.AppendCStringLiteral("[");
16760 builder.AppendString(time_zone_id);
16761 builder.AppendCStringLiteral("]");
16762 }
16763 // 14. Let calendarString be ?
16764 // MaybeFormatCalendarAnnotation(zonedDateTime.[[Calendar]], showCalendar).
16765 DirectHandle<String> calendar_string;
16767 isolate, calendar_string,
16768 MaybeFormatCalendarAnnotation(
16769 isolate, direct_handle(zoned_date_time->calendar(), isolate),
16770 show_calendar));
16771
16772 // 15. Return the string-concatenation of dateTimeString, offsetString,
16773 // timeZoneString, and calendarString.
16774 builder.AppendString(calendar_string);
16775 return builder.Finish();
16776}
16777
16778// #sec-temporal-temporalzoneddatetimetostring
16779MaybeDirectHandle<String> TemporalZonedDateTimeToString(
16780 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16781 Precision precision, ShowCalendar show_calendar,
16782 ShowTimeZone show_time_zone, ShowOffset show_offset,
16783 const char* method_name) {
16784 // 1. Assert: Type(zonedDateTime) is Object and zonedDateTime has an
16785 // [[InitializedTemporalZonedDateTime]] internal slot.
16786 // 2. If increment is not present, set it to 1.
16787 // 3. If unit is not present, set it to "nanosecond".
16788 // 4. If roundingMode is not present, set it to "trunc".
16789 return TemporalZonedDateTimeToString(
16790 isolate, zoned_date_time, precision, show_calendar, show_time_zone,
16791 show_offset, 1, Unit::kNanosecond, RoundingMode::kTrunc, method_name);
16792}
16793
16794} // namespace
16795// #sec-temporal.zoneddatetime.prototype.tojson
16797 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
16799 // 1. Let zonedDateTime be the this value.
16800 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16801 // [[InitializedTemporalZonedDateTime]]).
16802 // 3. Return ? TemporalZonedDateTimeToString(zonedDateTime, "auto", "auto",
16803 // "auto", "auto").
16804 return TemporalZonedDateTimeToString(
16805 isolate, zoned_date_time, Precision::kAuto, ShowCalendar::kAuto,
16806 ShowTimeZone::kAuto, ShowOffset::kAuto,
16807 "Temporal.ZonedDateTime.prototype.toJSON");
16808}
16809
16810// #sec-temporal.zoneddatetime.prototype.tolocalestring
16812 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16813 DirectHandle<Object> locales, DirectHandle<Object> options) {
16814 const char* method_name = "Temporal.ZonedDateTime.prototype.toLocaleString";
16815#ifdef V8_INTL_SUPPORT
16817 isolate, zoned_date_time, locales, options, method_name);
16818#else // V8_INTL_SUPPORT
16819 return TemporalZonedDateTimeToString(
16820 isolate, zoned_date_time, Precision::kAuto, ShowCalendar::kAuto,
16821 ShowTimeZone::kAuto, ShowOffset::kAuto, method_name);
16822#endif // V8_INTL_SUPPORT
16823}
16824
16825// #sec-temporal.zoneddatetime.prototype.tostring
16827 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16828 DirectHandle<Object> options_obj) {
16829 const char* method_name = "Temporal.ZonedDateTime.prototype.toString";
16830 // 1. Let zonedDateTime be the this value.
16831 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16832 // [[InitializedTemporalZonedDateTime]]).
16833 // 3. Set options to ? GetOptionsObject(options).
16836 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
16837
16838 // 4. Let precision be ? ToSecondsStringPrecision(options).
16839 StringPrecision precision;
16841 isolate, precision,
16842 ToSecondsStringPrecision(isolate, options, method_name),
16844
16845 // 5. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
16848 isolate, rounding_mode,
16849 ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
16850 method_name),
16852
16853 // 6. Let showCalendar be ? ToShowCalendarOption(options).
16854 ShowCalendar show_calendar;
16856 isolate, show_calendar,
16857 ToShowCalendarOption(isolate, options, method_name),
16859
16860 // 7. Let showTimeZone be ? ToShowTimeZoneNameOption(options).
16861 ShowTimeZone show_time_zone;
16863 isolate, show_time_zone,
16864 ToShowTimeZoneNameOption(isolate, options, method_name),
16866
16867 // 8. Let showOffset be ? ToShowOffsetOption(options).
16868 ShowOffset show_offset;
16870 isolate, show_offset, ToShowOffsetOption(isolate, options, method_name),
16872
16873 // 9. Return ? TemporalZonedDateTimeToString(zonedDateTime,
16874 // precision.[[Precision]], showCalendar, showTimeZone, showOffset,
16875 // precision.[[Increment]], precision.[[Unit]], roundingMode).
16876 return TemporalZonedDateTimeToString(
16877 isolate, zoned_date_time, precision.precision, show_calendar,
16878 show_time_zone, show_offset, precision.increment, precision.unit,
16879 rounding_mode, method_name);
16880}
16881
16882// #sec-temporal.now.zoneddatetime
16884 Isolate* isolate, DirectHandle<Object> calendar_like,
16885 DirectHandle<Object> temporal_time_zone_like) {
16886 const char* method_name = "Temporal.Now.zonedDateTime";
16887 // 1. Return ? SystemZonedDateTime(temporalTimeZoneLike, calendarLike).
16888 return SystemZonedDateTime(isolate, temporal_time_zone_like, calendar_like,
16889 method_name);
16890}
16891
16892// #sec-temporal.now.zoneddatetimeiso
16894 Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
16896 const char* method_name = "Temporal.Now.zonedDateTimeISO";
16897 // 1. Let calendar be ! GetISO8601Calendar().
16899 // 2. Return ? SystemZonedDateTime(temporalTimeZoneLike, calendar).
16900 return SystemZonedDateTime(isolate, temporal_time_zone_like, calendar,
16901 method_name);
16902}
16903
16904// #sec-temporal.zoneddatetime.prototype.round
16906 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
16907 DirectHandle<Object> round_to_obj) {
16908 const char* method_name = "Temporal.ZonedDateTime.prototype.round";
16909 Factory* factory = isolate->factory();
16910 // 1. Let temporalTime be the this value.
16911 // 2. Perform ? RequireInternalSlot(zonedDateTime,
16912 // [[InitializedTemporalZonedDateTime]]).
16913 // 3. If roundTo is undefined, then
16914 if (IsUndefined(*round_to_obj)) {
16915 // a. Throw a TypeError exception.
16917 }
16918
16919 DirectHandle<JSReceiver> round_to;
16920 // 4. If Type(roundTo) is String, then
16921 if (IsString(*round_to_obj)) {
16922 // a. Let paramString be roundTo.
16923 DirectHandle<String> param_string = Cast<String>(round_to_obj);
16924 // b. Set roundTo to ! OrdinaryObjectCreate(null).
16925 round_to = factory->NewJSObjectWithNullProto();
16926 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit",
16927 // paramString).
16928 CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
16929 factory->smallestUnit_string(),
16930 param_string, Just(kThrowOnError))
16931 .FromJust());
16932 // 5. Else
16933 } else {
16934 // a. Set roundTo to ? GetOptionsObject(roundTo).
16936 isolate, round_to,
16937 GetOptionsObject(isolate, round_to_obj, method_name));
16938 }
16939
16940 // 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time,
16941 // required, « "day" »).
16942 Unit smallest_unit;
16944 isolate, smallest_unit,
16945 GetTemporalUnit(isolate, round_to, "smallestUnit", UnitGroup::kTime,
16946 Unit::kDay, true, method_name, Unit::kDay),
16948
16949 // 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
16952 isolate, rounding_mode,
16953 ToTemporalRoundingMode(isolate, round_to, RoundingMode::kHalfExpand,
16954 method_name),
16956
16957 // 8. Let roundingIncrement be ? ToTemporalDateTimeRoundingIncrement(roundTo,
16958 // smallestUnit).
16959 double rounding_increment;
16961 isolate, rounding_increment,
16962 ToTemporalDateTimeRoundingIncrement(isolate, round_to, smallest_unit),
16964
16965 // 9. Let timeZone be zonedDateTime.[[TimeZone]].
16966 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
16967 // 10. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
16970 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
16971 .ToHandleChecked();
16972 // 11. Let calendar be zonedDateTime.[[Calendar]].
16973 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
16974 // 12. Let temporalDateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone,
16975 // instant, calendar).
16976 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
16978 isolate, temporal_date_time,
16980 calendar, method_name));
16981 // 13. Let isoCalendar be ! GetISO8601Calendar().
16983
16984 // 14. Let dtStart be ? CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
16985 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0, 0,
16986 // 0, isoCalendar).
16989 isolate, dt_start,
16991 isolate,
16992 {{temporal_date_time->iso_year(), temporal_date_time->iso_month(),
16993 temporal_date_time->iso_day()},
16994 {0, 0, 0, 0, 0, 0}},
16995 iso_calendar));
16996 // 15. Let instantStart be ? BuiltinTimeZoneGetInstantFor(timeZone, dtStart,
16997 // "compatible").
16998 DirectHandle<JSTemporalInstant> instant_start;
17000 isolate, instant_start,
17001 BuiltinTimeZoneGetInstantFor(isolate, time_zone, dt_start,
17002 Disambiguation::kCompatible, method_name));
17003 // 16. Let startNs be instantStart.[[Nanoseconds]].
17004 DirectHandle<BigInt> start_ns(instant_start->nanoseconds(), isolate);
17005 // 17. Let endNs be ? AddZonedDateTime(startNs, timeZone, calendar, 0, 0, 0,
17006 // 1, 0, 0, 0, 0, 0, 0).
17007 DirectHandle<BigInt> end_ns;
17009 isolate, end_ns,
17010 AddZonedDateTime(isolate, start_ns, time_zone, calendar,
17011 {0, 0, 0, {1, 0, 0, 0, 0, 0, 0}}, method_name));
17012 // 18. Let dayLengthNs be ℝ(endNs - startNs).
17013 DirectHandle<BigInt> day_length_ns =
17014 BigInt::Subtract(isolate, end_ns, start_ns).ToHandleChecked();
17015 // 19. If dayLengthNs ≤ 0, then
17016 if (day_length_ns->IsNegative() || !day_length_ns->ToBoolean()) {
17017 // a. Throw a RangeError exception.
17019 }
17020 // 20. Let roundResult be ! RoundISODateTime(temporalDateTime.[[ISOYear]],
17021 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]],
17022 // temporalDateTime.[[ISOHour]], temporalDateTime.[[ISOMinute]],
17023 // temporalDateTime.[[ISOSecond]], temporalDateTime.[[ISOMillisecond]],
17024 // temporalDateTime.[[ISOMicrosecond]], temporalDateTime.[[ISONanosecond]],
17025 // roundingIncrement, smallestUnit, roundingMode, dayLengthNs).
17026 DateTimeRecord round_result = RoundISODateTime(
17027 isolate,
17028 {{temporal_date_time->iso_year(), temporal_date_time->iso_month(),
17029 temporal_date_time->iso_day()},
17030 {temporal_date_time->iso_hour(), temporal_date_time->iso_minute(),
17031 temporal_date_time->iso_second(), temporal_date_time->iso_millisecond(),
17032 temporal_date_time->iso_microsecond(),
17033 temporal_date_time->iso_nanosecond()}},
17035 Object::NumberValue(*BigInt::ToNumber(isolate, day_length_ns)));
17036 // 21. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
17037 int64_t offset_nanoseconds;
17039 isolate, offset_nanoseconds,
17040 GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
17042 // 22. Let epochNanoseconds be ?
17043 // InterpretISODateTimeOffset(roundResult.[[Year]], roundResult.[[Month]],
17044 // roundResult.[[Day]], roundResult.[[Hour]], roundResult.[[Minute]],
17045 // roundResult.[[Second]], roundResult.[[Millisecond]],
17046 // roundResult.[[Microsecond]], roundResult.[[Nanosecond]], option,
17047 // offsetNanoseconds, timeZone, "compatible", "prefer", match exactly).
17048 DirectHandle<BigInt> epoch_nanoseconds;
17050 isolate, epoch_nanoseconds,
17051 InterpretISODateTimeOffset(
17052 isolate, round_result, OffsetBehaviour::kOption, offset_nanoseconds,
17053 time_zone, Disambiguation::kCompatible, Offset::kPrefer,
17054 MatchBehaviour::kMatchExactly, method_name));
17055
17056 // 23. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
17057 // calendar).
17058 return CreateTemporalZonedDateTime(isolate, epoch_nanoseconds, time_zone,
17059 calendar)
17060 .ToHandleChecked();
17061}
17062
17063namespace {
17064
17065// #sec-temporal-adddurationtoOrsubtractdurationfromzoneddatetime
17067AddDurationToOrSubtractDurationFromZonedDateTime(
17068 Isolate* isolate, Arithmetic operation,
17070 DirectHandle<Object> temporal_duration_like,
17071 DirectHandle<Object> options_obj, const char* method_name) {
17073 // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
17074 double sign = operation == Arithmetic::kSubtract ? -1.0 : 1.0;
17075 // 2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
17076 DurationRecord duration;
17078 isolate, duration,
17079 temporal::ToTemporalDurationRecord(isolate, temporal_duration_like,
17080 method_name),
17082
17083 TimeDurationRecord& time_duration = duration.time_duration;
17084
17085 // 3. Set options to ? GetOptionsObject(options).
17088 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
17089
17090 // 4. Let timeZone be zonedDateTime.[[TimeZone]].
17091 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
17092 // 5. Let calendar be zonedDateTime.[[Calendar]].
17093 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
17094 // 6. Let epochNanoseconds be ?
17095 // AddZonedDateTime(zonedDateTime.[[Nanoseconds]], timeZone, calendar,
17096 // sign x duration.[[Years]], sign x duration.[[Months]], sign x
17097 // duration.[[Weeks]], sign x duration.[[Days]], sign x duration.[[Hours]],
17098 // sign x duration.[[Minutes]], sign x duration.[[Seconds]], sign x
17099 // duration.[[Milliseconds]], sign x duration.[[Microseconds]], sign x
17100 // duration.[[Nanoseconds]], options).
17101 DirectHandle<BigInt> nanoseconds(zoned_date_time->nanoseconds(), isolate);
17102 duration.years *= sign;
17103 duration.months *= sign;
17104 duration.weeks *= sign;
17105 time_duration.days *= sign;
17106 time_duration.hours *= sign;
17107 time_duration.minutes *= sign;
17108 time_duration.seconds *= sign;
17109 time_duration.milliseconds *= sign;
17110 time_duration.microseconds *= sign;
17111 time_duration.nanoseconds *= sign;
17112 DirectHandle<BigInt> epoch_nanoseconds;
17114 isolate, epoch_nanoseconds,
17115 AddZonedDateTime(isolate, nanoseconds, time_zone, calendar, duration,
17116 options, method_name));
17117
17118 // 7. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone,
17119 // calendar).
17120 return CreateTemporalZonedDateTime(isolate, epoch_nanoseconds, time_zone,
17121 calendar);
17122}
17123
17124} // namespace
17125
17126// #sec-temporal.zoneddatetime.prototype.add
17128 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
17129 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
17131 return AddDurationToOrSubtractDurationFromZonedDateTime(
17132 isolate, Arithmetic::kAdd, zoned_date_time, temporal_duration_like,
17133 options, "Temporal.ZonedDateTime.prototype.add");
17134}
17135// #sec-temporal.zoneddatetime.prototype.subtract
17137 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
17138 DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
17140 return AddDurationToOrSubtractDurationFromZonedDateTime(
17141 isolate, Arithmetic::kSubtract, zoned_date_time, temporal_duration_like,
17142 options, "Temporal.ZonedDateTime.prototype.subtract");
17143}
17144
17145namespace {
17146
17147// #sec-temporal-differencetemporalzoneddatetime
17148MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalZonedDateTime(
17149 Isolate* isolate, TimePreposition operation,
17151 DirectHandle<Object> other_obj, DirectHandle<Object> options,
17152 const char* method_name) {
17154 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
17155 double sign = operation == TimePreposition::kSince ? -1 : 1;
17156 // 2. Set other to ? ToTemporalZonedDateTime(other).
17159 isolate, other, ToTemporalZonedDateTime(isolate, other_obj, method_name));
17160 // 3. If ? CalendarEquals(zonedDateTime.[[Calendar]], other.[[Calendar]]) is
17161 // false, then
17162 bool calendar_equals;
17164 isolate, calendar_equals,
17165 CalendarEqualsBool(isolate,
17166 direct_handle(zoned_date_time->calendar(), isolate),
17167 direct_handle(other->calendar(), isolate)),
17169 if (!calendar_equals) {
17170 // a. Throw a RangeError exception.
17172 }
17173 // 4. Let settings be ? GetDifferenceSettings(operation, options, datetime, «
17174 // », "nanosecond", "hour").
17175 DifferenceSettings settings;
17177 isolate, settings,
17178 GetDifferenceSettings(isolate, operation, options, UnitGroup::kDateTime,
17179 DisallowedUnitsInDifferenceSettings::kNone,
17180 Unit::kNanosecond, Unit::kHour, method_name),
17181 DirectHandle<JSTemporalDuration>());
17182
17183 // 5. If settings.[[LargestUnit]] is not one of "year", "month", "week", or
17184 // "day", then
17185 if (settings.largest_unit != Unit::kYear &&
17186 settings.largest_unit != Unit::kMonth &&
17187 settings.largest_unit != Unit::kWeek &&
17188 settings.largest_unit != Unit::kDay) {
17189 // 1. Let result be ! DifferenceInstant(zonedDateTime.[[Nanoseconds]],
17190 // other.[[Nanoseconds]], settings.[[RoundingIncrement]],
17191 // settings.[[SmallestUnit]], settings.[[LargestUnit]],
17192 // settings.[[RoundingMode]]).
17193 TimeDurationRecord balance_result = DifferenceInstant(
17194 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate),
17195 direct_handle(other->nanoseconds(), isolate),
17196 settings.rounding_increment, settings.smallest_unit,
17197 settings.largest_unit, settings.rounding_mode, method_name);
17198 // d. Return ! CreateTemporalDuration(0, 0, 0, 0, sign ×
17199 // balanceResult.[[Hours]], sign × balanceResult.[[Minutes]], sign ×
17200 // balanceResult.[[Seconds]], sign × balanceResult.[[Milliseconds]], sign ×
17201 // balanceResult.[[Microseconds]], sign × balanceResult.[[Nanoseconds]]).
17202 return CreateTemporalDuration(
17203 isolate,
17204 {0,
17205 0,
17206 0,
17207 {0, sign * balance_result.hours, sign * balance_result.minutes,
17208 sign * balance_result.seconds,
17209 sign * balance_result.milliseconds,
17210 sign * balance_result.microseconds,
17211 sign * balance_result.nanoseconds}})
17212 .ToHandleChecked();
17213 }
17214 // 6. If ? TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is
17215 // false, then
17216 bool equals;
17218 isolate, equals,
17219 TimeZoneEquals(isolate,
17220 direct_handle(zoned_date_time->time_zone(), isolate),
17221 direct_handle(other->time_zone(), isolate)),
17222 DirectHandle<JSTemporalDuration>());
17223 if (!equals) {
17224 // a. Throw a RangeError exception.
17226 }
17227 // 7. Let untilOptions be ? MergeLargestUnitOption(settings.[[Options]],
17228 // settings.[[LargestUnit]]).
17229 DirectHandle<JSReceiver> until_options;
17231 isolate, until_options,
17232 MergeLargestUnitOption(isolate, settings.options, settings.largest_unit));
17233 // 8. Let difference be ?
17234 // DifferenceZonedDateTime(zonedDateTime.[[Nanoseconds]],
17235 // other.[[Nanoseconds]], zonedDateTime.[[TimeZone]],
17236 // zonedDateTime.[[Calendar]], settings.[[LargestUnit]], untilOptions).
17237 DurationRecord difference;
17239 isolate, difference,
17240 DifferenceZonedDateTime(
17241 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate),
17242 direct_handle(other->nanoseconds(), isolate),
17243 direct_handle(zoned_date_time->time_zone(), isolate),
17244 direct_handle(zoned_date_time->calendar(), isolate),
17245 settings.largest_unit, until_options, method_name),
17246 DirectHandle<JSTemporalDuration>());
17247
17248 // 9. Let roundResult be (? RoundDuration(difference.[[Years]],
17249 // difference.[[Months]], difference.[[Weeks]], difference.[[Days]],
17250 // difference.[[Hours]], difference.[[Minutes]], difference.[[Seconds]],
17251 // difference.[[Milliseconds]], difference.[[Microseconds]],
17252 // difference.[[Nanoseconds]], settings.[[RoundingIncrement]],
17253 // settings.[[SmallestUnit]], settings.[[RoundingMode]],
17254 // zonedDateTime)).[[DurationRecord]].
17255 DurationRecordWithRemainder round_result;
17257 isolate, round_result,
17258 RoundDuration(isolate, difference, settings.rounding_increment,
17259 settings.smallest_unit, settings.rounding_mode,
17260 zoned_date_time, method_name),
17261 DirectHandle<JSTemporalDuration>());
17262 // 10. Let result be ? AdjustRoundedDurationDays(roundResult.[[Years]],
17263 // roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]],
17264 // roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]],
17265 // roundResult.[[Milliseconds]], roundResult.[[Microseconds]],
17266 // roundResult.[[Nanoseconds]], settings.[[RoundingIncrement]],
17267 // settings.[[SmallestUnit]], settings.[[RoundingMode]], zonedDateTime).
17268 DurationRecord result;
17270 isolate, result,
17271 AdjustRoundedDurationDays(isolate, round_result.record,
17272 settings.rounding_increment,
17273 settings.smallest_unit, settings.rounding_mode,
17274 zoned_date_time, method_name),
17275 DirectHandle<JSTemporalDuration>());
17276
17277 // 11. Return ! CreateTemporalDuration(sign × result.[[Years]], sign ×
17278 // result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], sign ×
17279 // result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]],
17280 // sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign ×
17281 // result.[[Nanoseconds]]).
17282 return CreateTemporalDuration(isolate,
17283 {sign * result.years,
17284 sign * result.months,
17285 sign * result.weeks,
17286 {sign * result.time_duration.days,
17287 sign * result.time_duration.hours,
17288 sign * result.time_duration.minutes,
17289 sign * result.time_duration.seconds,
17290 sign * result.time_duration.milliseconds,
17291 sign * result.time_duration.microseconds,
17292 sign * result.time_duration.nanoseconds}})
17293 .ToHandleChecked();
17294}
17295
17296} // namespace
17297
17298// #sec-temporal.zoneddatetime.prototype.until
17303 return DifferenceTemporalZonedDateTime(
17304 isolate, TimePreposition::kUntil, handle, other, options,
17305 "Temporal.ZonedDateTime.prototype.until");
17306}
17307
17308// #sec-temporal.zoneddatetime.prototype.since
17313 return DifferenceTemporalZonedDateTime(
17314 isolate, TimePreposition::kSince, handle, other, options,
17315 "Temporal.ZonedDateTime.prototype.since");
17316}
17317
17318// #sec-temporal.zoneddatetime.prototype.getisofields
17320 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17322 const char* method_name = "Temporal.ZonedDateTime.prototype.getISOFields";
17323 Factory* factory = isolate->factory();
17324 // 1. Let zonedDateTime be the this value.
17325 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17326 // [[InitializedTemporalZonedDateTime]]).
17327 // 3. Let fields be ! OrdinaryObjectCreate(%Object.prototype%).
17328 DirectHandle<JSObject> fields =
17329 isolate->factory()->NewJSObject(isolate->object_function());
17330 // 4. Let timeZone be zonedDateTime.[[TimeZone]].
17331 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
17332 // 5. Let instant be ? CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17335 isolate, instant,
17337 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate)));
17338
17339 // 6. Let calendar be zonedDateTime.[[Calendar]].
17340 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
17341 // 7. Let dateTime be ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone,
17342 // instant, calendar).
17345 isolate, date_time,
17347 calendar, method_name));
17348 // 8. Let offset be ? BuiltinTimeZoneGetOffsetStringFor(timeZone, instant).
17351 BuiltinTimeZoneGetOffsetStringFor(
17352 isolate, time_zone, instant, method_name));
17353
17354#define DEFINE_STRING_FIELD(obj, str, field) \
17355 CHECK(JSReceiver::CreateDataProperty(isolate, obj, factory->str##_string(), \
17356 field, Just(kThrowOnError)) \
17357 .FromJust());
17358
17359 // 9. Perform ! CreateDataPropertyOrThrow(fields, "calendar", calendar).
17360 // 10. Perform ! CreateDataPropertyOrThrow(fields, "isoDay",
17361 // 𝔽(dateTime.[[ISODay]])).
17362 // 11. Perform ! CreateDataPropertyOrThrow(fields, "isoHour",
17363 // 𝔽(temporalTime.[[ISOHour]])).
17364 // 12. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond",
17365 // 𝔽(temporalTime.[[ISOMicrosecond]])).
17366 // 13. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond",
17367 // 𝔽(temporalTime.[[ISOMillisecond]])).
17368 // 14. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute",
17369 // 𝔽(temporalTime.[[ISOMinute]])).
17370 // 15. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth",
17371 // 𝔽(temporalTime.[[ISOMonth]])).
17372 // 16. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond",
17373 // 𝔽(temporalTime.[[ISONanosecond]])).
17374 // 17. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond",
17375 // 𝔽(temporalTime.[[ISOSecond]])).
17376 // 18. Perform ! CreateDataPropertyOrThrow(fields, "isoYear",
17377 // 𝔽(temporalTime.[[ISOYear]])).
17378 // 19. Perform ! CreateDataPropertyOrThrow(fields, "offset", offset).
17379 // 20. Perform ! CreateDataPropertyOrThrow(fields, "timeZone", timeZone).
17381 DEFINE_INT_FIELD(fields, isoDay, iso_day, date_time)
17382 DEFINE_INT_FIELD(fields, isoHour, iso_hour, date_time)
17383 DEFINE_INT_FIELD(fields, isoMicrosecond, iso_microsecond, date_time)
17384 DEFINE_INT_FIELD(fields, isoMillisecond, iso_millisecond, date_time)
17385 DEFINE_INT_FIELD(fields, isoMinute, iso_minute, date_time)
17386 DEFINE_INT_FIELD(fields, isoMonth, iso_month, date_time)
17387 DEFINE_INT_FIELD(fields, isoNanosecond, iso_nanosecond, date_time)
17388 DEFINE_INT_FIELD(fields, isoSecond, iso_second, date_time)
17389 DEFINE_INT_FIELD(fields, isoYear, iso_year, date_time)
17391 DEFINE_STRING_FIELD(fields, timeZone, time_zone)
17392 // 21. Return fields.
17393 return fields;
17394}
17395
17396// #sec-temporal.now.instant
17399 return SystemInstant(isolate);
17400}
17401
17402// #sec-get-temporal.zoneddatetime.prototype.offsetnanoseconds
17404 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17406 // 1. Let zonedDateTime be the this value.
17407 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17408 // [[InitializedTemporalZonedDateTime]]).
17409 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
17410 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
17411 // 4. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17414 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
17415 .ToHandleChecked();
17416 // 5. Return 𝔽(? GetOffsetNanosecondsFor(timeZone, instant)).
17417 int64_t result;
17419 isolate, result,
17420 GetOffsetNanosecondsFor(
17421 isolate, time_zone, instant,
17422 "Temporal.ZonedDateTime.prototype.offsetNanoseconds"),
17424 return isolate->factory()->NewNumberFromInt64(result);
17425}
17426
17427// #sec-get-temporal.zoneddatetime.prototype.offset
17429 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17431 // 1. Let zonedDateTime be the this value.
17432 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17433 // [[InitializedTemporalZonedDateTime]]).
17434 // 3. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17437 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
17438 .ToHandleChecked();
17439 // 4. Return ? BuiltinTimeZoneGetOffsetStringFor(zonedDateTime.[[TimeZone]],
17440 // instant).
17441 return BuiltinTimeZoneGetOffsetStringFor(
17442 isolate, direct_handle(zoned_date_time->time_zone(), isolate), instant,
17443 "Temporal.ZonedDateTime.prototype.offset");
17444}
17445
17446// #sec-temporal.zoneddatetime.prototype.startofday
17448 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17450 const char* method_name = "Temporal.ZonedDateTime.prototype.startOfDay";
17451 // 1. Let zonedDateTime be the this value.
17452 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17453 // [[InitializedTemporalZonedDateTime]]).
17454 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
17455 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
17456 // 4. Let calendar be zonedDateTime.[[Calendar]].
17457 DirectHandle<JSReceiver> calendar(zoned_date_time->calendar(), isolate);
17458 // 5. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17461 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
17462 .ToHandleChecked();
17463 // 6. Let temporalDateTime be ?
17464 // BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant, calendar).
17465 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
17467 isolate, temporal_date_time,
17469 calendar, method_name));
17470 // 7. Let startDateTime be ?
17471 // CreateTemporalDateTime(temporalDateTime.[[ISOYear]],
17472 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], 0, 0, 0, 0, 0,
17473 // 0, calendar).
17476 isolate, start_date_time,
17478 isolate,
17479 {{temporal_date_time->iso_year(), temporal_date_time->iso_month(),
17480 temporal_date_time->iso_day()},
17481 {0, 0, 0, 0, 0, 0}},
17482 calendar));
17483 // 8. Let startInstant be ? BuiltinTimeZoneGetInstantFor(timeZone,
17484 // startDateTime, "compatible").
17485 DirectHandle<JSTemporalInstant> start_instant;
17487 isolate, start_instant,
17488 BuiltinTimeZoneGetInstantFor(isolate, time_zone, start_date_time,
17489 Disambiguation::kCompatible, method_name));
17490 // 9. Return ? CreateTemporalZonedDateTime(startInstant.[[Nanoseconds]],
17491 // timeZone, calendar).
17492 return CreateTemporalZonedDateTime(
17493 isolate, direct_handle(start_instant->nanoseconds(), isolate), time_zone,
17494 calendar);
17495}
17496
17497// #sec-temporal.zoneddatetime.prototype.toinstant
17499 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17501 // 1. Let zonedDateTime be the this value.
17502 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17503 // [[InitializedTemporalZonedDateTime]]).
17504 // 3. Return ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17506 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
17507 .ToHandleChecked();
17508}
17509
17510namespace {
17511
17512// Function implement shared steps of toplaindate, toplaintime, toplaindatetime
17513MaybeDirectHandle<JSTemporalPlainDateTime> ZonedDateTimeToPlainDateTime(
17514 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
17515 const char* method_name) {
17517 // 1. Let zonedDateTime be the this value.
17518 // 2. Perform ? RequireInternalSlot(zonedDateTime,
17519 // [[InitializedTemporalZonedDateTime]]).
17520 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
17521 DirectHandle<JSReceiver> time_zone(zoned_date_time->time_zone(), isolate);
17522 // 4. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
17525 isolate, direct_handle(zoned_date_time->nanoseconds(), isolate))
17526 .ToHandleChecked();
17527 // 5. 5. Return ? BuiltinTimeZoneGetPlainDateTimeFor(timeZone, instant,
17528 // zonedDateTime.[[Calendar]]).
17530 isolate, time_zone, instant,
17531 direct_handle(zoned_date_time->calendar(), isolate), method_name);
17532}
17533
17534} // namespace
17535
17536// #sec-temporal.zoneddatetime.prototype.toplaindate
17538 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17539 // Step 1-6 are the same as toplaindatetime
17540 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
17542 isolate, temporal_date_time,
17543 ZonedDateTimeToPlainDateTime(
17544 isolate, zoned_date_time,
17545 "Temporal.ZonedDateTime.prototype.toPlainDate"));
17546 // 7. Return ? CreateTemporalDate(temporalDateTime.[[ISOYear]],
17547 // temporalDateTime.[[ISOMonth]], temporalDateTime.[[ISODay]], calendar).
17548 return CreateTemporalDate(
17549 isolate,
17550 {temporal_date_time->iso_year(), temporal_date_time->iso_month(),
17551 temporal_date_time->iso_day()},
17552 direct_handle(zoned_date_time->calendar(), isolate));
17553}
17554
17555// #sec-temporal.zoneddatetime.prototype.toplaintime
17557 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17558 // Step 1-6 are the same as toplaindatetime
17559 DirectHandle<JSTemporalPlainDateTime> temporal_date_time;
17561 isolate, temporal_date_time,
17562 ZonedDateTimeToPlainDateTime(
17563 isolate, zoned_date_time,
17564 "Temporal.ZonedDateTime.prototype.toPlainTime"));
17565 // 7. Return ? CreateTemporalTime(temporalDateTime.[[ISOHour]],
17566 // temporalDateTime.[[ISOMinute]], temporalDateTime.[[ISOSecond]],
17567 // temporalDateTime.[[ISOMillisecond]], temporalDateTime.[[ISOMicrosecond]],
17568 // temporalDateTime.[[ISONanosecond]]).
17569 return CreateTemporalTime(
17570 isolate,
17571 {temporal_date_time->iso_hour(), temporal_date_time->iso_minute(),
17572 temporal_date_time->iso_second(), temporal_date_time->iso_millisecond(),
17573 temporal_date_time->iso_microsecond(),
17574 temporal_date_time->iso_nanosecond()});
17575}
17576
17577// #sec-temporal.zoneddatetime.prototype.toplaindatetime
17580 Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
17581 return ZonedDateTimeToPlainDateTime(
17582 isolate, zoned_date_time,
17583 "Temporal.ZonedDateTime.prototype.toPlainDateTime");
17584}
17585
17586// #sec-temporal.instant
17588 Isolate* isolate, DirectHandle<JSFunction> target,
17590 DirectHandle<Object> epoch_nanoseconds_obj) {
17592 // 1. If NewTarget is undefined, then
17593 if (IsUndefined(*new_target)) {
17594 // a. Throw a TypeError exception.
17595 THROW_NEW_ERROR(isolate,
17596 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
17597 isolate->factory()->NewStringFromAsciiChecked(
17598 "Temporal.Instant")));
17599 }
17600 // 2. Let epochNanoseconds be ? ToBigInt(epochNanoseconds).
17601 DirectHandle<BigInt> epoch_nanoseconds;
17603 isolate, epoch_nanoseconds,
17604 BigInt::FromObject(isolate, epoch_nanoseconds_obj));
17605 // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
17606 // RangeError exception.
17607 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
17609 }
17610 // 4. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).
17611 return temporal::CreateTemporalInstant(isolate, target, new_target,
17612 epoch_nanoseconds);
17613}
17614
17615namespace {
17616
17617// The logic in Temporal.Instant.fromEpochSeconds and fromEpochMilliseconds,
17618// are the same except a scaling factor, code all of them into the follow
17619// function.
17620MaybeDirectHandle<JSTemporalInstant> ScaleNumberToNanosecondsVerifyAndMake(
17621 Isolate* isolate, DirectHandle<BigInt> bigint, uint32_t scale) {
17623 DCHECK(scale == 1 || scale == 1000 || scale == 1000000 ||
17624 scale == 1000000000);
17625 // 2. Let epochNanoseconds be epochXseconds × scaleℤ.
17626 DirectHandle<BigInt> epoch_nanoseconds;
17627 if (scale == 1) {
17628 epoch_nanoseconds = bigint;
17629 } else {
17631 isolate, epoch_nanoseconds,
17632 BigInt::Multiply(isolate, BigInt::FromUint64(isolate, scale), bigint));
17633 }
17634 // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a
17635 // RangeError exception.
17636 if (!IsValidEpochNanoseconds(isolate, epoch_nanoseconds)) {
17638 }
17639 return temporal::CreateTemporalInstant(isolate, epoch_nanoseconds);
17640}
17641
17642MaybeDirectHandle<JSTemporalInstant> ScaleNumberToNanosecondsVerifyAndMake(
17643 Isolate* isolate, DirectHandle<Object> epoch_Xseconds, uint32_t scale) {
17645 // 1. Set epochXseconds to ? ToNumber(epochXseconds).
17646 ASSIGN_RETURN_ON_EXCEPTION(isolate, epoch_Xseconds,
17647 Object::ToNumber(isolate, epoch_Xseconds));
17648 // 2. Set epochMilliseconds to ? NumberToBigInt(epochMilliseconds).
17649 DirectHandle<BigInt> bigint;
17650 ASSIGN_RETURN_ON_EXCEPTION(isolate, bigint,
17651 BigInt::FromNumber(isolate, epoch_Xseconds));
17652 return ScaleNumberToNanosecondsVerifyAndMake(isolate, bigint, scale);
17653}
17654
17655MaybeDirectHandle<JSTemporalInstant> ScaleToNanosecondsVerifyAndMake(
17656 Isolate* isolate, DirectHandle<Object> epoch_Xseconds, uint32_t scale) {
17658 // 1. Set epochMicroseconds to ? ToBigInt(epochMicroseconds).
17659 DirectHandle<BigInt> bigint;
17660 ASSIGN_RETURN_ON_EXCEPTION(isolate, bigint,
17661 BigInt::FromObject(isolate, epoch_Xseconds));
17662 return ScaleNumberToNanosecondsVerifyAndMake(isolate, bigint, scale);
17663}
17664
17665} // namespace
17666
17667// #sec-temporal.instant.fromepochseconds
17669 Isolate* isolate, DirectHandle<Object> epoch_seconds) {
17671 return ScaleNumberToNanosecondsVerifyAndMake(isolate, epoch_seconds,
17672 1000000000);
17673}
17674
17675// #sec-temporal.instant.fromepochmilliseconds
17679 return ScaleNumberToNanosecondsVerifyAndMake(isolate, epoch_milliseconds,
17680 1000000);
17681}
17682
17683// #sec-temporal.instant.fromepochmicroseconds
17685 Isolate* isolate, DirectHandle<Object> epoch_microseconds) {
17687 return ScaleToNanosecondsVerifyAndMake(isolate, epoch_microseconds, 1000);
17688}
17689
17690// #sec-temporal.instant.fromepochnanoeconds
17692 Isolate* isolate, DirectHandle<Object> epoch_nanoseconds) {
17694 return ScaleToNanosecondsVerifyAndMake(isolate, epoch_nanoseconds, 1);
17695}
17696
17697// #sec-temporal.instant.compare
17699 Isolate* isolate, DirectHandle<Object> one_obj,
17700 DirectHandle<Object> two_obj) {
17702 const char* method_name = "Temporal.Instant.compare";
17703 // 1. Set one to ? ToTemporalInstant(one).
17706 ToTemporalInstant(isolate, one_obj, method_name));
17707 // 2. Set two to ? ToTemporalInstant(two).
17709 ASSIGN_RETURN_ON_EXCEPTION(isolate, two,
17710 ToTemporalInstant(isolate, two_obj, method_name));
17711 // 3. Return 𝔽(! CompareEpochNanoseconds(one.[[Nanoseconds]],
17712 // two.[[Nanoseconds]])).
17713 return CompareEpochNanoseconds(isolate,
17714 direct_handle(one->nanoseconds(), isolate),
17715 direct_handle(two->nanoseconds(), isolate));
17716}
17717
17718// #sec-temporal.instant.prototype.equals
17721 DirectHandle<Object> other_obj) {
17723 // 1. Let instant be the this value.
17724 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
17725 // 3. Set other to ? ToTemporalInstant(other).
17728 isolate, other,
17729 ToTemporalInstant(isolate, other_obj,
17730 "Temporal.Instant.prototype.equals"));
17731 // 4. If instant.[[Nanoseconds]] ≠ other.[[Nanoseconds]], return false.
17732 // 5. Return true.
17733 return isolate->factory()->ToBoolean(
17734 BigInt::EqualToBigInt(handle->nanoseconds(), other->nanoseconds()));
17735}
17736
17737namespace {
17738
17739// #sec-temporal-totemporalroundingincrement
17740Maybe<double> ToTemporalRoundingIncrement(
17741 Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
17742 double dividend, bool dividend_is_defined, bool inclusive) {
17743 double maximum;
17744 // 1. If dividend is undefined, then
17745 if (!dividend_is_defined) {
17746 // a. Let maximum be +∞.
17747 maximum = std::numeric_limits<double>::infinity();
17748 // 2. Else if inclusive is true, then
17749 } else if (inclusive) {
17750 // a. Let maximum be 𝔽(dividend).
17751 maximum = dividend;
17752 // 3. Else if dividend is more than 1, then
17753 } else if (dividend > 1) {
17754 // a. Let maximum be 𝔽(dividend-1).
17755 maximum = dividend - 1;
17756 // 4. Else,
17757 } else {
17758 // a. Let maximum be 1.
17759 maximum = 1;
17760 }
17761 // 5. Let increment be ? GetOption(normalizedOptions, "roundingIncrement", «
17762 // Number », empty, 1).
17763 double increment;
17765 isolate, increment,
17766 GetNumberOptionAsDouble(isolate, normalized_options,
17767 isolate->factory()->roundingIncrement_string(),
17768 1),
17769 Nothing<double>());
17770
17771 // 6. If increment < 1 or increment > maximum, throw a RangeError exception.
17772 if (increment < 1 || increment > maximum) {
17775 }
17776 // 7. Set increment to floor(ℝ(increment)).
17777 increment = std::floor(increment);
17778
17779 // 8. If dividend is not undefined and dividend modulo increment is not zero,
17780 // then
17781 if ((dividend_is_defined) && (std::fmod(dividend, increment) != 0)) {
17782 // a. Throw a RangeError exception.
17785 }
17786 // 9. Return increment.
17787 return Just(increment);
17788}
17789
17790// #sec-temporal-roundtemporalinstant
17791DirectHandle<BigInt> RoundTemporalInstant(Isolate* isolate,
17792 DirectHandle<BigInt> ns,
17793 double increment, Unit unit,
17796 // 1. Assert: Type(ns) is BigInt.
17797 double increment_ns;
17798 switch (unit) {
17799 // 2. If unit is "hour", then
17800 case Unit::kHour:
17801 // a. Let incrementNs be increment × 3.6 × 10^12.
17802 increment_ns = increment * 3.6e12;
17803 break;
17804 // 3. Else if unit is "minute", then
17805 case Unit::kMinute:
17806 // a. Let incrementNs be increment × 6 × 10^10.
17807 increment_ns = increment * 6e10;
17808 break;
17809 // 4. Else if unit is "second", then
17810 case Unit::kSecond:
17811 // a. Let incrementNs be increment × 10^9.
17812 increment_ns = increment * 1e9;
17813 break;
17814 // 5. Else if unit is "millisecond", then
17815 case Unit::kMillisecond:
17816 // a. Let incrementNs be increment × 10^6.
17817 increment_ns = increment * 1e6;
17818 break;
17819 // 6. Else if unit is "microsecond", then
17820 case Unit::kMicrosecond:
17821 // a. Let incrementNs be increment × 10^3.
17822 increment_ns = increment * 1e3;
17823 break;
17824 // 7. Else,
17825 // a. Assert: unit is "nanosecond".
17826 case Unit::kNanosecond:
17827 // b. Let incrementNs be increment.
17828 increment_ns = increment;
17829 break;
17830 default:
17831 UNREACHABLE();
17832 }
17833 // 8. Return ! RoundNumberToIncrementAsIfPositive(ℝ(ns), incrementNs,
17834 // roundingMode).
17835 return RoundNumberToIncrementAsIfPositive(isolate, ns, increment_ns,
17837}
17838
17839} // namespace
17840
17841// #sec-temporal.instant.prototype.round
17844 DirectHandle<Object> round_to_obj) {
17846 const char* method_name = "Temporal.Instant.prototype.round";
17847 Factory* factory = isolate->factory();
17848 // 1. Let instant be the this value.
17849 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
17850 // 3. If roundTo is undefined, then
17851 if (IsUndefined(*round_to_obj)) {
17852 // a. Throw a TypeError exception.
17854 }
17855 DirectHandle<JSReceiver> round_to;
17856 // 4. If Type(roundTo) is String, then
17857 if (IsString(*round_to_obj)) {
17858 // a. Let paramString be roundTo.
17859 DirectHandle<String> param_string = Cast<String>(round_to_obj);
17860 // b. Set roundTo to ! OrdinaryObjectCreate(null).
17861 round_to = factory->NewJSObjectWithNullProto();
17862 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit",
17863 // paramString).
17864 CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
17865 factory->smallestUnit_string(),
17866 param_string, Just(kThrowOnError))
17867 .FromJust());
17868 } else {
17869 // a. Set roundTo to ? GetOptionsObject(roundTo).
17871 isolate, round_to,
17872 GetOptionsObject(isolate, round_to_obj, method_name));
17873 }
17874
17875 // 6. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time,
17876 // required).
17877 Unit smallest_unit;
17879 isolate, smallest_unit,
17880 GetTemporalUnit(isolate, round_to, "smallestUnit", UnitGroup::kTime,
17881 Unit::kNotPresent, true, method_name),
17883
17884 // 7. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
17887 isolate, rounding_mode,
17888 ToTemporalRoundingMode(isolate, round_to, RoundingMode::kHalfExpand,
17889 method_name),
17891 double maximum;
17892 switch (smallest_unit) {
17893 // 8. If smallestUnit is "hour", then
17894 case Unit::kHour:
17895 // a. Let maximum be 24.
17896 maximum = 24;
17897 break;
17898 // 9. Else if smallestUnit is "minute", then
17899 case Unit::kMinute:
17900 // a. Let maximum be 1440.
17901 maximum = 1440;
17902 break;
17903 // 10. Else if smallestUnit is "second", then
17904 case Unit::kSecond:
17905 // a. Let maximum be 86400.
17906 maximum = 86400;
17907 break;
17908 // 11. Else if smallestUnit is "millisecond", then
17909 case Unit::kMillisecond:
17910 // a. Let maximum be 8.64 × 10^7.
17911 maximum = 8.64e7;
17912 break;
17913 // 12. Else if smallestUnit is "microsecond", then
17914 case Unit::kMicrosecond:
17915 // a. Let maximum be 8.64 × 10^10.
17916 maximum = 8.64e10;
17917 break;
17918 // 13. Else,
17919 case Unit::kNanosecond:
17920 // b. Let maximum be nsPerDay.
17921 maximum = kNsPerDay;
17922 break;
17923 // a. Assert: smallestUnit is "nanosecond".
17924 default:
17925 UNREACHABLE();
17926 }
17927 // 14. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo,
17928 // maximum, true).
17929 double rounding_increment;
17931 isolate, rounding_increment,
17932 ToTemporalRoundingIncrement(isolate, round_to, maximum, true, true),
17934 // 15. Let roundedNs be ! RoundTemporalInstant(instant.[[Nanoseconds]],
17935 // roundingIncrement, smallestUnit, roundingMode).
17936 DirectHandle<BigInt> rounded_ns = RoundTemporalInstant(
17937 isolate, DirectHandle<BigInt>(handle->nanoseconds(), isolate),
17939 // 16. Return ! CreateTemporalInstant(roundedNs).
17940 return temporal::CreateTemporalInstant(isolate, rounded_ns).ToHandleChecked();
17941}
17942
17943// #sec-temporal.instant.from
17945 Isolate* isolate, DirectHandle<Object> item) {
17947 // 1. If Type(item) is Object and item has an [[InitializedTemporalInstant]]
17948 // internal slot, then
17949 if (IsJSTemporalInstant(*item)) {
17950 // a. Return ? CreateTemporalInstant(item.[[Nanoseconds]]).
17952 isolate,
17953 direct_handle(Cast<JSTemporalInstant>(*item)->nanoseconds(), isolate));
17954 }
17955 // 2. Return ? ToTemporalInstant(item).
17956 return ToTemporalInstant(isolate, item, "Temporal.Instant.from");
17957}
17958
17959// #sec-temporal.instant.prototype.tozoneddatetime
17962 DirectHandle<Object> item_obj) {
17964 const char* method_name = "Temporal.Instant.prototype.toZonedDateTime";
17965 Factory* factory = isolate->factory();
17966 // 1. Let instant be the this value.
17967 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
17968 // 3. If Type(item) is not Object, then
17969 if (!IsJSReceiver(*item_obj)) {
17970 // a. Throw a TypeError exception.
17972 }
17974 // 4. Let calendarLike be ? Get(item, "calendar").
17975 DirectHandle<Object> calendar_like;
17977 isolate, calendar_like,
17978 JSReceiver::GetProperty(isolate, item, factory->calendar_string()));
17979 // 5. If calendarLike is undefined, then
17980 if (IsUndefined(*calendar_like)) {
17981 // a. Throw a TypeError exception.
17983 }
17984 // 6. Let calendar be ? ToTemporalCalendar(calendarLike).
17987 isolate, calendar,
17988 temporal::ToTemporalCalendar(isolate, calendar_like, method_name));
17989
17990 // 7. Let temporalTimeZoneLike be ? Get(item, "timeZone").
17991 DirectHandle<Object> temporal_time_zone_like;
17993 isolate, temporal_time_zone_like,
17994 JSReceiver::GetProperty(isolate, item, factory->timeZone_string()));
17995 // 8. If temporalTimeZoneLike is undefined, then
17996 if (IsUndefined(*calendar_like)) {
17997 // a. Throw a TypeError exception.
17999 }
18000 // 9. Let timeZone be ? ToTemporalTimeZone(temporalTimeZoneLike).
18003 isolate, time_zone,
18004 temporal::ToTemporalTimeZone(isolate, temporal_time_zone_like,
18005 method_name));
18006 // 10. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
18007 // calendar).
18008 return CreateTemporalZonedDateTime(
18009 isolate, DirectHandle<BigInt>(handle->nanoseconds(), isolate), time_zone,
18010 calendar);
18011}
18012
18013namespace {
18014
18015// #sec-temporal-temporalinstanttostring
18016MaybeDirectHandle<String> TemporalInstantToString(
18017 Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
18018 DirectHandle<Object> time_zone_obj, Precision precision,
18019 const char* method_name) {
18020 IncrementalStringBuilder builder(isolate);
18021 // 1. Assert: Type(instant) is Object.
18022 // 2. Assert: instant has an [[InitializedTemporalInstant]] internal slot.
18023 // 3. Let outputTimeZone be timeZone.
18024 DirectHandle<JSReceiver> output_time_zone;
18025
18026 // 4. If outputTimeZone is undefined, then
18027 if (IsUndefined(*time_zone_obj)) {
18028 // a. Set outputTimeZone to ! CreateTemporalTimeZone("UTC").
18029 output_time_zone = CreateTemporalTimeZoneUTC(isolate);
18030 } else {
18031 DCHECK(IsJSReceiver(*time_zone_obj));
18032 output_time_zone = Cast<JSReceiver>(time_zone_obj);
18033 }
18034
18035 // 5. Let isoCalendar be ! GetISO8601Calendar().
18036 DirectHandle<JSTemporalCalendar> iso_calendar =
18038 // 6. Let dateTime be ?
18039 // BuiltinTimeZoneGetPlainDateTimeFor(outputTimeZone, instant,
18040 // isoCalendar).
18041 DirectHandle<JSTemporalPlainDateTime> date_time;
18043 isolate, date_time,
18045 isolate, output_time_zone, instant, iso_calendar, method_name));
18046 // 7. Let dateTimeString be ? TemporalDateTimeToString(dateTime.[[ISOYear]],
18047 // dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
18048 // dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
18049 // dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
18050 // dateTime.[[ISONanosecond]], undefined, precision, "never").
18051
18052 DirectHandle<String> date_time_string;
18054 isolate, date_time_string,
18055 TemporalDateTimeToString(
18056 isolate,
18057 {{date_time->iso_year(), date_time->iso_month(),
18058 date_time->iso_day()},
18059 {date_time->iso_hour(), date_time->iso_minute(),
18060 date_time->iso_second(), date_time->iso_millisecond(),
18061 date_time->iso_microsecond(), date_time->iso_nanosecond()}},
18062 iso_calendar, // Unimportant due to ShowCalendar::kNever
18063 precision, ShowCalendar::kNever));
18064 builder.AppendString(date_time_string);
18065
18066 // 8. If timeZone is undefined, then
18067 if (IsUndefined(*time_zone_obj)) {
18068 // a. Let timeZoneString be "Z".
18069 builder.AppendCharacter('Z');
18070 } else {
18071 // 9. Else,
18072 DCHECK(IsJSReceiver(*time_zone_obj));
18073 DirectHandle<JSReceiver> time_zone = Cast<JSReceiver>(time_zone_obj);
18074
18075 // a. Let offsetNs be ? GetOffsetNanosecondsFor(timeZone, instant).
18076 int64_t offset_ns;
18078 isolate, offset_ns,
18079 GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
18080 DirectHandle<String>());
18081 // b. Let timeZoneString be ! FormatISOTimeZoneOffsetString(offsetNs).
18082 DirectHandle<String> time_zone_string =
18083 FormatISOTimeZoneOffsetString(isolate, offset_ns);
18084 builder.AppendString(time_zone_string);
18085 }
18086
18087 // 10. Return the string-concatenation of dateTimeString and timeZoneString.
18088 return builder.Finish();
18089}
18090
18091} // namespace
18092
18093// #sec-temporal.instant.prototype.tojson
18095 Isolate* isolate, DirectHandle<JSTemporalInstant> instant) {
18097 // 1. Let instant be the this value.
18098 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
18099 // 3. Return ? TemporalInstantToString(instant, undefined, "auto").
18100 return TemporalInstantToString(
18101 isolate, instant, isolate->factory()->undefined_value(), Precision::kAuto,
18102 "Temporal.Instant.prototype.toJSON");
18103}
18104
18105// #sec-temporal.instant.prototype.tolocalestring
18107 Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
18108 DirectHandle<Object> locales, DirectHandle<Object> options) {
18109 const char* method_name = "Temporal.Instant.prototype.toLocaleString";
18110#ifdef V8_INTL_SUPPORT
18111 return JSDateTimeFormat::TemporalToLocaleString(isolate, instant, locales,
18112 options, method_name);
18113#else // V8_INTL_SUPPORT
18114 return TemporalInstantToString(isolate, instant,
18115 isolate->factory()->undefined_value(),
18116 Precision::kAuto, method_name);
18117#endif // V8_INTL_SUPPORT
18118}
18119
18120// #sec-temporal.instant.prototype.tostring
18122 Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
18123 DirectHandle<Object> options_obj) {
18124 Factory* factory = isolate->factory();
18125 const char* method_name = "Temporal.Instant.prototype.toString";
18126 // 1. Let instant be the this value.
18127 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
18128 // 3. Set options to ? GetOptionsObject(options).
18131 isolate, options, GetOptionsObject(isolate, options_obj, method_name));
18132 // 4. Let timeZone be ? Get(options, "timeZone").
18135 isolate, time_zone,
18136 JSReceiver::GetProperty(isolate, options, factory->timeZone_string()));
18137
18138 // 5. If timeZone is not undefined, then
18139 if (!IsUndefined(*time_zone)) {
18140 // a. Set timeZone to ? ToTemporalTimeZone(timeZone).
18142 isolate, time_zone,
18143 temporal::ToTemporalTimeZone(isolate, time_zone, method_name));
18144 }
18145 // 6. Let precision be ? ToSecondsStringPrecision(options).
18146 StringPrecision precision;
18148 isolate, precision,
18149 ToSecondsStringPrecision(isolate, options, method_name),
18151 // 7. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
18154 isolate, rounding_mode,
18155 ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
18156 method_name),
18158 // 8. Let roundedNs be ! RoundTemporalInstant(instant.[[Nanoseconds]],
18159 // precision.[[Increment]], precision.[[Unit]], roundingMode).
18160 DirectHandle<BigInt> rounded_ns = RoundTemporalInstant(
18161 isolate, direct_handle(instant->nanoseconds(), isolate),
18162 precision.increment, precision.unit, rounding_mode);
18163
18164 // 9. Let roundedInstant be ! CreateTemporalInstant(roundedNs).
18165 DirectHandle<JSTemporalInstant> rounded_instant =
18166 temporal::CreateTemporalInstant(isolate, rounded_ns).ToHandleChecked();
18167
18168 // 10. Return ? TemporalInstantToString(roundedInstant, timeZone,
18169 // precision.[[Precision]]).
18170 return TemporalInstantToString(isolate, rounded_instant, time_zone,
18171 precision.precision,
18172 "Temporal.Instant.prototype.toString");
18173}
18174
18175// #sec-temporal.instant.prototype.tozoneddatetimeiso
18179 DirectHandle<Object> item_obj) {
18181 Factory* factory = isolate->factory();
18182 // 1. Let instant be the this value.
18183 // 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
18184 // 3. If Type(item) is Object, then
18185 if (IsJSReceiver(*item_obj)) {
18187 // a. Let timeZoneProperty be ? Get(item, "timeZone").
18188 DirectHandle<Object> time_zone_property;
18190 isolate, time_zone_property,
18191 JSReceiver::GetProperty(isolate, item, factory->timeZone_string()));
18192 // b. If timeZoneProperty is not undefined, then
18193 if (!IsUndefined(*time_zone_property)) {
18194 // i. Set item to timeZoneProperty.
18195 item_obj = time_zone_property;
18196 }
18197 }
18198 // 4. Let timeZone be ? ToTemporalTimeZone(item).
18201 isolate, time_zone,
18203 isolate, item_obj, "Temporal.Instant.prototype.toZonedDateTimeISO"));
18204 // 5. Let calendar be ! GetISO8601Calendar().
18207 // 6. Return ? CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone,
18208 // calendar).
18209 return CreateTemporalZonedDateTime(
18210 isolate, DirectHandle<BigInt>(handle->nanoseconds(), isolate), time_zone,
18211 calendar);
18212}
18213
18214namespace {
18215
18216// #sec-temporal-adddurationtoorsubtractdurationfrominstant
18217MaybeDirectHandle<JSTemporalInstant> AddDurationToOrSubtractDurationFromInstant(
18218 Isolate* isolate, Arithmetic operation,
18220 DirectHandle<Object> temporal_duration_like, const char* method_name) {
18222 // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
18223 double sign = operation == Arithmetic::kSubtract ? -1.0 : 1.0;
18224
18225 // See https://github.com/tc39/proposal-temporal/pull/2253
18226 // 2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
18227 DurationRecord duration;
18229 isolate, duration,
18230 temporal::ToTemporalDurationRecord(isolate, temporal_duration_like,
18231 method_name),
18233
18234 TimeDurationRecord& time_duration = duration.time_duration;
18235 if (time_duration.days != 0 || duration.months != 0 || duration.weeks != 0 ||
18236 duration.years != 0) {
18240 }
18241
18242 // 3. Let ns be ? AddInstant(instant.[[EpochNanoseconds]], sign x
18243 // duration.[[Hours]], sign x duration.[[Minutes]], sign x
18244 // duration.[[Seconds]], sign x duration.[[Milliseconds]], sign x
18245 // duration.[[Microseconds]], sign x duration.[[Nanoseconds]]).
18246 DirectHandle<BigInt> ns;
18248 isolate, ns,
18249 AddInstant(
18250 isolate, DirectHandle<BigInt>(handle->nanoseconds(), isolate),
18251 {0, sign * time_duration.hours, sign * time_duration.minutes,
18252 sign * time_duration.seconds, sign * time_duration.milliseconds,
18253 sign * time_duration.microseconds,
18254 sign * time_duration.nanoseconds}));
18255 // 4. Return ! CreateTemporalInstant(ns).
18256 return temporal::CreateTemporalInstant(isolate, ns);
18257}
18258
18259// #sec-temporal-negatetemporalroundingmode
18260RoundingMode NegateTemporalRoundingMode(RoundingMode rounding_mode) {
18261 switch (rounding_mode) {
18262 // 1. If roundingMode is "ceil", return "floor".
18263 case RoundingMode::kCeil:
18264 return RoundingMode::kFloor;
18265 // 2. If roundingMode is "floor", return "ceil".
18266 case RoundingMode::kFloor:
18267 return RoundingMode::kCeil;
18268 // 3. If roundingMode is "halfCeil", return "halfFloor".
18269 case RoundingMode::kHalfCeil:
18270 return RoundingMode::kHalfFloor;
18271 // 4. If roundingMode is "halfFloor", return "halfCeil".
18272 case RoundingMode::kHalfFloor:
18273 return RoundingMode::kHalfCeil;
18274 // 5. Return roundingMode.
18275 default:
18276 return rounding_mode;
18277 }
18278}
18279
18280// #sec-temporal-getdifferencesettings
18281Maybe<DifferenceSettings> GetDifferenceSettings(
18282 Isolate* isolate, TimePreposition operation, DirectHandle<Object> options,
18283 UnitGroup unit_group, DisallowedUnitsInDifferenceSettings disallowed_units,
18284 Unit fallback_smallest_unit, Unit smallest_largest_default_unit,
18285 const char* method_name) {
18286 DifferenceSettings record;
18287 // 1. Set options to ? GetOptionsObject(options).
18289 isolate, record.options, GetOptionsObject(isolate, options, method_name),
18291 // 2. Let smallestUnit be ? GetTemporalUnit(options, "smallestUnit",
18292 // unitGroup, fallbackSmallestUnit).
18294 isolate, record.smallest_unit,
18295 GetTemporalUnit(isolate, record.options, "smallestUnit", unit_group,
18296 fallback_smallest_unit,
18297 fallback_smallest_unit == Unit::kNotPresent, method_name),
18299 // 3. If disallowedUnits contains smallestUnit, throw a RangeError exception.
18300 if (disallowed_units == DisallowedUnitsInDifferenceSettings::kWeekAndDay) {
18301 if (record.smallest_unit == Unit::kWeek) {
18303 isolate,
18304 NewRangeError(MessageTemplate::kInvalidUnit,
18305 isolate->factory()->smallestUnit_string(),
18306 isolate->factory()->week_string()),
18308 }
18309 if (record.smallest_unit == Unit::kDay) {
18311 isolate,
18312 NewRangeError(MessageTemplate::kInvalidUnit,
18313 isolate->factory()->smallestUnit_string(),
18314 isolate->factory()->day_string()),
18316 }
18317 }
18318 // 4. Let defaultLargestUnit be !
18319 // LargerOfTwoTemporalUnits(smallestLargestDefaultUnit, smallestUnit).
18320 Unit default_largest_unit = LargerOfTwoTemporalUnits(
18321 smallest_largest_default_unit, record.smallest_unit);
18322 // 5. Let largestUnit be ? GetTemporalUnit(options, "largestUnit", unitGroup,
18323 // "auto").
18325 isolate, record.largest_unit,
18326 GetTemporalUnit(isolate, record.options, "largestUnit", unit_group,
18327 Unit::kAuto, false, method_name),
18329 // 6. If disallowedUnits contains largestUnit, throw a RangeError exception.
18330 if (disallowed_units == DisallowedUnitsInDifferenceSettings::kWeekAndDay) {
18331 if (record.largest_unit == Unit::kWeek) {
18333 isolate,
18334 NewRangeError(MessageTemplate::kInvalidUnit,
18335 isolate->factory()->largestUnit_string(),
18336 isolate->factory()->week_string()),
18338 }
18339 if (record.largest_unit == Unit::kDay) {
18341 isolate,
18342 NewRangeError(MessageTemplate::kInvalidUnit,
18343 isolate->factory()->largestUnit_string(),
18344 isolate->factory()->day_string()),
18346 }
18347 }
18348 // 7. If largestUnit is "auto", set largestUnit to defaultLargestUnit.
18349 if (record.largest_unit == Unit::kAuto) {
18350 record.largest_unit = default_largest_unit;
18351 }
18352 // 8. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not
18353 // largestUnit, throw a RangeError exception.
18354 if (LargerOfTwoTemporalUnits(record.largest_unit, record.smallest_unit) !=
18355 record.largest_unit) {
18357 isolate,
18358 NewRangeError(MessageTemplate::kInvalidArgumentForTemporal,
18359 isolate->factory()->largestUnit_string()),
18361 }
18362 // 9. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
18364 isolate, record.rounding_mode,
18365 ToTemporalRoundingMode(isolate, record.options, RoundingMode::kTrunc,
18366 method_name),
18368 // 10. If operation is since, then
18369 if (operation == TimePreposition::kSince) {
18370 // a. Set roundingMode to ! NegateTemporalRoundingMode(roundingMode).
18371 record.rounding_mode = NegateTemporalRoundingMode(record.rounding_mode);
18372 }
18373 // 11. Let maximum be !
18374 // MaximumTemporalDurationRoundingIncrement(smallestUnit).
18375 Maximum maximum =
18376 MaximumTemporalDurationRoundingIncrement(record.smallest_unit);
18377 // 12. Let roundingIncrement be ? ToTemporalRoundingIncrement(options,
18378 // maximum, false).
18380 isolate, record.rounding_increment,
18381 ToTemporalRoundingIncrement(isolate, record.options, maximum.value,
18382 maximum.defined, false),
18384 // 13. Return the Record { [[SmallestUnit]]: smallestUnit, [[LargestUnit]]:
18385 // largestUnit, [[RoundingMode]]: roundingMode, [[RoundingIncrement]]:
18386 // roundingIncrement, [[Options]]: options }.
18387 return Just(record);
18388}
18389
18390// #sec-temporal-differenceinstant
18391TimeDurationRecord DifferenceInstant(Isolate* isolate, DirectHandle<BigInt> ns1,
18392 DirectHandle<BigInt> ns2,
18393 double rounding_increment,
18394 Unit smallest_unit, Unit largest_unit,
18396 const char* method_name) {
18397 // 1. Assert: Type(ns1) is BigInt.
18398 // 2. Assert: Type(ns2) is BigInt.
18399 // 3. Assert: The following step cannot fail due to overflow in the Number
18400 // domain because abs(ns2 - ns1) <= 2 x nsMaxInstant.
18401
18402 // 4. Let roundResult be ! RoundDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, ns2 - ns1,
18403 // roundingIncrement, smallestUnit, roundingMode).[[DurationRecord]].
18404 DirectHandle<BigInt> diff =
18405 BigInt::Subtract(isolate, ns2, ns1).ToHandleChecked();
18406 // Note: Since diff could be very big and over the precision of double can
18407 // hold, break diff into diff_hours and diff_nanoseconds before pass into
18408 // RoundDuration.
18409 DirectHandle<BigInt> nanoseconds_in_a_hour =
18410 BigInt::FromUint64(isolate, 3600000000000);
18411 double diff_hours = Object::NumberValue(*BigInt::ToNumber(
18412 isolate,
18413 BigInt::Divide(isolate, diff, nanoseconds_in_a_hour).ToHandleChecked()));
18414 double diff_nanoseconds = Object::NumberValue(*BigInt::ToNumber(
18415 isolate, BigInt::Remainder(isolate, diff, nanoseconds_in_a_hour)
18416 .ToHandleChecked()));
18417 DurationRecordWithRemainder round_record =
18418 RoundDuration(
18419 isolate, {0, 0, 0, {0, diff_hours, 0, 0, 0, 0, diff_nanoseconds}},
18421 .ToChecked();
18422 // 5. Assert: roundResult.[[Days]] is 0.
18423 DCHECK_EQ(0, round_record.record.time_duration.days);
18424 // 6. Return ! BalanceDuration(0, roundResult.[[Hours]],
18425 // roundResult.[[Minutes]], roundResult.[[Seconds]],
18426 // roundResult.[[Milliseconds]], roundResult.[[Microseconds]],
18427 // roundResult.[[Nanoseconds]], largestUnit).
18428 return BalanceDuration(isolate, largest_unit,
18429 isolate->factory()->undefined_value(),
18430 round_record.record.time_duration, method_name)
18431 .ToChecked();
18432}
18433
18434// #sec-temporal-differencetemporalinstant
18435MaybeDirectHandle<JSTemporalDuration> DifferenceTemporalInstant(
18436 Isolate* isolate, TimePreposition operation,
18437 DirectHandle<JSTemporalInstant> instant, DirectHandle<Object> other_obj,
18438 DirectHandle<Object> options, const char* method_name) {
18440 // 1. If operation is since, let sign be -1. Otherwise, let sign be 1.
18441 double sign = operation == TimePreposition::kSince ? -1 : 1;
18442 // 2. Set other to ? ToTemporalInstant(other).
18443 DirectHandle<JSTemporalInstant> other;
18445 isolate, other, ToTemporalInstant(isolate, other_obj, method_name));
18446 // 3. Let settings be ? GetDifferenceSettings(operation, options, time, « »,
18447 // "nanosecond", "second").
18448 DifferenceSettings settings;
18450 isolate, settings,
18451 GetDifferenceSettings(isolate, operation, options, UnitGroup::kTime,
18452 DisallowedUnitsInDifferenceSettings::kNone,
18453 Unit::kNanosecond, Unit::kSecond, method_name),
18454 DirectHandle<JSTemporalDuration>());
18455 // 4. Let result be ! DifferenceInstant(instant.[[Nanoseconds]],
18456 // other.[[Nanoseconds]], settings.[[RoundingIncrement]],
18457 // settings.[[SmallestUnit]], settings.[[LargestUnit]],
18458 // settings.[[RoundingMode]]).
18459 TimeDurationRecord result = DifferenceInstant(
18460 isolate, direct_handle(instant->nanoseconds(), isolate),
18461 direct_handle(other->nanoseconds(), isolate), settings.rounding_increment,
18462 settings.smallest_unit, settings.largest_unit, settings.rounding_mode,
18463 method_name);
18464 // 5. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]],
18465 // sign × result.[[Minutes]], sign × result.[[Seconds]], sign ×
18466 // result.[[Milliseconds]], sign × result.[[Microseconds]], sign ×
18467 // result.[[Nanoseconds]]).
18468 return CreateTemporalDuration(
18469 isolate, {0,
18470 0,
18471 0,
18472 {0, sign * result.hours, sign * result.minutes,
18473 sign * result.seconds, sign * result.milliseconds,
18474 sign * result.microseconds, sign * result.nanoseconds}})
18475 .ToHandleChecked();
18476}
18477} // namespace
18478
18479// #sec-temporal.instant.prototype.add
18482 DirectHandle<Object> temporal_duration_like) {
18484 return AddDurationToOrSubtractDurationFromInstant(
18485 isolate, Arithmetic::kAdd, handle, temporal_duration_like,
18486 "Temporal.Instant.prototype.add");
18487}
18488
18489// #sec-temporal.instant.prototype.subtract
18492 DirectHandle<Object> temporal_duration_like) {
18494 return AddDurationToOrSubtractDurationFromInstant(
18495 isolate, Arithmetic::kSubtract, handle, temporal_duration_like,
18496 "Temporal.Instant.prototype.subtract");
18497}
18498
18499// #sec-temporal.instant.prototype.until
18504 return DifferenceTemporalInstant(isolate, TimePreposition::kUntil, handle,
18505 other, options,
18506 "Temporal.Instant.prototype.until");
18507}
18508
18509// #sec-temporal.instant.prototype.since
18514 return DifferenceTemporalInstant(isolate, TimePreposition::kSince, handle,
18515 other, options,
18516 "Temporal.Instant.prototype.since");
18517}
18518namespace temporal {
18519
18520// Step iii and iv of #sec-temporal.calendar.prototype.fields
18522 Isolate* isolate, DirectHandle<String> next_value,
18523 DirectHandle<FixedArray> fields_name) {
18524 Factory* factory = isolate->factory();
18525 // iii. iii. If fieldNames contains nextValue, then
18526 for (int i = 0; i < fields_name->length(); i++) {
18527 Tagged<Object> item = fields_name->get(i);
18528 DCHECK(IsString(item));
18529 if (String::Equals(isolate, next_value,
18530 direct_handle(Cast<String>(item), isolate))) {
18531 return isolate->factory()->true_value();
18532 }
18533 }
18534 // iv. If nextValue is not one of "year", "month", "monthCode", "day", "hour",
18535 // "minute", "second", "millisecond", "microsecond", "nanosecond", then
18536 if (!(String::Equals(isolate, next_value, factory->year_string()) ||
18537 String::Equals(isolate, next_value, factory->month_string()) ||
18538 String::Equals(isolate, next_value, factory->monthCode_string()) ||
18539 String::Equals(isolate, next_value, factory->day_string()) ||
18540 String::Equals(isolate, next_value, factory->hour_string()) ||
18541 String::Equals(isolate, next_value, factory->minute_string()) ||
18542 String::Equals(isolate, next_value, factory->second_string()) ||
18543 String::Equals(isolate, next_value, factory->millisecond_string()) ||
18544 String::Equals(isolate, next_value, factory->microsecond_string()) ||
18545 String::Equals(isolate, next_value, factory->nanosecond_string()))) {
18546 return isolate->factory()->true_value();
18547 }
18548 return isolate->factory()->false_value();
18549}
18550
18551// #sec-temporal-getbuiltincalendar
18557
18558// A simple convenient function to avoid the need to unnecessarily exposing
18559// the definition of enum Disambiguation.
18562 DirectHandle<JSTemporalPlainDateTime> date_time, const char* method_name) {
18563 return BuiltinTimeZoneGetInstantFor(isolate, time_zone, date_time,
18564 Disambiguation::kCompatible, method_name);
18565}
18566
18567} // namespace temporal
18568} // namespace v8::internal
#define T
#define one
interpreter::OperandScale scale
Definition builtins.cc:44
virtual double CurrentClockTimeMillisecondsHighResolution()
static MaybeHandle< BigInt > Remainder(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:488
static ComparisonResult CompareToBigInt(DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:579
static MaybeHandle< BigInt > Multiply(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:432
static DirectHandle< Number > ToNumber(Isolate *isolate, DirectHandle< BigInt > x)
Definition bigint.cc:1023
static MaybeHandle< BigInt > Divide(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:454
static MaybeHandle< String > ToString(Isolate *isolate, DirectHandle< BigInt > bigint, int radix=10, ShouldThrow should_throw=kThrowOnError)
Definition bigint.cc:835
static MaybeHandle< BigInt > Increment(Isolate *isolate, DirectHandle< BigInt > x)
Definition bigint.cc:599
static bool EqualToBigInt(Tagged< BigInt > x, Tagged< BigInt > y)
Definition bigint.cc:590
static V8_EXPORT_PRIVATE Handle< BigInt > FromUint64(Isolate *isolate, uint64_t n)
Definition bigint.cc:1355
static MaybeHandle< BigInt > Decrement(Isolate *isolate, DirectHandle< BigInt > x)
Definition bigint.cc:611
static Handle< BigInt > UnaryMinus(Isolate *isolate, DirectHandle< BigInt > x)
Definition bigint.cc:341
static V8_EXPORT_PRIVATE Handle< BigInt > FromInt64(Isolate *isolate, int64_t n)
Definition bigint.cc:1333
static MaybeHandle< BigInt > Add(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:516
static ComparisonResult CompareToNumber(DirectHandle< BigInt > x, DirectHandle< Object > y)
Definition bigint.cc:679
static MaybeHandle< BigInt > Subtract(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
Definition bigint.cc:536
static V8_EXPORT_PRIVATE MaybeHandle< BigInt > FromNumber(Isolate *isolate, DirectHandle< Object > number)
Definition bigint.cc:954
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > CallBuiltin(Isolate *isolate, DirectHandle< JSFunction > builtin, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:545
Handle< Number > NewNumber(double value)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< JSObject > NewJSObjectWithNullProto()
Definition factory.cc:3004
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
Handle< JSArray > NewJSArrayWithElements(DirectHandle< FixedArrayBase > elements, ElementsKind elements_kind, int length, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3228
static HandleType< FixedArray > RightTrimOrEmpty(Isolate *isolate, HandleType< FixedArray > array, int new_length)
static V8_EXPORT_PRIVATE HandleType< FixedArray > SetAndGrow(Isolate *isolate, HandleType< FixedArray > array, int index, DirectHandle< Object > value)
MaybeDirectHandle< String > Finish()
V8_INLINE void AppendCharacter(uint8_t c)
static V8_WARN_UNUSED_RESULT MaybeHandle< String > ConvertToLower(Isolate *isolate, DirectHandle< String > s)
static DirectHandleVector< BigInt > GetTimeZonePossibleOffsetNanoseconds(Isolate *isolate, int32_t time_zone_index, DirectHandle< BigInt > nanosecond_epoch)
static int32_t GetTimeZoneIndex(Isolate *isolate, DirectHandle< String > identifier)
static DirectHandle< Object > GetTimeZoneOffsetTransitionNanoseconds(Isolate *isolate, int32_t time_zone_index, DirectHandle< BigInt > nanosecond_epoch, Transition transition)
static DirectHandle< String > DefaultTimeZone(Isolate *isolate)
static V8_WARN_UNUSED_RESULT bool IsValidTimeZoneName(const icu::TimeZone &tz)
static V8_WARN_UNUSED_RESULT std::string TimeZoneIdFromIndex(int32_t index)
static V8_WARN_UNUSED_RESULT MaybeHandle< String > CanonicalizeTimeZoneName(Isolate *isolate, DirectHandle< String > identifier)
static int64_t GetTimeZoneOffsetNanoseconds(Isolate *isolate, int32_t time_zone_index, DirectHandle< BigInt > nanosecond_epoch)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > TemporalToLocaleString(Isolate *isolate, DirectHandle< JSReceiver > temporal, DirectHandle< Object > locales, DirectHandle< Object > options, const char *method_name)
static V8_WARN_UNUSED_RESULT Maybe< bool > CreateDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > key, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(Isolate *isolate, DirectHandle< JSReceiver > receiver, const char *key)
static V8_WARN_UNUSED_RESULT Maybe< bool > SetOrCopyDataProperties(Isolate *isolate, DirectHandle< JSReceiver > target, DirectHandle< Object > source, PropertiesEnumerationMode mode, base::Vector< DirectHandle< Object > > excluded_properties={}, bool use_set=true)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > DateAdd(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > date, DirectHandle< Object > durations, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, const char *method_name)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > DaysInWeek(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Year(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > MonthCode(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > MonthsInYear(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > DateFromFields(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > fields, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > DaysInMonth(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > DaysInYear(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Day(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > MonthDayFromFields(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > fields, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > DayOfWeek(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > DateUntil(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > one, DirectHandle< Object > two, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > MergeFields(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > fields, DirectHandle< Object > additional_fields)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > WeekOfYear(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalCalendar > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > identifier)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > YearMonthFromFields(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > fields, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > DayOfYear(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > InLeapYear(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Month(Isolate *isolate, DirectHandle< JSTemporalCalendar > calendar, DirectHandle< Object > temporal_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Negated(Isolate *isolate, DirectHandle< JSTemporalDuration > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalDuration > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Add(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > From(Isolate *isolate, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Blank(Isolate *isolate, DirectHandle< JSTemporalDuration > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Abs(Isolate *isolate, DirectHandle< JSTemporalDuration > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > years, DirectHandle< Object > months, DirectHandle< Object > weeks, DirectHandle< Object > days, DirectHandle< Object > hours, DirectHandle< Object > minutes, DirectHandle< Object > seconds, DirectHandle< Object > milliseconds, DirectHandle< Object > microseconds, DirectHandle< Object > nanoseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Sign(Isolate *isolate, DirectHandle< JSTemporalDuration > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Subtract(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > With(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > temporal_duration_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Round(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > round_to_obj)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Total(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > total_of)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalDuration > duration, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > ToZonedDateTime(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalInstant > instant)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > epoch_nanoseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > Subtract(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > temporal_duration_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > ToZonedDateTimeISO(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > Add(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > temporal_duration_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > FromEpochNanoseconds(Isolate *isolate, DirectHandle< Object > epoch_nanoseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > From(Isolate *isolate, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > Round(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > round_to)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > FromEpochMilliseconds(Isolate *isolate, DirectHandle< Object > epoch_milliseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > Now(Isolate *isolate)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > FromEpochMicroseconds(Isolate *isolate, DirectHandle< Object > epoch_microseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > FromEpochSeconds(Isolate *isolate, DirectHandle< Object > epoch_seconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalInstant > instant, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > WithCalendar(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > WithPlainTime(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_time_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > iso_year, DirectHandle< Object > iso_month, DirectHandle< Object > iso_day, DirectHandle< Object > hour, DirectHandle< Object > minute, DirectHandle< Object > second, DirectHandle< Object > millisecond, DirectHandle< Object > microsecond, DirectHandle< Object > nanosecond, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > Subtract(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > plain_date, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > ToZonedDateTime(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_time_zone_like, DirectHandle< Object > options_obj)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > Add(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > Round(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > round_to)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > Now(Isolate *isolate, DirectHandle< Object > calendar_like, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > With(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_date_time_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > NowISO(Isolate *isolate, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > ToPlainYearMonth(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > WithPlainDate(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > temporal_date_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > ToPlainTime(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > ToPlainDate(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > ToPlainMonthDay(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalPlainDateTime > date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > Subtract(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > iso_year, DirectHandle< Object > iso_month, DirectHandle< Object > iso_day, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > NowISO(Isolate *isolate, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > ToPlainMonthDay(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > ToZonedDateTime(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > With(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > Add(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > Now(Isolate *isolate, DirectHandle< Object > calendar_like, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > WithCalendar(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > ToPlainDateTime(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > temporal_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > ToPlainYearMonth(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalPlainDate > plain_date, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > With(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day, DirectHandle< Object > temporal_month_day_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > plain_date, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > ToPlainDate(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalPlainMonthDay > month_day)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > iso_month, DirectHandle< Object > iso_day, DirectHandle< Object > calendar_like, DirectHandle< Object > reference_iso_year)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > ToPlainDateTime(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > temporal_date)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > Round(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > round_to)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > With(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > temporal_time_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > Subtract(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > temporal_duration_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > NowISO(Isolate *isolate, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > ToZonedDateTime(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > hour, DirectHandle< Object > minute, DirectHandle< Object > second, DirectHandle< Object > millisecond, DirectHandle< Object > microsecond, DirectHandle< Object > nanosecond)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > Add(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > temporal_duration_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalPlainTime > plain_date, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > With(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > temporal_year_month_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > ToPlainDate(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > item)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > plain_date, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > iso_year, DirectHandle< Object > iso_month, DirectHandle< Object > calendar_like, DirectHandle< Object > reference_iso_day)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > Subtract(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > Add(Isolate *isolate, DirectHandle< JSTemporalPlainYearMonth > year_month, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalTimeZone > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > identifier)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > GetPlainDateTimeFor(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > instance, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetOffsetNanosecondsFor(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > instance)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > GetInstantFor(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > dateTime, DirectHandle< Object > options)
static MaybeDirectHandle< Object > ToString(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, const char *method_name)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalTimeZone > Now(Isolate *isolate)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetPreviousTransition(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > starting_point)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > GetOffsetStringFor(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > instance)
MaybeDirectHandle< String > id(Isolate *isolate) const
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetNextTransition(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > starting_point)
void set_offset_nanoseconds(int64_t offset_nanoseconds)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetPossibleInstantsFor(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > date_time)
static constexpr int32_t kUTCTimeZoneIndex
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Since(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > date_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToLocaleString(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > StartOfDay(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > Subtract(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > WithPlainDate(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > plain_date_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > WithPlainTime(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > plain_time_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > Offset(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Oddball > Equals(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > other)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > ToJSON(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDateTime > ToPlainDateTime(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > With(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > temporal_zoned_date_time_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > NowISO(Isolate *isolate, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > GetISOFields(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > WithCalendar(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainDate > ToPlainDate(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > HoursInDay(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > Add(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > temporal_duration_like, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainYearMonth > ToPlainYearMonth(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainMonthDay > ToPlainMonthDay(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalInstant > ToInstant(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > OffsetNanoseconds(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalPlainTime > ToPlainTime(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Smi > Compare(Isolate *isolate, DirectHandle< Object > one, DirectHandle< Object > two)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalDuration > Until(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > date_time, DirectHandle< Object > other, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > Constructor(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< Object > epoch_nanoseconds, DirectHandle< Object > time_zone_like, DirectHandle< Object > calendar_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > WithTimeZone(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > Now(Isolate *isolate, DirectHandle< Object > calendar_like, DirectHandle< Object > temporal_time_zone_like)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > Round(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< Object > round_to)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSTemporalZonedDateTime > From(Isolate *isolate, DirectHandle< Object > item, DirectHandle< Object > options)
static MaybeHandle< FixedArray > GetKeys(Isolate *isolate, DirectHandle< JSReceiver > object, KeyCollectionMode mode, PropertyFilter filter, GetKeysConversion keys_conversion=GetKeysConversion::kKeepNumbers, bool is_for_in=false, bool skip_indices=false)
Definition keys.cc:97
V8_INLINE DirectHandle< T > ToHandleChecked() const
static V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType ToString(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetPropertyOrElement(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Name > name)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToNumber(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToInteger(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT HandleType< JSReceiver >::MaybeType ToObject(Isolate *isolate, HandleType< T > object, const char *method_name=nullptr)
static double NumberValue(Tagged< Number > obj)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetMethod(Isolate *isolate, DirectHandle< JSReceiver > receiver, DirectHandle< Name > name)
Definition objects.cc:1125
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
Definition objects.cc:1248
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static V8_EXPORT_PRIVATE Handle< StringSet > New(Isolate *isolate)
Definition objects.cc:5615
static V8_EXPORT_PRIVATE Handle< StringSet > Add(Isolate *isolate, Handle< StringSet > stringset, DirectHandle< String > name)
Definition objects.cc:5619
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
bool Equals(Tagged< String > other) const
Definition string-inl.h:535
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
int start
int end
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
Definition isolate.h:300
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:276
#define MAYBE_RETURN_ON_EXCEPTION_VALUE(isolate, call, value)
Definition isolate.h:238
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
#define MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:440
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
Isolate * isolate
OptionalOpIndex index
int32_t offset
ArrayReduceDirection direction
double epoch_milliseconds
double hour
double second
double nanoseconds
#define ORDINARY_CREATE_FROM_CONSTRUCTOR(obj, target, new_target, T)
#define EXTRACT_CALENDAR(T, obj)
double remainder
#define CONSTRUCTOR(name)
#define DEFINE_STRING_FIELD(obj, str, field)
double minute
double nanosecond
double years
bool defined
DirectHandle< JSReceiver > options
#define DEFINE_INT_FIELD(obj, str, field, item)
double rounding_increment
int64_t day_length
#define CALENDAR_ABSTRACT_OPERATION_INT_ACTION(Name, name, Action)
Unit largest_unit
DirectHandle< Object > offset_string
#define NEW_TEMPORAL_INVALID_ARG_TYPE_ERROR()
TimeRecord time
double months
#define NEW_TEMPORAL_INVALID_ARG_RANGE_ERROR()
double weeks
double days
Precision precision
double microsecond
double increment
DirectHandle< JSTemporalPlainDate > relative_to
#define TEMPORAL_ENTER_FUNC()
TimeZoneRecord time_zone
#define THROW_INVALID_RANGE(T)
#define CALENDAR_ABSTRACT_OPERATION(Name, property)
DirectHandle< Object > calendar
double millisecond
DurationRecord record
DateRecord date
#define TO_INT_THROW_ON_INFTY(name, T)
RoundingMode rounding_mode
Unit smallest_unit
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
int x
int s
Definition mul-fft.cc:297
int m
Definition mul-fft.cc:294
int r
Definition mul-fft.cc:298
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
Maybe< DurationRecord > ToTemporalDurationRecord(Isolate *isolate, DirectHandle< Object > temporal_duration_like_obj, const char *method_name)
MaybeDirectHandle< JSTemporalTimeZone > CreateTemporalTimeZone(Isolate *isolate, DirectHandle< String > identifier)
MaybeDirectHandle< Object > InvokeCalendarMethod(Isolate *isolate, DirectHandle< JSReceiver > calendar, DirectHandle< String > name, DirectHandle< JSReceiver > date_like)
MaybeDirectHandle< JSTemporalPlainDateTime > CreateTemporalDateTime(Isolate *isolate, const DateTimeRecord &date_time, DirectHandle< JSReceiver > calendar)
MaybeDirectHandle< JSTemporalInstant > CreateTemporalInstant(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< BigInt > epoch_nanoseconds)
MaybeDirectHandle< JSTemporalCalendar > GetBuiltinCalendar(Isolate *isolate, DirectHandle< String > id)
MaybeDirectHandle< JSTemporalInstant > BuiltinTimeZoneGetInstantForCompatible(Isolate *isolate, DirectHandle< JSReceiver > time_zone, DirectHandle< JSTemporalPlainDateTime > date_time, const char *method_name)
MaybeDirectHandle< JSReceiver > ToTemporalCalendar(Isolate *isolate, DirectHandle< Object > temporal_calendar_like, const char *method_name)
MaybeDirectHandle< JSTemporalDuration > ToTemporalDuration(Isolate *isolate, DirectHandle< Object > item, const char *method_name)
Maybe< DurationRecord > ToPartialDuration(Isolate *isolate, DirectHandle< Object > temporal_duration_like_obj, const DurationRecord &input)
Maybe< bool > IterateDurationRecordFieldsTable(Isolate *isolate, DirectHandle< JSReceiver > temporal_duration_like, Maybe< bool >(*RowFunction)(Isolate *, DirectHandle< JSReceiver > temporal_duration_like, DirectHandle< String >, double *), DurationRecord *record)
bool IsValidDuration(Isolate *isolate, const DurationRecord &dur)
MaybeDirectHandle< JSTemporalPlainTime > ToTemporalTime(Isolate *isolate, DirectHandle< Object > item_obj, const char *method_name, ShowOverflow overflow=ShowOverflow::kConstrain)
MaybeDirectHandle< Oddball > IsInvalidTemporalCalendarField(Isolate *isolate, DirectHandle< String > next_value, DirectHandle< FixedArray > fields_name)
MaybeDirectHandle< JSReceiver > ToTemporalTimeZone(Isolate *isolate, DirectHandle< Object > temporal_time_zone_like, const char *method_name)
Maybe< TimeRecord > RegulateTime(Isolate *isolate, const TimeRecord &time, ShowOverflow overflow)
DirectHandle< JSTemporalCalendar > GetISO8601Calendar(Isolate *isolate)
MaybeDirectHandle< JSTemporalPlainDateTime > BuiltinTimeZoneGetPlainDateTimeFor(Isolate *isolate, DirectHandle< JSReceiver > time_zone, DirectHandle< JSTemporalInstant > instant, DirectHandle< JSReceiver > calendar, const char *method_name)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
@ kEnumerationOrder
Definition globals.h:2859
double MakeDate(double day, double time)
Definition date.cc:491
constexpr int kMinInt31
Definition globals.h:385
constexpr double kMaxSafeInteger
Definition globals.h:1985
bool IsNaN(Tagged< Object > obj)
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
bool IsNumber(Tagged< Object > obj)
Maybe< double > GetNumberOptionAsDouble(Isolate *isolate, DirectHandle< JSReceiver > options, DirectHandle< String > property, double default_value)
constexpr AddrMode Offset
MaybeDirectHandle< JSReceiver > GetOptionsObject(Isolate *isolate, DirectHandle< Object > options, const char *method_name)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
MaybeDirectHandle< Object > GetTransition(Isolate *isolate, DirectHandle< JSTemporalTimeZone > time_zone, DirectHandle< Object > starting_point_obj, const char *method_name)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
constexpr int U
MaybeDirectHandle< JSArray > GetIANATimeZoneEpochValueAsArrayOfInstant(Isolate *isolate, int32_t time_zone_index, const DateTimeRecord &date_time)
MaybeDirectHandle< T > ZonedDateTimeToPlainYearMonthOrMonthDay(Isolate *isolate, DirectHandle< JSTemporalZonedDateTime > zoned_date_time, DirectHandle< String > field_name_1, DirectHandle< String > field_name_2, const char *method_name)
double MakeDay(double year, double month, double date)
Definition date.cc:498
int32_t NumberToInt32(Tagged< Object > number)
double MakeTime(double hour, double min, double sec, double ms)
Definition date.cc:541
int FastD2I(double x)
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:669
return value
Definition map-inl.h:893
static bool IsMinusZero(double value)
constexpr int AsciiAlphaToLower(base::uc32 c)
Maybe< bool > GetStringOption(Isolate *isolate, DirectHandle< JSReceiver > options, const char *property, const std::vector< const char * > &values, const char *method_name, std::unique_ptr< char[]> *result)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
second_parts OffsetMillisecondsOrTimeZoneIndex offset_milliseconds_or_time_zone_index
MaybeDirectHandle< JSArray > GetIANATimeZoneEpochValueAsArrayOfInstantForUTC(Isolate *isolate, const DateTimeRecord &date_time)
template const char * string
MaybeDirectHandle< R > ToPlain(Isolate *isolate, DirectHandle< T > t, DirectHandle< String > f1, DirectHandle< String > f2)
second_parts offset_milliseconds
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
uint32_t equals
uint32_t compare
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
static int32_t Sign(const DurationRecord &dur)
static Maybe< TimeDurationRecord > Create(Isolate *isolate, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
Symbol identifier
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
wasm::ValueType type