Implement Temporal.Instant.{add, subtract, compare}

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2025-09-05 18:13:42 +09:00 committed by Patrick Kim
commit 7135cbaefe
12 changed files with 214 additions and 139 deletions

View file

@ -123,6 +123,21 @@ static Value builtinTemporalInstantFrom(ExecutionState& state, Value thisValue,
return Temporal::toTemporalInstant(state, argv[0]);
}
static Value builtinTemporalInstantCompare(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Set one to ? ToTemporalInstant(one).
auto one = Temporal::toTemporalInstant(state, argv[0]);
// Set two to ? ToTemporalInstant(two).
auto two = Temporal::toTemporalInstant(state, argv[1]);
// Return 𝔽(CompareEpochNanoseconds(one.[[EpochNanoseconds]], two.[[EpochNanoseconds]])).
if (one->epochNanoseconds() > two->epochNanoseconds()) {
return Value(1);
} else if (one->epochNanoseconds() < two->epochNanoseconds()) {
return Value(-1);
}
return Value(0);
}
static Value builtinTemporalInstantFromEpochMilliseconds(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Set epochMilliseconds to ? ToNumber(epochMilliseconds).
@ -231,6 +246,18 @@ static Value builtinTemporalInstantSince(ExecutionState& state, Value thisValue,
return instant->differenceTemporalInstant(state, TemporalInstantObject::DifferenceTemporalInstantOperation::Since, argv[0], argc > 1 ? argv[1] : Value());
}
static Value builtinTemporalInstantAdd(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_INSTANT2(instant, add);
return instant->addDurationToInstant(state, TemporalInstantObject::AddDurationOperation::Add, argv[0]);
}
static Value builtinTemporalInstantSubtract(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_INSTANT(instant, Subtract);
return instant->addDurationToInstant(state, TemporalInstantObject::AddDurationOperation::Subtract, argv[0]);
}
#define RESOLVE_THIS_BINDING_TO_PLAINDATE(NAME, BUILT_IN_METHOD) \
if (!thisValue.isObject() || !thisValue.asObject()->isTemporalPlainDateObject()) { \
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, state.context()->staticStrings().lazyCapitalPlainDate().string(), true, state.context()->staticStrings().lazy##BUILT_IN_METHOD().string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver); \
@ -469,6 +496,11 @@ void GlobalObject::installTemporal(ExecutionState& state)
NativeFunctionInfo(strings->lazyFromEpochNanoseconds(), builtinTemporalInstantFromEpochNanoseconds, 1, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstant->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyCompare()),
ObjectPropertyDescriptor(new NativeFunctionObject(state,
NativeFunctionInfo(strings->lazyCompare(), builtinTemporalInstantCompare, 2, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstantPrototype = m_temporalInstant->getFunctionPrototype(state).asObject();
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
@ -482,6 +514,8 @@ void GlobalObject::installTemporal(ExecutionState& state)
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->round), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->round, builtinTemporalInstantRound, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyUntil()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyUntil(), builtinTemporalInstantUntil, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySince()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySince(), builtinTemporalInstantSince, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->add), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->add, builtinTemporalInstantAdd, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalInstantPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySubtract()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySubtract(), builtinTemporalInstantSubtract, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
{
auto getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyGetEpochMilliseconds(), builtinTemporalInstantGetEpochMilliseconds, 0, NativeFunctionInfo::Strict));

View file

@ -993,6 +993,7 @@ namespace Escargot {
F(PlainTimeISO, "plainTimeISO") \
F(Since, "since") \
F(SmallestUnit, "smallestUnit") \
F(Subtract, "subtract") \
F(TemporalDotDuration, "Temporal.Duration") \
F(TemporalDotInstant, "Temporal.Instant") \
F(TemporalDotNow, "Temporal.Now") \

View file

@ -344,6 +344,30 @@ ISO8601::InternalDuration TemporalDurationObject::toInternalDurationRecord(ISO86
return ISO8601::InternalDuration(dateDuration, t);
}
// https://tc39.es/proposal-temporal/#sec-temporal-add24hourdaystonormalizedtimeduration
Int128 TemporalDurationObject::add24HourDaysToTimeDuration(ExecutionState& state, Int128 d, double days)
{
CheckedInt128 daysInNanoseconds = checkedCastDoubleToInt128(days) * ISO8601::ExactTime::nsPerDay;
CheckedInt128 result = d + daysInNanoseconds;
ASSERT(!result.hasOverflowed());
if (std::abs(result) > ISO8601::InternalDuration::maxTimeDuration) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Total time in duration is out of range");
return {};
}
return result;
}
ISO8601::InternalDuration TemporalDurationObject::toInternalDurationRecordWith24HourDays(ExecutionState& state, ISO8601::Duration duration)
{
// Let timeDuration be TimeDurationFromComponents(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
auto timeDuration = timeDurationFromComponents(state, duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
// Set timeDuration to ! Add24HourDaysToTimeDuration(timeDuration, duration.[[Days]]).
timeDuration = add24HourDaysToTimeDuration(state, timeDuration, duration.days());
// Let dateDuration be ! CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], 0).
ISO8601::Duration dateDuration = ISO8601::Duration{ duration.years(), duration.months(), duration.weeks(), 0, 0, 0, 0, 0, 0, 0 };
return ISO8601::InternalDuration::combineDateAndTimeDuration(dateDuration, timeDuration);
}
Int128 TemporalDurationObject::roundTimeDuration(ExecutionState& state, Int128 timeDuration, unsigned increment, ISO8601::DateTimeUnit unit, ISO8601::RoundingMode roundingMode)
{
// Let divisor be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Value" column contains unit.
@ -364,6 +388,24 @@ Int128 TemporalDurationObject::roundTimeDurationToIncrement(ExecutionState& stat
return rounded;
}
Int128 TemporalDurationObject::timeDurationFromComponents(ExecutionState& state, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
{
CheckedInt128 min = checkedCastDoubleToInt128(minutes) + checkedCastDoubleToInt128(hours) * Int128{ 60 };
CheckedInt128 sec = checkedCastDoubleToInt128(seconds) + min * Int128{ 60 };
CheckedInt128 millis = checkedCastDoubleToInt128(milliseconds) + sec * Int128{ 1000 };
CheckedInt128 micros = checkedCastDoubleToInt128(microseconds) + millis * Int128{ 1000 };
CheckedInt128 nanos = checkedCastDoubleToInt128(nanoseconds) + micros * Int128{ 1000 };
if (nanos.hasOverflowed() || std::abs(nanos) > ISO8601::InternalDuration::maxTimeDuration) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "time duration exceeds maximum");
}
// The components come from a TemporalDuration, so as per
// TemporalDuration::tryCreateIfValid(), these components can at most add up
// to ISO8601::InternalDuration::maxTimeDuration
ASSERT(!nanos.hasOverflowed());
ASSERT(std::abs(nanos) <= ISO8601::InternalDuration::maxTimeDuration);
return nanos;
}
} // namespace Escargot
#endif

View file

@ -79,15 +79,25 @@ public:
String* toString(ExecutionState& state, Value options);
static String* temporalDurationToString(ISO8601::Duration duration, Value precision);
// https://tc39.es/proposal-temporal/#sec-temporal-tointernaldurationrecord
static ISO8601::InternalDuration toInternalDurationRecord(ISO8601::Duration duration);
// https://tc39.es/proposal-temporal/#sec-temporal-tointernaldurationrecordwith24hourdays
static ISO8601::InternalDuration toInternalDurationRecordWith24HourDays(ExecutionState& state, ISO8601::Duration duration);
// https://tc39.es/proposal-temporal/#sec-temporal-roundtimeduration
static Int128 roundTimeDuration(ExecutionState& state, Int128 timeDuration, unsigned increment, ISO8601::DateTimeUnit unit, ISO8601::RoundingMode roundingMode);
// https://tc39.es/proposal-temporal/#sec-temporal-roundtimedurationtoincrement
static Int128 roundTimeDurationToIncrement(ExecutionState& state, Int128 d, Int128 increment, ISO8601::RoundingMode roundingMode);
// https://tc39.es/proposal-temporal/#sec-temporal-timedurationfromcomponents
static Int128 timeDurationFromComponents(ExecutionState& state, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
// https://tc39.es/proposal-temporal/#sec-temporal-add24hourdaystonormalizedtimeduration
static Int128 add24HourDaysToTimeDuration(ExecutionState& state, Int128 d, double days);
private:
ISO8601::Duration m_duration;
};

View file

@ -34,9 +34,7 @@ TemporalInstantObject::TemporalInstantObject(ExecutionState& state, Object* prot
Value TemporalInstantObject::epochMilliseconds() const
{
Int128 s = *m_nanoseconds;
s /= 1000000;
return Value(static_cast<int64_t>(s));
return Value(static_cast<int64_t>(ISO8601::ExactTime(*m_nanoseconds).floorEpochMilliseconds()));
}
@ -277,11 +275,41 @@ TemporalDurationObject* TemporalInstantObject::differenceTemporalInstant(Executi
return new TemporalDurationObject(state, result);
}
TemporalInstantObject* TemporalInstantObject::addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike)
TemporalInstantObject* TemporalInstantObject::addDurationToInstant(ExecutionState& state, AddDurationOperation operation, const Value& temporalDurationLike)
{
TemporalInstantObject* instant = this;
// TODO
return nullptr;
// Let duration be ? ToTemporalDuration(temporalDurationLike).
auto duration = Temporal::toTemporalDuration(state, temporalDurationLike)->duration();
bool hasPositive = false;
bool hasNegative = false;
for (auto n : duration) {
if (n > 0) {
hasPositive = true;
} else if (n < 0) {
hasNegative = true;
}
}
if (hasPositive && hasNegative) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid duration");
}
// If operation is subtract, set duration to CreateNegatedTemporalDuration(duration).
if (operation == AddDurationOperation::Subtract) {
duration = TemporalDurationObject::createNegatedTemporalDuration(duration);
}
// Let largestUnit be DefaultTemporalLargestUnit(duration).
auto largestUnit = duration.defaultTemporalLargestUnit();
// If TemporalUnitCategory(largestUnit) is date, throw a RangeError exception.
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid duration");
}
// Let internalDuration be ToInternalDurationRecordWith24HourDays(duration).
auto internalDuration = TemporalDurationObject::toInternalDurationRecordWith24HourDays(state, duration);
// Let ns be ? AddInstant(instant.[[EpochNanoseconds]], internalDuration.[[Time]]).
Int128 ns = addInstant(state, epochNanoseconds(), internalDuration.time());
// Return ! CreateTemporalInstant(ns).
return new TemporalInstantObject(state, state.context()->globalObject()->temporalInstantPrototype(), ns);
}
ISO8601::InternalDuration TemporalInstantObject::differenceInstant(ExecutionState& state, Int128 ns1, Int128 ns2, unsigned roundingIncrement,
@ -295,6 +323,18 @@ ISO8601::InternalDuration TemporalInstantObject::differenceInstant(ExecutionStat
return ISO8601::InternalDuration(ISO8601::Duration(), timeDuration);
}
Int128 TemporalInstantObject::addInstant(ExecutionState& state, Int128 epochNanoseconds, Int128 timeDuration)
{
// Let result be AddTimeDurationToEpochNanoseconds(timeDuration, epochNanoseconds).
auto result = timeDuration + epochNanoseconds;
// If IsValidEpochNanoseconds(result) is false, throw a RangeError exception.
if (!ISO8601::ExactTime(result).isValid()) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid time or date");
}
// Return result.
return result;
}
} // namespace Escargot
#endif

