mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:47:35 +00:00
LibJS: Use fully spec'd algorithm for ToISOWeekOfYear
This is an editorial change in the Temporal spec.
See: 33b62a3
This commit is contained in:
parent
b438839fcc
commit
741cc08221
3 changed files with 113 additions and 48 deletions
|
@ -607,35 +607,78 @@ u8 iso_days_in_month(i32 year, u8 month)
|
||||||
// 12.2.31 ToISOWeekOfYear ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisoweekofyear
|
// 12.2.31 ToISOWeekOfYear ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisoweekofyear
|
||||||
u8 to_iso_week_of_year(i32 year, u8 month, u8 day)
|
u8 to_iso_week_of_year(i32 year, u8 month, u8 day)
|
||||||
{
|
{
|
||||||
// 1. Assert: year is an integer.
|
// 1. Assert: IsValidISODate(year, month, day) is true.
|
||||||
// 2. Assert: month is an integer.
|
VERIFY(is_valid_iso_date(year, month, day));
|
||||||
// 3. Assert: day is an integer.
|
|
||||||
|
|
||||||
// 4. Let date be the date given by year, month, and day.
|
// 2. Let wednesday be 3.
|
||||||
// 5. Return date's week number according to ISO-8601 as an integer.
|
constexpr auto wednesday = 3;
|
||||||
auto t = make_date(make_day(year, month - 1, day), 0);
|
|
||||||
auto day_of_year = day_within_year(t) + 1;
|
|
||||||
auto day_of_week = week_day(t);
|
|
||||||
if (day_of_week == 0)
|
|
||||||
day_of_week = 7;
|
|
||||||
auto week = (day_of_year - day_of_week + 10) / 7;
|
|
||||||
|
|
||||||
|
// 3. Let thursday be 4.
|
||||||
|
constexpr auto thursday = 4;
|
||||||
|
|
||||||
|
// 4. Let friday be 5.
|
||||||
|
constexpr auto friday = 5;
|
||||||
|
|
||||||
|
// 5. Let saturday be 6.
|
||||||
|
constexpr auto saturday = 6;
|
||||||
|
|
||||||
|
// 6. Let daysInWeek be 7.
|
||||||
|
constexpr auto days_in_week = 7;
|
||||||
|
|
||||||
|
// 7. Let maxWeekNumber be 53.
|
||||||
|
constexpr auto max_week_number = 53;
|
||||||
|
|
||||||
|
// 8. Let dayOfYear be ToISODayOfYear(year, month, day).
|
||||||
|
auto day_of_year = to_iso_day_of_year(year, month, day);
|
||||||
|
|
||||||
|
// 9. Let dayOfWeek be ToISODayOfWeek(year, month, day).
|
||||||
|
auto day_of_week = to_iso_day_of_week(year, month, day);
|
||||||
|
|
||||||
|
// 10. Let week be floor((dayOfYear + daysInWeek - dayOfWeek + wednesday ) / daysInWeek).
|
||||||
|
auto week = static_cast<i32>(floor(static_cast<double>(day_of_year + days_in_week - day_of_week + wednesday) / days_in_week));
|
||||||
|
|
||||||
|
// 11. If week < 1, then
|
||||||
if (week < 1) {
|
if (week < 1) {
|
||||||
// NOTE: The resulting week is actually part of the previous year. If that year ends with a
|
// a. NOTE: This is the last week of the previous year.
|
||||||
// Thursday (i.e. the first day of the given year is a Friday, or day 5), or the previous
|
|
||||||
// year is a leap year and ends with a Friday (i.e. the first day of the given year is a
|
// b. Let dayOfJan1st be ToISODayOfWeek(year, 1, 1).
|
||||||
// Saturday, or day 6), it has 53 weeks, and 52 weeks otherwise.
|
auto day_of_jan_1st = to_iso_day_of_week(year, 1, 1);
|
||||||
auto day_of_jump = week_day(make_date(make_day(year, 0, 1), 0));
|
|
||||||
if (day_of_jump == 5 || (in_leap_year(time_from_year(year - 1)) && day_of_jump == 6))
|
// c. If dayOfJan1st is friday, then
|
||||||
return 53;
|
if (day_of_jan_1st == friday) {
|
||||||
else
|
// i. Return maxWeekNumber.
|
||||||
return 52;
|
return max_week_number;
|
||||||
} else if (week == 53) {
|
}
|
||||||
auto days_in_year = JS::days_in_year(year);
|
|
||||||
if (days_in_year - day_of_year < 4 - day_of_week)
|
// d. If dayOfJan1st is saturday, and InLeapYear(TimeFromYear(𝔽(year - 1))) is 1𝔽, then
|
||||||
return 1;
|
if (day_of_jan_1st == saturday && in_leap_year(time_from_year(year - 1))) {
|
||||||
|
// i. Return maxWeekNumber.
|
||||||
|
return max_week_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// e. Return maxWeekNumber - 1.
|
||||||
|
return max_week_number - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 12. If week is maxWeekNumber, then
|
||||||
|
if (week == max_week_number) {
|
||||||
|
// a. Let daysInYear be DaysInYear(𝔽(year)).
|
||||||
|
auto days_in_year = JS::days_in_year(year);
|
||||||
|
|
||||||
|
// b. Let daysLaterInYear be daysInYear - dayOfYear.
|
||||||
|
auto days_later_in_year = days_in_year - day_of_year;
|
||||||
|
|
||||||
|
// c. Let daysAfterThursday be thursday - dayOfWeek.
|
||||||
|
auto days_after_thursday = thursday - day_of_week;
|
||||||
|
|
||||||
|
// d. If daysLaterInYear < daysAfterThursday, then
|
||||||
|
if (days_later_in_year < days_after_thursday) {
|
||||||
|
// i. Return 1.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13. Return week.
|
||||||
return week;
|
return week;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -971,4 +1014,43 @@ ThrowCompletionOr<Object*> default_merge_calendar_fields(VM& vm, Object const& f
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 12.2.42 ToISODayOfYear ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisodayofyear
|
||||||
|
u16 to_iso_day_of_year(i32 year, u8 month, u8 day)
|
||||||
|
{
|
||||||
|
// 1. Assert: IsValidISODate(year, month, day) is true.
|
||||||
|
VERIFY(is_valid_iso_date(year, month, day));
|
||||||
|
|
||||||
|
// 2. Let epochDays be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
|
||||||
|
auto epoch_days = make_day(year, month - 1, day);
|
||||||
|
|
||||||
|
// 3. Assert: epochDays is finite.
|
||||||
|
VERIFY(isfinite(epoch_days));
|
||||||
|
|
||||||
|
// 4. Return ℝ(DayWithinYear(MakeDate(epochDays, +0𝔽))) + 1.
|
||||||
|
return day_within_year(make_date(epoch_days, 0)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12.2.43 ToISODayOfWeek ( year, month, day ), https://tc39.es/proposal-temporal/#sec-temporal-toisodayofweek
|
||||||
|
u8 to_iso_day_of_week(i32 year, u8 month, u8 day)
|
||||||
|
{
|
||||||
|
// 1. Assert: IsValidISODate(year, month, day) is true.
|
||||||
|
VERIFY(is_valid_iso_date(year, month, day));
|
||||||
|
|
||||||
|
// 2. Let epochDays be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
|
||||||
|
auto epoch_days = make_day(year, month - 1, day);
|
||||||
|
|
||||||
|
// 3. Assert: epochDays is finite.
|
||||||
|
VERIFY(isfinite(epoch_days));
|
||||||
|
|
||||||
|
// 4. Let dayOfWeek be WeekDay(MakeDate(epochDays, +0𝔽)).
|
||||||
|
auto day_of_week = week_day(make_date(epoch_days, 0));
|
||||||
|
|
||||||
|
// 5. If dayOfWeek = +0𝔽, return 7.
|
||||||
|
if (day_of_week == 0)
|
||||||
|
return 7;
|
||||||
|
|
||||||
|
// 6. Return ℝ(dayOfWeek).
|
||||||
|
return day_of_week;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,5 +75,7 @@ u8 iso_month(Object& temporal_object);
|
||||||
String iso_month_code(Object& temporal_object);
|
String iso_month_code(Object& temporal_object);
|
||||||
u8 iso_day(Object& temporal_object);
|
u8 iso_day(Object& temporal_object);
|
||||||
ThrowCompletionOr<Object*> default_merge_calendar_fields(VM&, Object const& fields, Object const& additional_fields);
|
ThrowCompletionOr<Object*> default_merge_calendar_fields(VM&, Object const& fields, Object const& additional_fields);
|
||||||
|
u16 to_iso_day_of_year(i32 year, u8 month, u8 day);
|
||||||
|
u8 to_iso_day_of_week(i32 year, u8 month, u8 day);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,21 +328,8 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::day_of_week)
|
||||||
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
||||||
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
||||||
|
|
||||||
// 5. Let epochDays be MakeDay(𝔽(temporalDate.[[ISOYear]]), 𝔽(temporalDate.[[ISOMonth]] - 1), 𝔽(temporalDate.[[ISODay]])).
|
// 5. Return 𝔽(ToISODayOfWeek(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
|
||||||
auto epoch_days = make_day(temporal_date->iso_year(), temporal_date->iso_month() - 1, temporal_date->iso_day());
|
return Value(to_iso_day_of_week(temporal_date->iso_year(), temporal_date->iso_month(), temporal_date->iso_day()));
|
||||||
|
|
||||||
// 6. Assert: epochDays is finite.
|
|
||||||
VERIFY(isfinite(epoch_days));
|
|
||||||
|
|
||||||
// 7. Let dayOfWeek be WeekDay(MakeDate(epochDays, +0𝔽)).
|
|
||||||
auto day_of_week = week_day(make_date(epoch_days, 0));
|
|
||||||
|
|
||||||
// 8. If dayOfWeek = +0𝔽, return 7𝔽.
|
|
||||||
if (day_of_week == 0)
|
|
||||||
return Value(7);
|
|
||||||
|
|
||||||
// 9. Return dayOfWeek.
|
|
||||||
return Value(day_of_week);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12.4.14 Temporal.Calendar.prototype.dayOfYear ( temporalDateLike ), https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.dayofyear
|
// 12.4.14 Temporal.Calendar.prototype.dayOfYear ( temporalDateLike ), https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.dayofyear
|
||||||
|
@ -359,14 +346,8 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::day_of_year)
|
||||||
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
||||||
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
||||||
|
|
||||||
// 5. Let epochDays be MakeDay(𝔽(temporalDate.[[ISOYear]]), 𝔽(temporalDate.[[ISOMonth]] - 1), 𝔽(temporalDate.[[ISODay]])).
|
// 5. Return 𝔽(ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
|
||||||
auto epoch_days = make_day(temporal_date->iso_year(), temporal_date->iso_month() - 1, temporal_date->iso_day());
|
return Value(to_iso_day_of_year(temporal_date->iso_year(), temporal_date->iso_month(), temporal_date->iso_day()));
|
||||||
|
|
||||||
// 6. Assert: epochDays is finite.
|
|
||||||
VERIFY(isfinite(epoch_days));
|
|
||||||
|
|
||||||
// 7. Return DayWithinYear(MakeDate(epochDays, +0𝔽)) + 1𝔽.
|
|
||||||
return Value(day_within_year(make_date(epoch_days, 0)) + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12.4.15 Temporal.Calendar.prototype.weekOfYear ( temporalDateLike ), https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.weekofyear
|
// 12.4.15 Temporal.Calendar.prototype.weekOfYear ( temporalDateLike ), https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.weekofyear
|
||||||
|
@ -383,7 +364,7 @@ JS_DEFINE_NATIVE_FUNCTION(CalendarPrototype::week_of_year)
|
||||||
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
// 4. Let temporalDate be ? ToTemporalDate(temporalDateLike).
|
||||||
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
auto* temporal_date = TRY(to_temporal_date(vm, vm.argument(0)));
|
||||||
|
|
||||||
// 5. Return 𝔽(! ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
|
// 5. Return 𝔽(ToISODayOfYear(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]])).
|
||||||
return Value(to_iso_week_of_year(temporal_date->iso_year(), temporal_date->iso_month(), temporal_date->iso_day()));
|
return Value(to_iso_week_of_year(temporal_date->iso_year(), temporal_date->iso_month(), temporal_date->iso_day()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue