1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "builtin/temporal/PlainDateTime.h"
9 #include "mozilla/Assertions.h"
12 #include <type_traits>
17 #include "NamespaceImports.h"
19 #include "builtin/temporal/Calendar.h"
20 #include "builtin/temporal/Duration.h"
21 #include "builtin/temporal/PlainDate.h"
22 #include "builtin/temporal/PlainMonthDay.h"
23 #include "builtin/temporal/PlainTime.h"
24 #include "builtin/temporal/PlainYearMonth.h"
25 #include "builtin/temporal/Temporal.h"
26 #include "builtin/temporal/TemporalFields.h"
27 #include "builtin/temporal/TemporalParser.h"
28 #include "builtin/temporal/TemporalRoundingMode.h"
29 #include "builtin/temporal/TemporalTypes.h"
30 #include "builtin/temporal/TemporalUnit.h"
31 #include "builtin/temporal/TimeZone.h"
32 #include "builtin/temporal/ToString.h"
33 #include "builtin/temporal/Wrapped.h"
34 #include "builtin/temporal/ZonedDateTime.h"
35 #include "ds/IdValuePair.h"
36 #include "gc/AllocKind.h"
37 #include "gc/Barrier.h"
38 #include "js/AllocPolicy.h"
39 #include "js/CallArgs.h"
40 #include "js/CallNonGenericMethod.h"
42 #include "js/ErrorReport.h"
43 #include "js/friend/ErrorMessages.h"
44 #include "js/GCVector.h"
46 #include "js/PropertyDescriptor.h"
47 #include "js/PropertySpec.h"
48 #include "js/RootingAPI.h"
49 #include "js/TypeDecls.h"
51 #include "vm/BytecodeUtil.h"
52 #include "vm/GlobalObject.h"
53 #include "vm/JSAtomState.h"
54 #include "vm/JSContext.h"
55 #include "vm/JSObject.h"
56 #include "vm/ObjectOperations.h"
57 #include "vm/PlainObject.h"
58 #include "vm/StringType.h"
60 #include "vm/JSObject-inl.h"
61 #include "vm/NativeObject-inl.h"
64 using namespace js::temporal
;
66 static inline bool IsPlainDateTime(Handle
<Value
> v
) {
67 return v
.isObject() && v
.toObject().is
<PlainDateTimeObject
>();
72 * IsValidISODateTime ( year, month, day, hour, minute, second, millisecond,
73 * microsecond, nanosecond )
75 bool js::temporal::IsValidISODateTime(const PlainDateTime
& dateTime
) {
76 return IsValidISODate(dateTime
.date
) && IsValidTime(dateTime
.time
);
81 * IsValidISODateTime ( year, month, day, hour, minute, second, millisecond,
82 * microsecond, nanosecond )
84 static bool ThrowIfInvalidISODateTime(JSContext
* cx
,
85 const PlainDateTime
& dateTime
) {
86 return ThrowIfInvalidISODate(cx
, dateTime
.date
) &&
87 ThrowIfInvalidTime(cx
, dateTime
.time
);
91 * ISODateTimeWithinLimits ( year, month, day, hour, minute, second,
92 * millisecond, microsecond, nanosecond )
95 static bool ISODateTimeWithinLimits(T year
, T month
, T day
, T hour
, T minute
,
96 T second
, T millisecond
, T microsecond
,
98 static_assert(std::is_same_v
<T
, int32_t> || std::is_same_v
<T
, double>);
101 MOZ_ASSERT(IsInteger(year
));
102 MOZ_ASSERT(IsInteger(month
));
103 MOZ_ASSERT(IsInteger(day
));
104 MOZ_ASSERT(IsInteger(hour
));
105 MOZ_ASSERT(IsInteger(minute
));
106 MOZ_ASSERT(IsInteger(second
));
107 MOZ_ASSERT(IsInteger(millisecond
));
108 MOZ_ASSERT(IsInteger(microsecond
));
109 MOZ_ASSERT(IsInteger(nanosecond
));
111 MOZ_ASSERT(IsValidISODate(year
, month
, day
));
113 IsValidTime(hour
, minute
, second
, millisecond
, microsecond
, nanosecond
));
115 // js> new Date(-8_64000_00000_00000).toISOString()
116 // "-271821-04-20T00:00:00.000Z"
118 // js> new Date(+8_64000_00000_00000).toISOString()
119 // "+275760-09-13T00:00:00.000Z"
121 constexpr int32_t minYear
= -271821;
122 constexpr int32_t maxYear
= 275760;
124 // Definitely in range.
125 if (minYear
< year
&& year
< maxYear
) {
131 if (year
!= minYear
) {
137 if (day
!= (20 - 1)) {
138 return day
> (20 - 1);
140 // Needs to be past midnight on April, 19.
141 return !(hour
== 0 && minute
== 0 && second
== 0 && millisecond
== 0 &&
142 microsecond
== 0 && nanosecond
== 0);
145 // 275760 September, 13
146 if (year
!= maxYear
) {
159 * ISODateTimeWithinLimits ( year, month, day, hour, minute, second,
160 * millisecond, microsecond, nanosecond )
162 template <typename T
>
163 static bool ISODateTimeWithinLimits(T year
, T month
, T day
) {
164 static_assert(std::is_same_v
<T
, int32_t> || std::is_same_v
<T
, double>);
166 MOZ_ASSERT(IsValidISODate(year
, month
, day
));
168 // js> new Date(-8_64000_00000_00000).toISOString()
169 // "-271821-04-20T00:00:00.000Z"
171 // js> new Date(+8_64000_00000_00000).toISOString()
172 // "+275760-09-13T00:00:00.000Z"
174 constexpr int32_t minYear
= -271821;
175 constexpr int32_t maxYear
= 275760;
177 // ISODateTimeWithinLimits is called with hour=12 and the remaining time
178 // components set to zero. That means the maximum value is exclusive, whereas
179 // the minimum value is inclusive.
181 // Definitely in range.
182 if (minYear
< year
&& year
< maxYear
) {
188 if (year
!= minYear
) {
194 if (day
< (20 - 1)) {
200 // 275760 September, 13
201 if (year
!= maxYear
) {
214 * ISODateTimeWithinLimits ( year, month, day, hour, minute, second,
215 * millisecond, microsecond, nanosecond )
217 bool js::temporal::ISODateTimeWithinLimits(double year
, double month
,
219 return ::ISODateTimeWithinLimits(year
, month
, day
);
223 * ISODateTimeWithinLimits ( year, month, day, hour, minute, second,
224 * millisecond, microsecond, nanosecond )
226 bool js::temporal::ISODateTimeWithinLimits(const PlainDateTime
& dateTime
) {
227 const auto& [date
, time
] = dateTime
;
228 return ::ISODateTimeWithinLimits(date
.year
, date
.month
, date
.day
, time
.hour
,
229 time
.minute
, time
.second
, time
.millisecond
,
230 time
.microsecond
, time
.nanosecond
);
234 * ISODateTimeWithinLimits ( year, month, day, hour, minute, second,
235 * millisecond, microsecond, nanosecond )
237 bool js::temporal::ISODateTimeWithinLimits(const PlainDate
& date
) {
238 return ::ISODateTimeWithinLimits(date
.year
, date
.month
, date
.day
);
242 * CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second,
243 * millisecond, microsecond, nanosecond, calendar [ , newTarget ] )
245 static PlainDateTimeObject
* CreateTemporalDateTime(
246 JSContext
* cx
, const CallArgs
& args
, double isoYear
, double isoMonth
,
247 double isoDay
, double hour
, double minute
, double second
,
248 double millisecond
, double microsecond
, double nanosecond
,
249 Handle
<CalendarValue
> calendar
) {
250 MOZ_ASSERT(IsInteger(isoYear
));
251 MOZ_ASSERT(IsInteger(isoMonth
));
252 MOZ_ASSERT(IsInteger(isoDay
));
253 MOZ_ASSERT(IsInteger(hour
));
254 MOZ_ASSERT(IsInteger(minute
));
255 MOZ_ASSERT(IsInteger(second
));
256 MOZ_ASSERT(IsInteger(millisecond
));
257 MOZ_ASSERT(IsInteger(microsecond
));
258 MOZ_ASSERT(IsInteger(nanosecond
));
261 if (!ThrowIfInvalidISODate(cx
, isoYear
, isoMonth
, isoDay
)) {
266 if (!ThrowIfInvalidTime(cx
, hour
, minute
, second
, millisecond
, microsecond
,
272 if (!ISODateTimeWithinLimits(isoYear
, isoMonth
, isoDay
, hour
, minute
, second
,
273 millisecond
, microsecond
, nanosecond
)) {
274 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
275 JSMSG_TEMPORAL_PLAIN_DATE_TIME_INVALID
);
280 Rooted
<JSObject
*> proto(cx
);
281 if (!GetPrototypeFromBuiltinConstructor(cx
, args
, JSProto_PlainDateTime
,
286 auto* dateTime
= NewObjectWithClassProto
<PlainDateTimeObject
>(cx
, proto
);
292 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_YEAR_SLOT
,
293 Int32Value(int32_t(isoYear
)));
296 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_MONTH_SLOT
,
297 Int32Value(int32_t(isoMonth
)));
300 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_DAY_SLOT
,
301 Int32Value(int32_t(isoDay
)));
304 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_HOUR_SLOT
,
305 Int32Value(int32_t(hour
)));
308 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_MINUTE_SLOT
,
309 Int32Value(int32_t(minute
)));
312 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_SECOND_SLOT
,
313 Int32Value(int32_t(second
)));
316 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_MILLISECOND_SLOT
,
317 Int32Value(int32_t(millisecond
)));
320 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_MICROSECOND_SLOT
,
321 Int32Value(int32_t(microsecond
)));
324 dateTime
->setFixedSlot(PlainDateTimeObject::ISO_NANOSECOND_SLOT
,
325 Int32Value(int32_t(nanosecond
)));
328 dateTime
->setFixedSlot(PlainDateTimeObject::CALENDAR_SLOT
,
336 * CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second,
337 * millisecond, microsecond, nanosecond, calendar [ , newTarget ] )
339 PlainDateTimeObject
* js::temporal::CreateTemporalDateTime(
340 JSContext
* cx
, const PlainDateTime
& dateTime
,
341 Handle
<CalendarValue
> calendar
) {
342 const auto& [date
, time
] = dateTime
;
343 const auto& [isoYear
, isoMonth
, isoDay
] = date
;
344 const auto& [hour
, minute
, second
, millisecond
, microsecond
, nanosecond
] =
348 if (!ThrowIfInvalidISODateTime(cx
, dateTime
)) {
353 if (!ISODateTimeWithinLimits(dateTime
)) {
354 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
355 JSMSG_TEMPORAL_PLAIN_DATE_TIME_INVALID
);
360 auto* object
= NewBuiltinClassInstance
<PlainDateTimeObject
>(cx
);
366 object
->setFixedSlot(PlainDateTimeObject::ISO_YEAR_SLOT
, Int32Value(isoYear
));
369 object
->setFixedSlot(PlainDateTimeObject::ISO_MONTH_SLOT
,
370 Int32Value(isoMonth
));
373 object
->setFixedSlot(PlainDateTimeObject::ISO_DAY_SLOT
, Int32Value(isoDay
));
376 object
->setFixedSlot(PlainDateTimeObject::ISO_HOUR_SLOT
, Int32Value(hour
));
379 object
->setFixedSlot(PlainDateTimeObject::ISO_MINUTE_SLOT
,
383 object
->setFixedSlot(PlainDateTimeObject::ISO_SECOND_SLOT
,
387 object
->setFixedSlot(PlainDateTimeObject::ISO_MILLISECOND_SLOT
,
388 Int32Value(millisecond
));
391 object
->setFixedSlot(PlainDateTimeObject::ISO_MICROSECOND_SLOT
,
392 Int32Value(microsecond
));
395 object
->setFixedSlot(PlainDateTimeObject::ISO_NANOSECOND_SLOT
,
396 Int32Value(nanosecond
));
399 object
->setFixedSlot(PlainDateTimeObject::CALENDAR_SLOT
, calendar
.toValue());
406 * CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second,
407 * millisecond, microsecond, nanosecond, calendar [ , newTarget ] )
409 bool js::temporal::CreateTemporalDateTime(
410 JSContext
* cx
, const PlainDateTime
& dateTime
,
411 Handle
<CalendarValue
> calendar
,
412 MutableHandle
<PlainDateTimeWithCalendar
> result
) {
414 if (!ThrowIfInvalidISODateTime(cx
, dateTime
)) {
419 if (!ISODateTimeWithinLimits(dateTime
)) {
420 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
421 JSMSG_TEMPORAL_PLAIN_DATE_TIME_INVALID
);
425 result
.set(PlainDateTimeWithCalendar
{dateTime
, calendar
});
430 * InterpretTemporalDateTimeFields ( calendarRec, fields, options )
432 bool js::temporal::InterpretTemporalDateTimeFields(
433 JSContext
* cx
, Handle
<CalendarRecord
> calendar
, Handle
<PlainObject
*> fields
,
434 Handle
<PlainObject
*> options
, PlainDateTime
* result
) {
435 // Step 1. (Not applicable in our implementation.)
438 MOZ_ASSERT(CalendarMethodsRecordHasLookedUp(calendar
,
439 CalendarMethod::DateFromFields
));
442 TemporalTimeLike timeResult
;
443 if (!ToTemporalTimeRecord(cx
, fields
, &timeResult
)) {
448 auto overflow
= TemporalOverflow::Constrain
;
449 if (!ToTemporalOverflow(cx
, options
, &overflow
)) {
454 Rooted
<Value
> overflowValue(cx
);
455 if (overflow
== TemporalOverflow::Constrain
) {
456 overflowValue
.setString(cx
->names().constrain
);
458 MOZ_ASSERT(overflow
== TemporalOverflow::Reject
);
459 overflowValue
.setString(cx
->names().reject
);
461 if (!DefineDataProperty(cx
, options
, cx
->names().overflow
, overflowValue
)) {
467 js::temporal::CalendarDateFromFields(cx
, calendar
, fields
, options
);
471 auto date
= ToPlainDate(&temporalDate
.unwrap());
475 if (!RegulateTime(cx
, timeResult
, overflow
, &time
)) {
480 *result
= {date
, time
};
485 * InterpretTemporalDateTimeFields ( calendarRec, fields, options )
487 bool js::temporal::InterpretTemporalDateTimeFields(
488 JSContext
* cx
, Handle
<CalendarRecord
> calendar
, Handle
<PlainObject
*> fields
,
489 PlainDateTime
* result
) {
490 // TODO: Avoid creating the options object when CalendarDateFromFields calls
491 // the built-in Calendar.prototype.dateFromFields method.
492 Rooted
<PlainObject
*> options(cx
, NewPlainObjectWithProto(cx
, nullptr));
497 return InterpretTemporalDateTimeFields(cx
, calendar
, fields
, options
, result
);
501 * ToTemporalDateTime ( item [ , options ] )
503 static Wrapped
<PlainDateTimeObject
*> ToTemporalDateTime(
504 JSContext
* cx
, Handle
<Value
> item
, Handle
<JSObject
*> maybeOptions
) {
505 // Step 1. (Not applicable)
508 Rooted
<PlainObject
*> maybeResolvedOptions(cx
);
510 maybeResolvedOptions
= SnapshotOwnProperties(cx
, maybeOptions
);
511 if (!maybeResolvedOptions
) {
517 Rooted
<CalendarValue
> calendar(cx
);
518 PlainDateTime result
;
519 if (item
.isObject()) {
520 Rooted
<JSObject
*> itemObj(cx
, &item
.toObject());
523 if (itemObj
->canUnwrapAs
<PlainDateTimeObject
>()) {
528 if (auto* zonedDateTime
= itemObj
->maybeUnwrapIf
<ZonedDateTimeObject
>()) {
529 auto epochInstant
= ToInstant(zonedDateTime
);
530 Rooted
<TimeZoneValue
> timeZone(cx
, zonedDateTime
->timeZone());
531 Rooted
<CalendarValue
> calendar(cx
, zonedDateTime
->calendar());
533 if (!timeZone
.wrap(cx
)) {
536 if (!calendar
.wrap(cx
)) {
541 if (maybeResolvedOptions
) {
542 TemporalOverflow ignored
;
543 if (!ToTemporalOverflow(cx
, maybeResolvedOptions
, &ignored
)) {
549 return GetPlainDateTimeFor(cx
, timeZone
, epochInstant
, calendar
);
553 if (auto* date
= itemObj
->maybeUnwrapIf
<PlainDateObject
>()) {
554 PlainDateTime dateTime
= {ToPlainDate(date
), {}};
555 Rooted
<CalendarValue
> calendar(cx
, date
->calendar());
556 if (!calendar
.wrap(cx
)) {
561 if (maybeResolvedOptions
) {
562 TemporalOverflow ignored
;
563 if (!ToTemporalOverflow(cx
, maybeResolvedOptions
, &ignored
)) {
569 return CreateTemporalDateTime(cx
, dateTime
, calendar
);
573 if (!GetTemporalCalendarWithISODefault(cx
, itemObj
, &calendar
)) {
578 Rooted
<CalendarRecord
> calendarRec(cx
);
579 if (!CreateCalendarMethodsRecord(cx
, calendar
,
581 CalendarMethod::DateFromFields
,
582 CalendarMethod::Fields
,
589 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
590 if (!CalendarFields(cx
, calendarRec
,
591 {CalendarField::Day
, CalendarField::Month
,
592 CalendarField::MonthCode
, CalendarField::Year
},
598 if (!AppendSorted(cx
, fieldNames
.get(),
601 TemporalField::Microsecond
,
602 TemporalField::Millisecond
,
603 TemporalField::Minute
,
604 TemporalField::Nanosecond
,
605 TemporalField::Second
,
611 Rooted
<PlainObject
*> fields(cx
,
612 PrepareTemporalFields(cx
, itemObj
, fieldNames
));
618 if (maybeResolvedOptions
) {
619 if (!InterpretTemporalDateTimeFields(cx
, calendarRec
, fields
,
620 maybeResolvedOptions
, &result
)) {
624 if (!InterpretTemporalDateTimeFields(cx
, calendarRec
, fields
, &result
)) {
630 if (!item
.isString()) {
631 ReportValueError(cx
, JSMSG_UNEXPECTED_TYPE
, JSDVG_IGNORE_STACK
, item
,
632 nullptr, "not a string");
635 Rooted
<JSString
*> string(cx
, item
.toString());
638 Rooted
<JSString
*> calendarString(cx
);
639 if (!ParseTemporalDateTimeString(cx
, string
, &result
, &calendarString
)) {
644 MOZ_ASSERT(IsValidISODate(result
.date
));
647 MOZ_ASSERT(IsValidTime(result
.time
));
650 if (calendarString
) {
651 if (!ToBuiltinCalendar(cx
, calendarString
, &calendar
)) {
655 calendar
.set(CalendarValue(cx
->names().iso8601
));
659 if (maybeResolvedOptions
) {
660 TemporalOverflow ignored
;
661 if (!ToTemporalOverflow(cx
, maybeResolvedOptions
, &ignored
)) {
668 return CreateTemporalDateTime(cx
, result
, calendar
);
672 * ToTemporalDateTime ( item [ , options ] )
674 Wrapped
<PlainDateTimeObject
*> js::temporal::ToTemporalDateTime(
675 JSContext
* cx
, Handle
<Value
> item
) {
676 return ::ToTemporalDateTime(cx
, item
, nullptr);
680 * ToTemporalDateTime ( item [ , options ] )
682 bool js::temporal::ToTemporalDateTime(JSContext
* cx
, Handle
<Value
> item
,
683 PlainDateTime
* result
) {
684 auto obj
= ::ToTemporalDateTime(cx
, item
, nullptr);
689 *result
= ToPlainDateTime(&obj
.unwrap());
694 * ToTemporalDateTime ( item [ , options ] )
696 static bool ToTemporalDateTime(
697 JSContext
* cx
, Handle
<Value
> item
,
698 MutableHandle
<PlainDateTimeWithCalendar
> result
) {
699 Handle
<JSObject
*> options
= nullptr;
701 auto* obj
= ::ToTemporalDateTime(cx
, item
, options
).unwrapOrNull();
706 auto dateTime
= ToPlainDateTime(obj
);
707 Rooted
<CalendarValue
> calendar(cx
, obj
->calendar());
708 if (!calendar
.wrap(cx
)) {
712 result
.set(PlainDateTimeWithCalendar
{dateTime
, calendar
});
717 * CompareISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2,
718 * d2, h2, min2, s2, ms2, mus2, ns2 )
720 static int32_t CompareISODateTime(const PlainDateTime
& one
,
721 const PlainDateTime
& two
) {
722 // Step 1. (Not applicable in our implementation.)
725 if (int32_t dateResult
= CompareISODate(one
.date
, two
.date
)) {
730 return CompareTemporalTime(one
.time
, two
.time
);
734 * AddDateTime ( year, month, day, hour, minute, second, millisecond,
735 * microsecond, nanosecond, calendarRec, years, months, weeks, days, norm,
738 static bool AddDateTime(JSContext
* cx
, const PlainDateTime
& dateTime
,
739 Handle
<CalendarRecord
> calendar
,
740 const NormalizedDuration
& duration
,
741 Handle
<JSObject
*> options
, PlainDateTime
* result
) {
742 MOZ_ASSERT(IsValidDuration(duration
));
745 MOZ_ASSERT(IsValidISODateTime(dateTime
));
746 MOZ_ASSERT(ISODateTimeWithinLimits(dateTime
));
749 auto timeResult
= AddTime(dateTime
.time
, duration
.time
);
752 const auto& datePart
= dateTime
.date
;
755 auto dateDuration
= DateDuration
{
757 duration
.date
.months
,
759 duration
.date
.days
+ timeResult
.days
,
761 if (!ThrowIfInvalidDuration(cx
, dateDuration
)) {
767 if (!AddDate(cx
, calendar
, datePart
, dateDuration
, options
, &addedDate
)) {
772 *result
= {addedDate
, timeResult
.time
};
777 * DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2,
778 * d2, h2, min2, s2, ms2, mus2, ns2, calendarRec, largestUnit, options )
780 static bool DifferenceISODateTime(JSContext
* cx
, const PlainDateTime
& one
,
781 const PlainDateTime
& two
,
782 Handle
<CalendarRecord
> calendar
,
783 TemporalUnit largestUnit
,
784 Handle
<PlainObject
*> maybeOptions
,
785 NormalizedDuration
* result
) {
787 MOZ_ASSERT(IsValidISODateTime(one
));
788 MOZ_ASSERT(IsValidISODateTime(two
));
789 MOZ_ASSERT(ISODateTimeWithinLimits(one
));
790 MOZ_ASSERT(ISODateTimeWithinLimits(two
));
794 one
.date
!= two
.date
&& largestUnit
< TemporalUnit::Day
,
795 CalendarMethodsRecordHasLookedUp(calendar
, CalendarMethod::DateUntil
));
798 auto timeDuration
= DifferenceTime(one
.time
, two
.time
);
801 int32_t timeSign
= NormalizedTimeDurationSign(timeDuration
);
804 int32_t dateSign
= CompareISODate(two
.date
, one
.date
);
807 auto adjustedDate
= one
.date
;
810 if (timeSign
== -dateSign
) {
812 adjustedDate
= BalanceISODate(adjustedDate
.year
, adjustedDate
.month
,
813 adjustedDate
.day
- timeSign
);
816 if (!Add24HourDaysToNormalizedTimeDuration(cx
, timeDuration
, -timeSign
,
822 MOZ_ASSERT(IsValidISODate(adjustedDate
));
823 MOZ_ASSERT(ISODateTimeWithinLimits(adjustedDate
));
825 // TODO: Avoid allocating CreateTemporalDate.
828 Rooted
<PlainDateObject
*> date1(
829 cx
, CreateTemporalDate(cx
, adjustedDate
, calendar
.receiver()));
835 Rooted
<PlainDateObject
*> date2(
836 cx
, CreateTemporalDate(cx
, two
.date
, calendar
.receiver()));
842 auto dateLargestUnit
= std::min(TemporalUnit::Day
, largestUnit
);
844 DateDuration dateDifference
;
848 // The spec performs an unnecessary copy operation. As an optimization, we
850 auto untilOptions
= maybeOptions
;
853 Rooted
<Value
> largestUnitValue(
854 cx
, StringValue(TemporalUnitToString(cx
, dateLargestUnit
)));
855 if (!DefineDataProperty(cx
, untilOptions
, cx
->names().largestUnit
,
861 if (!DifferenceDate(cx
, calendar
, date1
, date2
, untilOptions
,
867 if (!DifferenceDate(cx
, calendar
, date1
, date2
, dateLargestUnit
,
874 return CreateNormalizedDurationRecord(cx
, dateDifference
, timeDuration
,
879 * DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2,
880 * d2, h2, min2, s2, ms2, mus2, ns2, calendarRec, largestUnit, options )
882 bool js::temporal::DifferenceISODateTime(JSContext
* cx
,
883 const PlainDateTime
& one
,
884 const PlainDateTime
& two
,
885 Handle
<CalendarRecord
> calendar
,
886 TemporalUnit largestUnit
,
887 DateDuration
* result
) {
888 NormalizedDuration normalized
;
889 if (!::DifferenceISODateTime(cx
, one
, two
, calendar
, largestUnit
, nullptr,
893 *result
= normalized
.date
;
898 * DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2,
899 * d2, h2, min2, s2, ms2, mus2, ns2, calendarRec, largestUnit, options )
901 bool js::temporal::DifferenceISODateTime(
902 JSContext
* cx
, const PlainDateTime
& one
, const PlainDateTime
& two
,
903 Handle
<CalendarRecord
> calendar
, TemporalUnit largestUnit
,
904 Handle
<PlainObject
*> options
, DateDuration
* result
) {
905 NormalizedDuration normalized
;
906 if (!::DifferenceISODateTime(cx
, one
, two
, calendar
, largestUnit
, options
,
910 *result
= normalized
.date
;
915 * RoundISODateTime ( year, month, day, hour, minute, second, millisecond,
916 * microsecond, nanosecond, increment, unit, roundingMode [ , dayLength ] )
918 static PlainDateTime
RoundISODateTime(const PlainDateTime
& dateTime
,
919 Increment increment
, TemporalUnit unit
,
920 TemporalRoundingMode roundingMode
) {
921 const auto& [date
, time
] = dateTime
;
924 MOZ_ASSERT(IsValidISODateTime(dateTime
));
925 MOZ_ASSERT(ISODateTimeWithinLimits(dateTime
));
927 // Step 2. (Not applicable in our implementation.)
930 auto roundedTime
= RoundTime(time
, increment
, unit
, roundingMode
);
931 MOZ_ASSERT(0 <= roundedTime
.days
&& roundedTime
.days
<= 1);
934 auto balanceResult
= BalanceISODate(date
.year
, date
.month
,
935 date
.day
+ int32_t(roundedTime
.days
));
938 return {balanceResult
, roundedTime
.time
};
942 * DifferenceTemporalPlainDateTime ( operation, dateTime, other, options )
944 static bool DifferenceTemporalPlainDateTime(JSContext
* cx
,
945 TemporalDifference operation
,
946 const CallArgs
& args
) {
947 Rooted
<PlainDateTimeWithCalendar
> dateTime(
948 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
950 // Step 1. (Not applicable in our implementation.)
953 Rooted
<PlainDateTimeWithCalendar
> other(cx
);
954 if (!::ToTemporalDateTime(cx
, args
.get(0), &other
)) {
959 if (!CalendarEqualsOrThrow(cx
, dateTime
.calendar(), other
.calendar())) {
964 DifferenceSettings settings
;
965 Rooted
<PlainObject
*> resolvedOptions(cx
);
966 if (args
.hasDefined(1)) {
967 Rooted
<JSObject
*> options(
968 cx
, RequireObjectArg(cx
, "options", ToName(operation
), args
[1]));
974 resolvedOptions
= SnapshotOwnProperties(cx
, options
);
975 if (!resolvedOptions
) {
980 if (!GetDifferenceSettings(
981 cx
, operation
, resolvedOptions
, TemporalUnitGroup::DateTime
,
982 TemporalUnit::Nanosecond
, TemporalUnit::Day
, &settings
)) {
988 TemporalUnit::Nanosecond
,
990 TemporalRoundingMode::Trunc
,
996 bool datePartsIdentical
= dateTime
.date() == other
.date();
999 if (datePartsIdentical
&& dateTime
.time() == other
.time()) {
1000 auto* obj
= CreateTemporalDuration(cx
, {});
1005 args
.rval().setObject(*obj
);
1010 Rooted
<CalendarRecord
> calendar(cx
);
1011 if (!CreateCalendarMethodsRecord(cx
, dateTime
.calendar(),
1013 CalendarMethod::DateAdd
,
1014 CalendarMethod::DateUntil
,
1021 NormalizedDuration diff
;
1022 if (!::DifferenceISODateTime(cx
, dateTime
, other
, calendar
,
1023 settings
.largestUnit
, resolvedOptions
, &diff
)) {
1028 bool roundingGranularityIsNoop
=
1029 settings
.smallestUnit
== TemporalUnit::Nanosecond
&&
1030 settings
.roundingIncrement
== Increment
{1};
1033 DateDuration balancedDate
;
1034 TimeDuration balancedTime
;
1035 if (!roundingGranularityIsNoop
) {
1037 Rooted
<PlainDateObject
*> relativeTo(
1038 cx
, CreateTemporalDate(cx
, dateTime
.date(), dateTime
.calendar()));
1044 NormalizedDuration roundResult
;
1045 if (!temporal::RoundDuration(cx
, diff
, settings
.roundingIncrement
,
1046 settings
.smallestUnit
, settings
.roundingMode
,
1047 relativeTo
, calendar
, &roundResult
)) {
1052 NormalizedTimeDuration withDays
;
1053 if (!Add24HourDaysToNormalizedTimeDuration(
1054 cx
, roundResult
.time
, roundResult
.date
.days
, &withDays
)) {
1059 if (!BalanceTimeDuration(cx
, withDays
, settings
.largestUnit
,
1065 auto toBalance
= DateDuration
{
1066 roundResult
.date
.years
,
1067 roundResult
.date
.months
,
1068 roundResult
.date
.weeks
,
1071 if (!temporal::BalanceDateDurationRelative(
1072 cx
, toBalance
, settings
.largestUnit
, settings
.smallestUnit
,
1073 relativeTo
, calendar
, &balancedDate
)) {
1078 NormalizedTimeDuration withDays
;
1079 if (!Add24HourDaysToNormalizedTimeDuration(cx
, diff
.time
, diff
.date
.days
,
1085 if (!BalanceTimeDuration(cx
, withDays
, settings
.largestUnit
,
1098 MOZ_ASSERT(IsValidDuration(balancedDate
));
1101 Duration duration
= {
1102 double(balancedDate
.years
), double(balancedDate
.months
),
1103 double(balancedDate
.weeks
), double(balancedDate
.days
),
1104 double(balancedTime
.hours
), double(balancedTime
.minutes
),
1105 double(balancedTime
.seconds
), double(balancedTime
.milliseconds
),
1106 balancedTime
.microseconds
, balancedTime
.nanoseconds
,
1108 if (operation
== TemporalDifference::Since
) {
1109 duration
= duration
.negate();
1112 auto* obj
= CreateTemporalDuration(cx
, duration
);
1117 args
.rval().setObject(*obj
);
1121 enum class PlainDateTimeDuration
{ Add
, Subtract
};
1124 * AddDurationToOrSubtractDurationFromPlainDateTime ( operation, dateTime,
1125 * temporalDurationLike, options )
1127 static bool AddDurationToOrSubtractDurationFromPlainDateTime(
1128 JSContext
* cx
, PlainDateTimeDuration operation
, const CallArgs
& args
) {
1129 Rooted
<PlainDateTimeWithCalendar
> dateTime(
1130 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1132 // Step 1. (Not applicable in our implementation.)
1136 if (!ToTemporalDurationRecord(cx
, args
.get(0), &duration
)) {
1141 Rooted
<JSObject
*> options(cx
);
1142 if (args
.hasDefined(1)) {
1144 operation
== PlainDateTimeDuration::Add
? "add" : "subtract";
1145 options
= RequireObjectArg(cx
, "options", name
, args
[1]);
1147 options
= NewPlainObjectWithProto(cx
, nullptr);
1154 Rooted
<CalendarRecord
> calendar(cx
);
1155 if (!CreateCalendarMethodsRecord(cx
, dateTime
.calendar(),
1157 CalendarMethod::DateAdd
,
1164 if (operation
== PlainDateTimeDuration::Subtract
) {
1165 duration
= duration
.negate();
1167 auto normalized
= CreateNormalizedDurationRecord(duration
);
1170 PlainDateTime result
;
1171 if (!AddDateTime(cx
, dateTime
, calendar
, normalized
, options
, &result
)) {
1176 MOZ_ASSERT(IsValidISODateTime(result
));
1179 auto* obj
= CreateTemporalDateTime(cx
, result
, dateTime
.calendar());
1184 args
.rval().setObject(*obj
);
1189 * Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ ,
1190 * second [ , millisecond [ , microsecond [ , nanosecond [ , calendarLike ] ] ]
1193 static bool PlainDateTimeConstructor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1194 CallArgs args
= CallArgsFromVp(argc
, vp
);
1197 if (!ThrowIfNotConstructing(cx
, args
, "Temporal.PlainDateTime")) {
1203 if (!ToIntegerWithTruncation(cx
, args
.get(0), "year", &isoYear
)) {
1209 if (!ToIntegerWithTruncation(cx
, args
.get(1), "month", &isoMonth
)) {
1215 if (!ToIntegerWithTruncation(cx
, args
.get(2), "day", &isoDay
)) {
1221 if (args
.hasDefined(3)) {
1222 if (!ToIntegerWithTruncation(cx
, args
[3], "hour", &hour
)) {
1229 if (args
.hasDefined(4)) {
1230 if (!ToIntegerWithTruncation(cx
, args
[4], "minute", &minute
)) {
1237 if (args
.hasDefined(5)) {
1238 if (!ToIntegerWithTruncation(cx
, args
[5], "second", &second
)) {
1244 double millisecond
= 0;
1245 if (args
.hasDefined(6)) {
1246 if (!ToIntegerWithTruncation(cx
, args
[6], "millisecond", &millisecond
)) {
1252 double microsecond
= 0;
1253 if (args
.hasDefined(7)) {
1254 if (!ToIntegerWithTruncation(cx
, args
[7], "microsecond", µsecond
)) {
1260 double nanosecond
= 0;
1261 if (args
.hasDefined(8)) {
1262 if (!ToIntegerWithTruncation(cx
, args
[8], "nanosecond", &nanosecond
)) {
1268 Rooted
<CalendarValue
> calendar(cx
);
1269 if (!ToTemporalCalendarWithISODefault(cx
, args
.get(9), &calendar
)) {
1274 auto* temporalDateTime
= CreateTemporalDateTime(
1275 cx
, args
, isoYear
, isoMonth
, isoDay
, hour
, minute
, second
, millisecond
,
1276 microsecond
, nanosecond
, calendar
);
1277 if (!temporalDateTime
) {
1281 args
.rval().setObject(*temporalDateTime
);
1286 * Temporal.PlainDateTime.from ( item [ , options ] )
1288 static bool PlainDateTime_from(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1289 CallArgs args
= CallArgsFromVp(argc
, vp
);
1292 Rooted
<JSObject
*> options(cx
);
1293 if (args
.hasDefined(1)) {
1294 options
= RequireObjectArg(cx
, "options", "from", args
[1]);
1301 if (args
.get(0).isObject()) {
1302 JSObject
* item
= &args
[0].toObject();
1303 if (auto* temporalDateTime
= item
->maybeUnwrapIf
<PlainDateTimeObject
>()) {
1304 auto dateTime
= ToPlainDateTime(temporalDateTime
);
1306 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1307 if (!calendar
.wrap(cx
)) {
1313 TemporalOverflow ignored
;
1314 if (!ToTemporalOverflow(cx
, options
, &ignored
)) {
1320 auto* result
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
1325 args
.rval().setObject(*result
);
1331 auto result
= ToTemporalDateTime(cx
, args
.get(0), options
);
1336 args
.rval().setObject(*result
);
1341 * Temporal.PlainDateTime.compare ( one, two )
1343 static bool PlainDateTime_compare(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1344 CallArgs args
= CallArgsFromVp(argc
, vp
);
1348 if (!ToTemporalDateTime(cx
, args
.get(0), &one
)) {
1354 if (!ToTemporalDateTime(cx
, args
.get(1), &two
)) {
1359 args
.rval().setInt32(CompareISODateTime(one
, two
));
1364 * get Temporal.PlainDateTime.prototype.calendarId
1366 static bool PlainDateTime_calendarId(JSContext
* cx
, const CallArgs
& args
) {
1367 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1370 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1371 auto* calendarId
= ToTemporalCalendarIdentifier(cx
, calendar
);
1376 args
.rval().setString(calendarId
);
1381 * get Temporal.PlainDateTime.prototype.calendarId
1383 static bool PlainDateTime_calendarId(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1385 CallArgs args
= CallArgsFromVp(argc
, vp
);
1386 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_calendarId
>(cx
,
1391 * get Temporal.PlainDateTime.prototype.year
1393 static bool PlainDateTime_year(JSContext
* cx
, const CallArgs
& args
) {
1395 Rooted
<PlainDateTimeObject
*> dateTime(
1396 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1397 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1400 return CalendarYear(cx
, calendar
, dateTime
, args
.rval());
1404 * get Temporal.PlainDateTime.prototype.year
1406 static bool PlainDateTime_year(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1408 CallArgs args
= CallArgsFromVp(argc
, vp
);
1409 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_year
>(cx
, args
);
1413 * get Temporal.PlainDateTime.prototype.month
1415 static bool PlainDateTime_month(JSContext
* cx
, const CallArgs
& args
) {
1417 Rooted
<PlainDateTimeObject
*> dateTime(
1418 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1419 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1422 return CalendarMonth(cx
, calendar
, dateTime
, args
.rval());
1426 * get Temporal.PlainDateTime.prototype.month
1428 static bool PlainDateTime_month(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1430 CallArgs args
= CallArgsFromVp(argc
, vp
);
1431 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_month
>(cx
, args
);
1435 * get Temporal.PlainDateTime.prototype.monthCode
1437 static bool PlainDateTime_monthCode(JSContext
* cx
, const CallArgs
& args
) {
1439 Rooted
<PlainDateTimeObject
*> dateTime(
1440 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1441 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1444 return CalendarMonthCode(cx
, calendar
, dateTime
, args
.rval());
1448 * get Temporal.PlainDateTime.prototype.monthCode
1450 static bool PlainDateTime_monthCode(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1452 CallArgs args
= CallArgsFromVp(argc
, vp
);
1453 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_monthCode
>(cx
,
1458 * get Temporal.PlainDateTime.prototype.day
1460 static bool PlainDateTime_day(JSContext
* cx
, const CallArgs
& args
) {
1462 Rooted
<PlainDateTimeObject
*> dateTime(
1463 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1464 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1467 return CalendarDay(cx
, calendar
, dateTime
, args
.rval());
1471 * get Temporal.PlainDateTime.prototype.day
1473 static bool PlainDateTime_day(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1475 CallArgs args
= CallArgsFromVp(argc
, vp
);
1476 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_day
>(cx
, args
);
1480 * get Temporal.PlainDateTime.prototype.hour
1482 static bool PlainDateTime_hour(JSContext
* cx
, const CallArgs
& args
) {
1484 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1485 args
.rval().setInt32(dateTime
->isoHour());
1490 * get Temporal.PlainDateTime.prototype.hour
1492 static bool PlainDateTime_hour(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1494 CallArgs args
= CallArgsFromVp(argc
, vp
);
1495 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_hour
>(cx
, args
);
1499 * get Temporal.PlainDateTime.prototype.minute
1501 static bool PlainDateTime_minute(JSContext
* cx
, const CallArgs
& args
) {
1503 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1504 args
.rval().setInt32(dateTime
->isoMinute());
1509 * get Temporal.PlainDateTime.prototype.minute
1511 static bool PlainDateTime_minute(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1513 CallArgs args
= CallArgsFromVp(argc
, vp
);
1514 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_minute
>(cx
, args
);
1518 * get Temporal.PlainDateTime.prototype.second
1520 static bool PlainDateTime_second(JSContext
* cx
, const CallArgs
& args
) {
1522 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1523 args
.rval().setInt32(dateTime
->isoSecond());
1528 * get Temporal.PlainDateTime.prototype.second
1530 static bool PlainDateTime_second(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1532 CallArgs args
= CallArgsFromVp(argc
, vp
);
1533 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_second
>(cx
, args
);
1537 * get Temporal.PlainDateTime.prototype.millisecond
1539 static bool PlainDateTime_millisecond(JSContext
* cx
, const CallArgs
& args
) {
1541 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1542 args
.rval().setInt32(dateTime
->isoMillisecond());
1547 * get Temporal.PlainDateTime.prototype.millisecond
1549 static bool PlainDateTime_millisecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1551 CallArgs args
= CallArgsFromVp(argc
, vp
);
1552 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_millisecond
>(cx
,
1557 * get Temporal.PlainDateTime.prototype.microsecond
1559 static bool PlainDateTime_microsecond(JSContext
* cx
, const CallArgs
& args
) {
1561 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1562 args
.rval().setInt32(dateTime
->isoMicrosecond());
1567 * get Temporal.PlainDateTime.prototype.microsecond
1569 static bool PlainDateTime_microsecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1571 CallArgs args
= CallArgsFromVp(argc
, vp
);
1572 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_microsecond
>(cx
,
1577 * get Temporal.PlainDateTime.prototype.nanosecond
1579 static bool PlainDateTime_nanosecond(JSContext
* cx
, const CallArgs
& args
) {
1581 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1582 args
.rval().setInt32(dateTime
->isoNanosecond());
1587 * get Temporal.PlainDateTime.prototype.nanosecond
1589 static bool PlainDateTime_nanosecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1591 CallArgs args
= CallArgsFromVp(argc
, vp
);
1592 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_nanosecond
>(cx
,
1597 * get Temporal.PlainDateTime.prototype.dayOfWeek
1599 static bool PlainDateTime_dayOfWeek(JSContext
* cx
, const CallArgs
& args
) {
1601 Rooted
<PlainDateTimeObject
*> dateTime(
1602 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1603 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1606 return CalendarDayOfWeek(cx
, calendar
, dateTime
, args
.rval());
1610 * get Temporal.PlainDateTime.prototype.dayOfWeek
1612 static bool PlainDateTime_dayOfWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1614 CallArgs args
= CallArgsFromVp(argc
, vp
);
1615 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_dayOfWeek
>(cx
,
1620 * get Temporal.PlainDateTime.prototype.dayOfYear
1622 static bool PlainDateTime_dayOfYear(JSContext
* cx
, const CallArgs
& args
) {
1624 Rooted
<PlainDateTimeObject
*> dateTime(
1625 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1626 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1629 return CalendarDayOfYear(cx
, calendar
, dateTime
, args
.rval());
1633 * get Temporal.PlainDateTime.prototype.dayOfYear
1635 static bool PlainDateTime_dayOfYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1637 CallArgs args
= CallArgsFromVp(argc
, vp
);
1638 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_dayOfYear
>(cx
,
1643 * get Temporal.PlainDateTime.prototype.weekOfYear
1645 static bool PlainDateTime_weekOfYear(JSContext
* cx
, const CallArgs
& args
) {
1647 Rooted
<PlainDateTimeObject
*> dateTime(
1648 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1649 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1652 return CalendarWeekOfYear(cx
, calendar
, dateTime
, args
.rval());
1656 * get Temporal.PlainDateTime.prototype.weekOfYear
1658 static bool PlainDateTime_weekOfYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1660 CallArgs args
= CallArgsFromVp(argc
, vp
);
1661 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_weekOfYear
>(cx
,
1666 * get Temporal.PlainDateTime.prototype.yearOfWeek
1668 static bool PlainDateTime_yearOfWeek(JSContext
* cx
, const CallArgs
& args
) {
1670 Rooted
<PlainDateTimeObject
*> dateTime(
1671 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1672 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1675 return CalendarYearOfWeek(cx
, calendar
, dateTime
, args
.rval());
1679 * get Temporal.PlainDateTime.prototype.yearOfWeek
1681 static bool PlainDateTime_yearOfWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1683 CallArgs args
= CallArgsFromVp(argc
, vp
);
1684 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_yearOfWeek
>(cx
,
1689 * get Temporal.PlainDateTime.prototype.daysInWeek
1691 static bool PlainDateTime_daysInWeek(JSContext
* cx
, const CallArgs
& args
) {
1693 Rooted
<PlainDateTimeObject
*> dateTime(
1694 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1695 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1698 return CalendarDaysInWeek(cx
, calendar
, dateTime
, args
.rval());
1702 * get Temporal.PlainDateTime.prototype.daysInWeek
1704 static bool PlainDateTime_daysInWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1706 CallArgs args
= CallArgsFromVp(argc
, vp
);
1707 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInWeek
>(cx
,
1712 * get Temporal.PlainDateTime.prototype.daysInMonth
1714 static bool PlainDateTime_daysInMonth(JSContext
* cx
, const CallArgs
& args
) {
1716 Rooted
<PlainDateTimeObject
*> dateTime(
1717 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1718 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1721 return CalendarDaysInMonth(cx
, calendar
, dateTime
, args
.rval());
1725 * get Temporal.PlainDateTime.prototype.daysInMonth
1727 static bool PlainDateTime_daysInMonth(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1729 CallArgs args
= CallArgsFromVp(argc
, vp
);
1730 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInMonth
>(cx
,
1735 * get Temporal.PlainDateTime.prototype.daysInYear
1737 static bool PlainDateTime_daysInYear(JSContext
* cx
, const CallArgs
& args
) {
1739 Rooted
<PlainDateTimeObject
*> dateTime(
1740 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1741 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1744 return CalendarDaysInYear(cx
, calendar
, dateTime
, args
.rval());
1748 * get Temporal.PlainDateTime.prototype.daysInYear
1750 static bool PlainDateTime_daysInYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1752 CallArgs args
= CallArgsFromVp(argc
, vp
);
1753 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInYear
>(cx
,
1758 * get Temporal.PlainDateTime.prototype.monthsInYear
1760 static bool PlainDateTime_monthsInYear(JSContext
* cx
, const CallArgs
& args
) {
1762 Rooted
<PlainDateTimeObject
*> dateTime(
1763 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1764 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1767 return CalendarMonthsInYear(cx
, calendar
, dateTime
, args
.rval());
1771 * get Temporal.PlainDateTime.prototype.monthsInYear
1773 static bool PlainDateTime_monthsInYear(JSContext
* cx
, unsigned argc
,
1776 CallArgs args
= CallArgsFromVp(argc
, vp
);
1777 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_monthsInYear
>(
1782 * get Temporal.PlainDateTime.prototype.inLeapYear
1784 static bool PlainDateTime_inLeapYear(JSContext
* cx
, const CallArgs
& args
) {
1786 Rooted
<PlainDateTimeObject
*> dateTime(
1787 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1788 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1791 return CalendarInLeapYear(cx
, calendar
, dateTime
, args
.rval());
1795 * get Temporal.PlainDateTime.prototype.inLeapYear
1797 static bool PlainDateTime_inLeapYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1799 CallArgs args
= CallArgsFromVp(argc
, vp
);
1800 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_inLeapYear
>(cx
,
1805 * Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )
1807 static bool PlainDateTime_with(JSContext
* cx
, const CallArgs
& args
) {
1808 Rooted
<PlainDateTimeObject
*> dateTime(
1809 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1812 Rooted
<JSObject
*> temporalDateTimeLike(
1813 cx
, RequireObjectArg(cx
, "temporalDateTimeLike", "with", args
.get(0)));
1814 if (!temporalDateTimeLike
) {
1817 if (!ThrowIfTemporalLikeObject(cx
, temporalDateTimeLike
)) {
1822 Rooted
<PlainObject
*> resolvedOptions(cx
);
1823 if (args
.hasDefined(1)) {
1824 Rooted
<JSObject
*> options(cx
,
1825 RequireObjectArg(cx
, "options", "with", args
[1]));
1829 resolvedOptions
= SnapshotOwnProperties(cx
, options
);
1831 resolvedOptions
= NewPlainObjectWithProto(cx
, nullptr);
1833 if (!resolvedOptions
) {
1838 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
1839 Rooted
<CalendarRecord
> calendar(cx
);
1840 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
1842 CalendarMethod::DateFromFields
,
1843 CalendarMethod::Fields
,
1844 CalendarMethod::MergeFields
,
1851 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
1852 if (!CalendarFields(cx
, calendar
,
1853 {CalendarField::Day
, CalendarField::Month
,
1854 CalendarField::MonthCode
, CalendarField::Year
},
1860 Rooted
<PlainObject
*> fields(cx
,
1861 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
1868 using FieldName
= ImmutableTenuredPtr
<PropertyName
*> JSAtomState::*;
1873 {&JSAtomState::hour
, dateTime
->isoHour()},
1874 {&JSAtomState::minute
, dateTime
->isoMinute()},
1875 {&JSAtomState::second
, dateTime
->isoSecond()},
1876 {&JSAtomState::millisecond
, dateTime
->isoMillisecond()},
1877 {&JSAtomState::microsecond
, dateTime
->isoMicrosecond()},
1878 {&JSAtomState::nanosecond
, dateTime
->isoNanosecond()},
1881 Rooted
<Value
> timeFieldValue(cx
);
1882 for (const auto& timeField
: timeFields
) {
1883 Handle
<PropertyName
*> name
= cx
->names().*(timeField
.name
);
1884 timeFieldValue
.setInt32(timeField
.value
);
1886 if (!DefineDataProperty(cx
, fields
, name
, timeFieldValue
)) {
1892 if (!AppendSorted(cx
, fieldNames
.get(),
1894 TemporalField::Hour
,
1895 TemporalField::Microsecond
,
1896 TemporalField::Millisecond
,
1897 TemporalField::Minute
,
1898 TemporalField::Nanosecond
,
1899 TemporalField::Second
,
1905 Rooted
<PlainObject
*> partialDateTime(
1906 cx
, PreparePartialTemporalFields(cx
, temporalDateTimeLike
, fieldNames
));
1907 if (!partialDateTime
) {
1912 Rooted
<JSObject
*> mergedFields(
1913 cx
, CalendarMergeFields(cx
, calendar
, fields
, partialDateTime
));
1914 if (!mergedFields
) {
1919 fields
= PrepareTemporalFields(cx
, mergedFields
, fieldNames
);
1925 PlainDateTime result
;
1926 if (!InterpretTemporalDateTimeFields(cx
, calendar
, fields
, resolvedOptions
,
1932 MOZ_ASSERT(IsValidISODateTime(result
));
1935 auto* obj
= CreateTemporalDateTime(cx
, result
, calendar
.receiver());
1940 args
.rval().setObject(*obj
);
1945 * Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )
1947 static bool PlainDateTime_with(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1949 CallArgs args
= CallArgsFromVp(argc
, vp
);
1950 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_with
>(cx
, args
);
1954 * Temporal.PlainDateTime.prototype.withPlainTime ( [ plainTimeLike ] )
1956 static bool PlainDateTime_withPlainTime(JSContext
* cx
, const CallArgs
& args
) {
1957 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1958 auto date
= ToPlainDate(temporalDateTime
);
1959 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1962 PlainTime time
= {};
1963 if (args
.hasDefined(0)) {
1964 if (!ToTemporalTime(cx
, args
[0], &time
)) {
1970 auto* obj
= CreateTemporalDateTime(cx
, {date
, time
}, calendar
);
1975 args
.rval().setObject(*obj
);
1980 * Temporal.PlainDateTime.prototype.withPlainTime ( [ plainTimeLike ] )
1982 static bool PlainDateTime_withPlainTime(JSContext
* cx
, unsigned argc
,
1985 CallArgs args
= CallArgsFromVp(argc
, vp
);
1986 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withPlainTime
>(
1991 * Temporal.PlainDateTime.prototype.withPlainDate ( plainDateLike )
1993 static bool PlainDateTime_withPlainDate(JSContext
* cx
, const CallArgs
& args
) {
1994 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1995 auto time
= ToPlainTime(temporalDateTime
);
1996 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1999 Rooted
<PlainDateWithCalendar
> plainDate(cx
);
2000 if (!ToTemporalDate(cx
, args
.get(0), &plainDate
)) {
2003 auto date
= plainDate
.date();
2006 if (!ConsolidateCalendars(cx
, calendar
, plainDate
.calendar(), &calendar
)) {
2011 auto* obj
= CreateTemporalDateTime(cx
, {date
, time
}, calendar
);
2016 args
.rval().setObject(*obj
);
2021 * Temporal.PlainDateTime.prototype.withPlainDate ( plainDateLike )
2023 static bool PlainDateTime_withPlainDate(JSContext
* cx
, unsigned argc
,
2026 CallArgs args
= CallArgsFromVp(argc
, vp
);
2027 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withPlainDate
>(
2032 * Temporal.PlainDateTime.prototype.withCalendar ( calendar )
2034 static bool PlainDateTime_withCalendar(JSContext
* cx
, const CallArgs
& args
) {
2035 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2036 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2039 Rooted
<CalendarValue
> calendar(cx
);
2040 if (!ToTemporalCalendar(cx
, args
.get(0), &calendar
)) {
2045 auto* result
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
2050 args
.rval().setObject(*result
);
2055 * Temporal.PlainDateTime.prototype.withCalendar ( calendar )
2057 static bool PlainDateTime_withCalendar(JSContext
* cx
, unsigned argc
,
2060 CallArgs args
= CallArgsFromVp(argc
, vp
);
2061 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withCalendar
>(
2066 * Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )
2068 static bool PlainDateTime_add(JSContext
* cx
, const CallArgs
& args
) {
2070 return AddDurationToOrSubtractDurationFromPlainDateTime(
2071 cx
, PlainDateTimeDuration::Add
, args
);
2075 * Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )
2077 static bool PlainDateTime_add(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2079 CallArgs args
= CallArgsFromVp(argc
, vp
);
2080 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_add
>(cx
, args
);
2084 * Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options
2087 static bool PlainDateTime_subtract(JSContext
* cx
, const CallArgs
& args
) {
2089 return AddDurationToOrSubtractDurationFromPlainDateTime(
2090 cx
, PlainDateTimeDuration::Subtract
, args
);
2094 * Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options
2097 static bool PlainDateTime_subtract(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2099 CallArgs args
= CallArgsFromVp(argc
, vp
);
2100 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_subtract
>(cx
,
2105 * Temporal.PlainDateTime.prototype.until ( other [ , options ] )
2107 static bool PlainDateTime_until(JSContext
* cx
, const CallArgs
& args
) {
2109 return DifferenceTemporalPlainDateTime(cx
, TemporalDifference::Until
, args
);
2113 * Temporal.PlainDateTime.prototype.until ( other [ , options ] )
2115 static bool PlainDateTime_until(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2117 CallArgs args
= CallArgsFromVp(argc
, vp
);
2118 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_until
>(cx
, args
);
2122 * Temporal.PlainDateTime.prototype.since ( other [ , options ] )
2124 static bool PlainDateTime_since(JSContext
* cx
, const CallArgs
& args
) {
2126 return DifferenceTemporalPlainDateTime(cx
, TemporalDifference::Since
, args
);
2130 * Temporal.PlainDateTime.prototype.since ( other [ , options ] )
2132 static bool PlainDateTime_since(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2134 CallArgs args
= CallArgsFromVp(argc
, vp
);
2135 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_since
>(cx
, args
);
2139 * Temporal.PlainDateTime.prototype.round ( roundTo )
2141 static bool PlainDateTime_round(JSContext
* cx
, const CallArgs
& args
) {
2142 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2143 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2144 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2147 auto smallestUnit
= TemporalUnit::Auto
;
2148 auto roundingMode
= TemporalRoundingMode::HalfExpand
;
2149 auto roundingIncrement
= Increment
{1};
2150 if (args
.get(0).isString()) {
2151 // Step 4. (Not applicable in our implementation.)
2154 Rooted
<JSString
*> paramString(cx
, args
[0].toString());
2155 if (!GetTemporalUnit(cx
, paramString
, TemporalUnitKey::SmallestUnit
,
2156 TemporalUnitGroup::DayTime
, &smallestUnit
)) {
2160 MOZ_ASSERT(TemporalUnit::Day
<= smallestUnit
&&
2161 smallestUnit
<= TemporalUnit::Nanosecond
);
2163 // Steps 6-8 and 10-12. (Implicit)
2166 Rooted
<JSObject
*> roundTo(
2167 cx
, RequireObjectArg(cx
, "roundTo", "round", args
.get(0)));
2173 if (!ToTemporalRoundingIncrement(cx
, roundTo
, &roundingIncrement
)) {
2178 if (!ToTemporalRoundingMode(cx
, roundTo
, &roundingMode
)) {
2183 if (!GetTemporalUnit(cx
, roundTo
, TemporalUnitKey::SmallestUnit
,
2184 TemporalUnitGroup::DayTime
, &smallestUnit
)) {
2188 if (smallestUnit
== TemporalUnit::Auto
) {
2189 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2190 JSMSG_TEMPORAL_MISSING_OPTION
, "smallestUnit");
2194 MOZ_ASSERT(TemporalUnit::Day
<= smallestUnit
&&
2195 smallestUnit
<= TemporalUnit::Nanosecond
);
2198 auto maximum
= Increment
{1};
2199 bool inclusive
= true;
2200 if (smallestUnit
> TemporalUnit::Day
) {
2201 maximum
= MaximumTemporalDurationRoundingIncrement(smallestUnit
);
2206 if (!ValidateTemporalRoundingIncrement(cx
, roundingIncrement
, maximum
,
2213 if (smallestUnit
== TemporalUnit::Nanosecond
&&
2214 roundingIncrement
== Increment
{1}) {
2215 auto* obj
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
2220 args
.rval().setObject(*obj
);
2226 RoundISODateTime(dateTime
, roundingIncrement
, smallestUnit
, roundingMode
);
2229 auto* obj
= CreateTemporalDateTime(cx
, result
, calendar
);
2234 args
.rval().setObject(*obj
);
2239 * Temporal.PlainDateTime.prototype.round ( roundTo )
2241 static bool PlainDateTime_round(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2243 CallArgs args
= CallArgsFromVp(argc
, vp
);
2244 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_round
>(cx
, args
);
2248 * Temporal.PlainDateTime.prototype.equals ( other )
2250 static bool PlainDateTime_equals(JSContext
* cx
, const CallArgs
& args
) {
2251 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2252 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2253 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2256 Rooted
<PlainDateTimeWithCalendar
> other(cx
);
2257 if (!::ToTemporalDateTime(cx
, args
.get(0), &other
)) {
2262 bool equals
= dateTime
== other
.dateTime();
2263 if (equals
&& !CalendarEquals(cx
, calendar
, other
.calendar(), &equals
)) {
2267 args
.rval().setBoolean(equals
);
2272 * Temporal.PlainDateTime.prototype.equals ( other )
2274 static bool PlainDateTime_equals(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2276 CallArgs args
= CallArgsFromVp(argc
, vp
);
2277 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_equals
>(cx
, args
);
2281 * Temporal.PlainDateTime.prototype.toString ( [ options ] )
2283 static bool PlainDateTime_toString(JSContext
* cx
, const CallArgs
& args
) {
2284 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2285 auto dt
= ToPlainDateTime(dateTime
);
2286 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2288 SecondsStringPrecision precision
= {Precision::Auto(),
2289 TemporalUnit::Nanosecond
, Increment
{1}};
2290 auto roundingMode
= TemporalRoundingMode::Trunc
;
2291 auto showCalendar
= CalendarOption::Auto
;
2292 if (args
.hasDefined(0)) {
2294 Rooted
<JSObject
*> options(
2295 cx
, RequireObjectArg(cx
, "options", "toString", args
[0]));
2301 if (!ToCalendarNameOption(cx
, options
, &showCalendar
)) {
2306 auto digits
= Precision::Auto();
2307 if (!ToFractionalSecondDigits(cx
, options
, &digits
)) {
2312 if (!ToTemporalRoundingMode(cx
, options
, &roundingMode
)) {
2317 auto smallestUnit
= TemporalUnit::Auto
;
2318 if (!GetTemporalUnit(cx
, options
, TemporalUnitKey::SmallestUnit
,
2319 TemporalUnitGroup::Time
, &smallestUnit
)) {
2324 if (smallestUnit
== TemporalUnit::Hour
) {
2325 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2326 JSMSG_TEMPORAL_INVALID_UNIT_OPTION
, "hour",
2332 precision
= ToSecondsStringPrecision(smallestUnit
, digits
);
2337 RoundISODateTime(dt
, precision
.increment
, precision
.unit
, roundingMode
);
2340 JSString
* str
= ::TemporalDateTimeToString(cx
, result
, calendar
,
2341 precision
.precision
, showCalendar
);
2346 args
.rval().setString(str
);
2351 * Temporal.PlainDateTime.prototype.toString ( [ options ] )
2353 static bool PlainDateTime_toString(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2355 CallArgs args
= CallArgsFromVp(argc
, vp
);
2356 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toString
>(cx
,
2361 * Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )
2363 static bool PlainDateTime_toLocaleString(JSContext
* cx
, const CallArgs
& args
) {
2364 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2365 auto dt
= ToPlainDateTime(dateTime
);
2366 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2369 JSString
* str
= ::TemporalDateTimeToString(
2370 cx
, dt
, calendar
, Precision::Auto(), CalendarOption::Auto
);
2375 args
.rval().setString(str
);
2380 * Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )
2382 static bool PlainDateTime_toLocaleString(JSContext
* cx
, unsigned argc
,
2385 CallArgs args
= CallArgsFromVp(argc
, vp
);
2386 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toLocaleString
>(
2391 * Temporal.PlainDateTime.prototype.toJSON ( )
2393 static bool PlainDateTime_toJSON(JSContext
* cx
, const CallArgs
& args
) {
2394 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2395 auto dt
= ToPlainDateTime(dateTime
);
2396 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2399 JSString
* str
= ::TemporalDateTimeToString(
2400 cx
, dt
, calendar
, Precision::Auto(), CalendarOption::Auto
);
2405 args
.rval().setString(str
);
2410 * Temporal.PlainDateTime.prototype.toJSON ( )
2412 static bool PlainDateTime_toJSON(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2414 CallArgs args
= CallArgsFromVp(argc
, vp
);
2415 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toJSON
>(cx
, args
);
2419 * Temporal.PlainDateTime.prototype.valueOf ( )
2421 static bool PlainDateTime_valueOf(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2422 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_CANT_CONVERT_TO
,
2423 "PlainDateTime", "primitive type");
2428 * Temporal.PlainDateTime.prototype.getISOFields ( )
2430 static bool PlainDateTime_getISOFields(JSContext
* cx
, const CallArgs
& args
) {
2431 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2432 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2433 auto calendar
= temporalDateTime
->calendar();
2436 Rooted
<IdValueVector
> fields(cx
, IdValueVector(cx
));
2439 if (!fields
.emplaceBack(NameToId(cx
->names().calendar
), calendar
.toValue())) {
2444 if (!fields
.emplaceBack(NameToId(cx
->names().isoDay
),
2445 Int32Value(dateTime
.date
.day
))) {
2450 if (!fields
.emplaceBack(NameToId(cx
->names().isoHour
),
2451 Int32Value(dateTime
.time
.hour
))) {
2456 if (!fields
.emplaceBack(NameToId(cx
->names().isoMicrosecond
),
2457 Int32Value(dateTime
.time
.microsecond
))) {
2462 if (!fields
.emplaceBack(NameToId(cx
->names().isoMillisecond
),
2463 Int32Value(dateTime
.time
.millisecond
))) {
2468 if (!fields
.emplaceBack(NameToId(cx
->names().isoMinute
),
2469 Int32Value(dateTime
.time
.minute
))) {
2474 if (!fields
.emplaceBack(NameToId(cx
->names().isoMonth
),
2475 Int32Value(dateTime
.date
.month
))) {
2480 if (!fields
.emplaceBack(NameToId(cx
->names().isoNanosecond
),
2481 Int32Value(dateTime
.time
.nanosecond
))) {
2486 if (!fields
.emplaceBack(NameToId(cx
->names().isoSecond
),
2487 Int32Value(dateTime
.time
.second
))) {
2492 if (!fields
.emplaceBack(NameToId(cx
->names().isoYear
),
2493 Int32Value(dateTime
.date
.year
))) {
2498 auto* obj
= NewPlainObjectWithUniqueNames(cx
, fields
);
2503 args
.rval().setObject(*obj
);
2508 * Temporal.PlainDateTime.prototype.getISOFields ( )
2510 static bool PlainDateTime_getISOFields(JSContext
* cx
, unsigned argc
,
2513 CallArgs args
= CallArgsFromVp(argc
, vp
);
2514 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_getISOFields
>(
2519 * Temporal.PlainDateTime.prototype.getCalendar ( )
2521 static bool PlainDateTime_getCalendar(JSContext
* cx
, const CallArgs
& args
) {
2522 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2523 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2526 auto* obj
= ToTemporalCalendarObject(cx
, calendar
);
2531 args
.rval().setObject(*obj
);
2536 * Temporal.PlainDateTime.prototype.getCalendar ( )
2538 static bool PlainDateTime_getCalendar(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2540 CallArgs args
= CallArgsFromVp(argc
, vp
);
2541 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_getCalendar
>(cx
,
2546 * Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ ,
2549 static bool PlainDateTime_toZonedDateTime(JSContext
* cx
, const CallArgs
& args
) {
2550 Rooted
<PlainDateTimeObject
*> dateTime(
2551 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2552 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2555 Rooted
<TimeZoneValue
> timeZone(cx
);
2556 if (!ToTemporalTimeZone(cx
, args
.get(0), &timeZone
)) {
2560 auto disambiguation
= TemporalDisambiguation::Compatible
;
2561 if (args
.hasDefined(1)) {
2563 Rooted
<JSObject
*> options(
2564 cx
, RequireObjectArg(cx
, "options", "toZonedDateTime", args
[1]));
2570 if (!ToTemporalDisambiguation(cx
, options
, &disambiguation
)) {
2577 if (!GetInstantFor(cx
, timeZone
, dateTime
, disambiguation
, &instant
)) {
2582 auto* result
= CreateTemporalZonedDateTime(cx
, instant
, timeZone
, calendar
);
2587 args
.rval().setObject(*result
);
2592 * Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ ,
2595 static bool PlainDateTime_toZonedDateTime(JSContext
* cx
, unsigned argc
,
2598 CallArgs args
= CallArgsFromVp(argc
, vp
);
2599 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toZonedDateTime
>(
2604 * Temporal.PlainDateTime.prototype.toPlainDate ( )
2606 static bool PlainDateTime_toPlainDate(JSContext
* cx
, const CallArgs
& args
) {
2607 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2608 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2611 auto* obj
= CreateTemporalDate(cx
, ToPlainDate(dateTime
), calendar
);
2616 args
.rval().setObject(*obj
);
2621 * Temporal.PlainDateTime.prototype.toPlainDate ( )
2623 static bool PlainDateTime_toPlainDate(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2625 CallArgs args
= CallArgsFromVp(argc
, vp
);
2626 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainDate
>(cx
,
2631 * Temporal.PlainDateTime.prototype.toPlainYearMonth ( )
2633 static bool PlainDateTime_toPlainYearMonth(JSContext
* cx
,
2634 const CallArgs
& args
) {
2635 Rooted
<PlainDateTimeObject
*> dateTime(
2636 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2637 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
2640 Rooted
<CalendarRecord
> calendar(cx
);
2641 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
2643 CalendarMethod::Fields
,
2644 CalendarMethod::YearMonthFromFields
,
2651 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
2652 if (!CalendarFields(cx
, calendar
,
2653 {CalendarField::MonthCode
, CalendarField::Year
},
2659 Rooted
<PlainObject
*> fields(cx
,
2660 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
2666 auto obj
= CalendarYearMonthFromFields(cx
, calendar
, fields
);
2671 args
.rval().setObject(*obj
);
2676 * Temporal.PlainDateTime.prototype.toPlainYearMonth ( )
2678 static bool PlainDateTime_toPlainYearMonth(JSContext
* cx
, unsigned argc
,
2681 CallArgs args
= CallArgsFromVp(argc
, vp
);
2682 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainYearMonth
>(
2687 * Temporal.PlainDateTime.prototype.toPlainMonthDay ( )
2689 static bool PlainDateTime_toPlainMonthDay(JSContext
* cx
, const CallArgs
& args
) {
2690 Rooted
<PlainDateTimeObject
*> dateTime(
2691 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2692 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
2695 Rooted
<CalendarRecord
> calendar(cx
);
2696 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
2698 CalendarMethod::Fields
,
2699 CalendarMethod::MonthDayFromFields
,
2706 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
2707 if (!CalendarFields(cx
, calendar
,
2708 {CalendarField::Day
, CalendarField::MonthCode
},
2714 Rooted
<PlainObject
*> fields(cx
,
2715 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
2721 auto obj
= CalendarMonthDayFromFields(cx
, calendar
, fields
);
2726 args
.rval().setObject(*obj
);
2731 * Temporal.PlainDateTime.prototype.toPlainMonthDay ( )
2733 static bool PlainDateTime_toPlainMonthDay(JSContext
* cx
, unsigned argc
,
2736 CallArgs args
= CallArgsFromVp(argc
, vp
);
2737 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainMonthDay
>(
2742 * Temporal.PlainDateTime.prototype.toPlainTime ( )
2744 static bool PlainDateTime_toPlainTime(JSContext
* cx
, const CallArgs
& args
) {
2745 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2748 auto* obj
= CreateTemporalTime(cx
, ToPlainTime(dateTime
));
2753 args
.rval().setObject(*obj
);
2758 * Temporal.PlainDateTime.prototype.toPlainTime ( )
2760 static bool PlainDateTime_toPlainTime(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2762 CallArgs args
= CallArgsFromVp(argc
, vp
);
2763 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainTime
>(cx
,
2767 const JSClass
PlainDateTimeObject::class_
= {
2768 "Temporal.PlainDateTime",
2769 JSCLASS_HAS_RESERVED_SLOTS(PlainDateTimeObject::SLOT_COUNT
) |
2770 JSCLASS_HAS_CACHED_PROTO(JSProto_PlainDateTime
),
2772 &PlainDateTimeObject::classSpec_
,
2775 const JSClass
& PlainDateTimeObject::protoClass_
= PlainObject::class_
;
2777 static const JSFunctionSpec PlainDateTime_methods
[] = {
2778 JS_FN("from", PlainDateTime_from
, 1, 0),
2779 JS_FN("compare", PlainDateTime_compare
, 2, 0),
2783 static const JSFunctionSpec PlainDateTime_prototype_methods
[] = {
2784 JS_FN("with", PlainDateTime_with
, 1, 0),
2785 JS_FN("withPlainTime", PlainDateTime_withPlainTime
, 0, 0),
2786 JS_FN("withPlainDate", PlainDateTime_withPlainDate
, 1, 0),
2787 JS_FN("withCalendar", PlainDateTime_withCalendar
, 1, 0),
2788 JS_FN("add", PlainDateTime_add
, 1, 0),
2789 JS_FN("subtract", PlainDateTime_subtract
, 1, 0),
2790 JS_FN("until", PlainDateTime_until
, 1, 0),
2791 JS_FN("since", PlainDateTime_since
, 1, 0),
2792 JS_FN("round", PlainDateTime_round
, 1, 0),
2793 JS_FN("equals", PlainDateTime_equals
, 1, 0),
2794 JS_FN("toString", PlainDateTime_toString
, 0, 0),
2795 JS_FN("toLocaleString", PlainDateTime_toLocaleString
, 0, 0),
2796 JS_FN("toJSON", PlainDateTime_toJSON
, 0, 0),
2797 JS_FN("valueOf", PlainDateTime_valueOf
, 0, 0),
2798 JS_FN("toZonedDateTime", PlainDateTime_toZonedDateTime
, 1, 0),
2799 JS_FN("toPlainDate", PlainDateTime_toPlainDate
, 0, 0),
2800 JS_FN("toPlainYearMonth", PlainDateTime_toPlainYearMonth
, 0, 0),
2801 JS_FN("toPlainMonthDay", PlainDateTime_toPlainMonthDay
, 0, 0),
2802 JS_FN("toPlainTime", PlainDateTime_toPlainTime
, 0, 0),
2803 JS_FN("getISOFields", PlainDateTime_getISOFields
, 0, 0),
2804 JS_FN("getCalendar", PlainDateTime_getCalendar
, 0, 0),
2808 static const JSPropertySpec PlainDateTime_prototype_properties
[] = {
2809 JS_PSG("calendarId", PlainDateTime_calendarId
, 0),
2810 JS_PSG("year", PlainDateTime_year
, 0),
2811 JS_PSG("month", PlainDateTime_month
, 0),
2812 JS_PSG("monthCode", PlainDateTime_monthCode
, 0),
2813 JS_PSG("day", PlainDateTime_day
, 0),
2814 JS_PSG("hour", PlainDateTime_hour
, 0),
2815 JS_PSG("minute", PlainDateTime_minute
, 0),
2816 JS_PSG("second", PlainDateTime_second
, 0),
2817 JS_PSG("millisecond", PlainDateTime_millisecond
, 0),
2818 JS_PSG("microsecond", PlainDateTime_microsecond
, 0),
2819 JS_PSG("nanosecond", PlainDateTime_nanosecond
, 0),
2820 JS_PSG("dayOfWeek", PlainDateTime_dayOfWeek
, 0),
2821 JS_PSG("dayOfYear", PlainDateTime_dayOfYear
, 0),
2822 JS_PSG("weekOfYear", PlainDateTime_weekOfYear
, 0),
2823 JS_PSG("yearOfWeek", PlainDateTime_yearOfWeek
, 0),
2824 JS_PSG("daysInWeek", PlainDateTime_daysInWeek
, 0),
2825 JS_PSG("daysInMonth", PlainDateTime_daysInMonth
, 0),
2826 JS_PSG("daysInYear", PlainDateTime_daysInYear
, 0),
2827 JS_PSG("monthsInYear", PlainDateTime_monthsInYear
, 0),
2828 JS_PSG("inLeapYear", PlainDateTime_inLeapYear
, 0),
2829 JS_STRING_SYM_PS(toStringTag
, "Temporal.PlainDateTime", JSPROP_READONLY
),
2833 const ClassSpec
PlainDateTimeObject::classSpec_
= {
2834 GenericCreateConstructor
<PlainDateTimeConstructor
, 3,
2835 gc::AllocKind::FUNCTION
>,
2836 GenericCreatePrototype
<PlainDateTimeObject
>,
2837 PlainDateTime_methods
,
2839 PlainDateTime_prototype_methods
,
2840 PlainDateTime_prototype_properties
,
2842 ClassSpec::DontDefineConstructor
,