diff --git a/AK/Time.cpp b/AK/Time.cpp index d10340e5978..ff84eb51727 100644 --- a/AK/Time.cpp +++ b/AK/Time.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, the SerenityOS developers. + * Copyright (c) 2025, Shannon Booth * * 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(day_of_year), 0, 0, 0, 0); +} + UnixDateTime UnixDateTime::now() { return UnixDateTime { now_time_from_clock(CLOCK_REALTIME) }; diff --git a/AK/Time.h b/AK/Time.h index 718290a42ce..83d20099004 100644 --- a/AK/Time.h +++ b/AK/Time.h @@ -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)