View file

@ -53,18 +53,21 @@ public:
};
TemporalDurationObject* differenceTemporalInstant(ExecutionState& state, DifferenceTemporalInstantOperation operation, Value other, Value options);
private:
// https://tc39.es/proposal-temporal/#sec-temporal-adddurationtoinstant
enum class AddDurationOperation {
Add,
Subtract
};
TemporalInstantObject* addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike);
TemporalInstantObject* addDurationToInstant(ExecutionState& state, AddDurationOperation operation, const Value& temporalDurationLike);
// https://tc39.es/proposal-temporal/#sec-temporal-differenceinstant
static ISO8601::InternalDuration differenceInstant(ExecutionState& state, Int128 ns1, Int128 ns2, unsigned roundingIncrement,
ISO8601::DateTimeUnit smallestUnit, ISO8601::RoundingMode roundingMode);
// https://tc39.es/proposal-temporal/#sec-temporal-addinstant
static Int128 addInstant(ExecutionState& state, Int128 epochNanoseconds, Int128 timeDuration);
private:
Int128* m_nanoseconds; // [[EpochNanoseconds]]
};

View file

@ -452,7 +452,7 @@ TemporalDurationObject* Temporal::toTemporalDuration(ExecutionState& state, cons
// Return ? ParseTemporalDurationString(item).
auto duration = ISO8601::Duration::parseDurationString(item.asString());
if (!duration) {
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, msg);
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, msg);
}
return new TemporalDurationObject(state, duration.value());
}

