[Temporal] Add Calendar.prototype.weekOfYear

Also add AO: ToISOWeekOfYear

Spec Text:
https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.weekofyear
https://tc39.es/proposal-temporal/#sec-temporal-toisoweekofyear

Note- this is only the non-intl version. intl version in
https://tc39.es/proposal-temporal/#sup-temporal.calendar.prototype.weekofyear
will be implemented in later cl.

PR https://github.com/tc39/proposal-temporal/pull/2378

Sync spec text for ToISODayOfYear and ToISODayOfWeek
in the comment and add DCHECK for assertion.


Bug: v8:11544
Change-Id: If07ff76551707d17d125e41bc624c12da6efa45a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3531567
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82733}
This commit is contained in:
Frank Tang 2022-08-22 14:17:44 -07:00 committed by V8 LUCI CQ
parent f7eda75efd
commit 4b14efad61
5 changed files with 116 additions and 58 deletions

View File

@ -38,10 +38,6 @@ namespace internal {
JSTemporal##T::NowISO(isolate, args.atOrUndefined(isolate, 1))); \
}
/* Temporal.Calendar */
/* Temporal #sec-temporal.calendar.prototype.weekofyear */
TO_BE_IMPLEMENTED(TemporalCalendarPrototypeWeekOfYear)
#define TEMPORAL_CONSTRUCTOR1(T) \
BUILTIN(Temporal##T##Constructor) { \
HandleScope scope(isolate); \
@ -664,7 +660,7 @@ TEMPORAL_PROTOTYPE_METHOD2(Calendar, MonthDayFromFields, monthDayFromFields)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, MonthsInYear, monthsInYear)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, Year, year)
TEMPORAL_PROTOTYPE_METHOD2(Calendar, YearMonthFromFields, yearMonthFromFields)
TEMPORAL_PROTOTYPE_METHOD1(Calendar, WeekOfYear, weekOfYear)
// #sec-temporal.calendar.from
BUILTIN(TemporalCalendarFrom) {
HandleScope scope(isolate);

View File

@ -9503,12 +9503,11 @@ namespace {
// #sec-temporal-toisodayofyear
int32_t ToISODayOfYear(Isolate* isolate, const DateRecordCommon& date) {
TEMPORAL_ENTER_FUNC();
// 1. Assert: year is an integer.
// 2. Assert: month is an integer.
// 3. Assert: day is an integer.
// 4. Let date be the date given by year, month, and day.
// 5. Return date's ordinal date in the year according to ISO-8601.
// 1. Assert: IsValidISODate(year, month, day) is *true*.
DCHECK(IsValidISODate(isolate, date));
// 2. Let _epochDays_ be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
// 3. Assert: _epochDays_ is finite.
// 4. Return (DayWithinYear(MakeDate(_epochDays_, *+0*<sub>𝔽</sub>))) + 1.
// Note: In ISO 8601, Jan: month=1, Dec: month=12,
// In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
return date.day +
@ -9524,25 +9523,31 @@ bool IsPlainDatePlainDateTimeOrPlainYearMonth(
}
// #sec-temporal-toisodayofweek
int32_t ToISODayOfWeek(Isolate* isolate, int32_t year, int32_t month,
int32_t day) {
int32_t ToISODayOfWeek(Isolate* isolate, const DateRecordCommon& date) {
TEMPORAL_ENTER_FUNC();
// 1. Assert: year is an integer.
// 2. Assert: month is an integer.
// 3. Assert: day is an integer.
// 4. Let date be the date given by year, month, and day.
// 5. Return date's day of the week according to ISO-8601.
// 1. Assert: IsValidISODate(year, month, day) is *true*.
DCHECK(IsValidISODate(isolate, date));
// 2. Let _epochDays_ be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
// Note: "- 1" after "date.day" came from the MakeyDay AO in
// "9. Return Day(t) + dt - 1𝔽."
int32_t epoch_days =
isolate->date_cache()->DaysFromYearMonth(date.year, date.month - 1) +
date.day - 1;
// 3. Assert: _epochDays_ is finite.
// 4. Let _dayOfWeek_ be WeekDay(MakeDate(_epochDays_, *+0*<sub>𝔽</sub>)).
int32_t weekday = isolate->date_cache()->Weekday(epoch_days);
// 5. If _dayOfWeek_ = *+0*<sub>𝔽</sub>, return 7.
// Note: In ISO 8601, Jan: month=1, Dec: month=12.
// In DateCache API, Jan: month=0, Dec: month=11 so we need to - 1 for month.
// Weekday() expect "the number of days since the epoch" as input and the
// value of day is 1-based so we need to minus 1 to calculate "the number of
// days" because the number of days on the epoch (1970/1/1) should be 0,
// not 1.
int32_t weekday = isolate->date_cache()->Weekday(
isolate->date_cache()->DaysFromYearMonth(year, month - 1) + day - 1);
// not 1
// Note: In ISO 8601, Sun: weekday=7 Mon: weekday=1
// In DateCache API, Sun: weekday=0 Mon: weekday=1
// 6. Return (_dayOfWeek_).
return weekday == 0 ? 7 : weekday;
}
@ -10019,6 +10024,68 @@ Maybe<DateRecordCommon> ISOYearMonthFromFields(Isolate* isolate,
result.day = 1;
return Just(result);
}
// #sec-temporal-toisoweekofyear
int32_t ToISOWeekOfYear(Isolate* isolate, const DateRecordCommon& date) {
TEMPORAL_ENTER_FUNC();
// 1. Assert: IsValidISODate(year, month, day) is *true*.
DCHECK(IsValidISODate(isolate, date));
// 2. Let wednesday be 3.
constexpr int32_t kWednesday = 3;
// 3. Let thursday_ be 4.
constexpr int32_t kThursday = 4;
// 4. Let friday be 5.
constexpr int32_t kFriday = 5;
// 5. Let saturday be 6.
constexpr int32_t kSaturday = 6;
// 6. Let daysInWeek be 7.
constexpr int32_t kDaysInWeek = 7;
// 7. Let maxWeekNumber be 53.
constexpr int32_t kMaxWeekNumber = 53;
// 8. Let dayOfYear be ToISODayOfYear(year, month, day).
int32_t day_of_year = ToISODayOfYear(isolate, date);
// 9. Let dayOfWeek be ToISODayOfWeek(year, month, day).
int32_t day_of_week = ToISODayOfWeek(isolate, date);
// 10. Let week be floor((dayOfYear + daysInWeek - dayOfWeek + wednesday ) /
// daysInWeek).
int32_t week =
(day_of_year + kDaysInWeek - day_of_week + kWednesday) / kDaysInWeek;
// 11. If week < 1, then
if (week < 1) {
// a. NOTE: This is the last week of the previous year.
// b. Let dayOfJan1st be ToISODayOfWeek(year, 1, 1).
int32_t day_of_jan_1st = ToISODayOfWeek(isolate, {date.year, 1, 1});
// c. If dayOfJan1st is friday, then
if (day_of_jan_1st == kFriday) {
// a. Return maxWeekNumber.
return kMaxWeekNumber;
}
// d. If dayOfJan1st is saturday, and InLeapYear(TimeFromYear(𝔽(year - 1)))
// is *1*<sub>𝔽</sub>, then
if (day_of_jan_1st == kSaturday && IsISOLeapYear(isolate, date.year - 1)) {
// i. Return maxWeekNumber.
return kMaxWeekNumber;
}
// e. Return maxWeekNumber - 1.
return kMaxWeekNumber - 1;
}
// 12. If week is maxWeekNumber, then
if (week == kMaxWeekNumber) {
// a. Let daysInYear be DaysInYear(𝔽(year)).
int32_t days_in_year = ISODaysInYear(isolate, date.year);
// b. Let daysLaterInYear be daysInYear - dayOfYear.
int32_t days_later_in_year = days_in_year - day_of_year;
// c. Let daysAfterThursday be thursday - dayOfWeek.
int32_t days_after_thursday = kThursday - day_of_week;
// d. If daysLaterInYear &lt; daysAfterThursday, then
if (days_later_in_year < days_after_thursday) {
// 1. Return 1.
return 1;
}
}
// 13. Return week.
return week;
}
} // namespace
@ -10257,9 +10324,9 @@ MaybeHandle<Smi> JSTemporalCalendar::DayOfWeek(
Smi);
// a. Let value be ! ToISODayOfWeek(temporalDate.[[ISOYear]],
// temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
int32_t value =
ToISODayOfWeek(isolate, temporal_date->iso_year(),
temporal_date->iso_month(), temporal_date->iso_day());
int32_t value = ToISODayOfWeek(
isolate, {temporal_date->iso_year(), temporal_date->iso_month(),
temporal_date->iso_day()});
return handle(Smi::FromInt(value), isolate);
}
@ -10736,6 +10803,30 @@ MaybeHandle<Object> JSTemporalCalendar::EraYear(
#endif // V8_INTL_SUPPORT
// #sec-temporal.calendar.prototype.weekofyear
MaybeHandle<Smi> JSTemporalCalendar::WeekOfYear(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> temporal_date_like) {
// 1. Let calendar be the this value.
// 2. Perform ? RequireInternalSlot(calendar,
// [[InitializedTemporalCalendar]]).
// 3. Assert: calendar.[[Identifier]] is "iso8601".
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
Handle<JSTemporalPlainDate> temporal_date;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, temporal_date,
ToTemporalDate(isolate, temporal_date_like,
isolate->factory()->NewJSObjectWithNullProto(),
"Temporal.Calendar.prototype.weekOfYear"),
Smi);
// a. Let value be ! ToISOWeekOfYear(temporalDate.[[ISOYear]],
// temporalDate.[[ISOMonth]], temporalDate.[[ISODay]]).
int32_t value = ToISOWeekOfYear(
isolate, {temporal_date->iso_year(), temporal_date->iso_month(),
temporal_date->iso_day()});
return handle(Smi::FromInt(value), isolate);
}
// #sec-temporal.calendar.prototype.tostring
MaybeHandle<String> JSTemporalCalendar::ToString(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,

View File

@ -137,6 +137,11 @@ class JSTemporalCalendar
Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> temporal_date_like);
// #sec-temporal.calendar.prototype.weekofyear
V8_WARN_UNUSED_RESULT static MaybeHandle<Smi> WeekOfYear(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,
Handle<Object> temporal_date_like);
// #sec-temporal.calendar.prototype.tostring
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
Isolate* isolate, Handle<JSTemporalCalendar> calendar,

View File

@ -42,11 +42,6 @@
# All tests in the bug directory are expected to fail.
'bugs/*': [FAIL],
##############################################################################
# Temporal tests to be implemented
# https://crbug.com/v8/11544
'temporal/calendar-week-of-year': [FAIL],
##############################################################################
# Open bugs.

View File

@ -438,22 +438,8 @@
'built-ins/Temporal/Duration/prototype/total/relativeto-string-datetime': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=11544
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindate': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-plaindatetime': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-datefromfields-called-with-options-undefined': [FAIL],
'built-ins/Temporal/Duration/prototype/total/relativeto-string-zoneddatetime': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-with-utc-designator': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/basic': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/branding': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-fields-iterable': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/calendar-temporal-object': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/cross-year': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror': [FAIL],
'built-ins/Temporal/Duration/compare/relativeto-sub-minute-offset': [FAIL],
'built-ins/Temporal/Duration/prototype/add/relativeto-sub-minute-offset': [FAIL],
'built-ins/Temporal/Duration/prototype/round/relativeto-string-datetime': [FAIL],
@ -467,7 +453,6 @@
'built-ins/Temporal/Now/zonedDateTimeISO/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/Now/zonedDateTime/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/PlainDate/prototype/weekOfYear/basic': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/since/argument-zoneddatetime-negative-epochnanoseconds': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/since/balance-negative-duration': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/timezone-string-multiple-offsets': [FAIL],
@ -500,12 +485,10 @@
'built-ins/Temporal/ZonedDateTime/prototype/withTimeZone/timezone-string-multiple-offsets': [FAIL],
'intl402/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror': [FAIL],
'intl402/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror': [FAIL],
'intl402/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror': [FAIL],
'intl402/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror': [FAIL],
'intl402/Temporal/Duration/prototype/round/relativeto-string-datetime': [FAIL],
'intl402/Temporal/Duration/prototype/total/relativeto-string-datetime': [FAIL],
'intl402/Temporal/PlainYearMonth/from/argument-object': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/year-zero': [FAIL],
'built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-no-implicit-midnight': [FAIL],
'built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-no-implicit-midnight': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-no-implicit-midnight': [FAIL],
@ -515,11 +498,9 @@
'built-ins/Temporal/PlainTime/prototype/until/argument-string-no-implicit-midnight': [FAIL],
'built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-no-implicit-midnight': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-invalid': [FAIL],
'built-ins/Temporal/PlainDateTime/datetime-math': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/until/casts-argument': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/until/returns-days': [FAIL],
'built-ins/Temporal/PlainDateTime/prototype/weekOfYear/basic': [FAIL],
'built-ins/Temporal/Instant/prototype/round/rounding-direction': [FAIL],
'built-ins/Temporal/Instant/prototype/toString/rounding-direction': [FAIL],
@ -599,19 +580,10 @@
'built-ins/Temporal/Duration/prototype/subtract/relativeto-propertybag-calendar-number': [FAIL],
'built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-calendar-number': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-number': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-wrong-type': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-wrong-type': [FAIL],
'built-ins/Temporal/Duration/prototype/round/relativeto-wrong-type': [SKIP],
'built-ins/Temporal/ZonedDateTime/timezone-string-multiple-offsets': [FAIL],
'built-ins/Temporal/Calendar/prototype/dateFromFields/missing-properties': [FAIL],
'built-ins/Temporal/Calendar/prototype/monthDayFromFields/missing-properties': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-leap-second': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-leap-second': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-year-zero': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-string-time-separators': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-convert': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-zoneddatetime-slots': [FAIL],
'built-ins/Temporal/Duration/prototype/add/relativeto-year': [FAIL],
'built-ins/Temporal/Instant/from/argument-string': [FAIL],
'intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations': [FAIL],
@ -716,7 +688,6 @@
'intl402/Temporal/TimeZone/prototype/getNextTransition/subtract-second-and-nanosecond-from-last-transition': [FAIL],
'intl402/Temporal/TimeZone/prototype/getPreviousTransition/nanoseconds-subtracted-or-added-at-dst-transition': [FAIL],
'built-ins/Temporal/Calendar/prototype/weekOfYear/argument-propertybag-calendar-string': [FAIL],
'built-ins/Temporal/Duration/prototype/toString/fractionalseconddigits-non-integer': [FAIL],
'built-ins/Temporal/Instant/prototype/add/minimum-maximum-instant': [FAIL],
'built-ins/Temporal/Instant/prototype/subtract/minimum-maximum-instant': [FAIL],