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 NormalizedDuration
* result
) {
888 return ::DifferenceISODateTime(cx
, one
, two
, calendar
, largestUnit
, nullptr,
893 * DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2,
894 * d2, h2, min2, s2, ms2, mus2, ns2, calendarRec, largestUnit, options )
896 bool js::temporal::DifferenceISODateTime(
897 JSContext
* cx
, const PlainDateTime
& one
, const PlainDateTime
& two
,
898 Handle
<CalendarRecord
> calendar
, TemporalUnit largestUnit
,
899 Handle
<PlainObject
*> options
, NormalizedDuration
* result
) {
900 return ::DifferenceISODateTime(cx
, one
, two
, calendar
, largestUnit
, options
,
905 * RoundISODateTime ( year, month, day, hour, minute, second, millisecond,
906 * microsecond, nanosecond, increment, unit, roundingMode [ , dayLength ] )
908 static PlainDateTime
RoundISODateTime(const PlainDateTime
& dateTime
,
909 Increment increment
, TemporalUnit unit
,
910 TemporalRoundingMode roundingMode
) {
911 const auto& [date
, time
] = dateTime
;
914 MOZ_ASSERT(IsValidISODateTime(dateTime
));
915 MOZ_ASSERT(ISODateTimeWithinLimits(dateTime
));
917 // Step 2. (Not applicable in our implementation.)
920 auto roundedTime
= RoundTime(time
, increment
, unit
, roundingMode
);
921 MOZ_ASSERT(0 <= roundedTime
.days
&& roundedTime
.days
<= 1);
924 auto balanceResult
= BalanceISODate(date
.year
, date
.month
,
925 date
.day
+ int32_t(roundedTime
.days
));
928 return {balanceResult
, roundedTime
.time
};
932 * DifferenceTemporalPlainDateTime ( operation, dateTime, other, options )
934 static bool DifferenceTemporalPlainDateTime(JSContext
* cx
,
935 TemporalDifference operation
,
936 const CallArgs
& args
) {
937 Rooted
<PlainDateTimeWithCalendar
> dateTime(
938 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
940 // Step 1. (Not applicable in our implementation.)
943 Rooted
<PlainDateTimeWithCalendar
> other(cx
);
944 if (!::ToTemporalDateTime(cx
, args
.get(0), &other
)) {
949 if (!CalendarEqualsOrThrow(cx
, dateTime
.calendar(), other
.calendar())) {
954 DifferenceSettings settings
;
955 Rooted
<PlainObject
*> resolvedOptions(cx
);
956 if (args
.hasDefined(1)) {
957 Rooted
<JSObject
*> options(
958 cx
, RequireObjectArg(cx
, "options", ToName(operation
), args
[1]));
964 resolvedOptions
= SnapshotOwnProperties(cx
, options
);
965 if (!resolvedOptions
) {
970 if (!GetDifferenceSettings(
971 cx
, operation
, resolvedOptions
, TemporalUnitGroup::DateTime
,
972 TemporalUnit::Nanosecond
, TemporalUnit::Day
, &settings
)) {
978 TemporalUnit::Nanosecond
,
980 TemporalRoundingMode::Trunc
,
986 bool datePartsIdentical
= dateTime
.date() == other
.date();
989 if (datePartsIdentical
&& dateTime
.time() == other
.time()) {
990 auto* obj
= CreateTemporalDuration(cx
, {});
995 args
.rval().setObject(*obj
);
1000 Rooted
<CalendarRecord
> calendar(cx
);
1001 if (!CreateCalendarMethodsRecord(cx
, dateTime
.calendar(),
1003 CalendarMethod::DateAdd
,
1004 CalendarMethod::DateUntil
,
1011 NormalizedDuration diff
;
1012 if (!::DifferenceISODateTime(cx
, dateTime
, other
, calendar
,
1013 settings
.largestUnit
, resolvedOptions
, &diff
)) {
1018 bool roundingGranularityIsNoop
=
1019 settings
.smallestUnit
== TemporalUnit::Nanosecond
&&
1020 settings
.roundingIncrement
== Increment
{1};
1023 DateDuration balancedDate
;
1024 TimeDuration balancedTime
;
1025 if (!roundingGranularityIsNoop
) {
1027 Rooted
<PlainDateObject
*> relativeTo(
1028 cx
, CreateTemporalDate(cx
, dateTime
.date(), dateTime
.calendar()));
1034 NormalizedDuration roundResult
;
1035 if (!temporal::RoundDuration(cx
, diff
, settings
.roundingIncrement
,
1036 settings
.smallestUnit
, settings
.roundingMode
,
1037 relativeTo
, calendar
, &roundResult
)) {
1042 NormalizedTimeDuration withDays
;
1043 if (!Add24HourDaysToNormalizedTimeDuration(
1044 cx
, roundResult
.time
, roundResult
.date
.days
, &withDays
)) {
1049 balancedTime
= BalanceTimeDuration(withDays
, settings
.largestUnit
);
1052 auto toBalance
= DateDuration
{
1053 roundResult
.date
.years
,
1054 roundResult
.date
.months
,
1055 roundResult
.date
.weeks
,
1058 if (!temporal::BalanceDateDurationRelative(
1059 cx
, toBalance
, settings
.largestUnit
, settings
.smallestUnit
,
1060 relativeTo
, calendar
, &balancedDate
)) {
1065 NormalizedTimeDuration withDays
;
1066 if (!Add24HourDaysToNormalizedTimeDuration(cx
, diff
.time
, diff
.date
.days
,
1072 balancedTime
= BalanceTimeDuration(withDays
, settings
.largestUnit
);
1082 MOZ_ASSERT(IsValidDuration(balancedDate
));
1085 Duration duration
= {
1086 double(balancedDate
.years
), double(balancedDate
.months
),
1087 double(balancedDate
.weeks
), double(balancedDate
.days
),
1088 double(balancedTime
.hours
), double(balancedTime
.minutes
),
1089 double(balancedTime
.seconds
), double(balancedTime
.milliseconds
),
1090 balancedTime
.microseconds
, balancedTime
.nanoseconds
,
1092 if (operation
== TemporalDifference::Since
) {
1093 duration
= duration
.negate();
1096 auto* obj
= CreateTemporalDuration(cx
, duration
);
1101 args
.rval().setObject(*obj
);
1105 enum class PlainDateTimeDuration
{ Add
, Subtract
};
1108 * AddDurationToOrSubtractDurationFromPlainDateTime ( operation, dateTime,
1109 * temporalDurationLike, options )
1111 static bool AddDurationToOrSubtractDurationFromPlainDateTime(
1112 JSContext
* cx
, PlainDateTimeDuration operation
, const CallArgs
& args
) {
1113 Rooted
<PlainDateTimeWithCalendar
> dateTime(
1114 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1116 // Step 1. (Not applicable in our implementation.)
1120 if (!ToTemporalDurationRecord(cx
, args
.get(0), &duration
)) {
1125 Rooted
<JSObject
*> options(cx
);
1126 if (args
.hasDefined(1)) {
1128 operation
== PlainDateTimeDuration::Add
? "add" : "subtract";
1129 options
= RequireObjectArg(cx
, "options", name
, args
[1]);
1131 options
= NewPlainObjectWithProto(cx
, nullptr);
1138 Rooted
<CalendarRecord
> calendar(cx
);
1139 if (!CreateCalendarMethodsRecord(cx
, dateTime
.calendar(),
1141 CalendarMethod::DateAdd
,
1148 if (operation
== PlainDateTimeDuration::Subtract
) {
1149 duration
= duration
.negate();
1151 auto normalized
= CreateNormalizedDurationRecord(duration
);
1154 PlainDateTime result
;
1155 if (!AddDateTime(cx
, dateTime
, calendar
, normalized
, options
, &result
)) {
1160 MOZ_ASSERT(IsValidISODateTime(result
));
1163 auto* obj
= CreateTemporalDateTime(cx
, result
, dateTime
.calendar());
1168 args
.rval().setObject(*obj
);
1173 * Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ ,
1174 * second [ , millisecond [ , microsecond [ , nanosecond [ , calendarLike ] ] ]
1177 static bool PlainDateTimeConstructor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1178 CallArgs args
= CallArgsFromVp(argc
, vp
);
1181 if (!ThrowIfNotConstructing(cx
, args
, "Temporal.PlainDateTime")) {
1187 if (!ToIntegerWithTruncation(cx
, args
.get(0), "year", &isoYear
)) {
1193 if (!ToIntegerWithTruncation(cx
, args
.get(1), "month", &isoMonth
)) {
1199 if (!ToIntegerWithTruncation(cx
, args
.get(2), "day", &isoDay
)) {
1205 if (args
.hasDefined(3)) {
1206 if (!ToIntegerWithTruncation(cx
, args
[3], "hour", &hour
)) {
1213 if (args
.hasDefined(4)) {
1214 if (!ToIntegerWithTruncation(cx
, args
[4], "minute", &minute
)) {
1221 if (args
.hasDefined(5)) {
1222 if (!ToIntegerWithTruncation(cx
, args
[5], "second", &second
)) {
1228 double millisecond
= 0;
1229 if (args
.hasDefined(6)) {
1230 if (!ToIntegerWithTruncation(cx
, args
[6], "millisecond", &millisecond
)) {
1236 double microsecond
= 0;
1237 if (args
.hasDefined(7)) {
1238 if (!ToIntegerWithTruncation(cx
, args
[7], "microsecond", µsecond
)) {
1244 double nanosecond
= 0;
1245 if (args
.hasDefined(8)) {
1246 if (!ToIntegerWithTruncation(cx
, args
[8], "nanosecond", &nanosecond
)) {
1252 Rooted
<CalendarValue
> calendar(cx
);
1253 if (!ToTemporalCalendarWithISODefault(cx
, args
.get(9), &calendar
)) {
1258 auto* temporalDateTime
= CreateTemporalDateTime(
1259 cx
, args
, isoYear
, isoMonth
, isoDay
, hour
, minute
, second
, millisecond
,
1260 microsecond
, nanosecond
, calendar
);
1261 if (!temporalDateTime
) {
1265 args
.rval().setObject(*temporalDateTime
);
1270 * Temporal.PlainDateTime.from ( item [ , options ] )
1272 static bool PlainDateTime_from(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1273 CallArgs args
= CallArgsFromVp(argc
, vp
);
1276 Rooted
<JSObject
*> options(cx
);
1277 if (args
.hasDefined(1)) {
1278 options
= RequireObjectArg(cx
, "options", "from", args
[1]);
1285 if (args
.get(0).isObject()) {
1286 JSObject
* item
= &args
[0].toObject();
1287 if (auto* temporalDateTime
= item
->maybeUnwrapIf
<PlainDateTimeObject
>()) {
1288 auto dateTime
= ToPlainDateTime(temporalDateTime
);
1290 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1291 if (!calendar
.wrap(cx
)) {
1297 TemporalOverflow ignored
;
1298 if (!ToTemporalOverflow(cx
, options
, &ignored
)) {
1304 auto* result
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
1309 args
.rval().setObject(*result
);
1315 auto result
= ToTemporalDateTime(cx
, args
.get(0), options
);
1320 args
.rval().setObject(*result
);
1325 * Temporal.PlainDateTime.compare ( one, two )
1327 static bool PlainDateTime_compare(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1328 CallArgs args
= CallArgsFromVp(argc
, vp
);
1332 if (!ToTemporalDateTime(cx
, args
.get(0), &one
)) {
1338 if (!ToTemporalDateTime(cx
, args
.get(1), &two
)) {
1343 args
.rval().setInt32(CompareISODateTime(one
, two
));
1348 * get Temporal.PlainDateTime.prototype.calendarId
1350 static bool PlainDateTime_calendarId(JSContext
* cx
, const CallArgs
& args
) {
1351 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1354 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1355 auto* calendarId
= ToTemporalCalendarIdentifier(cx
, calendar
);
1360 args
.rval().setString(calendarId
);
1365 * get Temporal.PlainDateTime.prototype.calendarId
1367 static bool PlainDateTime_calendarId(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1369 CallArgs args
= CallArgsFromVp(argc
, vp
);
1370 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_calendarId
>(cx
,
1375 * get Temporal.PlainDateTime.prototype.year
1377 static bool PlainDateTime_year(JSContext
* cx
, const CallArgs
& args
) {
1379 Rooted
<PlainDateTimeObject
*> dateTime(
1380 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1381 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1384 return CalendarYear(cx
, calendar
, dateTime
, args
.rval());
1388 * get Temporal.PlainDateTime.prototype.year
1390 static bool PlainDateTime_year(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1392 CallArgs args
= CallArgsFromVp(argc
, vp
);
1393 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_year
>(cx
, args
);
1397 * get Temporal.PlainDateTime.prototype.month
1399 static bool PlainDateTime_month(JSContext
* cx
, const CallArgs
& args
) {
1401 Rooted
<PlainDateTimeObject
*> dateTime(
1402 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1403 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1406 return CalendarMonth(cx
, calendar
, dateTime
, args
.rval());
1410 * get Temporal.PlainDateTime.prototype.month
1412 static bool PlainDateTime_month(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1414 CallArgs args
= CallArgsFromVp(argc
, vp
);
1415 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_month
>(cx
, args
);
1419 * get Temporal.PlainDateTime.prototype.monthCode
1421 static bool PlainDateTime_monthCode(JSContext
* cx
, const CallArgs
& args
) {
1423 Rooted
<PlainDateTimeObject
*> dateTime(
1424 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1425 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1428 return CalendarMonthCode(cx
, calendar
, dateTime
, args
.rval());
1432 * get Temporal.PlainDateTime.prototype.monthCode
1434 static bool PlainDateTime_monthCode(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1436 CallArgs args
= CallArgsFromVp(argc
, vp
);
1437 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_monthCode
>(cx
,
1442 * get Temporal.PlainDateTime.prototype.day
1444 static bool PlainDateTime_day(JSContext
* cx
, const CallArgs
& args
) {
1446 Rooted
<PlainDateTimeObject
*> dateTime(
1447 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1448 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1451 return CalendarDay(cx
, calendar
, dateTime
, args
.rval());
1455 * get Temporal.PlainDateTime.prototype.day
1457 static bool PlainDateTime_day(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1459 CallArgs args
= CallArgsFromVp(argc
, vp
);
1460 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_day
>(cx
, args
);
1464 * get Temporal.PlainDateTime.prototype.hour
1466 static bool PlainDateTime_hour(JSContext
* cx
, const CallArgs
& args
) {
1468 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1469 args
.rval().setInt32(dateTime
->isoHour());
1474 * get Temporal.PlainDateTime.prototype.hour
1476 static bool PlainDateTime_hour(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1478 CallArgs args
= CallArgsFromVp(argc
, vp
);
1479 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_hour
>(cx
, args
);
1483 * get Temporal.PlainDateTime.prototype.minute
1485 static bool PlainDateTime_minute(JSContext
* cx
, const CallArgs
& args
) {
1487 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1488 args
.rval().setInt32(dateTime
->isoMinute());
1493 * get Temporal.PlainDateTime.prototype.minute
1495 static bool PlainDateTime_minute(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1497 CallArgs args
= CallArgsFromVp(argc
, vp
);
1498 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_minute
>(cx
, args
);
1502 * get Temporal.PlainDateTime.prototype.second
1504 static bool PlainDateTime_second(JSContext
* cx
, const CallArgs
& args
) {
1506 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1507 args
.rval().setInt32(dateTime
->isoSecond());
1512 * get Temporal.PlainDateTime.prototype.second
1514 static bool PlainDateTime_second(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1516 CallArgs args
= CallArgsFromVp(argc
, vp
);
1517 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_second
>(cx
, args
);
1521 * get Temporal.PlainDateTime.prototype.millisecond
1523 static bool PlainDateTime_millisecond(JSContext
* cx
, const CallArgs
& args
) {
1525 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1526 args
.rval().setInt32(dateTime
->isoMillisecond());
1531 * get Temporal.PlainDateTime.prototype.millisecond
1533 static bool PlainDateTime_millisecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1535 CallArgs args
= CallArgsFromVp(argc
, vp
);
1536 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_millisecond
>(cx
,
1541 * get Temporal.PlainDateTime.prototype.microsecond
1543 static bool PlainDateTime_microsecond(JSContext
* cx
, const CallArgs
& args
) {
1545 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1546 args
.rval().setInt32(dateTime
->isoMicrosecond());
1551 * get Temporal.PlainDateTime.prototype.microsecond
1553 static bool PlainDateTime_microsecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1555 CallArgs args
= CallArgsFromVp(argc
, vp
);
1556 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_microsecond
>(cx
,
1561 * get Temporal.PlainDateTime.prototype.nanosecond
1563 static bool PlainDateTime_nanosecond(JSContext
* cx
, const CallArgs
& args
) {
1565 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1566 args
.rval().setInt32(dateTime
->isoNanosecond());
1571 * get Temporal.PlainDateTime.prototype.nanosecond
1573 static bool PlainDateTime_nanosecond(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1575 CallArgs args
= CallArgsFromVp(argc
, vp
);
1576 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_nanosecond
>(cx
,
1581 * get Temporal.PlainDateTime.prototype.dayOfWeek
1583 static bool PlainDateTime_dayOfWeek(JSContext
* cx
, const CallArgs
& args
) {
1585 Rooted
<PlainDateTimeObject
*> dateTime(
1586 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1587 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1590 return CalendarDayOfWeek(cx
, calendar
, dateTime
, args
.rval());
1594 * get Temporal.PlainDateTime.prototype.dayOfWeek
1596 static bool PlainDateTime_dayOfWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1598 CallArgs args
= CallArgsFromVp(argc
, vp
);
1599 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_dayOfWeek
>(cx
,
1604 * get Temporal.PlainDateTime.prototype.dayOfYear
1606 static bool PlainDateTime_dayOfYear(JSContext
* cx
, const CallArgs
& args
) {
1608 Rooted
<PlainDateTimeObject
*> dateTime(
1609 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1610 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1613 return CalendarDayOfYear(cx
, calendar
, dateTime
, args
.rval());
1617 * get Temporal.PlainDateTime.prototype.dayOfYear
1619 static bool PlainDateTime_dayOfYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1621 CallArgs args
= CallArgsFromVp(argc
, vp
);
1622 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_dayOfYear
>(cx
,
1627 * get Temporal.PlainDateTime.prototype.weekOfYear
1629 static bool PlainDateTime_weekOfYear(JSContext
* cx
, const CallArgs
& args
) {
1631 Rooted
<PlainDateTimeObject
*> dateTime(
1632 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1633 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1636 return CalendarWeekOfYear(cx
, calendar
, dateTime
, args
.rval());
1640 * get Temporal.PlainDateTime.prototype.weekOfYear
1642 static bool PlainDateTime_weekOfYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1644 CallArgs args
= CallArgsFromVp(argc
, vp
);
1645 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_weekOfYear
>(cx
,
1650 * get Temporal.PlainDateTime.prototype.yearOfWeek
1652 static bool PlainDateTime_yearOfWeek(JSContext
* cx
, const CallArgs
& args
) {
1654 Rooted
<PlainDateTimeObject
*> dateTime(
1655 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1656 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1659 return CalendarYearOfWeek(cx
, calendar
, dateTime
, args
.rval());
1663 * get Temporal.PlainDateTime.prototype.yearOfWeek
1665 static bool PlainDateTime_yearOfWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1667 CallArgs args
= CallArgsFromVp(argc
, vp
);
1668 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_yearOfWeek
>(cx
,
1673 * get Temporal.PlainDateTime.prototype.daysInWeek
1675 static bool PlainDateTime_daysInWeek(JSContext
* cx
, const CallArgs
& args
) {
1677 Rooted
<PlainDateTimeObject
*> dateTime(
1678 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1679 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1682 return CalendarDaysInWeek(cx
, calendar
, dateTime
, args
.rval());
1686 * get Temporal.PlainDateTime.prototype.daysInWeek
1688 static bool PlainDateTime_daysInWeek(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1690 CallArgs args
= CallArgsFromVp(argc
, vp
);
1691 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInWeek
>(cx
,
1696 * get Temporal.PlainDateTime.prototype.daysInMonth
1698 static bool PlainDateTime_daysInMonth(JSContext
* cx
, const CallArgs
& args
) {
1700 Rooted
<PlainDateTimeObject
*> dateTime(
1701 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1702 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1705 return CalendarDaysInMonth(cx
, calendar
, dateTime
, args
.rval());
1709 * get Temporal.PlainDateTime.prototype.daysInMonth
1711 static bool PlainDateTime_daysInMonth(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1713 CallArgs args
= CallArgsFromVp(argc
, vp
);
1714 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInMonth
>(cx
,
1719 * get Temporal.PlainDateTime.prototype.daysInYear
1721 static bool PlainDateTime_daysInYear(JSContext
* cx
, const CallArgs
& args
) {
1723 Rooted
<PlainDateTimeObject
*> dateTime(
1724 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1725 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1728 return CalendarDaysInYear(cx
, calendar
, dateTime
, args
.rval());
1732 * get Temporal.PlainDateTime.prototype.daysInYear
1734 static bool PlainDateTime_daysInYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1736 CallArgs args
= CallArgsFromVp(argc
, vp
);
1737 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_daysInYear
>(cx
,
1742 * get Temporal.PlainDateTime.prototype.monthsInYear
1744 static bool PlainDateTime_monthsInYear(JSContext
* cx
, const CallArgs
& args
) {
1746 Rooted
<PlainDateTimeObject
*> dateTime(
1747 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1748 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1751 return CalendarMonthsInYear(cx
, calendar
, dateTime
, args
.rval());
1755 * get Temporal.PlainDateTime.prototype.monthsInYear
1757 static bool PlainDateTime_monthsInYear(JSContext
* cx
, unsigned argc
,
1760 CallArgs args
= CallArgsFromVp(argc
, vp
);
1761 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_monthsInYear
>(
1766 * get Temporal.PlainDateTime.prototype.inLeapYear
1768 static bool PlainDateTime_inLeapYear(JSContext
* cx
, const CallArgs
& args
) {
1770 Rooted
<PlainDateTimeObject
*> dateTime(
1771 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1772 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
1775 return CalendarInLeapYear(cx
, calendar
, dateTime
, args
.rval());
1779 * get Temporal.PlainDateTime.prototype.inLeapYear
1781 static bool PlainDateTime_inLeapYear(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1783 CallArgs args
= CallArgsFromVp(argc
, vp
);
1784 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_inLeapYear
>(cx
,
1789 * Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )
1791 static bool PlainDateTime_with(JSContext
* cx
, const CallArgs
& args
) {
1792 Rooted
<PlainDateTimeObject
*> dateTime(
1793 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
1796 Rooted
<JSObject
*> temporalDateTimeLike(
1797 cx
, RequireObjectArg(cx
, "temporalDateTimeLike", "with", args
.get(0)));
1798 if (!temporalDateTimeLike
) {
1801 if (!ThrowIfTemporalLikeObject(cx
, temporalDateTimeLike
)) {
1806 Rooted
<PlainObject
*> resolvedOptions(cx
);
1807 if (args
.hasDefined(1)) {
1808 Rooted
<JSObject
*> options(cx
,
1809 RequireObjectArg(cx
, "options", "with", args
[1]));
1813 resolvedOptions
= SnapshotOwnProperties(cx
, options
);
1815 resolvedOptions
= NewPlainObjectWithProto(cx
, nullptr);
1817 if (!resolvedOptions
) {
1822 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
1823 Rooted
<CalendarRecord
> calendar(cx
);
1824 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
1826 CalendarMethod::DateFromFields
,
1827 CalendarMethod::Fields
,
1828 CalendarMethod::MergeFields
,
1835 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
1836 if (!CalendarFields(cx
, calendar
,
1837 {CalendarField::Day
, CalendarField::Month
,
1838 CalendarField::MonthCode
, CalendarField::Year
},
1844 Rooted
<PlainObject
*> fields(cx
,
1845 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
1852 using FieldName
= ImmutableTenuredPtr
<PropertyName
*> JSAtomState::*;
1857 {&JSAtomState::hour
, dateTime
->isoHour()},
1858 {&JSAtomState::minute
, dateTime
->isoMinute()},
1859 {&JSAtomState::second
, dateTime
->isoSecond()},
1860 {&JSAtomState::millisecond
, dateTime
->isoMillisecond()},
1861 {&JSAtomState::microsecond
, dateTime
->isoMicrosecond()},
1862 {&JSAtomState::nanosecond
, dateTime
->isoNanosecond()},
1865 Rooted
<Value
> timeFieldValue(cx
);
1866 for (const auto& timeField
: timeFields
) {
1867 Handle
<PropertyName
*> name
= cx
->names().*(timeField
.name
);
1868 timeFieldValue
.setInt32(timeField
.value
);
1870 if (!DefineDataProperty(cx
, fields
, name
, timeFieldValue
)) {
1876 if (!AppendSorted(cx
, fieldNames
.get(),
1878 TemporalField::Hour
,
1879 TemporalField::Microsecond
,
1880 TemporalField::Millisecond
,
1881 TemporalField::Minute
,
1882 TemporalField::Nanosecond
,
1883 TemporalField::Second
,
1889 Rooted
<PlainObject
*> partialDateTime(
1890 cx
, PreparePartialTemporalFields(cx
, temporalDateTimeLike
, fieldNames
));
1891 if (!partialDateTime
) {
1896 Rooted
<JSObject
*> mergedFields(
1897 cx
, CalendarMergeFields(cx
, calendar
, fields
, partialDateTime
));
1898 if (!mergedFields
) {
1903 fields
= PrepareTemporalFields(cx
, mergedFields
, fieldNames
);
1909 PlainDateTime result
;
1910 if (!InterpretTemporalDateTimeFields(cx
, calendar
, fields
, resolvedOptions
,
1916 MOZ_ASSERT(IsValidISODateTime(result
));
1919 auto* obj
= CreateTemporalDateTime(cx
, result
, calendar
.receiver());
1924 args
.rval().setObject(*obj
);
1929 * Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )
1931 static bool PlainDateTime_with(JSContext
* cx
, unsigned argc
, Value
* vp
) {
1933 CallArgs args
= CallArgsFromVp(argc
, vp
);
1934 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_with
>(cx
, args
);
1938 * Temporal.PlainDateTime.prototype.withPlainTime ( [ plainTimeLike ] )
1940 static bool PlainDateTime_withPlainTime(JSContext
* cx
, const CallArgs
& args
) {
1941 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1942 auto date
= ToPlainDate(temporalDateTime
);
1943 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1946 PlainTime time
= {};
1947 if (args
.hasDefined(0)) {
1948 if (!ToTemporalTime(cx
, args
[0], &time
)) {
1954 auto* obj
= CreateTemporalDateTime(cx
, {date
, time
}, calendar
);
1959 args
.rval().setObject(*obj
);
1964 * Temporal.PlainDateTime.prototype.withPlainTime ( [ plainTimeLike ] )
1966 static bool PlainDateTime_withPlainTime(JSContext
* cx
, unsigned argc
,
1969 CallArgs args
= CallArgsFromVp(argc
, vp
);
1970 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withPlainTime
>(
1975 * Temporal.PlainDateTime.prototype.withPlainDate ( plainDateLike )
1977 static bool PlainDateTime_withPlainDate(JSContext
* cx
, const CallArgs
& args
) {
1978 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
1979 auto time
= ToPlainTime(temporalDateTime
);
1980 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
1983 Rooted
<PlainDateWithCalendar
> plainDate(cx
);
1984 if (!ToTemporalDate(cx
, args
.get(0), &plainDate
)) {
1987 auto date
= plainDate
.date();
1990 if (!ConsolidateCalendars(cx
, calendar
, plainDate
.calendar(), &calendar
)) {
1995 auto* obj
= CreateTemporalDateTime(cx
, {date
, time
}, calendar
);
2000 args
.rval().setObject(*obj
);
2005 * Temporal.PlainDateTime.prototype.withPlainDate ( plainDateLike )
2007 static bool PlainDateTime_withPlainDate(JSContext
* cx
, unsigned argc
,
2010 CallArgs args
= CallArgsFromVp(argc
, vp
);
2011 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withPlainDate
>(
2016 * Temporal.PlainDateTime.prototype.withCalendar ( calendar )
2018 static bool PlainDateTime_withCalendar(JSContext
* cx
, const CallArgs
& args
) {
2019 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2020 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2023 Rooted
<CalendarValue
> calendar(cx
);
2024 if (!ToTemporalCalendar(cx
, args
.get(0), &calendar
)) {
2029 auto* result
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
2034 args
.rval().setObject(*result
);
2039 * Temporal.PlainDateTime.prototype.withCalendar ( calendar )
2041 static bool PlainDateTime_withCalendar(JSContext
* cx
, unsigned argc
,
2044 CallArgs args
= CallArgsFromVp(argc
, vp
);
2045 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_withCalendar
>(
2050 * Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )
2052 static bool PlainDateTime_add(JSContext
* cx
, const CallArgs
& args
) {
2054 return AddDurationToOrSubtractDurationFromPlainDateTime(
2055 cx
, PlainDateTimeDuration::Add
, args
);
2059 * Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )
2061 static bool PlainDateTime_add(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2063 CallArgs args
= CallArgsFromVp(argc
, vp
);
2064 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_add
>(cx
, args
);
2068 * Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options
2071 static bool PlainDateTime_subtract(JSContext
* cx
, const CallArgs
& args
) {
2073 return AddDurationToOrSubtractDurationFromPlainDateTime(
2074 cx
, PlainDateTimeDuration::Subtract
, args
);
2078 * Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options
2081 static bool PlainDateTime_subtract(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2083 CallArgs args
= CallArgsFromVp(argc
, vp
);
2084 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_subtract
>(cx
,
2089 * Temporal.PlainDateTime.prototype.until ( other [ , options ] )
2091 static bool PlainDateTime_until(JSContext
* cx
, const CallArgs
& args
) {
2093 return DifferenceTemporalPlainDateTime(cx
, TemporalDifference::Until
, args
);
2097 * Temporal.PlainDateTime.prototype.until ( other [ , options ] )
2099 static bool PlainDateTime_until(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2101 CallArgs args
= CallArgsFromVp(argc
, vp
);
2102 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_until
>(cx
, args
);
2106 * Temporal.PlainDateTime.prototype.since ( other [ , options ] )
2108 static bool PlainDateTime_since(JSContext
* cx
, const CallArgs
& args
) {
2110 return DifferenceTemporalPlainDateTime(cx
, TemporalDifference::Since
, args
);
2114 * Temporal.PlainDateTime.prototype.since ( other [ , options ] )
2116 static bool PlainDateTime_since(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2118 CallArgs args
= CallArgsFromVp(argc
, vp
);
2119 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_since
>(cx
, args
);
2123 * Temporal.PlainDateTime.prototype.round ( roundTo )
2125 static bool PlainDateTime_round(JSContext
* cx
, const CallArgs
& args
) {
2126 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2127 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2128 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2131 auto smallestUnit
= TemporalUnit::Auto
;
2132 auto roundingMode
= TemporalRoundingMode::HalfExpand
;
2133 auto roundingIncrement
= Increment
{1};
2134 if (args
.get(0).isString()) {
2135 // Step 4. (Not applicable in our implementation.)
2138 Rooted
<JSString
*> paramString(cx
, args
[0].toString());
2139 if (!GetTemporalUnit(cx
, paramString
, TemporalUnitKey::SmallestUnit
,
2140 TemporalUnitGroup::DayTime
, &smallestUnit
)) {
2144 MOZ_ASSERT(TemporalUnit::Day
<= smallestUnit
&&
2145 smallestUnit
<= TemporalUnit::Nanosecond
);
2147 // Steps 6-8 and 10-12. (Implicit)
2150 Rooted
<JSObject
*> roundTo(
2151 cx
, RequireObjectArg(cx
, "roundTo", "round", args
.get(0)));
2157 if (!ToTemporalRoundingIncrement(cx
, roundTo
, &roundingIncrement
)) {
2162 if (!ToTemporalRoundingMode(cx
, roundTo
, &roundingMode
)) {
2167 if (!GetTemporalUnit(cx
, roundTo
, TemporalUnitKey::SmallestUnit
,
2168 TemporalUnitGroup::DayTime
, &smallestUnit
)) {
2172 if (smallestUnit
== TemporalUnit::Auto
) {
2173 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2174 JSMSG_TEMPORAL_MISSING_OPTION
, "smallestUnit");
2178 MOZ_ASSERT(TemporalUnit::Day
<= smallestUnit
&&
2179 smallestUnit
<= TemporalUnit::Nanosecond
);
2182 auto maximum
= Increment
{1};
2183 bool inclusive
= true;
2184 if (smallestUnit
> TemporalUnit::Day
) {
2185 maximum
= MaximumTemporalDurationRoundingIncrement(smallestUnit
);
2190 if (!ValidateTemporalRoundingIncrement(cx
, roundingIncrement
, maximum
,
2197 if (smallestUnit
== TemporalUnit::Nanosecond
&&
2198 roundingIncrement
== Increment
{1}) {
2199 auto* obj
= CreateTemporalDateTime(cx
, dateTime
, calendar
);
2204 args
.rval().setObject(*obj
);
2210 RoundISODateTime(dateTime
, roundingIncrement
, smallestUnit
, roundingMode
);
2213 auto* obj
= CreateTemporalDateTime(cx
, result
, calendar
);
2218 args
.rval().setObject(*obj
);
2223 * Temporal.PlainDateTime.prototype.round ( roundTo )
2225 static bool PlainDateTime_round(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2227 CallArgs args
= CallArgsFromVp(argc
, vp
);
2228 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_round
>(cx
, args
);
2232 * Temporal.PlainDateTime.prototype.equals ( other )
2234 static bool PlainDateTime_equals(JSContext
* cx
, const CallArgs
& args
) {
2235 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2236 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2237 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2240 Rooted
<PlainDateTimeWithCalendar
> other(cx
);
2241 if (!::ToTemporalDateTime(cx
, args
.get(0), &other
)) {
2246 bool equals
= dateTime
== other
.dateTime();
2247 if (equals
&& !CalendarEquals(cx
, calendar
, other
.calendar(), &equals
)) {
2251 args
.rval().setBoolean(equals
);
2256 * Temporal.PlainDateTime.prototype.equals ( other )
2258 static bool PlainDateTime_equals(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2260 CallArgs args
= CallArgsFromVp(argc
, vp
);
2261 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_equals
>(cx
, args
);
2265 * Temporal.PlainDateTime.prototype.toString ( [ options ] )
2267 static bool PlainDateTime_toString(JSContext
* cx
, const CallArgs
& args
) {
2268 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2269 auto dt
= ToPlainDateTime(dateTime
);
2270 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2272 SecondsStringPrecision precision
= {Precision::Auto(),
2273 TemporalUnit::Nanosecond
, Increment
{1}};
2274 auto roundingMode
= TemporalRoundingMode::Trunc
;
2275 auto showCalendar
= CalendarOption::Auto
;
2276 if (args
.hasDefined(0)) {
2278 Rooted
<JSObject
*> options(
2279 cx
, RequireObjectArg(cx
, "options", "toString", args
[0]));
2285 if (!ToCalendarNameOption(cx
, options
, &showCalendar
)) {
2290 auto digits
= Precision::Auto();
2291 if (!ToFractionalSecondDigits(cx
, options
, &digits
)) {
2296 if (!ToTemporalRoundingMode(cx
, options
, &roundingMode
)) {
2301 auto smallestUnit
= TemporalUnit::Auto
;
2302 if (!GetTemporalUnit(cx
, options
, TemporalUnitKey::SmallestUnit
,
2303 TemporalUnitGroup::Time
, &smallestUnit
)) {
2308 if (smallestUnit
== TemporalUnit::Hour
) {
2309 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2310 JSMSG_TEMPORAL_INVALID_UNIT_OPTION
, "hour",
2316 precision
= ToSecondsStringPrecision(smallestUnit
, digits
);
2321 RoundISODateTime(dt
, precision
.increment
, precision
.unit
, roundingMode
);
2324 JSString
* str
= ::TemporalDateTimeToString(cx
, result
, calendar
,
2325 precision
.precision
, showCalendar
);
2330 args
.rval().setString(str
);
2335 * Temporal.PlainDateTime.prototype.toString ( [ options ] )
2337 static bool PlainDateTime_toString(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2339 CallArgs args
= CallArgsFromVp(argc
, vp
);
2340 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toString
>(cx
,
2345 * Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )
2347 static bool PlainDateTime_toLocaleString(JSContext
* cx
, const CallArgs
& args
) {
2348 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2349 auto dt
= ToPlainDateTime(dateTime
);
2350 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2353 JSString
* str
= ::TemporalDateTimeToString(
2354 cx
, dt
, calendar
, Precision::Auto(), CalendarOption::Auto
);
2359 args
.rval().setString(str
);
2364 * Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )
2366 static bool PlainDateTime_toLocaleString(JSContext
* cx
, unsigned argc
,
2369 CallArgs args
= CallArgsFromVp(argc
, vp
);
2370 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toLocaleString
>(
2375 * Temporal.PlainDateTime.prototype.toJSON ( )
2377 static bool PlainDateTime_toJSON(JSContext
* cx
, const CallArgs
& args
) {
2378 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2379 auto dt
= ToPlainDateTime(dateTime
);
2380 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2383 JSString
* str
= ::TemporalDateTimeToString(
2384 cx
, dt
, calendar
, Precision::Auto(), CalendarOption::Auto
);
2389 args
.rval().setString(str
);
2394 * Temporal.PlainDateTime.prototype.toJSON ( )
2396 static bool PlainDateTime_toJSON(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2398 CallArgs args
= CallArgsFromVp(argc
, vp
);
2399 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toJSON
>(cx
, args
);
2403 * Temporal.PlainDateTime.prototype.valueOf ( )
2405 static bool PlainDateTime_valueOf(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2406 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_CANT_CONVERT_TO
,
2407 "PlainDateTime", "primitive type");
2412 * Temporal.PlainDateTime.prototype.getISOFields ( )
2414 static bool PlainDateTime_getISOFields(JSContext
* cx
, const CallArgs
& args
) {
2415 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2416 auto dateTime
= ToPlainDateTime(temporalDateTime
);
2417 auto calendar
= temporalDateTime
->calendar();
2420 Rooted
<IdValueVector
> fields(cx
, IdValueVector(cx
));
2423 if (!fields
.emplaceBack(NameToId(cx
->names().calendar
), calendar
.toValue())) {
2428 if (!fields
.emplaceBack(NameToId(cx
->names().isoDay
),
2429 Int32Value(dateTime
.date
.day
))) {
2434 if (!fields
.emplaceBack(NameToId(cx
->names().isoHour
),
2435 Int32Value(dateTime
.time
.hour
))) {
2440 if (!fields
.emplaceBack(NameToId(cx
->names().isoMicrosecond
),
2441 Int32Value(dateTime
.time
.microsecond
))) {
2446 if (!fields
.emplaceBack(NameToId(cx
->names().isoMillisecond
),
2447 Int32Value(dateTime
.time
.millisecond
))) {
2452 if (!fields
.emplaceBack(NameToId(cx
->names().isoMinute
),
2453 Int32Value(dateTime
.time
.minute
))) {
2458 if (!fields
.emplaceBack(NameToId(cx
->names().isoMonth
),
2459 Int32Value(dateTime
.date
.month
))) {
2464 if (!fields
.emplaceBack(NameToId(cx
->names().isoNanosecond
),
2465 Int32Value(dateTime
.time
.nanosecond
))) {
2470 if (!fields
.emplaceBack(NameToId(cx
->names().isoSecond
),
2471 Int32Value(dateTime
.time
.second
))) {
2476 if (!fields
.emplaceBack(NameToId(cx
->names().isoYear
),
2477 Int32Value(dateTime
.date
.year
))) {
2482 auto* obj
= NewPlainObjectWithUniqueNames(cx
, fields
);
2487 args
.rval().setObject(*obj
);
2492 * Temporal.PlainDateTime.prototype.getISOFields ( )
2494 static bool PlainDateTime_getISOFields(JSContext
* cx
, unsigned argc
,
2497 CallArgs args
= CallArgsFromVp(argc
, vp
);
2498 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_getISOFields
>(
2503 * Temporal.PlainDateTime.prototype.getCalendar ( )
2505 static bool PlainDateTime_getCalendar(JSContext
* cx
, const CallArgs
& args
) {
2506 auto* temporalDateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2507 Rooted
<CalendarValue
> calendar(cx
, temporalDateTime
->calendar());
2510 auto* obj
= ToTemporalCalendarObject(cx
, calendar
);
2515 args
.rval().setObject(*obj
);
2520 * Temporal.PlainDateTime.prototype.getCalendar ( )
2522 static bool PlainDateTime_getCalendar(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2524 CallArgs args
= CallArgsFromVp(argc
, vp
);
2525 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_getCalendar
>(cx
,
2530 * Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ ,
2533 static bool PlainDateTime_toZonedDateTime(JSContext
* cx
, const CallArgs
& args
) {
2534 Rooted
<PlainDateTimeObject
*> dateTime(
2535 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2536 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2539 Rooted
<TimeZoneValue
> timeZone(cx
);
2540 if (!ToTemporalTimeZone(cx
, args
.get(0), &timeZone
)) {
2544 auto disambiguation
= TemporalDisambiguation::Compatible
;
2545 if (args
.hasDefined(1)) {
2547 Rooted
<JSObject
*> options(
2548 cx
, RequireObjectArg(cx
, "options", "toZonedDateTime", args
[1]));
2554 if (!ToTemporalDisambiguation(cx
, options
, &disambiguation
)) {
2561 if (!GetInstantFor(cx
, timeZone
, dateTime
, disambiguation
, &instant
)) {
2566 auto* result
= CreateTemporalZonedDateTime(cx
, instant
, timeZone
, calendar
);
2571 args
.rval().setObject(*result
);
2576 * Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ ,
2579 static bool PlainDateTime_toZonedDateTime(JSContext
* cx
, unsigned argc
,
2582 CallArgs args
= CallArgsFromVp(argc
, vp
);
2583 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toZonedDateTime
>(
2588 * Temporal.PlainDateTime.prototype.toPlainDate ( )
2590 static bool PlainDateTime_toPlainDate(JSContext
* cx
, const CallArgs
& args
) {
2591 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2592 Rooted
<CalendarValue
> calendar(cx
, dateTime
->calendar());
2595 auto* obj
= CreateTemporalDate(cx
, ToPlainDate(dateTime
), calendar
);
2600 args
.rval().setObject(*obj
);
2605 * Temporal.PlainDateTime.prototype.toPlainDate ( )
2607 static bool PlainDateTime_toPlainDate(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2609 CallArgs args
= CallArgsFromVp(argc
, vp
);
2610 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainDate
>(cx
,
2615 * Temporal.PlainDateTime.prototype.toPlainYearMonth ( )
2617 static bool PlainDateTime_toPlainYearMonth(JSContext
* cx
,
2618 const CallArgs
& args
) {
2619 Rooted
<PlainDateTimeObject
*> dateTime(
2620 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2621 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
2624 Rooted
<CalendarRecord
> calendar(cx
);
2625 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
2627 CalendarMethod::Fields
,
2628 CalendarMethod::YearMonthFromFields
,
2635 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
2636 if (!CalendarFields(cx
, calendar
,
2637 {CalendarField::MonthCode
, CalendarField::Year
},
2643 Rooted
<PlainObject
*> fields(cx
,
2644 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
2650 auto obj
= CalendarYearMonthFromFields(cx
, calendar
, fields
);
2655 args
.rval().setObject(*obj
);
2660 * Temporal.PlainDateTime.prototype.toPlainYearMonth ( )
2662 static bool PlainDateTime_toPlainYearMonth(JSContext
* cx
, unsigned argc
,
2665 CallArgs args
= CallArgsFromVp(argc
, vp
);
2666 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainYearMonth
>(
2671 * Temporal.PlainDateTime.prototype.toPlainMonthDay ( )
2673 static bool PlainDateTime_toPlainMonthDay(JSContext
* cx
, const CallArgs
& args
) {
2674 Rooted
<PlainDateTimeObject
*> dateTime(
2675 cx
, &args
.thisv().toObject().as
<PlainDateTimeObject
>());
2676 Rooted
<CalendarValue
> calendarValue(cx
, dateTime
->calendar());
2679 Rooted
<CalendarRecord
> calendar(cx
);
2680 if (!CreateCalendarMethodsRecord(cx
, calendarValue
,
2682 CalendarMethod::Fields
,
2683 CalendarMethod::MonthDayFromFields
,
2690 JS::RootedVector
<PropertyKey
> fieldNames(cx
);
2691 if (!CalendarFields(cx
, calendar
,
2692 {CalendarField::Day
, CalendarField::MonthCode
},
2698 Rooted
<PlainObject
*> fields(cx
,
2699 PrepareTemporalFields(cx
, dateTime
, fieldNames
));
2705 auto obj
= CalendarMonthDayFromFields(cx
, calendar
, fields
);
2710 args
.rval().setObject(*obj
);
2715 * Temporal.PlainDateTime.prototype.toPlainMonthDay ( )
2717 static bool PlainDateTime_toPlainMonthDay(JSContext
* cx
, unsigned argc
,
2720 CallArgs args
= CallArgsFromVp(argc
, vp
);
2721 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainMonthDay
>(
2726 * Temporal.PlainDateTime.prototype.toPlainTime ( )
2728 static bool PlainDateTime_toPlainTime(JSContext
* cx
, const CallArgs
& args
) {
2729 auto* dateTime
= &args
.thisv().toObject().as
<PlainDateTimeObject
>();
2732 auto* obj
= CreateTemporalTime(cx
, ToPlainTime(dateTime
));
2737 args
.rval().setObject(*obj
);
2742 * Temporal.PlainDateTime.prototype.toPlainTime ( )
2744 static bool PlainDateTime_toPlainTime(JSContext
* cx
, unsigned argc
, Value
* vp
) {
2746 CallArgs args
= CallArgsFromVp(argc
, vp
);
2747 return CallNonGenericMethod
<IsPlainDateTime
, PlainDateTime_toPlainTime
>(cx
,
2751 const JSClass
PlainDateTimeObject::class_
= {
2752 "Temporal.PlainDateTime",
2753 JSCLASS_HAS_RESERVED_SLOTS(PlainDateTimeObject::SLOT_COUNT
) |
2754 JSCLASS_HAS_CACHED_PROTO(JSProto_PlainDateTime
),
2756 &PlainDateTimeObject::classSpec_
,
2759 const JSClass
& PlainDateTimeObject::protoClass_
= PlainObject::class_
;
2761 static const JSFunctionSpec PlainDateTime_methods
[] = {
2762 JS_FN("from", PlainDateTime_from
, 1, 0),
2763 JS_FN("compare", PlainDateTime_compare
, 2, 0),
2767 static const JSFunctionSpec PlainDateTime_prototype_methods
[] = {
2768 JS_FN("with", PlainDateTime_with
, 1, 0),
2769 JS_FN("withPlainTime", PlainDateTime_withPlainTime
, 0, 0),
2770 JS_FN("withPlainDate", PlainDateTime_withPlainDate
, 1, 0),
2771 JS_FN("withCalendar", PlainDateTime_withCalendar
, 1, 0),
2772 JS_FN("add", PlainDateTime_add
, 1, 0),
2773 JS_FN("subtract", PlainDateTime_subtract
, 1, 0),
2774 JS_FN("until", PlainDateTime_until
, 1, 0),
2775 JS_FN("since", PlainDateTime_since
, 1, 0),
2776 JS_FN("round", PlainDateTime_round
, 1, 0),
2777 JS_FN("equals", PlainDateTime_equals
, 1, 0),
2778 JS_FN("toString", PlainDateTime_toString
, 0, 0),
2779 JS_FN("toLocaleString", PlainDateTime_toLocaleString
, 0, 0),
2780 JS_FN("toJSON", PlainDateTime_toJSON
, 0, 0),
2781 JS_FN("valueOf", PlainDateTime_valueOf
, 0, 0),
2782 JS_FN("toZonedDateTime", PlainDateTime_toZonedDateTime
, 1, 0),
2783 JS_FN("toPlainDate", PlainDateTime_toPlainDate
, 0, 0),
2784 JS_FN("toPlainYearMonth", PlainDateTime_toPlainYearMonth
, 0, 0),
2785 JS_FN("toPlainMonthDay", PlainDateTime_toPlainMonthDay
, 0, 0),
2786 JS_FN("toPlainTime", PlainDateTime_toPlainTime
, 0, 0),
2787 JS_FN("getISOFields", PlainDateTime_getISOFields
, 0, 0),
2788 JS_FN("getCalendar", PlainDateTime_getCalendar
, 0, 0),
2792 static const JSPropertySpec PlainDateTime_prototype_properties
[] = {
2793 JS_PSG("calendarId", PlainDateTime_calendarId
, 0),
2794 JS_PSG("year", PlainDateTime_year
, 0),
2795 JS_PSG("month", PlainDateTime_month
, 0),
2796 JS_PSG("monthCode", PlainDateTime_monthCode
, 0),
2797 JS_PSG("day", PlainDateTime_day
, 0),
2798 JS_PSG("hour", PlainDateTime_hour
, 0),
2799 JS_PSG("minute", PlainDateTime_minute
, 0),
2800 JS_PSG("second", PlainDateTime_second
, 0),
2801 JS_PSG("millisecond", PlainDateTime_millisecond
, 0),
2802 JS_PSG("microsecond", PlainDateTime_microsecond
, 0),
2803 JS_PSG("nanosecond", PlainDateTime_nanosecond
, 0),
2804 JS_PSG("dayOfWeek", PlainDateTime_dayOfWeek
, 0),
2805 JS_PSG("dayOfYear", PlainDateTime_dayOfYear
, 0),
2806 JS_PSG("weekOfYear", PlainDateTime_weekOfYear
, 0),
2807 JS_PSG("yearOfWeek", PlainDateTime_yearOfWeek
, 0),
2808 JS_PSG("daysInWeek", PlainDateTime_daysInWeek
, 0),
2809 JS_PSG("daysInMonth", PlainDateTime_daysInMonth
, 0),
2810 JS_PSG("daysInYear", PlainDateTime_daysInYear
, 0),
2811 JS_PSG("monthsInYear", PlainDateTime_monthsInYear
, 0),
2812 JS_PSG("inLeapYear", PlainDateTime_inLeapYear
, 0),
2813 JS_STRING_SYM_PS(toStringTag
, "Temporal.PlainDateTime", JSPROP_READONLY
),
2817 const ClassSpec
PlainDateTimeObject::classSpec_
= {
2818 GenericCreateConstructor
<PlainDateTimeConstructor
, 3,
2819 gc::AllocKind::FUNCTION
>,
2820 GenericCreatePrototype
<PlainDateTimeObject
>,
2821 PlainDateTime_methods
,
2823 PlainDateTime_prototype_methods
,
2824 PlainDateTime_prototype_properties
,
2826 ClassSpec::DontDefineConstructor
,