1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 10:14:58 +00:00
serenity/Tests/LibCore/TestLibCoreDateTime.cpp
Timothy Flynn 350fdf1e43 LibCore+LibTimeZone: Support time zone names in Core::DateTime::parse
LibCore currently cannot depend on LibTimeZone directly. All build-time
code generators depend on LibCore, so there'd be a circular dependency:
LibCore -> LibTimeZone -> GenerateTZData -> LibCore.

So to support parsing time zone names and applying their offsets, add a
couple of weakly-defined helper functions. These work similar to the way
AK::String declares some methods that LibUnicode defines. Any user who
wants to parse time zone names (from outside of LibCore itself) can link
against LibTimeZone to receive full support.
2023-11-08 09:28:17 +01:00

85 lines
3.1 KiB
C++

/*
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <LibCore/DateTime.h>
#include <LibCore/System.h>
#include <LibTest/TestCase.h>
#include <time.h>
class TimeZoneGuard {
public:
explicit TimeZoneGuard(StringView time_zone)
{
if (auto const* current_time_zone = getenv("TZ"))
m_time_zone = MUST(String::from_utf8({ current_time_zone, strlen(current_time_zone) }));
update(time_zone);
}
~TimeZoneGuard()
{
if (m_time_zone.has_value())
TRY_OR_FAIL(Core::System::setenv("TZ"sv, *m_time_zone, true));
else
TRY_OR_FAIL(Core::System::unsetenv("TZ"sv));
tzset();
}
void update(StringView time_zone)
{
TRY_OR_FAIL(Core::System::setenv("TZ"sv, time_zone, true));
tzset();
}
private:
Optional<String> m_time_zone;
};
TEST_CASE(parse_time_zone_name)
{
EXPECT(!Core::DateTime::parse("%Z"sv, ""sv).has_value());
EXPECT(!Core::DateTime::parse("%Z"sv, "123"sv).has_value());
EXPECT(!Core::DateTime::parse("%Z"sv, "notatimezone"sv).has_value());
auto test = [](auto format, auto time, u32 year, u32 month, u32 day, u32 hour, u32 minute) {
auto result = Core::DateTime::parse(format, time);
VERIFY(result.has_value());
EXPECT_EQ(year, result->year());
EXPECT_EQ(month, result->month());
EXPECT_EQ(day, result->day());
EXPECT_EQ(hour, result->hour());
EXPECT_EQ(minute, result->minute());
};
TimeZoneGuard guard { "UTC"sv };
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 UTC"sv, 2023, 01, 23, 10, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 America/New_York"sv, 2023, 01, 23, 15, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Europe/Paris"sv, 2023, 01, 23, 9, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Australia/Perth"sv, 2023, 01, 23, 2, 50);
guard.update("America/New_York"sv);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 UTC"sv, 2023, 01, 23, 5, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 America/New_York"sv, 2023, 01, 23, 10, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Europe/Paris"sv, 2023, 01, 23, 4, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Australia/Perth"sv, 2023, 01, 22, 21, 50);
guard.update("Europe/Paris"sv);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 UTC"sv, 2023, 01, 23, 11, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 America/New_York"sv, 2023, 01, 23, 16, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Europe/Paris"sv, 2023, 01, 23, 10, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Australia/Perth"sv, 2023, 01, 23, 3, 50);
guard.update("Australia/Perth"sv);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 UTC"sv, 2023, 01, 23, 18, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 America/New_York"sv, 2023, 01, 23, 23, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Europe/Paris"sv, 2023, 01, 23, 17, 50);
test("%Y/%m/%d %R %Z"sv, "2023/01/23 10:50 Australia/Perth"sv, 2023, 01, 23, 10, 50);
}