Skip to content

Commit dccf2f9

Browse files
committed
Implement Temporal.ZonedDateTime.since, until
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
1 parent 83c9e9a commit dccf2f9

File tree

8 files changed

+320
-249
lines changed

8 files changed

+320
-249
lines changed

src/builtins/BuiltinTemporal.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,18 @@ static Value builtinTemporalZonedDateTimeSubtract(ExecutionState& state, Value t
12621262
return zonedDateTime->addDurationToZonedDateTime(state, TemporalZonedDateTimeObject::AddDurationToZonedDateTimeOperation::Subtract, argv[0], argc > 1 ? argv[1] : Value());
12631263
}
12641264

1265+
static Value builtinTemporalZonedDateTimeSince(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
1266+
{
1267+
RESOLVE_THIS_BINDING_TO_ZONEDDATETIME(zonedDateTime, Since);
1268+
return zonedDateTime->differenceTemporalZonedDateTime(state, TemporalZonedDateTimeObject::DifferenceTemporalZonedDateTime::Since, argv[0], argc > 1 ? argv[1] : Value());
1269+
}
1270+
1271+
static Value builtinTemporalZonedDateTimeUntil(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
1272+
{
1273+
RESOLVE_THIS_BINDING_TO_ZONEDDATETIME(zonedDateTime, Until);
1274+
return zonedDateTime->differenceTemporalZonedDateTime(state, TemporalZonedDateTimeObject::DifferenceTemporalZonedDateTime::Until, argv[0], argc > 1 ? argv[1] : Value());
1275+
}
1276+
12651277
void GlobalObject::initializeTemporal(ExecutionState& state)
12661278
{
12671279
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(
@@ -1812,6 +1824,9 @@ void GlobalObject::installTemporal(ExecutionState& state)
18121824
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyWithCalendar()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyWithCalendar(), builtinTemporalZonedDateTimeWithCalendar, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
18131825
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->add), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->add, builtinTemporalZonedDateTimeAdd, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
18141826
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySubtract()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySubtract(), builtinTemporalZonedDateTimeSubtract, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
1827+
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazyUntil()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazyUntil(), builtinTemporalZonedDateTimeUntil, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
1828+
m_temporalZonedDateTimePrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->lazySince()), ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->lazySince(), builtinTemporalZonedDateTimeSince, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
1829+
18151830

18161831
{
18171832
AtomicString name(state.context(), "get calendarId");

src/runtime/TemporalDurationObject.cpp

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,44 @@ ISO8601::Duration TemporalDurationObject::temporalDurationFromInternal(Execution
9090
Int128 milliseconds = 0, microseconds = 0;
9191

9292
// Let sign be TimeDurationSign(internalDuration.[[Time]]).
93-
int32_t sign = internalDuration.sign();
94-
9593
// Let nanoseconds be abs(internalDuration.[[Time]]).
96-
auto nanoseconds = std::abs(internalDuration.time());
94+
int32_t sign;
95+
Int128 nanoseconds = internalDuration.time();
96+
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
97+
sign = internalDuration.sign();
98+
nanoseconds = std::abs(nanoseconds);
99+
} else {
100+
sign = internalDuration.timeDurationSign();
101+
if (sign == -1 && internalDuration.dateDuration().sign() == 1) {
102+
if (largestUnit == ISO8601::DateTimeUnit::Hour) {
103+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerDay;
104+
} else if (largestUnit == ISO8601::DateTimeUnit::Minute) {
105+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerHour;
106+
} else if (largestUnit == ISO8601::DateTimeUnit::Second) {
107+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMinute;
108+
} else if (largestUnit == ISO8601::DateTimeUnit::Millisecond) {
109+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerSecond;
110+
} else if (largestUnit == ISO8601::DateTimeUnit::Microsecond) {
111+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMillisecond;
112+
} else {
113+
nanoseconds = nanoseconds + ISO8601::ExactTime::nsPerMicrosecond;
114+
}
115+
} else if (sign == 1 && internalDuration.dateDuration().sign() == -1) {
116+
if (largestUnit == ISO8601::DateTimeUnit::Hour) {
117+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerDay;
118+
} else if (largestUnit == ISO8601::DateTimeUnit::Minute) {
119+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerHour;
120+
} else if (largestUnit == ISO8601::DateTimeUnit::Second) {
121+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMinute;
122+
} else if (largestUnit == ISO8601::DateTimeUnit::Millisecond) {
123+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerSecond;
124+
} else if (largestUnit == ISO8601::DateTimeUnit::Microsecond) {
125+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMillisecond;
126+
} else {
127+
nanoseconds = nanoseconds - ISO8601::ExactTime::nsPerMicrosecond;
128+
}
129+
}
130+
}
97131

98132
// If TemporalUnitCategory(largestUnit) is date, then
99133
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
@@ -195,30 +229,52 @@ ISO8601::Duration TemporalDurationObject::temporalDurationFromInternal(Execution
195229
// Assert: largestUnit is nanosecond.
196230
}
197231

232+
if (ISO8601::toDateTimeCategory(largestUnit) == ISO8601::DateTimeUnitCategory::Date) {
233+
if (hours) {
234+
hours *= sign;
235+
}
236+
if (minutes) {
237+
minutes *= sign;
238+
}
239+
if (seconds) {
240+
seconds *= sign;
241+
}
242+
if (milliseconds) {
243+
milliseconds *= sign;
244+
}
245+
if (microseconds) {
246+
microseconds *= sign;
247+
}
248+
if (nanoseconds) {
249+
nanoseconds *= sign;
250+
}
251+
} else {
252+
// remove -0.0
253+
if (std::signbit(days) && !days) {
254+
days = 0;
255+
}
256+
if (std::signbit(hours) && !hours) {
257+
hours = 0;
258+
}
259+
if (std::signbit(minutes) && !minutes) {
260+
minutes = 0;
261+
}
262+
if (std::signbit(seconds) && !seconds) {
263+
seconds = 0;
264+
}
265+
}
266+
198267
// Return ? CreateTemporalDuration(internalDuration.[[Date]].[[Years]], internalDuration.[[Date]].[[Months]],
199268
// internalDuration.[[Date]].[[Weeks]], internalDuration.[[Date]].[[Days]] + days × sign,
200269
// hours × sign, minutes × sign, seconds × sign, milliseconds × sign, microseconds × sign, nanoseconds × sign).
201-
if (hours) {
202-
hours *= sign;
203-
}
204-
if (minutes) {
205-
minutes *= sign;
206-
}
207-
if (seconds) {
208-
seconds *= sign;
209-
}
210-
if (milliseconds) {
211-
milliseconds *= sign;
212-
}
213-
if (microseconds) {
214-
microseconds *= sign;
215-
}
216-
if (nanoseconds) {
217-
nanoseconds *= sign;
270+
auto value = ISO8601::Duration{ internalDuration.dateDuration().years(), internalDuration.dateDuration().months(), internalDuration.dateDuration().weeks(), internalDuration.dateDuration().days() + days * sign, hours, minutes,
271+
static_cast<double>(seconds), static_cast<double>(milliseconds), static_cast<double>(microseconds), static_cast<double>(nanoseconds) };
272+
273+
if (!value.isValid()) {
274+
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid Duration value");
218275
}
219276

220-
return ISO8601::Duration{ internalDuration.dateDuration().years(), internalDuration.dateDuration().months(), internalDuration.dateDuration().weeks(), internalDuration.dateDuration().days() + days * sign, hours, minutes,
221-
static_cast<double>(seconds), static_cast<double>(milliseconds), static_cast<double>(microseconds), static_cast<double>(nanoseconds) };
277+
return value;
222278
}
223279

224280
ISO8601::Duration TemporalDurationObject::createNegatedTemporalDuration(ISO8601::Duration duration)

src/runtime/TemporalObject.cpp

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ void Temporal::formatSecondsStringFraction(StringBuilder& builder, Int128 fracti
238238
}
239239
}
240240

241+
ISO8601::PlainDateTime Temporal::toPlainDateTime(Int128 epochNanoseconds)
242+
{
243+
int64_t computedEpoch = ISO8601::ExactTime(epochNanoseconds).floorEpochMilliseconds();
244+
DateObject::DateTimeInfo timeInfo;
245+
DateObject::computeTimeInfoFromEpoch(computedEpoch, timeInfo);
246+
auto d = Temporal::balanceTime(0, 0, 0, 0, 0, epochNanoseconds % ISO8601::ExactTime::nsPerDay);
247+
return ISO8601::PlainDateTime(ISO8601::PlainDate(timeInfo.year, timeInfo.month + 1, timeInfo.mday),
248+
ISO8601::PlainTime(d.hours(), d.minutes(), d.seconds(), d.milliseconds(), d.microseconds(), d.nanoseconds()));
249+
}
250+
241251
int32_t Temporal::computeTimeZoneOffset(ExecutionState& state, String* name, int64_t epoch)
242252
{
243253
auto u16 = name->toUTF16StringData();
@@ -912,7 +922,11 @@ Int128 Temporal::interpretISODateTimeOffset(ExecutionState& state, ISO8601::Plai
912922
// TODO Let epochNanoseconds be GetUTCEpochNanoseconds(balanced).
913923
// TODO If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
914924
// Return epochNanoseconds.
915-
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() + offsetNanoseconds;
925+
auto ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() + offsetNanoseconds;
926+
if (!ISO8601::isValidEpochNanoseconds(ns)) {
927+
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid date-time value");
928+
}
929+
return ns;
916930
}
917931

918932
// TODO
@@ -947,10 +961,18 @@ Int128 Temporal::interpretISODateTimeOffset(ExecutionState& state, ISO8601::Plai
947961
}
948962
}
949963

964+
Int128 ns;
950965
if (hasUTCDesignator) {
951-
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds();
966+
ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds();
967+
} else {
968+
ns = ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() - timeZoneOffsetNanoseconds.valueOr(0);
952969
}
953-
return ISO8601::ExactTime::fromPlainDateTime(isoDateTime).epochNanoseconds() - timeZoneOffsetNanoseconds.valueOr(0);
970+
971+
if (!ISO8601::isValidEpochNanoseconds(ns)) {
972+
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid date-time value");
973+
}
974+
975+
return ns;
954976
}
955977

956978
TemporalZonedDateTimeObject* Temporal::toTemporalZonedDateTime(ExecutionState& state, Value item, Value options)
@@ -1836,17 +1858,6 @@ bool Temporal::isPartialTemporalObject(ExecutionState& state, Value value)
18361858
return true;
18371859
}
18381860

1839-
template <typename T>
1840-
T nonNegativeModulo(T x, int y)
1841-
{
1842-
T result = x % y;
1843-
if (!result)
1844-
return 0;
1845-
if (result < 0)
1846-
result += y;
1847-
return result;
1848-
}
1849-
18501861
template <>
18511862
double nonNegativeModulo(double x, int y)
18521863
{
@@ -1858,19 +1869,6 @@ double nonNegativeModulo(double x, int y)
18581869
return result;
18591870
}
18601871

1861-
template <typename T>
1862-
T intFloor(T x, int y)
1863-
{
1864-
if (x > 0) {
1865-
return x / y;
1866-
}
1867-
if (x % y) {
1868-
return x / y - 1;
1869-
} else {
1870-
return x / y;
1871-
}
1872-
}
1873-
18741872
ISO8601::Duration Temporal::balanceTime(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond)
18751873
{
18761874
microsecond += std::floor(nanosecond / 1000);
@@ -3286,12 +3284,7 @@ ISO8601::InternalDuration Temporal::differenceISODateTime(ExecutionState& state,
32863284
// Let timeDuration be DifferenceTime(isoDateTime1.[[Time]], isoDateTime2.[[Time]]).
32873285
auto timeDuration = differenceTime(isoDateTime1.plainTime(), isoDateTime2.plainTime());
32883286
// Let timeSign be TimeDurationSign(timeDuration).
3289-
int timeSign = 0;
3290-
if (timeDuration < 0) {
3291-
timeSign = -1;
3292-
} else if (timeDuration > 0) {
3293-
timeSign = 1;
3294-
}
3287+
int timeSign = timeDurationSign(timeDuration);
32953288
// Let dateSign be CompareISODate(isoDateTime1.[[ISODate]], isoDateTime2.[[ISODate]]).
32963289
auto dateSign = isoDateTime1.plainDate().compare(isoDateTime2.plainDate());
32973290
// Let adjustedDate be isoDateTime2.[[ISODate]].
@@ -3384,11 +3377,7 @@ ISO8601::PlainDateTime Temporal::getISODateTimeFor(ExecutionState& state, Option
33843377
// 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).
33853378
int64_t offsetNanoseconds = timeZone ? getOffsetNanosecondsFor(state, timeZone.value(), epochNs) : 0;
33863379
epochNs += offsetNanoseconds;
3387-
DateObject::DateTimeInfo timeInfo;
3388-
DateObject::computeTimeInfoFromEpoch(ISO8601::ExactTime(epochNs).floorEpochMilliseconds(), timeInfo);
3389-
auto d = Temporal::balanceTime(0, 0, 0, 0, 0, epochNs % ISO8601::ExactTime::nsPerDay);
3390-
return ISO8601::PlainDateTime(ISO8601::PlainDate(timeInfo.year, timeInfo.month + 1, timeInfo.mday),
3391-
ISO8601::PlainTime(d.hours(), d.minutes(), d.seconds(), d.milliseconds(), d.microseconds(), d.nanoseconds()));
3380+
return toPlainDateTime(epochNs);
33923381
}
33933382

33943383
int64_t Temporal::getOffsetNanosecondsFor(ExecutionState& state, TimeZone timeZone, Int128 epochNs)

src/runtime/TemporalObject.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@
3131

3232
namespace Escargot {
3333

34+
template <typename T>
35+
T nonNegativeModulo(T x, int y)
36+
{
37+
T result = x % y;
38+
if (!result)
39+
return 0;
40+
if (result < 0)
41+
result += y;
42+
return result;
43+
}
44+
45+
template <typename T>
46+
T intFloor(T x, int y)
47+
{
48+
if (x > 0) {
49+
return x / y;
50+
}
51+
if (x % y) {
52+
return x / y - 1;
53+
} else {
54+
return x / y;
55+
}
56+
}
57+
3458
class Calendar {
3559
public:
3660
// sync with 'canonicalCodeForDisplayNames'
@@ -260,6 +284,17 @@ class Temporal {
260284
static ISO8601::PlainDate computeISODate(ExecutionState& state, UCalendar* ucal);
261285
static TimeZone parseTimeZone(ExecutionState& state, String* input);
262286
static void formatSecondsStringFraction(StringBuilder& builder, Int128 fraction, Value precision);
287+
static ISO8601::PlainDateTime toPlainDateTime(Int128 epochNanoseconds);
288+
289+
static int timeDurationSign(Int128 t)
290+
{
291+
if (t < 0) {
292+
return -1;
293+
} else if (t > 0) {
294+
return 1;
295+
}
296+
return 0;
297+
}
263298

264299
// returns offset(milliseconds)
265300
static int32_t computeTimeZoneOffset(ExecutionState& state, String* name, int64_t epoch);

src/runtime/TemporalPlainDateObject.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ ISO8601::Duration TemporalPlainDateObject::differenceTemporalPlainDate(Execution
575575
auto isoDateTimeOther = other->computeISODate(state);
576576
// Let destEpochNs be GetUTCEpochNanoseconds(isoDateTimeOther).
577577
auto destEpochNs = ISO8601::ExactTime::fromPlainDate(isoDateTimeOther).epochNanoseconds();
578+
// Set duration to ? RoundRelativeDuration(duration, originEpochNs, destEpochNs, isoDateTime, unset, temporalDate.[[Calendar]], settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
578579
duration = Temporal::roundRelativeDuration(state, duration, destEpochNs, ISO8601::PlainDateTime(isoDateTime, ISO8601::PlainTime()), NullOption, calendarID(), toTemporalUnit(settings.largestUnit), settings.roundingIncrement, toTemporalUnit(settings.smallestUnit), settings.roundingMode);
579580
}
580581

0 commit comments

Comments
 (0)