Commit 972d7e5a authored by Frank Tang's avatar Frank Tang Committed by V8 LUCI CQ

[Temporal] Add TimeZone getOffset(Nanoseconds|String)For

Also add the non-intl version of AO
GetIANATimeZoneOffsetNanoseconds which only implement for UTC.
(intl version implement other tz come later)

Also fix bug in JSTemporalTimeZone::offset_nanoseconds() that
"1000000L * offset_milliseconds()" may overflow int32_t before returning as int64_t by first casting offset_milliseconds() to int64_t in the operation so the whole formula is calculating under 64 bits not 32 bits. This bug fix some  *timezone-string-datetime tests.

Spec Text:
https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.getoffsetnanosecondsfor
https://tc39.es/proposal-temporal/#sec-temporal.timezone.prototype.getoffsetstringfor
https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneoffsetnanoseconds

Bug: v8:11544
Change-Id: I2227dbfc8d6ed3ef83edcef5a9b903b8642b5902
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3534622Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80606}
parent 010de10e
......@@ -275,12 +275,6 @@ TO_BE_IMPLEMENTED(TemporalPlainMonthDayPrototypeToJSON)
/* Temporal #sec-temporal.plainmonthday.prototype.toplaindate */
TO_BE_IMPLEMENTED(TemporalPlainMonthDayPrototypeToPlainDate)
/* Temporal.TimeZone */
/* Temporal #sec-temporal.timezone.prototype.getoffsetnanosecondsfor */
TO_BE_IMPLEMENTED(TemporalTimeZonePrototypeGetOffsetNanosecondsFor)
/* Temporal #sec-temporal.timezone.prototype.getoffsetstringfor */
TO_BE_IMPLEMENTED(TemporalTimeZonePrototypeGetOffsetStringFor)
/* Temporal.Calendar */
/* Temporal #sec-temporal.calendar.prototype.weekofyear */
TO_BE_IMPLEMENTED(TemporalCalendarPrototypeWeekOfYear)
......@@ -801,8 +795,15 @@ BUILTIN(TemporalCalendarFrom) {
// TimeZone
TEMPORAL_CONSTRUCTOR1(TimeZone)
TEMPORAL_PROTOTYPE_METHOD2(TimeZone, GetInstantFor, getInstantFor)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetNextTransition, getNextTransition)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetOffsetNanosecondsFor,
getOffsetNanosecondsFor)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetOffsetStringFor, getOffsetStringFor)
TEMPORAL_PROTOTYPE_METHOD2(TimeZone, GetPlainDateTimeFor, getPlainDateTimeFor)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetPossibleInstantsFor,
getPossibleInstantFor)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetPreviousTransition,
getPreviousTransition)
// #sec-get-temporal.timezone.prototype.id
BUILTIN(TemporalTimeZonePrototypeId) {
......@@ -841,10 +842,6 @@ BUILTIN(TemporalTimeZonePrototypeToString) {
isolate, JSTemporalTimeZone::ToString(isolate, time_zone, method_name));
}
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetNextTransition, getNextTransition)
TEMPORAL_PROTOTYPE_METHOD2(TimeZone, GetPlainDateTimeFor, getPlainDateTimeFor)
TEMPORAL_PROTOTYPE_METHOD1(TimeZone, GetPreviousTransition,
getPreviousTransition)
// #sec-temporal.timezone.from
BUILTIN(TemporalTimeZoneFrom) {
HandleScope scope(isolate);
......
......@@ -3011,18 +3011,18 @@ Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(Isolate* isolate,
// a. Assert: sign is not undefined.
DCHECK(!parsed->tzuo_sign_is_undefined());
// b. Set hours to ! ToIntegerOrInfinity(hours).
int32_t hours = parsed->tzuo_hour;
int64_t hours = parsed->tzuo_hour;
// c. If sign is the code unit 0x002D (HYPHEN-MINUS) or the code unit 0x2212
// (MINUS SIGN), then i. Set sign to −1. d. Else, i. Set sign to 1.
int32_t sign = parsed->tzuo_sign;
int64_t sign = parsed->tzuo_sign;
// e. Set minutes to ! ToIntegerOrInfinity(minutes).
int32_t minutes =
int64_t minutes =
parsed->tzuo_minute_is_undefined() ? 0 : parsed->tzuo_minute;
// f. Set seconds to ! ToIntegerOrInfinity(seconds).
int32_t seconds =
int64_t seconds =
parsed->tzuo_second_is_undefined() ? 0 : parsed->tzuo_second;
// g. If fraction is not undefined, then
int32_t nanoseconds;
int64_t nanoseconds;
if (!parsed->tzuo_nanosecond_is_undefined()) {
// i. Set fraction to the string-concatenation of the previous value of
// fraction and the string "000000000".
......@@ -3039,7 +3039,7 @@ Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(Isolate* isolate,
// seconds) × 10^9 + nanoseconds).
int64_t offset_nanoseconds =
sign *
(((hours * 60 + minutes) * 60 + seconds) * 1000000000L + nanoseconds);
(((hours * 60 + minutes) * 60 + seconds) * 1000000000 + nanoseconds);
// j. Let offsetString be ! FormatTimeZoneOffsetString(offsetNanoseconds).
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, offset_string,
......@@ -6877,6 +6877,21 @@ MaybeHandle<Object> GetIANATimeZonePreviousTransition(
#endif // V8_INTL_SUPPORT
}
MaybeHandle<Object> GetIANATimeZoneOffsetNanoseconds(Isolate* isolate,
Handle<BigInt> nanoseconds,
int32_t time_zone_index) {
#ifdef V8_INTL_SUPPORT
// TODO(ftang) Handle offset for other timezone
if (time_zone_index == JSTemporalTimeZone::kUTCTimeZoneIndex) {
return handle(Smi::zero(), isolate);
}
UNREACHABLE();
#else // V8_INTL_SUPPORT
DCHECK_EQ(time_zone_index, JSTemporalTimeZone::kUTCTimeZoneIndex);
return handle(Smi::zero(), isolate);
#endif // V8_INTL_SUPPORT
}
} // namespace
// #sec-temporal.timezone.prototype.getplaindatetimefor
......@@ -7051,6 +7066,53 @@ MaybeHandle<JSArray> JSTemporalTimeZone::GetPossibleInstantsFor(
isolate, time_zone->time_zone_index(), date_time_record);
}
// #sec-temporal.timezone.prototype.getoffsetnanosecondsfor
MaybeHandle<Object> JSTemporalTimeZone::GetOffsetNanosecondsFor(
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
Handle<Object> instant_obj) {
TEMPORAL_ENTER_FUNC();
// 1. Let timeZone be the this value.
// 2. Perform ? RequireInternalSlot(timeZone,
// [[InitializedTemporalTimeZone]]).
// 3. Set instant to ? ToTemporalInstant(instant).
Handle<JSTemporalInstant> instant;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, instant,
ToTemporalInstant(isolate, instant_obj,
"Temporal.TimeZone.prototype.getOffsetNanosecondsFor"),
Smi);
// 4. If timeZone.[[OffsetNanoseconds]] is not undefined, return
// timeZone.[[OffsetNanoseconds]].
if (time_zone->is_offset()) {
return isolate->factory()->NewNumberFromInt64(
time_zone->offset_nanoseconds());
}
// 5. Return ! GetIANATimeZoneOffsetNanoseconds(instant.[[Nanoseconds]],
// timeZone.[[Identifier]]).
return GetIANATimeZoneOffsetNanoseconds(
isolate, Handle<BigInt>(instant->nanoseconds(), isolate),
time_zone->time_zone_index());
}
// #sec-temporal.timezone.prototype.getoffsetstringfor
MaybeHandle<String> JSTemporalTimeZone::GetOffsetStringFor(
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
Handle<Object> instant_obj) {
TEMPORAL_ENTER_FUNC();
const char* method_name = "Temporal.TimeZone.prototype.getOffsetStringFor";
// 1. Let timeZone be the this value.
// 2. Perform ? RequireInternalSlot(timeZone,
// [[InitializedTemporalTimeZone]]).
// 3. Set instant to ? ToTemporalInstant(instant).
Handle<JSTemporalInstant> instant;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, instant, ToTemporalInstant(isolate, instant_obj, method_name),
String);
// 4. Return ? BuiltinTimeZoneGetOffsetStringFor(timeZone, instant).
return BuiltinTimeZoneGetOffsetStringFor(isolate, time_zone, instant,
method_name);
}
// #sec-temporal.timezone.prototype.tostring
MaybeHandle<Object> JSTemporalTimeZone::ToString(
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
......@@ -7066,12 +7128,13 @@ int32_t JSTemporalTimeZone::time_zone_index() const {
int64_t JSTemporalTimeZone::offset_nanoseconds() const {
TEMPORAL_ENTER_FUNC();
DCHECK(is_offset());
return 1000000L * offset_milliseconds() + offset_sub_milliseconds();
return static_cast<int64_t>(offset_milliseconds()) * 1000000 +
static_cast<int64_t>(offset_sub_milliseconds());
}
void JSTemporalTimeZone::set_offset_nanoseconds(int64_t ns) {
this->set_offset_milliseconds(static_cast<int32_t>(ns / 1000000L));
this->set_offset_sub_milliseconds(static_cast<int32_t>(ns % 1000000L));
this->set_offset_milliseconds(static_cast<int32_t>(ns / 1000000));
this->set_offset_sub_milliseconds(static_cast<int32_t>(ns % 1000000));
}
MaybeHandle<String> JSTemporalTimeZone::id(Isolate* isolate) const {
......
......@@ -437,6 +437,16 @@ class JSTemporalTimeZone
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
Handle<Object> date_time);
// #sec-temporal.timezone.prototype.getoffsetnanosecondsfor
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> GetOffsetNanosecondsFor(
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
Handle<Object> instance);
// #sec-temporal.timezone.prototype.getoffsetstringfor
V8_WARN_UNUSED_RESULT static MaybeHandle<String> GetOffsetStringFor(
Isolate* isolate, Handle<JSTemporalTimeZone> time_zone,
Handle<Object> instance);
// #sec-temporal.timezone.prototype.tostring
static MaybeHandle<Object> ToString(Isolate* isolate,
Handle<JSTemporalTimeZone> time_zone,
......
......@@ -68,18 +68,15 @@
'temporal/plain-date-add': [FAIL],
'temporal/plain-date-compare': [FAIL],
'temporal/plain-date-equals': [FAIL],
'temporal/plain-date-from': [FAIL],
'temporal/plain-date-time-add': [FAIL],
'temporal/plain-date-time-compare': [FAIL],
'temporal/plain-date-time-equals': [FAIL],
'temporal/plain-date-time-from': [FAIL],
'temporal/plain-date-time-subtract': [FAIL],
'temporal/plain-date-time-to-json': [FAIL],
'temporal/plain-date-time-to-plain-date': [FAIL],
'temporal/plain-date-time-to-plain-month-day': [FAIL],
'temporal/plain-date-time-to-plain-time': [FAIL],
'temporal/plain-date-time-to-plain-year-month': [FAIL],
'temporal/plain-date-time-valueOf': [FAIL],
'temporal/plain-date-time-with': [FAIL],
'temporal/plain-date-time-with-plain-date': [FAIL],
'temporal/plain-date-time-with-plain-time': [FAIL],
......@@ -87,7 +84,6 @@
'temporal/plain-date-to-plain-date-time': [FAIL],
'temporal/plain-date-to-plain-month-day': [FAIL],
'temporal/plain-date-to-plain-year-month': [FAIL],
'temporal/plain-date-valueOf': [FAIL],
'temporal/plain-date-with': [FAIL],
##############################################################################
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment