AK: Introduce UnixDateTime::from_iso8601_week

This is intended to be used by the <input> element 'week' type state
and convert that to milliseconds from the Unix epoch (ignoring leap
seconds).

I am certain there is a much better way of writing this that does
not need a loop, but I am less convinced about writing that without
running into some edge case I didn't consider.
This commit is contained in:
Shannon Booth 2025-02-07 17:16:54 +13:00 committed by Sam Atkins
parent 08331f5d62
commit ad8a0e4940
Notes: github-actions[bot] 2025-02-22 19:10:50 +00:00
2 changed files with 25 additions and 0 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -271,6 +272,27 @@ MonotonicTime MonotonicTime::now_coarse()
return MonotonicTime { now_time_from_clock(CLOCK_MONOTONIC_COARSE) };
}
UnixDateTime UnixDateTime::from_iso8601_week(u32 week_year, u32 week)
{
auto january_1_weekday = day_of_week(week_year, 1, 1);
i32 offset_to_monday = (january_1_weekday <= 3) ? -january_1_weekday : 7 - january_1_weekday;
i32 first_monday_of_year = 1 + offset_to_monday;
i32 day_of_year = (first_monday_of_year + (week - 1) * 7) + 1;
// FIXME: There should be a more efficient way to do this that doesn't require a loop.
u8 month = 1;
while (true) {
auto days = days_in_month(week_year, month);
if (day_of_year <= days)
break;
day_of_year -= days;
++month;
}
return UnixDateTime::from_unix_time_parts(week_year, month, static_cast<u8>(day_of_year), 0, 0, 0, 0);
}
UnixDateTime UnixDateTime::now()
{
return UnixDateTime { now_time_from_clock(CLOCK_REALTIME) };

View file

@ -379,6 +379,9 @@ public:
return UnixDateTime {};
}
// Creates UNIX time from an ISO 8601 Week, such as 2025-W06, with year 2025 and week 6.
[[nodiscard]] static UnixDateTime from_iso8601_week(u32 year, u32 week);
// Creates UNIX time from a unix timestamp.
// Note that the returned time is probably not equivalent to the same timestamp in UTC time, since UNIX time does not observe leap seconds.
[[nodiscard]] constexpr static UnixDateTime from_unix_time_parts(i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond)