Implement Temporal.ZonedDateTime.since, until

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2025-11-12 17:54:22 +09:00 committed by Patrick Kim
commit dccf2f9256
8 changed files with 320 additions and 249 deletions

View file

@ -1262,6 +1262,18 @@ static Value builtinTemporalZonedDateTimeSubtract(ExecutionState& state, Value t
return zonedDateTime->addDurationToZonedDateTime(state, TemporalZonedDateTimeObject::AddDurationToZonedDateTimeOperation::Subtract, argv[0], argc > 1 ? argv[1] : Value());
}
static Value builtinTemporalZonedDateTimeSince(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_ZONEDDATETIME(zonedDateTime, Since);
return zonedDateTime->differenceTemporalZonedDateTime(state, TemporalZonedDateTimeObject::DifferenceTemporalZonedDateTime::Since, argv[0], argc > 1 ? argv[1] : Value());
}
static Value builtinTemporalZonedDateTimeUntil(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
RESOLVE_THIS_BINDING_TO_ZONEDDATETIME(zonedDateTime, Until);
return zonedDateTime->differenceTemporalZonedDateTime(state, TemporalZonedDateTimeObject::DifferenceTemporalZonedDateTime::Until, argv[0], argc > 1 ? argv[1] : Value());
}
void GlobalObject::initializeTemporal(ExecutionState& state)
{
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(
@ -1812,6 +1824,9 @@ void GlobalObject::installTemporal(ExecutionState& state)
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyWithCalendar()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyWithCalendar(), builtinTemporalZonedDateTimeWithCalendar, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->add), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->add, builtinTemporalZonedDateTimeAdd, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySubtract()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySubtract(), builtinTemporalZonedDateTimeSubtract, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyUntil()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyUntil(), builtinTemporalZonedDateTimeUntil, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySince()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySince(), builtinTemporalZonedDateTimeSince, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
{
AtomicString name(state.context(), "get calendarId");

View file

@ -90,10 +90,44 @@ ISO8601::Duration TemporalDurationObject::temporalDurationFromInternal(Execution
Int128 milliseconds = 0, microseconds = 0;
// Let sign be TimeDurationSign(internalDuration.[[Time]]).
int32_t sign = internalDuration.sign();
// Let nanoseconds be abs(internalDuration.[[Time]]).
auto nanoseconds = std::abs(internalDuration.time());
int32_t sign;
Int128 nanoseconds = internalDuration.time();
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
sign = internalDuration.sign();
nanoseconds = std::abs(nanoseconds);
} else {
sign = internalDuration.timeDurationSign();
if (sign == -1 && internalDuration.dateDuration().sign() == 1) {
if (largestUnit == ISO8601::DateTimeUnit::Hour) {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerDay;
} else if (largestUnit == ISO8601::DateTimeUnit::Minute) {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerHour;
} else if (largestUnit == ISO8601::DateTimeUnit::Second) {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMinute;
} else if (largestUnit == ISO8601::DateTimeUnit::Millisecond) {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerSecond;
} else if (largestUnit == ISO8601::DateTimeUnit::Microsecond) {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMillisecond;
} else {
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMicrosecond;
}
} else if (sign == 1 && internalDuration.dateDuration().sign() == -1) {
if (largestUnit == ISO8601::DateTimeUnit::Hour) {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerDay;
} else if (largestUnit == ISO8601::DateTimeUnit::Minute) {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerHour;
} else if (largestUnit == ISO8601::DateTimeUnit::Second) {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMinute;
} else if (largestUnit == ISO8601::DateTimeUnit::Millisecond) {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerSecond;
} else if (largestUnit == ISO8601::DateTimeUnit::Microsecond) {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMillisecond;
} else {
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMicrosecond;
}
}
}
// If TemporalUnitCategory(largestUnit) is date, then
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
@ -195,30 +229,52 @@ ISO8601::Duration TemporalDurationObject::temporalDurationFromInternal(Execution
// Assert: largestUnit is nanosecond.
}
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
if (hours) {
hours *= sign;
}
if (minutes) {
minutes *= sign;
}
if (seconds) {
seconds *= sign;
}
if (milliseconds) {
milliseconds *= sign;
}
if (microseconds) {
microseconds *= sign;
}
if (nanoseconds) {
nanoseconds *= sign;
}
} else {
// remove -0.0
if (std::signbit(days) && !days) {
days = 0;
}
if (std::signbit(hours) && !hours) {
hours = 0;
}
if (std::signbit(minutes) && !minutes) {
minutes = 0;
}
if (std::signbit(seconds) && !seconds) {
seconds = 0;
}
}
// Return ? CreateTemporalDuration(internalDuration.[[Date]].[[Years]], internalDuration.[[Date]].[[Months]],
// internalDuration.[[Date]].[[Weeks]], internalDuration.[[Date]].[[Days]] + days × sign,
// hours × sign, minutes × sign, seconds × sign, milliseconds × sign, microseconds × sign, nanoseconds × sign).
if (hours) {
hours *= sign;
}
if (minutes) {
minutes *= sign;
}
if (seconds) {
seconds *= sign;
}
if (milliseconds) {
milliseconds *= sign;
}
if (microseconds) {
microseconds *= sign;
}
if (nanoseconds) {
nanoseconds *= sign;
auto value = ISO8601::Duration{ internalDuration.dateDuration().years(), internalDuration.dateDuration().months(), internalDuration.dateDuration().weeks(), internalDuration.dateDuration().days() + days * sign, hours, minutes,
static_cast<double>(seconds), static_cast<double>(milliseconds), static_cast<double>(microseconds), static_cast<double>(nanoseconds) };
if (!value.isValid()) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid Duration value");
}
return ISO8601::Duration{ internalDuration.dateDuration().years(), internalDuration.dateDuration().months(), internalDuration.dateDuration().weeks(), internalDuration.dateDuration().days() + days * sign, hours, minutes,
static_cast<double>(seconds), static_cast<double>(milliseconds), static_cast<double>(microseconds), static_cast<double>(nanoseconds) };
return value;
}
ISO8601::Duration TemporalDurationObject::createNegatedTemporalDuration(ISO8601::Duration duration)

View file

@ -238,6 +238,16 @@ void Temporal::formatSecondsStringFraction(StringBuilder& builder, Int128 fracti
}
}
ISO8601::PlainDateTime Temporal::toPlainDateTime(Int128 epochNanoseconds)
{
int64_t computedEpoch = ISO8601::ExactTime(epochNanoseconds).floorEpochMilliseconds();
DateObject::DateTimeInfo timeInfo;
DateObject::computeTimeInfoFromEpoch(computedEpoch, timeInfo);
auto d = Temporal::balanceTime(0, 0, 0, 0, 0, epochNanoseconds % ISO8601::ExactTime::nsPerDay);
return ISO8601::PlainDateTime(ISO8601::PlainDate(timeInfo.year, timeInfo.month + 1, timeInfo.mday),
ISO8601::PlainTime(d.hours(), d.minutes(), d.seconds(), d.milliseconds(), d.microseconds(), d.nanoseconds()));
}
int32_t Temporal::computeTimeZoneOffset(ExecutionState& state, String* name, int64_t epoch)
{
auto u16 = name->toUTF16StringData();
@ -912,7 +922,11 @@ Int128 Temporal::interpretISODateTimeOffset(ExecutionState& state, ISO8601::Plai
// TODO Let epochNanoseconds be GetUTCEpochNanoseconds(balanced).
// TODO If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
// Return epochNanoseconds.
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() + offsetNanoseconds;
auto ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() + offsetNanoseconds;
if (!ISO8601::isValidEpochNanoseconds(ns)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid date-time value");
}
return ns;
}
// TODO
@ -947,10 +961,18 @@ Int128 Temporal::interpretISODateTimeOffset(ExecutionState& state, ISO8601::Plai
}
}
Int128 ns;
if (hasUTCDesignator) {
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds();
ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds();
} else {
ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() - timeZoneOffsetNanoseconds.valueOr(0);
}
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() - timeZoneOffsetNanoseconds.valueOr(0);
if (!ISO8601::isValidEpochNanoseconds(ns)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid date-time value");
}
return ns;
}
TemporalZonedDateTimeObject* Temporal::toTemporalZonedDateTime(ExecutionState& state, Value item, Value options)
@ -1836,17 +1858,6 @@ bool Temporal::isPartialTemporalObject(ExecutionState& state, Value value)
return true;
}
template <typename T>
T nonNegativeModulo(T x, int y)
{
T result = x % y;
if (!result)
return 0;
if (result < 0)
result += y;
return result;
}
template <>
double nonNegativeModulo(double x, int y)
{
@ -1858,19 +1869,6 @@ double nonNegativeModulo(double x, int y)
return result;
}
template <typename T>
T intFloor(T x, int y)
{
if (x > 0) {
return x / y;
}
if (x % y) {
return x / y - 1;
} else {
return x / y;
}
}
ISO8601::Duration Temporal::balanceTime(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond)
{
microsecond += std::floor(nanosecond / 1000);
@ -3286,12 +3284,7 @@ ISO8601::InternalDuration Temporal::differenceISODateTime(ExecutionState& state,
// Let timeDuration be DifferenceTime(isoDateTime1.[[Time]], isoDateTime2.[[Time]]).
auto timeDuration = differenceTime(isoDateTime1.plainTime(), isoDateTime2.plainTime());
// Let timeSign be TimeDurationSign(timeDuration).
int timeSign = 0;
if (timeDuration < 0) {
timeSign = -1;
} else if (timeDuration > 0) {
timeSign = 1;
}
int timeSign = timeDurationSign(timeDuration);
// Let dateSign be CompareISODate(isoDateTime1.[[ISODate]], isoDateTime2.[[ISODate]]).
auto dateSign = isoDateTime1.plainDate().compare(isoDateTime2.plainDate());
// Let adjustedDate be isoDateTime2.[[ISODate]].
@ -3384,11 +3377,7 @@ ISO8601::PlainDateTime Temporal::getISODateTimeFor(ExecutionState& state, Option
// Return BalanceISODateTime(result.[[ISODate]].[[Year]], result.[[ISODate]].[[Month]], result.[[ISODate]].[[Day]], result.[[Time]].[[Hour]], result.[[Time]].[[Minute]], result.[[Time]].[[Second]], result.[[Time]].[[Millisecond]], result.[[Time]].[[Microsecond]], result.[[Time]].[[Nanosecond]] + offsetNanoseconds).
int64_t offsetNanoseconds = timeZone ? getOffsetNanosecondsFor(state, timeZone.value(), epochNs) : 0;
epochNs += offsetNanoseconds;
DateObject::DateTimeInfo timeInfo;
DateObject::computeTimeInfoFromEpoch(ISO8601::ExactTime(epochNs).floorEpochMilliseconds(), timeInfo);
auto d = Temporal::balanceTime(0, 0, 0, 0, 0, epochNs % ISO8601::ExactTime::nsPerDay);
return ISO8601::PlainDateTime(ISO8601::PlainDate(timeInfo.year, timeInfo.month + 1, timeInfo.mday),
ISO8601::PlainTime(d.hours(), d.minutes(), d.seconds(), d.milliseconds(), d.microseconds(), d.nanoseconds()));
return toPlainDateTime(epochNs);
}
int64_t Temporal::getOffsetNanosecondsFor(ExecutionState& state, TimeZone timeZone, Int128 epochNs)

View file

@ -31,6 +31,30 @@
namespace Escargot {
template <typename T>
T nonNegativeModulo(T x, int y)
{
T result = x % y;
if (!result)
return 0;
if (result < 0)
result += y;
return result;
}
template <typename T>
T intFloor(T x, int y)
{
if (x > 0) {
return x / y;
}
if (x % y) {
return x / y - 1;
} else {
return x / y;
}
}
class Calendar {
public:
// sync with 'canonicalCodeForDisplayNames'
@ -260,6 +284,17 @@ public:
static ISO8601::PlainDate computeISODate(ExecutionState& state, UCalendar* ucal);
static TimeZone parseTimeZone(ExecutionState& state, String* input);
static void formatSecondsStringFraction(StringBuilder& builder, Int128 fraction, Value precision);
static ISO8601::PlainDateTime toPlainDateTime(Int128 epochNanoseconds);
static int timeDurationSign(Int128 t)
{
if (t < 0) {
return -1;
} else if (t > 0) {
return 1;
}
return 0;
}
// returns offset(milliseconds)
static int32_t computeTimeZoneOffset(ExecutionState& state, String* name, int64_t epoch);

View file

@ -575,6 +575,7 @@ ISO8601::Duration TemporalPlainDateObject::differenceTemporalPlainDate(Execution
auto isoDateTimeOther = other->computeISODate(state);
// Let destEpochNs be GetUTCEpochNanoseconds(isoDateTimeOther).
auto destEpochNs = ISO8601::ExactTime::fromPlainDate(isoDateTimeOther).epochNanoseconds();
// Set duration to ? RoundRelativeDuration(duration, originEpochNs, destEpochNs, isoDateTime, unset, temporalDate.[[Calendar]], settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
duration = Temporal::roundRelativeDuration(state, duration, destEpochNs, ISO8601::PlainDateTime(isoDateTime, ISO8601::PlainTime()), NullOption, calendarID(), toTemporalUnit(settings.largestUnit), settings.roundingIncrement, toTemporalUnit(settings.smallestUnit), settings.roundingMode);
}

View file

@ -64,12 +64,7 @@ void TemporalZonedDateTimeObject::init(ExecutionState& state, ComputedTimeZone t
{
m_timeZone = timeZone;
Int128 timezoneAppliedEpochNanoseconds = *m_epochNanoseconds + timeZone.offset();
int64_t computedEpoch = ISO8601::ExactTime(timezoneAppliedEpochNanoseconds).floorEpochMilliseconds();
DateObject::DateTimeInfo timeInfo;
DateObject::computeTimeInfoFromEpoch(computedEpoch, timeInfo);
auto d = Temporal::balanceTime(0, 0, 0, 0, 0, timezoneAppliedEpochNanoseconds % ISO8601::ExactTime::nsPerDay);
*m_plainDateTime = ISO8601::PlainDateTime(ISO8601::PlainDate(timeInfo.year, timeInfo.month + 1, timeInfo.mday),
ISO8601::PlainTime(d.hours(), d.minutes(), d.seconds(), d.milliseconds(), d.microseconds(), d.nanoseconds()));
*m_plainDateTime = Temporal::toPlainDateTime(timezoneAppliedEpochNanoseconds);
if (!ISO8601::isValidEpochNanoseconds(*m_epochNanoseconds)) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Out of range date-time");
@ -380,6 +375,155 @@ TemporalZonedDateTimeObject* TemporalZonedDateTimeObject::addDurationToZonedDate
return new TemporalZonedDateTimeObject(state, state.context()->globalObject()->temporalZonedDateTimePrototype(), epochNanoseconds, timeZone, calendar);
}
TemporalDurationObject* TemporalZonedDateTimeObject::differenceTemporalZonedDateTime(ExecutionState& state, DifferenceTemporalZonedDateTime operation, Value otherInput, Value options)
{
// Set other to ? ToTemporalZonedDateTime(other).
auto other = Temporal::toTemporalZonedDateTime(state, otherInput, Value());
// If CalendarEquals(zonedDateTime.[[Calendar]], other.[[Calendar]]) is false, then
if (other->calendarID() != calendarID()) {
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "calendar is not same");
}
// Let resolvedOptions be ? GetOptionsObject(options).
auto resolvedOptions = Intl::getOptionsObject(state, options);
// Let settings be ? GetDifferenceSettings(operation, resolvedOptions, datetime, « », nanosecond, hour).
auto settings = Temporal::getDifferenceSettings(state, operation == DifferenceTemporalZonedDateTime::Since, resolvedOptions, ISO8601::DateTimeUnitCategory::DateTime, nullptr, 0, TemporalUnit::Nanosecond, TemporalUnit::Hour);
// If TemporalUnitCategory(settings.[[LargestUnit]]) is time, then
if (ISO8601::toDateTimeCategory(settings.largestUnit) == ISO8601::DateTimeUnitCategory::Time) {
// Let internalDuration be DifferenceInstant(zonedDateTime.[[EpochNanoseconds]], other.[[EpochNanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
auto internalDuration = TemporalInstantObject::differenceInstant(state, epochNanoseconds(), other->epochNanoseconds(), settings.roundingIncrement, settings.smallestUnit, settings.roundingMode);
// Let result be ! TemporalDurationFromInternal(internalDuration, settings.[[LargestUnit]]).
auto result = TemporalDurationObject::temporalDurationFromInternal(state, internalDuration, settings.largestUnit);
// If operation is since, set result to CreateNegatedTemporalDuration(result).
if (operation == DifferenceTemporalZonedDateTime::Since) {
result = TemporalDurationObject::createNegatedTemporalDuration(result);
}
// Return result.
return new TemporalDurationObject(state, result);
}
// If TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, then
if (!timeZoneEquals(timeZone(), other->timeZone())) {
// Throw a RangeError exception.
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "timeZone is not same");
}
// If zonedDateTime.[[EpochNanoseconds]] = other.[[EpochNanoseconds]], then
if (epochNanoseconds() == other->epochNanoseconds()) {
// Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
return new TemporalDurationObject(state, {});
}
// Let internalDuration be ? DifferenceZonedDateTimeWithRounding(zonedDateTime.[[EpochNanoseconds]], other.[[EpochNanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
auto internalDuration = differenceZonedDateTimeWithRounding(state, epochNanoseconds(), other->epochNanoseconds(), timeZone(), calendarID(), settings.largestUnit, settings.roundingIncrement, settings.smallestUnit, settings.roundingMode);
// Let result be ! TemporalDurationFromInternal(internalDuration, hour).
ISO8601::Duration result;
if (settings.smallestUnit <= ISO8601::DateTimeUnit::Day) {
result = TemporalDurationObject::temporalDurationFromInternal(state, internalDuration, settings.smallestUnit);
} else {
result = TemporalDurationObject::temporalDurationFromInternal(state, internalDuration, ISO8601::DateTimeUnit::Hour);
}
// If operation is since, set result to CreateNegatedTemporalDuration(result).
if (operation == DifferenceTemporalZonedDateTime::Since) {
result = TemporalDurationObject::createNegatedTemporalDuration(result);
}
// Return result.
return new TemporalDurationObject(state, result);
}
ISO8601::InternalDuration TemporalZonedDateTimeObject::differenceZonedDateTimeWithRounding(ExecutionState& state, Int128 ns1, Int128 ns2, TimeZone timeZone, Calendar calendar,
ISO8601::DateTimeUnit largestUnit, unsigned roundingIncrement, ISO8601::DateTimeUnit smallestUnit, ISO8601::RoundingMode roundingMode)
{
// If TemporalUnitCategory(largestUnit) is time, then
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Time) {
// Return DifferenceInstant(ns1, ns2, roundingIncrement, smallestUnit, roundingMode).
return TemporalInstantObject::differenceInstant(state, ns1, ns2, roundingIncrement, smallestUnit, roundingMode);
}
// Let difference be ? DifferenceZonedDateTime(ns1, ns2, timeZone, calendar, largestUnit).
auto difference = differenceZonedDateTime(state, ns1, ns2, timeZone, calendar, largestUnit);
// If smallestUnit is nanosecond and roundingIncrement = 1, return difference.
if (smallestUnit == ISO8601::DateTimeUnit::Nanosecond && roundingIncrement == 1) {
return difference;
}
// Let dateTime be GetISODateTimeFor(timeZone, ns1).
auto dateTime = Temporal::getISODateTimeFor(state, timeZone, ns1);
// Return ? RoundRelativeDuration(difference, ns1, ns2, dateTime, timeZone, calendar, largestUnit, roundingIncrement, smallestUnit, roundingMode).
return Temporal::roundRelativeDuration(state, difference, ns2, Temporal::toPlainDateTime(ns1), timeZone, calendar, toTemporalUnit(largestUnit), roundingIncrement, toTemporalUnit(smallestUnit), roundingMode);
}
ISO8601::InternalDuration TemporalZonedDateTimeObject::differenceZonedDateTime(ExecutionState& state, Int128 ns1, Int128 ns2, TimeZone timeZone, Calendar calendar, ISO8601::DateTimeUnit largestUnit)
{
// If ns1 = ns2, return CombineDateAndTimeDuration(ZeroDateDuration(), 0).
if (ns1 == ns2) {
return {};
}
// Let startDateTime be GetISODateTimeFor(timeZone, ns1).
auto startDateTime = Temporal::getISODateTimeFor(state, timeZone, ns1);
// Let endDateTime be GetISODateTimeFor(timeZone, ns2).
auto endDateTime = Temporal::getISODateTimeFor(state, timeZone, ns2);
// If CompareISODate(startDateTime.[[ISODate]], endDateTime.[[ISODate]]) = 0, then
if (startDateTime.plainDate().compare(endDateTime.plainDate()) == 0) {
// Let timeDuration be TimeDurationFromEpochNanosecondsDifference(ns2, ns1).
// Return CombineDateAndTimeDuration(ZeroDateDuration(), timeDuration).
Int128 timeDuration = Temporal::timeDurationFromEpochNanosecondsDifference(ns2, ns1);
return ISO8601::InternalDuration(ISO8601::Duration(), timeDuration);
}
int sign;
// If ns2 - ns1 < 0, let sign be -1; else let sign be 1.
if (ns2 - ns1 < 0) {
sign = -1;
} else {
sign = 1;
}
int maxDayCorrection;
// If sign = 1, let maxDayCorrection be 2; else let maxDayCorrection be 1.
if (sign == 1) {
maxDayCorrection = 2;
} else {
maxDayCorrection = 1;
}
// Let dayCorrection be 0.
int dayCorrection = 0;
// Let timeDuration be DifferenceTime(startDateTime.[[Time]], endDateTime.[[Time]]).
auto timeDuration = Temporal::differenceTime(startDateTime.plainTime(), endDateTime.plainTime());
// If TimeDurationSign(timeDuration) = -sign, set dayCorrection to dayCorrection + 1.
if (Temporal::timeDurationSign(timeDuration) == -sign) {
dayCorrection = dayCorrection + 1;
}
ISO8601::PlainDateTime intermediateDateTime = ISO8601::PlainDateTime(ISO8601::PlainDate(), ISO8601::PlainTime());
// Let success be false.
bool success = false;
// Repeat, while dayCorrection ≤ maxDayCorrection and success is false,
while (dayCorrection <= maxDayCorrection && !success) {
// Let intermediateDate be BalanceISODate(endDateTime.[[ISODate]].[[Year]], endDateTime.[[ISODate]].[[Month]], endDateTime.[[ISODate]].[[Day]] - dayCorrection × sign).
auto intermediateDate = Temporal::balanceISODate(state, endDateTime.plainDate().year(), endDateTime.plainDate().month(),
endDateTime.plainDate().day() - dayCorrection * sign);
// Let intermediateDateTime be CombineISODateAndTimeRecord(intermediateDate, startDateTime.[[Time]]).
intermediateDateTime = ISO8601::PlainDateTime(intermediateDate, startDateTime.plainTime());
// Let intermediateNs be ? GetEpochNanosecondsFor(timeZone, intermediateDateTime, compatible).
auto intermediateNs = Temporal::getEpochNanosecondsFor(state, timeZone, intermediateDateTime,
TemporalDisambiguationOption::Compatible);
// Set timeDuration to TimeDurationFromEpochNanosecondsDifference(ns2, intermediateNs).
Int128 timeDuration = Temporal::timeDurationFromEpochNanosecondsDifference(ns2, intermediateNs);
// Let timeSign be TimeDurationSign(timeDuration).
auto timeSign = Temporal::timeDurationSign(timeDuration);
// If sign ≠ -timeSign, then
if (sign != -timeSign) {
// Set success to true.
success = true;
}
// Set dayCorrection to dayCorrection + 1.
dayCorrection++;
}
// Let dateLargestUnit be LargerOfTwoTemporalUnits(largestUnit, day).
auto dateLargestUnit = Temporal::largerOfTwoTemporalUnits(largestUnit, ISO8601::DateTimeUnit::Day);
// Let dateDifference be CalendarDateUntil(calendar, startDateTime.[[ISODate]], intermediateDateTime.[[ISODate]], dateLargestUnit).
auto dateDifference = Temporal::calendarDateUntil(calendar, startDateTime.plainDate(), intermediateDateTime.plainDate(), toTemporalUnit(dateLargestUnit));
// Return CombineDateAndTimeDuration(dateDifference, timeDuration).
return ISO8601::InternalDuration(dateDifference, timeDuration);
}
} // namespace Escargot
#endif

View file

@ -195,6 +195,20 @@ public:
};
TemporalZonedDateTimeObject* addDurationToZonedDateTime(ExecutionState& state, AddDurationToZonedDateTimeOperation operation, Value temporalDurationLike, Value options);
// https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalzoneddatetime
enum class DifferenceTemporalZonedDateTime {
Until,
Since
};
TemporalDurationObject* differenceTemporalZonedDateTime(ExecutionState& state, DifferenceTemporalZonedDateTime operation, Value other, Value options);
// https://tc39.es/proposal-temporal/#sec-temporal-differencezoneddatetimewithrounding
ISO8601::InternalDuration differenceZonedDateTimeWithRounding(ExecutionState& state, Int128 ns1, Int128 ns2, TimeZone timeZone, Calendar calendar,
ISO8601::DateTimeUnit largestUnit, unsigned roundingIncrement, ISO8601::DateTimeUnit smallestUnit, ISO8601::RoundingMode roundingMode);
// https://tc39.es/proposal-temporal/#sec-temporal-differencezoneddatetime
ISO8601::InternalDuration differenceZonedDateTime(ExecutionState& state, Int128 ns1, Int128 ns2, TimeZone timeZone, Calendar calendar, ISO8601::DateTimeUnit largestUnit);
private:
void init(ExecutionState& state, ComputedTimeZone timeZone);
Int128* m_epochNanoseconds;

View file

@ -296,7 +296,6 @@
<test id="built-ins/Temporal/Duration/prototype/round/valid-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/round/year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/subtract/argument-duration-max"><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>
<test id="built-ins/Temporal/Duration/prototype/total/balance-subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/Duration/prototype/total/balances-days-up-to-both-years-and-months"><reason>TODO</reason></test>
@ -538,95 +537,8 @@
<test id="built-ins/Temporal/ZonedDateTime/prototype/round/throws-on-invalid-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/round/throws-without-smallestunit"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/round/valid-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-case-insensitive"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-invalid-iso-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-iso-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-calendar-year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-invalid-offset-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-offset-not-agreeing-with-timezone"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-datetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-multiple-offsets"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-sub-minute-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-calendar-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-calendar-annotation-invalid-key"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-critical-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-date-with-utc-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-limits"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-minus-sign"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-multiple-calendar"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-multiple-time-zone"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-sub-minute-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-time-separators"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-time-zone-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/argument-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/balance-negative-time-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/calendar-temporal-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/can-return-lower-or-higher-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/casts-argument"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/defaults-to-returning-hours"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/does-not-include-higher-units-than-necessary"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/invalid-rounding-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-default"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-smallestunit-mismatch"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/largestunit-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/name"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/negative-epochnanoseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/not-a-constructor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/options-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/options-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/reversibility-of-differences"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/round-cross-unit-boundary"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/rounding-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-nan"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-non-integer"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-ceil"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-expand"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-floor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfCeil"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfEven"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfExpand"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfFloor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-halfTrunc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-trunc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/rounds-relative-to-receiver"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/same-epoch-nanoseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/since-until"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/smallestunit-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/valid-rounding-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/weeks-and-months-are-mutually-exclusive"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/zoneddatetime-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/since/zoneddatetime-string-multiple-offsets"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/length"><reason>TODO</reason></test>
@ -635,93 +547,8 @@
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/subclassing-ignored"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/startOfDay/throws-if-epoch-nanoseconds-outside-valid-limits"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-case-insensitive"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-invalid-iso-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-iso-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-calendar-year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-invalid-offset-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-offset-not-agreeing-with-timezone"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-datetime"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-multiple-offsets"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-sub-minute-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-calendar-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-calendar-annotation-invalid-key"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-critical-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-date-with-utc-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-limits"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-minus-sign"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-multiple-calendar"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-multiple-time-zone"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-sub-minute-offset"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-time-separators"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-time-zone-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-unknown-annotation"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/argument-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/balance-negative-time-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/builtin"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/calendar-temporal-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/can-return-lower-or-higher-units"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/casts-argument"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/defaults-to-returning-hours"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/does-not-include-higher-units-than-necessary"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/invalid-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-default"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-smallestunit-mismatch"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/largestunit-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/leap-second"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/length"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/name"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/negative-epochnanoseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/not-a-constructor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/options-object"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/options-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/round-cross-unit-boundary"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/rounding-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-nan"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-non-integer"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-out-of-range"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-ceil"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-expand"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-floor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfCeil"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfEven"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfExpand"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfFloor"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-halfTrunc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-trunc"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/rounds-relative-to-receiver"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/same-epoch-nanoseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-invalid-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-plurals-accepted"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-undefined"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/smallestunit-wrong-type"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/subseconds"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/until-since"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/valid-rounding-increments"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/weeks-and-months-are-mutually-exclusive"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/year-zero"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/zoneddatetime-string"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/until/zoneddatetime-string-multiple-offsets"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/valueOf/basic"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/valueOf/branding"><reason>TODO</reason></test>
<test id="built-ins/Temporal/ZonedDateTime/prototype/valueOf/prop-desc"><reason>TODO</reason></test>
@ -948,14 +775,9 @@
<test id="intl402/Temporal/ZonedDateTime/prototype/hoursInDay/same-date-starts-twice"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/offsetNanoseconds/nanoseconds-subtracted-or-added-at-dst-transition"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/round/dst-skipped-cross-midnight"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/argument-propertybag-timezone-string-datetime"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/calendar-mismatch"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/canonicalize-calendar"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/canonicalize-iana-identifiers-before-comparing"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/dst-balancing-result"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/dst-month-day-boundary"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/dst-rounding-result"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/since/sub-minute-offset"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/startOfDay/dst-skipped-cross-midnight"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/startOfDay/same-date-starts-twice"><reason>TODO</reason></test>
@ -970,14 +792,9 @@
<test id="intl402/Temporal/ZonedDateTime/prototype/toLocaleString/options-timeZone"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/toLocaleString/options-timeZoneName-affects-instance-time-zone"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/toLocaleString/options-undefined"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/argument-propertybag-timezone-string-datetime"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/calendar-mismatch"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/canonicalize-calendar"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/canonicalize-iana-identifiers-before-comparing"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/dst-balancing-result"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/dst-month-day-boundary"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/dst-rounding-result"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/infinity-throws-rangeerror"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/until/sub-minute-offset"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/with/non-iso-calendar-fields"><reason>TODO</reason></test>
<test id="intl402/Temporal/ZonedDateTime/prototype/with/offset-property-sub-minute"><reason>TODO</reason></test>