AK: Implement Formatter<UnixDateTime>

Implement StringBuilder's Formatter<UnixDateTime>. Add necessary tests.
This commit is contained in:
Tomasz Strejczek 2025-07-16 20:25:39 +02:00 committed by Jelle Raaijmakers
parent ea32e39d68
commit 5cde267979
2 changed files with 47 additions and 0 deletions

View File

@ -11,9 +11,12 @@
#include <AK/Badge.h>
#include <AK/Checked.h>
#include <AK/Platform.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/Types.h>
#ifdef AK_OS_WINDOWS
# include <time.h>
// https://learn.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-timeval
struct timeval {
long tv_sec { 0 };
@ -637,6 +640,25 @@ constexpr Duration operator""_sec(unsigned long long seconds) { return Duration:
}
template<>
struct Formatter<UnixDateTime> : StandardFormatter {
ErrorOr<void> format(FormatBuilder& builder, UnixDateTime const& value)
{
auto result_time = value.to_timespec().tv_sec;
struct tm tm;
#ifdef AK_OS_WINDOWS
if (gmtime_s(&tm, &result_time) != 0)
#else
if (gmtime_r(&result_time, &tm) == nullptr)
#endif
return Error::from_string_literal("Formatter<UnixDateTime>::format gmtime_r failed");
return builder.builder().try_appendff("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
};
}
#if USING_AK_GLOBALLY

View File

@ -890,3 +890,28 @@ TEST_CASE(parse_time_from_gmt)
EXPECT_EQ(tm.tm_min, 30);
EXPECT_EQ(tm.tm_sec, 45);
}
TEST_CASE(formatter_unix_date_time)
{
auto test = [](auto expected, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second) {
auto data = AK::UnixDateTime::from_unix_time_parts(year, month, day, hour, minute, second, 0);
StringBuilder builder;
builder.appendff("{}", data);
auto result = builder.to_string();
VERIFY(!result.is_error());
EXPECT_EQ(expected, builder.to_string().value());
};
test("2023-01-05 00:00:00"sv, 2023, 1, 5, 0, 0, 0);
test("1970-01-01 00:00:00"sv, 1970, 1, 1, 0, 0, 0); // Edge case for Unix epoch
test("1970-01-01 23:59:59"sv, 1970, 1, 1, 23, 59, 59); // Edge case for Unix epoch
test("2000-02-29 12:34:56"sv, 2000, 2, 29, 12, 34, 56); // Leap year (valid)
test("1999-12-31 23:59:59"sv, 1999, 12, 31, 23, 59, 59); // Y2K edge
test("2024-02-29 23:59:59"sv, 2024, 2, 29, 23, 59, 59); // Next leap year
test("1980-01-01 00:00:00"sv, 1980, 1, 1, 0, 0, 0); // Another leap year start
test("2038-01-19 03:14:07"sv, 2038, 1, 19, 3, 14, 7); // 32-bit Unix time max
test("2022-12-31 23:59:59"sv, 2022, 12, 31, 23, 59, 59); // End of year
test("2023-04-01 00:00:00"sv, 2023, 4, 1, 0, 0, 0); // Start of month
}