View file

@ -53,7 +53,6 @@
#include "runtime/Context.h"
#include "runtime/Object.h"
#include "intl/Intl.h"
#include "CheckedArithmetic.h"
namespace Escargot {
namespace ISO8601 {
@ -156,7 +155,7 @@ static void handleFraction(Duration& duration, int factor, std::string fractionS
static double parseInt(std::string src)
{
return std::stoi(src);
return std::stod(src);
}
DateTimeUnitCategory toDateTimeCategory(DateTimeUnit u)
@ -1540,49 +1539,6 @@ InternalDuration InternalDuration::combineDateAndTimeDuration(Duration dateDurat
return InternalDuration{ std::move(dateDuration), timeDuration };
}
using CheckedInt128 = Checked<Int128, RecordOverflow>;
static CheckedInt128 checkedCastDoubleToInt128(double n)
{
// Based on __fixdfti() and __fixunsdfti() from compiler_rt:
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixint_impl.inc
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixuint_impl.inc
static constexpr int significandBits = std::numeric_limits<double>::digits - 1;
static constexpr int exponentBits = std::numeric_limits<uint64_t>::digits - std::numeric_limits<double>::digits;
static constexpr int exponentBias = std::numeric_limits<double>::max_exponent - 1;
static constexpr uint64_t implicitBit = uint64_t{ 1 } << significandBits;
static constexpr uint64_t significandMask = implicitBit - uint64_t{ 1 };
static constexpr uint64_t signMask = uint64_t{ 1 } << (significandBits + exponentBits);
static constexpr uint64_t absMask = signMask - uint64_t{ 1 };
// Break n into sign, exponent, significand parts.
const uint64_t bits = *reinterpret_cast<uint64_t*>(&n);
const uint64_t nAbs = bits & absMask;
const int sign = bits & signMask ? -1 : 1;
const int exponent = (nAbs >> significandBits) - exponentBias;
const uint64_t significand = (nAbs & significandMask) | implicitBit;
// If exponent is negative, the result is zero.
if (exponent < 0)
return { 0 };
// If the value is too large for the integer type, overflow.
if (exponent >= 128)
return { ResultOverflowed };
// If 0 <= exponent < significandBits, right shift to get the result.
// Otherwise, shift left.
Int128 result{ significand };
if (exponent < significandBits)
result >>= significandBits - exponent;
else
result <<= exponent - significandBits;
result *= sign;
return { result };
}
Optional<ExactTime> parseISODateTimeWithInstantFormat(String* input)
{
// https://tc39.es/proposal-temporal/#prod-TemporalInstantString

66
src/util/Int128.cpp Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2021 Sony Interactive Entertainment Inc.
* Copyright (C) 2021 Apple Inc. All rights reserved.
* Copyright (c) 2025-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "Escargot.h"
#include "Int128.h"
namespace Escargot {
CheckedInt128 checkedCastDoubleToInt128(double n)
{
// Based on __fixdfti() and __fixunsdfti() from compiler_rt:
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixint_impl.inc
// https://github.com/llvm/llvm-project/blob/f3671de5500ff1f8210419226a9603a7d83b1a31/compiler-rt/lib/builtins/fp_fixuint_impl.inc
static constexpr int significandBits = std::numeric_limits<double>::digits - 1;
static constexpr int exponentBits = std::numeric_limits<uint64_t>::digits - std::numeric_limits<double>::digits;
static constexpr int exponentBias = std::numeric_limits<double>::max_exponent - 1;
static constexpr uint64_t implicitBit = uint64_t{ 1 } << significandBits;
static constexpr uint64_t significandMask = implicitBit - uint64_t{ 1 };
static constexpr uint64_t signMask = uint64_t{ 1 } << (significandBits + exponentBits);
static constexpr uint64_t absMask = signMask - uint64_t{ 1 };
// Break n into sign, exponent, significand parts.
const uint64_t bits = *reinterpret_cast<uint64_t*>(&n);
const uint64_t nAbs = bits & absMask;
const int sign = bits & signMask ? -1 : 1;
const int exponent = (nAbs >> significandBits) - exponentBias;
const uint64_t significand = (nAbs & significandMask) | implicitBit;
// If exponent is negative, the result is zero.
if (exponent < 0)
return { 0 };
// If the value is too large for the integer type, overflow.
if (exponent >= 128)
return { ResultOverflowed };
// If 0 <= exponent < significandBits, right shift to get the result.
// Otherwise, shift left.
Int128 result{ significand };
if (exponent < significandBits)
result >>= significandBits - exponent;
else
result <<= exponent - significandBits;
result *= sign;
return { result };
}
} // namespace Escargot

View file

@ -81,9 +81,13 @@ static __forceinline int __builtin_clzl(unsigned long x)
#undef INT128_SPECIALIZATION
#define INT128_NO_EXPORT
#include "CheckedArithmetic.h"
namespace Escargot {
using Int128 = large_int::int128_t;
using CheckedInt128 = Checked<Int128, RecordOverflow>;
CheckedInt128 checkedCastDoubleToInt128(double n);
} // namespace Escargot

View file

@ -187,19 +187,19 @@ static inline bool isInBounds(Source value)
template <typename T>
struct RemoveChecked {
typedef T CleanType;
static const CleanType DefaultValue = 0;
static constexpr CleanType DefaultValue = 0;
};
template <typename T>
struct RemoveChecked<Checked<T, CrashOnOverflow> > {
typedef typename RemoveChecked<T>::CleanType CleanType;
static const CleanType DefaultValue = 0;
static constexpr CleanType DefaultValue = 0;
};
template <typename T>
struct RemoveChecked<Checked<T, RecordOverflow> > {
typedef typename RemoveChecked<T>::CleanType CleanType;
static const CleanType DefaultValue = 0;
static constexpr CleanType DefaultValue = 0;
};
// The ResultBase and SignednessSelector are used to workaround typeof not being

View file

@ -183,8 +183,6 @@
<test id="built-ins/Temporal/Duration/from/argument-duration-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/argument-duration-precision-exact-numerical-values"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/argument-object-invalid"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/argument-string-fractional-with-zero-subparts"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/argument-string-invalid"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/argument-string-is-infinity"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/from/negative-inifinity-throws-rangeerror"><reason>TODO</reason></test>
@ -381,8 +379,6 @@
<test id="built-ins/Temporal/Duration/prototype/toJSON/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toLocaleString/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toLocaleString/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toString/balance-subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toString/negative-components"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toString/smallestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/toString/total-of-duration-time-units-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/total/balance-negative-result"><reason>TODO</reason></test>
@ -469,85 +465,10 @@
<test id="built-ins/Temporal/Duration/prototype/with/sign-conflict-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/with/sign-replace"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/with/subclassing-ignored"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-object-tostring"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-calendar-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-calendar-annotation-invalid-key"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-critical-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-date-with-utc-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-invalid"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-limits"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-minus-sign"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-multiple-calendar"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-multiple-time-zone"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-time-separators"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-time-zone-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-string-with-offset-not-valid-epoch-nanoseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/argument-zoneddatetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/cross-epoch"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/exhaustive"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/instant-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/instant-string-multiple-offsets"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/instant-string-sub-minute-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/name"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/not-a-constructor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/compare/year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/from/argument-zoneddatetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-duration-max"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-duration-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-mixed-sign"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-not-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-string-fractional-units-rounding-mode"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/argument-string-negative-fractional-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/basic"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/cross-epoch"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/disallowed-duration-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/minimum-maximum-instant"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/name"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/negative-infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/non-integer-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/not-a-constructor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/order-of-operations"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/result-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/add/subclassing-ignored"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/epochMilliseconds/basic"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/equals/argument-zoneddatetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/since/add-subtract"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/since/argument-zoneddatetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/since/subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-duration-max"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-duration-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-mixed-sign"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-not-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string-fractional-units-rounding-mode"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/argument-string-negative-fractional-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/basic"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/disallowed-duration-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/minimum-maximum-instant"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/name"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/negative-infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/non-integer-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/not-a-constructor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/order-of-operations"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/result-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/subtract/subclassing-ignored"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/toString/smallestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/builtin"><reason>TODO</reason></test>
@ -565,9 +486,7 @@
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-string-year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/to-zoned-date-time-iso"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/until/add-subtract"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/until/argument-zoneddatetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Instant/prototype/until/subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Now/plainDateISO/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Now/plainDateISO/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Now/plainDateISO/return-value"><reason>TODO</reason></test>