[Temporal] Add toJSON, toString, and non-intl toLocaleString to Instant

Also add AOs: FormatISOTimeZoneOffsetString, TemporalInstantToString,
GetUnsignedRoundingMode, ApplyUnsignedRoundingMode, RoundTemporalInstant

Also update the RoundNumberToIncrement implementation and a BigInt version.

Fix the test setup in test/mjsunit/temporal/instant-to-json.js since fromEpochSeconds and fromEpochMilliseconds do not take BigInt

Spec Text:
https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.tojson
https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.tolocalestring
https://tc39.es/proposal-temporal/#sec-temporal.instant.prototype.tostring
https://tc39.es/proposal-temporal/#sec-temporal-temporalinstanttostring
https://tc39.es/proposal-temporal/#sec-temporal-formatisotimezoneoffsetstring
https://tc39.es/proposal-temporal/#sec-temporal-getunsignedroundingmode
https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode
https://tc39.es/proposal-temporal/#sec-temporal-roundtemporalinstant
https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement

This does NOT implement the intl version of toLocaleString
specified in (notice the "sup" not "sec" after #) yet.
https://tc39.es/proposal-temporal/#sup-temporal.instant.prototype.tolocalestring

Bug: v8:11544
Change-Id: I807afd5bf550d2a65a4732a8e536056eea79cf8f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3696483
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81428}
This commit is contained in:
Frank Tang 2022-06-29 00:51:32 -07:00 committed by V8 LUCI CQ
parent 9262713316
commit 1a5cfc20e1
6 changed files with 505 additions and 92 deletions

View File

@ -88,12 +88,6 @@ TO_BE_IMPLEMENTED(TemporalDurationPrototypeToString)
TO_BE_IMPLEMENTED(TemporalInstantPrototypeUntil)
/* Temporal #sec-temporal.instant.prototype.since */
TO_BE_IMPLEMENTED(TemporalInstantPrototypeSince)
/* Temporal #sec-temporal.instant.prototype.tolocalestring */
TO_BE_IMPLEMENTED(TemporalInstantPrototypeToLocaleString)
/* Temporal #sec-temporal.instant.prototype.tostring */
TO_BE_IMPLEMENTED(TemporalInstantPrototypeToString)
/* Temporal #sec-temporal.instant.tojson */
TO_BE_IMPLEMENTED(TemporalInstantPrototypeToJSON)
/* Temporal.PlainYearMonth */
/* Temporal #sec-temporal.plainyearmonth.prototype.until */
@ -638,6 +632,9 @@ TEMPORAL_GET_BIGINT_AFTER_DIVID(Instant, EpochMicroseconds, nanoseconds, 1000,
TEMPORAL_PROTOTYPE_METHOD1(Instant, Add, add)
TEMPORAL_PROTOTYPE_METHOD1(Instant, Round, round)
TEMPORAL_PROTOTYPE_METHOD1(Instant, Subtract, subtract)
TEMPORAL_PROTOTYPE_METHOD0(Instant, ToJSON, toJSON)
TEMPORAL_PROTOTYPE_METHOD2(Instant, ToLocaleString, toLocaleString)
TEMPORAL_PROTOTYPE_METHOD1(Instant, ToString, toString)
TEMPORAL_PROTOTYPE_METHOD1(Instant, ToZonedDateTime, toZonedDateTime)
TEMPORAL_PROTOTYPE_METHOD1(Instant, ToZonedDateTimeISO, toZonedDateTimeISO)

View File

@ -181,7 +181,25 @@ V8_WARN_UNUSED_RESULT Maybe<Offset> ToTemporalOffset(Isolate* isolate,
const char* method_name);
// sec-temporal-totemporalroundingmode
enum class RoundingMode { kCeil, kFloor, kTrunc, kHalfExpand };
enum class RoundingMode {
kCeil,
kFloor,
kExpand,
kTrunc,
kHalfCeil,
kHalfFloor,
kHalfExpand,
kHalfTrunc,
kHalfEven
};
// #table-temporal-unsigned-rounding-modes
enum class UnsignedRoundingMode {
kInfinity,
kZero,
kHalfInfinity,
kHalfZero,
kHalfEven
};
enum class MatchBehaviour { kMatchExactly, kMatchMinutes };
@ -1029,11 +1047,18 @@ MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZoneFromIndex(
return object;
}
MaybeHandle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(
Handle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(
Isolate* isolate, Handle<JSFunction> target,
Handle<HeapObject> new_target) {
TEMPORAL_ENTER_FUNC();
return CreateTemporalTimeZoneFromIndex(isolate, target, new_target, 0);
return CreateTemporalTimeZoneFromIndex(isolate, target, new_target, 0)
.ToHandleChecked();
}
Handle<JSTemporalTimeZone> CreateTemporalTimeZoneUTC(Isolate* isolate) {
TEMPORAL_ENTER_FUNC();
return CreateTemporalTimeZoneUTC(isolate, CONSTRUCTOR(time_zone),
CONSTRUCTOR(time_zone));
}
bool IsUTC(Isolate* isolate, Handle<String> time_zone);
@ -11350,40 +11375,227 @@ MaybeHandle<String> JSTemporalPlainTime::ToLocaleString(
namespace {
// #sec-temporal-getunsignedroundingmode
UnsignedRoundingMode GetUnsignedRoundingMode(RoundingMode rounding_mode,
bool is_negative) {
// 1. If isNegative is true, return the specification type in the third column
// of Table 14 where the first column is roundingMode and the second column is
// "negative".
if (is_negative) {
switch (rounding_mode) {
case RoundingMode::kCeil:
return UnsignedRoundingMode::kZero;
case RoundingMode::kFloor:
return UnsignedRoundingMode::kInfinity;
case RoundingMode::kExpand:
return UnsignedRoundingMode::kInfinity;
case RoundingMode::kTrunc:
return UnsignedRoundingMode::kZero;
case RoundingMode::kHalfCeil:
return UnsignedRoundingMode::kHalfZero;
case RoundingMode::kHalfFloor:
return UnsignedRoundingMode::kHalfInfinity;
case RoundingMode::kHalfExpand:
return UnsignedRoundingMode::kHalfInfinity;
case RoundingMode::kHalfTrunc:
return UnsignedRoundingMode::kHalfZero;
case RoundingMode::kHalfEven:
return UnsignedRoundingMode::kHalfEven;
}
}
// 2. Else, return the specification type in the third column of Table 14
// where the first column is roundingMode and the second column is "positive".
switch (rounding_mode) {
case RoundingMode::kCeil:
return UnsignedRoundingMode::kInfinity;
case RoundingMode::kFloor:
return UnsignedRoundingMode::kZero;
case RoundingMode::kExpand:
return UnsignedRoundingMode::kInfinity;
case RoundingMode::kTrunc:
return UnsignedRoundingMode::kZero;
case RoundingMode::kHalfCeil:
return UnsignedRoundingMode::kHalfInfinity;
case RoundingMode::kHalfFloor:
return UnsignedRoundingMode::kHalfZero;
case RoundingMode::kHalfExpand:
return UnsignedRoundingMode::kHalfInfinity;
case RoundingMode::kHalfTrunc:
return UnsignedRoundingMode::kHalfZero;
case RoundingMode::kHalfEven:
return UnsignedRoundingMode::kHalfEven;
}
}
// #sec-temporal-applyunsignedroundingmode
double ApplyUnsignedRoundingMode(double x, double r1, double r2,
UnsignedRoundingMode unsigned_rounding_mode) {
// 1. If x is equal to r1, return r1.
if (x == r1) return r1;
// 2. Assert: r1 < x < r2.
DCHECK_LT(r1, x);
DCHECK_LT(x, r2);
// 3. Assert: unsignedRoundingMode is not undefined.
// 4. If unsignedRoundingMode is zero, return r1.
if (unsigned_rounding_mode == UnsignedRoundingMode::kZero) return r1;
// 5. If unsignedRoundingMode is infinity, return r2.
if (unsigned_rounding_mode == UnsignedRoundingMode::kInfinity) return r2;
// 6. Let d1 be x r1.
double d1 = x - r1;
// 7. Let d2 be r2 x.
double d2 = r2 - x;
// 8. If d1 < d2, return r1.
if (d1 < d2) return r1;
// 9. If d2 < d1, return r2.
if (d2 < d1) return r2;
// 10. Assert: d1 is equal to d2.
DCHECK_EQ(d1, d2);
// 11. If unsignedRoundingMode is half-zero, return r1.
if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfZero) return r1;
// 12. If unsignedRoundingMode is half-infinity, return r2.
if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfInfinity) return r2;
// 13. Assert: unsignedRoundingMode is half-even.
DCHECK_EQ(unsigned_rounding_mode, UnsignedRoundingMode::kHalfEven);
// 14. Let cardinality be (r1 / (r2 r1)) modulo 2.
int64_t cardinality = static_cast<int64_t>(r1) % 2;
// 15. If cardinality is 0, return r1.
if (cardinality == 0) return r1;
// 16. Return r2.
return r2;
}
// #sec-temporal-applyunsignedroundingmode
Handle<BigInt> ApplyUnsignedRoundingMode(
Isolate* isolate, Handle<BigInt> num, Handle<BigInt> increment,
Handle<BigInt> r1, Handle<BigInt> r2,
UnsignedRoundingMode unsigned_rounding_mode) {
// 1. If x is equal to r1, return r1.
Handle<BigInt> rr1 =
BigInt::Multiply(isolate, increment, r1).ToHandleChecked();
Handle<BigInt> rr2 =
BigInt::Multiply(isolate, increment, r2).ToHandleChecked();
if (BigInt::EqualToBigInt(*num, *rr1)) return r1;
// 2. Assert: r1 < x < r2.
DCHECK_EQ(BigInt::CompareToBigInt(rr1, num), ComparisonResult::kLessThan);
DCHECK_EQ(BigInt::CompareToBigInt(num, rr2), ComparisonResult::kLessThan);
// 3. Assert: unsignedRoundingMode is not undefined.
// 4. If unsignedRoundingMode is zero, return r1.
if (unsigned_rounding_mode == UnsignedRoundingMode::kZero) return r1;
// 5. If unsignedRoundingMode is infinity, return r2.
if (unsigned_rounding_mode == UnsignedRoundingMode::kInfinity) return r2;
// 6. Let d1 be x r1.
Handle<BigInt> dd1 = BigInt::Subtract(isolate, num, rr1).ToHandleChecked();
// 7. Let d2 be r2 x.
Handle<BigInt> dd2 = BigInt::Subtract(isolate, rr2, num).ToHandleChecked();
// 8. If d1 < d2, return r1.
if (BigInt::CompareToBigInt(dd1, dd2) == ComparisonResult::kLessThan)
return r1;
// 9. If d2 < d1, return r2.
if (BigInt::CompareToBigInt(dd2, dd1) == ComparisonResult::kLessThan)
return r2;
// 10. Assert: d1 is equal to d2.
DCHECK_EQ(BigInt::CompareToBigInt(dd1, dd2), ComparisonResult::kEqual);
// 11. If unsignedRoundingMode is half-zero, return r1.
if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfZero) return r1;
// 12. If unsignedRoundingMode is half-infinity, return r2.
if (unsigned_rounding_mode == UnsignedRoundingMode::kHalfInfinity) return r2;
// 13. Assert: unsignedRoundingMode is half-even.
DCHECK_EQ(unsigned_rounding_mode, UnsignedRoundingMode::kHalfEven);
// 14. Let cardinality be (r1 / (r2 r1)) modulo 2.
Handle<BigInt> cardinality =
BigInt::Remainder(isolate, r1, BigInt::FromInt64(isolate, 2))
.ToHandleChecked();
// 15. If cardinality is 0, return r1.
if (!cardinality->ToBoolean()) return r1;
// 16. Return r2.
return r2;
}
// #sec-temporal-roundnumbertoincrement
// For the case that x is double.
double RoundNumberToIncrement(Isolate* isolate, double x, double increment,
RoundingMode rounding_mode) {
TEMPORAL_ENTER_FUNC();
// 3. Let quotient be x / increment.
double rounded;
switch (rounding_mode) {
// 4. If roundingMode is "ceil", then
case RoundingMode::kCeil:
// a. Let rounded be floor(quotient).
rounded = -std::floor(-x / increment);
break;
// 5. Else if roundingMode is "floor", then
case RoundingMode::kFloor:
// a. Let rounded be floor(quotient).
rounded = std::floor(x / increment);
break;
// 6. Else if roundingMode is "trunc", then
case RoundingMode::kTrunc:
// a. Let rounded be the integral part of quotient, removing any
// fractional digits.
rounded =
(x > 0) ? std::floor(x / increment) : -std::floor(-x / increment);
break;
// 7. Else,
default:
// a. Let rounded be ! RoundHalfAwayFromZero(quotient).
rounded = std::round(x / increment);
break;
// 1. Let quotient be x / increment.
double quotient = x / increment;
bool is_negative;
// 2. If quotient < 0, then
if (quotient < 0) {
// a. Let isNegative be true.
is_negative = true;
// b. Set quotient to -quotient.
quotient = -quotient;
// 3. Else,
} else {
// a. Let isNegative be false.
is_negative = false;
}
// 8. Return rounded × increment.
// 4. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode,
// isNegative).
UnsignedRoundingMode unsigned_rounding_mode =
GetUnsignedRoundingMode(rounding_mode, is_negative);
// 5. Let r1 be the largest integer such that r1 ≤ quotient.
double r1 = std::floor(quotient);
// 6. Let r2 be the smallest integer such that r2 > quotient.
double r2 = std::floor(quotient + 1);
// 7. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2,
// unsignedRoundingMode).
double rounded =
ApplyUnsignedRoundingMode(quotient, r1, r2, unsigned_rounding_mode);
// 8. If isNegative is true, set rounded to -rounded.
if (is_negative) {
rounded = -rounded;
}
// 9. Return rounded × increment.
return rounded * increment;
}
// For the case that x and return are BigInt.
Handle<BigInt> RoundNumberToIncrement(Isolate* isolate, Handle<BigInt> x,
double increment,
RoundingMode rounding_mode) {
TEMPORAL_ENTER_FUNC();
// 1. Let quotient be x / increment.
bool is_negative;
// 2. If quotient < 0, then
if (x->IsNegative() != increment < 0) {
// a. Let isNegative be true.
is_negative = true;
// b. Set quotient to -quotient.
x = BigInt::UnaryMinus(isolate, x);
// 3. Else,
} else {
// a. Let isNegative be false.
is_negative = false;
}
// 4. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode,
// isNegative).
UnsignedRoundingMode unsigned_rounding_mode =
GetUnsignedRoundingMode(rounding_mode, is_negative);
// 5. Let r1 be the largest integer such that r1 ≤ quotient.
Handle<BigInt> increment_bigint =
BigInt::FromNumber(isolate, isolate->factory()->NewNumber(increment))
.ToHandleChecked();
Handle<BigInt> r1 =
BigInt::Divide(isolate, x, increment_bigint).ToHandleChecked();
// 6. Let r2 be the smallest integer such that r2 > quotient.
Handle<BigInt> r2 = BigInt::Increment(isolate, r1).ToHandleChecked();
// 7. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2,
// unsignedRoundingMode).
Handle<BigInt> rounded = ApplyUnsignedRoundingMode(
isolate, x, increment_bigint, r1, r2, unsigned_rounding_mode);
// 8. If isNegative is true, set rounded to -rounded.
if (is_negative) {
rounded = BigInt::UnaryMinus(isolate, rounded);
}
// 9. Return rounded × increment.
return BigInt::Multiply(isolate, rounded, increment_bigint).ToHandleChecked();
}
DateTimeRecordCommon RoundTime(Isolate* isolate, const TimeRecordCommon& time,
double increment, Unit unit,
RoundingMode rounding_mode,
@ -13671,6 +13883,243 @@ MaybeHandle<JSTemporalZonedDateTime> JSTemporalInstant::ToZonedDateTime(
calendar);
}
namespace {
// #sec-temporal-formatisotimezoneoffsetstring
V8_WARN_UNUSED_RESULT Handle<String> FormatISOTimeZoneOffsetString(
Isolate* isolate, int64_t offset_nanoseconds) {
IncrementalStringBuilder builder(isolate);
// 1. Assert: offsetNanoseconds is an integer.
// 2. Set offsetNanoseconds to ! RoundNumberToIncrement(offsetNanoseconds, 60
// × 10^9, "halfExpand").
offset_nanoseconds = RoundNumberToIncrement(isolate, offset_nanoseconds, 6e10,
RoundingMode::kHalfExpand);
// 3. If offsetNanoseconds ≥ 0, let sign be "+"; otherwise, let sign be "-".
builder.AppendCharacter((offset_nanoseconds >= 0) ? '+' : '-');
// 4. Set offsetNanoseconds to abs(offsetNanoseconds).
offset_nanoseconds = abs(offset_nanoseconds);
// 5. Let minutes be offsetNanoseconds / (60 × 10^9) modulo 60.
int32_t minutes = (offset_nanoseconds / 60000000000) % 60;
// 6. Let hours be floor(offsetNanoseconds / (3600 × 10^9)).
int32_t hours = offset_nanoseconds / 3600000000000;
// 7. Let h be ToZeroPaddedDecimalString(hours, 2).
ToZeroPaddedDecimalString(&builder, hours, 2);
// 8. Let m be ToZeroPaddedDecimalString(minutes, 2).
ToZeroPaddedDecimalString(&builder, minutes, 2);
// 9. Return the string-concatenation of sign, h, the code unit 0x003A
// (COLON), and m.
return builder.Finish().ToHandleChecked();
}
// #sec-temporal-temporalinstanttostring
MaybeHandle<String> TemporalInstantToString(Isolate* isolate,
Handle<JSTemporalInstant> instant,
Handle<Object> time_zone_obj,
Precision precision,
const char* method_name) {
IncrementalStringBuilder builder(isolate);
// 1. Assert: Type(instant) is Object.
// 2. Assert: instant has an [[InitializedTemporalInstant]] internal slot.
// 3. Let outputTimeZone be timeZone.
Handle<JSReceiver> output_time_zone;
// 4. If outputTimeZone is undefined, then
if (time_zone_obj->IsUndefined()) {
// a. Set outputTimeZone to ! CreateTemporalTimeZone("UTC").
output_time_zone = CreateTemporalTimeZoneUTC(isolate);
} else {
DCHECK(time_zone_obj->IsJSReceiver());
output_time_zone = Handle<JSReceiver>::cast(time_zone_obj);
}
// 5. Let isoCalendar be ! GetISO8601Calendar().
Handle<JSTemporalCalendar> iso_calendar =
temporal::GetISO8601Calendar(isolate);
// 6. Let dateTime be ?
// BuiltinTimeZoneGetPlainDateTimeFor(outputTimeZone, instant,
// isoCalendar).
Handle<JSTemporalPlainDateTime> date_time;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, date_time,
temporal::BuiltinTimeZoneGetPlainDateTimeFor(
isolate, output_time_zone, instant, iso_calendar, method_name),
String);
// 7. Let dateTimeString be ? TemporalDateTimeToString(dateTime.[[ISOYear]],
// dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]],
// dateTime.[[ISOMinute]], dateTime.[[ISOSecond]],
// dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
// dateTime.[[ISONanosecond]], undefined, precision, "never").
Handle<String> date_time_string;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, date_time_string,
TemporalDateTimeToString(
isolate,
{{date_time->iso_year(), date_time->iso_month(),
date_time->iso_day()},
{date_time->iso_hour(), date_time->iso_minute(),
date_time->iso_second(), date_time->iso_millisecond(),
date_time->iso_microsecond(), date_time->iso_nanosecond()}},
iso_calendar, // Unimportant due to ShowCalendar::kNever
precision, ShowCalendar::kNever),
String);
builder.AppendString(date_time_string);
// 8. If timeZone is undefined, then
if (time_zone_obj->IsUndefined()) {
// a. Let timeZoneString be "Z".
builder.AppendCharacter('Z');
} else {
// 9. Else,
DCHECK(time_zone_obj->IsJSReceiver());
Handle<JSReceiver> time_zone = Handle<JSReceiver>::cast(time_zone_obj);
// a. Let offsetNs be ? GetOffsetNanosecondsFor(timeZone, instant).
int64_t offset_ns;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, offset_ns,
GetOffsetNanosecondsFor(isolate, time_zone, instant, method_name),
Handle<String>());
// b. Let timeZoneString be ! FormatISOTimeZoneOffsetString(offsetNs).
Handle<String> time_zone_string =
FormatISOTimeZoneOffsetString(isolate, offset_ns);
builder.AppendString(time_zone_string);
}
// 10. Return the string-concatenation of dateTimeString and timeZoneString.
return builder.Finish();
}
} // namespace
// #sec-temporal.instant.prototype.tojson
MaybeHandle<String> JSTemporalInstant::ToJSON(
Isolate* isolate, Handle<JSTemporalInstant> instant) {
TEMPORAL_ENTER_FUNC();
// 1. Let instant be the this value.
// 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
// 3. Return ? TemporalInstantToString(instant, undefined, "auto").
return TemporalInstantToString(
isolate, instant, isolate->factory()->undefined_value(), Precision::kAuto,
"Temporal.Instant.prototype.toJSON");
}
// #sec-temporal.instant.prototype.tolocalestring
MaybeHandle<String> JSTemporalInstant::ToLocaleString(
Isolate* isolate, Handle<JSTemporalInstant> instant, Handle<Object> locales,
Handle<Object> options) {
// TODO(ftang) Implement #sup-temporal.instant.prototype.tolocalestring
return TemporalInstantToString(
isolate, instant, isolate->factory()->undefined_value(), Precision::kAuto,
"Temporal.Instant.prototype.toLocaleString");
}
namespace {
// #sec-temporal-roundtemporalinstant
Handle<BigInt> RoundTemporalInstant(Isolate* isolate, Handle<BigInt> ns,
double increment, Unit unit,
RoundingMode rounding_mode) {
// 1. Assert: Type(ns) is BigInt.
TEMPORAL_ENTER_FUNC();
double increment_ns;
switch (unit) {
// 2. If unit is "hour", then
case Unit::kHour:
// a. Let incrementNs be increment × 3.6 × 10^12.
increment_ns = increment * 3.6e12;
break;
// 3. If unit is "minute", then
case Unit::kMinute:
// a. Let incrementNs be increment × 6 × 10^10.
increment_ns = increment * 6e10;
break;
// 4. If unit is "second", then
case Unit::kSecond:
// a. Let incrementNs be increment × 10^9.
increment_ns = increment * 1e9;
break;
// 5. If unit is "millisecond", then
case Unit::kMillisecond:
// a. Let incrementNs be increment × 10^6.
increment_ns = increment * 1e6;
break;
// 6. If unit is "microsecond", then
case Unit::kMicrosecond:
// a. Let incrementNs be increment × 10^3.
increment_ns = increment * 1e3;
break;
// 7. Else,
// a. Assert: unit is "nanosecond".
case Unit::kNanosecond:
// b. Let incrementNs be increment.
increment_ns = increment;
break;
default:
UNREACHABLE();
}
// 8. Return RoundNumberToIncrement((ns), incrementNs, roundingMode).
return RoundNumberToIncrement(isolate, ns, increment_ns, rounding_mode);
}
} // namespace
// #sec-temporal.instant.prototype.tostring
MaybeHandle<String> JSTemporalInstant::ToString(
Isolate* isolate, Handle<JSTemporalInstant> instant,
Handle<Object> options_obj) {
Factory* factory = isolate->factory();
const char* method_name = "Temporal.Instant.prototype.toString";
// 1. Let instant be the this value.
// 2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
// 3. Set options to ? GetOptionsObject(options).
Handle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name),
String);
// 4. Let timeZone be ? Get(options, "timeZone").
Handle<Object> time_zone;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, time_zone,
JSReceiver::GetProperty(isolate, options, factory->timeZone_string()),
String);
// 5. If timeZone is not undefined, then
if (!time_zone->IsUndefined()) {
// a. Set timeZone to ? ToTemporalTimeZone(timeZone).
ASSIGN_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZone(isolate, time_zone, method_name), String);
}
// 6. Let precision be ? ToSecondsStringPrecision(options).
StringPrecision precision;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, precision,
ToSecondsStringPrecision(isolate, options, method_name),
Handle<String>());
// 7. Let roundingMode be ? ToTemporalRoundingMode(options, "trunc").
RoundingMode rounding_mode;
MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, rounding_mode,
ToTemporalRoundingMode(isolate, options, RoundingMode::kTrunc,
method_name),
Handle<String>());
// 8. Let roundedNs be ! RoundTemporalInstant(instant.[[Nanoseconds]],
// precision.[[Increment]], precision.[[Unit]], roundingMode).
Handle<BigInt> rounded_ns =
RoundTemporalInstant(isolate, handle(instant->nanoseconds(), isolate),
precision.increment, precision.unit, rounding_mode);
// 9. Let roundedInstant be ! CreateTemporalInstant(roundedNs).
Handle<JSTemporalInstant> rounded_instant =
temporal::CreateTemporalInstant(isolate, rounded_ns).ToHandleChecked();
// 10. Return ? TemporalInstantToString(roundedInstant, timeZone,
// precision.[[Precision]]).
return TemporalInstantToString(isolate, rounded_instant, time_zone,
precision.precision,
"Temporal.Instant.prototype.toString");
}
// #sec-temporal.instant.prototype.tozoneddatetimeiso
MaybeHandle<JSTemporalZonedDateTime> JSTemporalInstant::ToZonedDateTimeISO(
Isolate* isolate, Handle<JSTemporalInstant> handle,

View File

@ -279,6 +279,20 @@ class JSTemporalInstant
Isolate* isolate, Handle<JSTemporalInstant> instant,
Handle<Object> temporal_duration_like);
// #sec-temporal.instant.prototype.tojson
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToJSON(
Isolate* isolate, Handle<JSTemporalInstant> instant);
// #sec-temporal.instant.prototype.tolocalestring
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleString(
Isolate* isolate, Handle<JSTemporalInstant> instant,
Handle<Object> locales, Handle<Object> options);
// #sec-temporal.instant.prototype.tostring
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
Isolate* isolate, Handle<JSTemporalInstant> instant,
Handle<Object> options);
DECL_PRINTER(JSTemporalInstant)
TQ_OBJECT_CONSTRUCTORS(JSTemporalInstant)

View File

@ -51,8 +51,6 @@
'temporal/instant-constructor': [FAIL],
'temporal/instant-from-epoch-milliseconds': [FAIL],
'temporal/instant-from-epoch-seconds': [FAIL],
'temporal/instant-to-json': [FAIL],
'temporal/instant-toJSON': [FAIL],
'temporal/plain-date-time-add': [FAIL],
'temporal/plain-date-time-subtract': [FAIL],
'temporal/plain-date-time-to-json': [FAIL],

View File

@ -5,27 +5,27 @@
assertEquals("1970-01-01T00:00:00Z",
(Temporal.Instant.fromEpochSeconds(0n)).toJSON());
(Temporal.Instant.fromEpochSeconds(0)).toJSON());
let days_in_sec = 24n * 60n * 60n;
let days_in_sec = 24 * 60 * 60;
assertEquals("1970-12-31T23:59:59Z",
Temporal.Instant.fromEpochSeconds((365n * days_in_sec) - 1n).toJSON());
Temporal.Instant.fromEpochSeconds((365 * days_in_sec) - 1).toJSON());
assertEquals("1971-01-01T00:00:00Z",
Temporal.Instant.fromEpochSeconds((365n * days_in_sec)).toJSON());
Temporal.Instant.fromEpochSeconds((365 * days_in_sec)).toJSON());
assertEquals("1971-12-31T23:59:59Z",
Temporal.Instant.fromEpochSeconds((2n *365n * days_in_sec - 1n)).toJSON());
Temporal.Instant.fromEpochSeconds((2 *365 * days_in_sec - 1)).toJSON());
assertEquals("1972-01-01T00:00:00Z",
Temporal.Instant.fromEpochSeconds((2n *365n * days_in_sec)).toJSON());
Temporal.Instant.fromEpochSeconds((2 *365 * days_in_sec)).toJSON());
// 1972 is a leap year
assertEquals("1972-02-28T00:00:00Z",
Temporal.Instant.fromEpochSeconds(((2n *365n + 58n) * days_in_sec)).toJSON());
Temporal.Instant.fromEpochSeconds(((2 *365 + 58) * days_in_sec)).toJSON());
assertEquals("1972-02-29T00:00:00Z",
Temporal.Instant.fromEpochSeconds(((2n *365n + 59n) * days_in_sec)).toJSON());
Temporal.Instant.fromEpochSeconds(((2 *365 + 59) * days_in_sec)).toJSON());
assertEquals("1985-01-01T00:00:00Z",
Temporal.Instant.fromEpochSeconds(((15n *365n + 4n) * days_in_sec)).toJSON());
Temporal.Instant.fromEpochSeconds(((15 *365 + 4) * days_in_sec)).toJSON());
// Test with Date
@ -37,9 +37,8 @@ for (i = 0; i < number_of_random_test ; i++) {
// Temporal auto precision will remove trailing zeros in milliseconds so we only
// compare the first 19 char- to second.
let d = new Date(ms)
let bigd = BigInt(d)
dateout = d.toJSON().substr(0,19);
temporalout = Temporal.Instant.fromEpochMilliseconds(bigd).toJSON().substr(0, 19);
temporalout = Temporal.Instant.fromEpochMilliseconds(ms).toJSON().substr(0, 19);
if (dateout[0] != '0') {
assertEquals(dateout, temporalout, ms);
}

View File

@ -541,7 +541,6 @@
'built-ins/Temporal/Instant/compare/instant-string': [FAIL],
'built-ins/Temporal/Instant/from/instant-string': [FAIL],
'built-ins/Temporal/Instant/from/timezone-custom': [FAIL],
'built-ins/Temporal/Instant/prototype/equals/argument-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/equals/instant-string': [FAIL],
'built-ins/Temporal/Instant/prototype/round/subclassing-ignored': [FAIL],
'built-ins/Temporal/Instant/prototype/since/argument-zoneddatetime': [FAIL],
@ -566,41 +565,11 @@
'built-ins/Temporal/Instant/prototype/since/smallestunit-plurals-accepted': [FAIL],
'built-ins/Temporal/Instant/prototype/since/smallestunit-undefined': [FAIL],
'built-ins/Temporal/Instant/prototype/since/smallestunit-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toJSON/basic': [FAIL],
'built-ins/Temporal/Instant/prototype/toJSON/branding': [FAIL],
'built-ins/Temporal/Instant/prototype/toJSON/negative-epochnanoseconds': [FAIL],
'built-ins/Temporal/Instant/prototype/toJSON/timezone-getoffsetnanosecondsfor-not-callable': [FAIL],
'built-ins/Temporal/Instant/prototype/toJSON/year-format': [FAIL],
'built-ins/Temporal/Instant/prototype/toLocaleString/branding': [FAIL],
'built-ins/Temporal/Instant/prototype/toLocaleString/return-string': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/basic': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/branding': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-invalid-string': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-nan': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-non-integer': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-out-of-range': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-undefined': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/negative-epochnanoseconds': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/options-undefined': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/precision': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-invalid-string': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-undefined': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-invalid-string': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-plurals-accepted': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-undefined': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-valid-units': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-getoffsetnanosecondsfor-non-integer': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-getoffsetnanosecondsfor-not-callable': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-getoffsetnanosecondsfor-out-of-range': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-getoffsetnanosecondsfor-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-offset': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-string-datetime': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/year-format': [FAIL],
'built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/Instant/prototype/toZonedDateTime/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/Instant/prototype/until/argument-zoneddatetime': [FAIL],
@ -979,7 +948,6 @@
'built-ins/Temporal/TimeZone/prototype/getInstantFor/options-undefined': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/balance-negative-time-units': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/instant-string': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/pre-epoch': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-zoneddatetime-balance-negative-time-units': [FAIL],
'built-ins/Temporal/ZonedDateTime/compare/zoneddatetime-string': [FAIL],
'built-ins/Temporal/ZonedDateTime/compare/zoneddatetime-string-multiple-offsets': [FAIL],
@ -1417,16 +1385,9 @@
'built-ins/Temporal/Duration/prototype/toString/smallestunit-fractionalseconddigits': [FAIL],
'built-ins/Temporal/Instant/prototype/round/rounding-direction': [FAIL],
'built-ins/Temporal/Instant/prototype/since/options-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-auto': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/fractionalseconddigits-number': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/options-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/rounding-cross-midnight': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/rounding-direction': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-ceil': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-floor': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-halfExpand': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/roundingmode-trunc': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/smallestunit-fractionalseconddigits': [FAIL],
'built-ins/Temporal/Instant/prototype/until/options-wrong-type': [FAIL],
'built-ins/Temporal/PlainDate/prototype/since/options-wrong-type': [FAIL],
'built-ins/Temporal/PlainDate/prototype/until/options-wrong-type': [FAIL],
@ -1546,12 +1507,9 @@
'built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-calendar-wrong-type': [FAIL],
'built-ins/Temporal/Duration/prototype/total/relativeto-wrong-type': [FAIL],
'built-ins/Temporal/Duration/prototype/total/timezone-wrong-type': [FAIL],
'built-ins/Temporal/Instant/compare/argument-wrong-type': [FAIL],
'built-ins/Temporal/Instant/from/argument-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/since/argument-object-tostring': [FAIL],
'built-ins/Temporal/Instant/prototype/since/argument-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/since/instant-string-sub-minute-offset': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-wrong-type': [FAIL],
'built-ins/Temporal/Instant/prototype/toZonedDateTime/calendar-number': [FAIL],
'built-ins/Temporal/Instant/prototype/until/argument-object-tostring': [FAIL],
'built-ins/Temporal/Instant/prototype/until/argument-wrong-type': [FAIL],
@ -1618,7 +1576,6 @@
'built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-wrong-type': [FAIL],
'built-ins/Temporal/PlainYearMonth/prototype/until/argument-wrong-type': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getInstantFor/argument-propertybag-calendar-number': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/calendar-number': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/limits': [FAIL],
'built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/argument-propertybag-calendar-number': [FAIL],
@ -1694,7 +1651,6 @@
'built-ins/Temporal/Instant/prototype/since/leap-second': [FAIL],
'built-ins/Temporal/Instant/prototype/subtract/argument-string-negative-fractional-units': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-string-leap-second': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/timezone-string-year-zero': [FAIL],
'built-ins/Temporal/Instant/prototype/until/argument-string-invalid': [FAIL],
'built-ins/Temporal/Instant/prototype/until/argument-string-time-separators': [FAIL],
'built-ins/Temporal/Instant/prototype/until/leap-second': [FAIL],