ladybird/Tests/AK/TestTime.cpp
Tomasz Strejczek ea32e39d68 AK: Add UnixDateTime::parse() method
Copy parse() method from LibCore::DateTime::parse(). Augment the method
to handle parsing from GMT time. Fix incorrect handling of year in '%D'
format specifier. Remove all format specifiers related to time zones.
Copy relevant tests and add additional ones.
2025-09-30 12:39:01 +02:00

893 lines
49 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/Time.h>
#ifdef AK_OS_WINDOWS
# include <time.h>
# define gmtime_r(time, tm) gmtime_s(tm, time)
#endif
using AK::Duration;
#if (defined(__TIMESIZE) && __TIMESIZE < 64) || defined(AK_OS_WINDOWS) // NOTE: See AK/Time.h, on Windows we hardcode to long's for timeval
# define TIME_T_IS_32BIT
#endif
#define EXPECT_DURATION(t, s, ns) \
do { \
auto ts = (t).to_timespec(); \
EXPECT_EQ(ts.tv_sec, (s)); \
EXPECT_EQ(ts.tv_nsec, (ns)); \
} while (0)
TEST_CASE(is_sane)
{
auto t0 = Duration::from_seconds(0);
auto t2 = Duration::from_seconds(2);
auto t5 = Duration::from_seconds(5);
auto tn3 = Duration::from_seconds(-3);
EXPECT(t0 == t0);
EXPECT(t2 == t2);
EXPECT(t5 == t5);
EXPECT(t0 != t2);
EXPECT(t2 != tn3);
EXPECT(t2 != t5);
EXPECT_DURATION(t0, 0, 0);
EXPECT_DURATION(t2, 2, 0);
EXPECT_DURATION(t5, 5, 0);
EXPECT_DURATION(t2 + t5, 7, 0);
EXPECT_DURATION(tn3 + t2, -1, 0);
EXPECT_DURATION(tn3 + t5, 2, 0);
}
TEST_CASE(limits)
{
EXPECT_DURATION(Duration::min(), (i64)-0x8000'0000'0000'0000, 0);
EXPECT_DURATION(Duration::max(), 0x7fff'ffff'ffff'ffff, 999'999'999);
}
TEST_CASE(seconds_parsing)
{
EXPECT_DURATION(Duration::from_seconds(0), 0, 0);
EXPECT_DURATION(Duration::from_seconds(42), 42, 0);
EXPECT_DURATION(Duration::from_seconds(-1), -1, 0);
// "6.4.4.1.5: The type of an integer constant is the first of the corresponding list in which its value can be represented."
// In the case of "0x8000'0000", the list is "int, unsigned int, …", and unsigned int (u32) matches.
// Then the unary minus: On unsigned 32-bit integers, -0x8000'0000 == 0x8000'0000, which only then is made signed again.
// So we would pass a medium-large *positive* number to 'from_seconds', which is not what we want to test here.
// That's why this is the only place that needs an "LL" suffix.
EXPECT_DURATION(Duration::from_seconds(-0x8000'0000LL), -0x8000'0000LL, 0);
EXPECT_DURATION(Duration::from_seconds(-0x8000'0000'0000'0000), (i64)-0x8000'0000'0000'0000, 0);
EXPECT_DURATION(Duration::from_seconds(0x7fff'ffff'ffff'ffff), 0x7fff'ffff'ffff'ffff, 0);
}
TEST_CASE(timespec_parsing)
{
EXPECT_DURATION(Duration::from_timespec(timespec { 2, 4 }), 2, 4);
EXPECT_DURATION(Duration::from_timespec(timespec { 1234, 5678 }), 1234, 5678);
EXPECT_DURATION(Duration::from_timespec(timespec { 0, 1'000'000'000 }), 1, 0);
EXPECT_DURATION(Duration::from_timespec(timespec { 8, 2'000'000'000 }), 10, 0);
EXPECT_DURATION(Duration::from_timespec(timespec { 0, 2'147'483'647 }), 2, 147'483'647);
EXPECT_DURATION(Duration::from_timespec(timespec { 1, -1 }), 0, 999'999'999);
EXPECT_DURATION(Duration::from_timespec(timespec { 0, -1 }), -1, 999'999'999);
EXPECT_DURATION(Duration::from_timespec(timespec { -1, 0 }), -1, 0);
EXPECT_DURATION(Duration::from_timespec(timespec { -1, 1'000'000'001 }), 0, 1);
EXPECT_DURATION(Duration::from_timespec(timespec { -2, 2'000'000'003 }), 0, 3);
EXPECT_DURATION(Duration::from_timespec(timespec { -2, 1'999'999'999 }), -1, 999'999'999);
#ifndef TIME_T_IS_32BIT
EXPECT_DURATION(Duration::from_timespec(timespec { 0x7fff'ffff'ffff'fffe, 999'999'998 }), 0x7fff'ffff'ffff'fffe, 999'999'998);
EXPECT_DURATION(Duration::from_timespec(timespec { 0x7fff'ffff'ffff'fffe, 1'999'999'998 }), 0x7fff'ffff'ffff'ffff, 999'999'998);
EXPECT_DURATION(Duration::from_timespec(timespec { 0x7fff'ffff'ffff'fffe, 1'999'999'999 }), 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_DURATION(Duration::from_timespec(timespec { 0x7fff'ffff'ffff'fffe, 2'000'000'000 }), 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_DURATION(Duration::from_timespec(timespec { -0x7fff'ffff'ffff'fffe, -1 }), -0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_DURATION(Duration::from_timespec(timespec { -0x7fff'ffff'ffff'fffe, -999'999'999 }), -0x7fff'ffff'ffff'ffff, 1);
EXPECT_DURATION(Duration::from_timespec(timespec { -0x7fff'ffff'ffff'fffe, -1'999'999'999 }), (i64)-0x8000'0000'0000'0000, 1);
EXPECT_DURATION(Duration::from_timespec(timespec { -0x7fff'ffff'ffff'fffe, -2'000'000'000 }), (i64)-0x8000'0000'0000'0000, 0);
EXPECT_DURATION(Duration::from_timespec(timespec { -0x7fff'ffff'ffff'fffe, -2'000'000'001 }), (i64)-0x8000'0000'0000'0000, 0);
#endif
}
TEST_CASE(timeval_parsing)
{
EXPECT_DURATION(Duration::from_timeval(timeval { 2, 4 }), 2, 4'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 1234, 5'678 }), 1234, 5'678'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -123, -45'678 }), -124, 954'322'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 0, 1'000'000 }), 1, 0);
EXPECT_DURATION(Duration::from_timeval(timeval { 0, 1'000'000'000 }), 1'000, 0);
EXPECT_DURATION(Duration::from_timeval(timeval { 8, 2'000'000 }), 10, 0);
EXPECT_DURATION(Duration::from_timeval(timeval { 0, 2'147'483'647 }), 2'147, 483'647'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 1, -1 }), 0, 999'999'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 0, -1 }), -1, 999'999'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -1, 0 }), -1, 0);
EXPECT_DURATION(Duration::from_timeval(timeval { -1, 1'000'001 }), 0, 1'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -2, 2'000'003 }), 0, 3'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -2, 1'999'999 }), -1, 999'999'000);
#ifndef TIME_T_IS_32BIT
EXPECT_DURATION(Duration::from_timeval(timeval { 0x7fff'ffff'ffff'fffe, 999'998 }), 0x7fff'ffff'ffff'fffe, 999'998'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 0x7fff'ffff'ffff'fffe, 1'999'998 }), 0x7fff'ffff'ffff'ffff, 999'998'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 0x7fff'ffff'ffff'fffe, 1'999'999 }), 0x7fff'ffff'ffff'ffff, 999'999'000);
EXPECT_DURATION(Duration::from_timeval(timeval { 0x7fff'ffff'ffff'fffe, 2'000'000 }), 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_DURATION(Duration::from_timeval(timeval { -0x7fff'ffff'ffff'fffe, -1 }), -0x7fff'ffff'ffff'ffff, 999'999'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -0x7fff'ffff'ffff'fffe, -999'999 }), -0x7fff'ffff'ffff'ffff, 1'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -0x7fff'ffff'ffff'fffe, -1'999'999 }), (i64)-0x8000'0000'0000'0000, 1'000);
EXPECT_DURATION(Duration::from_timeval(timeval { -0x7fff'ffff'ffff'fffe, -2'000'000 }), (i64)-0x8000'0000'0000'0000, 0);
EXPECT_DURATION(Duration::from_timeval(timeval { -0x7fff'ffff'ffff'fffe, -2'000'001 }), (i64)-0x8000'0000'0000'0000, 0);
#endif
}
#define DURATION(s, ns) \
Duration::from_timespec(timespec { (s), (ns) })
TEST_CASE(addition)
{
#define EXPECT_ADDITION(s1, ns1, s2, ns2, sr, nsr) \
do { \
EXPECT_DURATION(DURATION(s1, ns1) + DURATION(s2, ns2), sr, nsr); \
EXPECT_DURATION(DURATION(s2, ns2) + DURATION(s1, ns1), sr, nsr); \
auto t = DURATION(s1, ns1); \
t += DURATION(s2, ns2); \
EXPECT_DURATION(t, sr, nsr); \
} while (0)
EXPECT_ADDITION(11, 123'456'789, 22, 900'000'000, 34, 23'456'789);
#ifndef TIME_T_IS_32BIT
EXPECT_ADDITION(0, 0, 9223372036854775807LL, 999'999'998, 0x7fff'ffff'ffff'ffff, 999'999'998);
EXPECT_ADDITION(0, 1, 9223372036854775807LL, 999'999'998, 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_ADDITION(0, 2, 9223372036854775807LL, 999'999'998, 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_ADDITION(0x80, 40, 0x7fff'ffff'ffff'ff7f, 999'999'958, 0x7fff'ffff'ffff'ffff, 999'999'998);
EXPECT_ADDITION(0x80, 41, 0x7fff'ffff'ffff'ff7f, 999'999'958, 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_ADDITION(0x80, 42, 0x7fff'ffff'ffff'ff7f, 999'999'958, 0x7fff'ffff'ffff'ffff, 999'999'999);
#endif
EXPECT_ADDITION(-2, 5, -3, 7, -5, 12);
EXPECT_ADDITION(-2, 999'999'995, -3, 999'999'997, -4, 999'999'992);
#ifndef TIME_T_IS_32BIT
EXPECT_ADDITION(-0x7fff'ffff'ffff'ffff, 999'999'995, -1, 6, -0x7fff'ffff'ffff'ffff, 1);
EXPECT_ADDITION(-0x7fff'ffff'ffff'ffff, 999'999'995, -2, 6, (i64)-0x8000'0000'0000'0000, 1);
EXPECT_ADDITION(-0x7fff'ffff'ffff'ffff, 999'999'995, -2, 5, (i64)-0x8000'0000'0000'0000, 0);
EXPECT_ADDITION(-0x7fff'ffff'ffff'ffff, 999'999'995, -2, 4, (i64)-0x8000'0000'0000'0000, 0);
EXPECT_ADDITION((i64)-0x8000'0000'0000'0000, 999'999'995, 0x7fff'ffff'ffff'ffff, 4, -1, 999'999'999);
EXPECT_ADDITION((i64)-0x8000'0000'0000'0000, 999'999'995, 0x7fff'ffff'ffff'ffff, 5, 0, 0);
EXPECT_ADDITION((i64)-0x8000'0000'0000'0000, 999'999'995, 0x7fff'ffff'ffff'ffff, 6, 0, 1);
#endif
#undef EXPECT_ADDITION
}
TEST_CASE(subtraction)
{
#define EXPECT_SUBTRACTION(s1, ns1, s2, ns2, sr, nsr) \
do { \
EXPECT_DURATION(DURATION(s1, ns1) - DURATION(s2, ns2), sr, nsr); \
auto t = DURATION(s1, ns1); \
t -= DURATION(s2, ns2); \
EXPECT_DURATION(t, sr, nsr); \
} while (0)
EXPECT_SUBTRACTION(5, 0, 3, 0, 2, 0);
EXPECT_SUBTRACTION(0, 0, 0, 0, 0, 0);
EXPECT_SUBTRACTION(0, 5, 0, 3, 0, 2);
#ifndef TIME_T_IS_32BIT
EXPECT_SUBTRACTION(0x7fff'ffff'ffff'ffff, 999'999'999, 8, 123, 0x7fff'ffff'ffff'fff7, 999'999'876);
#endif
EXPECT_SUBTRACTION(1, 0, 0, 999'999'999, 0, 1);
#ifndef TIME_T_IS_32BIT
EXPECT_SUBTRACTION(0x7fff'ffff'ffff'ffff, 0, 1, 999'999'999, 0x7fff'ffff'ffff'fffd, 1);
#endif
EXPECT_SUBTRACTION(3, 0, 5, 0, -2, 0);
EXPECT_SUBTRACTION(0, 3, 0, 5, -1, 999'999'998);
#ifndef TIME_T_IS_32BIT
EXPECT_SUBTRACTION(0, 0, 0x7fff'ffff'ffff'ffff, 999'999'999, (i64)-0x8000'0000'0000'0000, 1);
EXPECT_SUBTRACTION(0, 0, (i64)-0x8000'0000'0000'0000, 0, 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_SUBTRACTION(-1, 999'999'999, (i64)-0x8000'0000'0000'0000, 0, 0x7fff'ffff'ffff'ffff, 999'999'999);
EXPECT_SUBTRACTION(-1, 999'999'998, (i64)-0x8000'0000'0000'0000, 0, 0x7fff'ffff'ffff'ffff, 999'999'998);
#endif
EXPECT_SUBTRACTION(123, 456, 123, 455, 0, 1);
EXPECT_SUBTRACTION(123, 456, 123, 456, 0, 0);
EXPECT_SUBTRACTION(123, 456, 123, 457, -1, 999'999'999);
EXPECT_SUBTRACTION(124, 456, 123, 455, 1, 1);
EXPECT_SUBTRACTION(124, 456, 123, 456, 1, 0);
EXPECT_SUBTRACTION(124, 456, 123, 457, 0, 999'999'999);
#ifndef TIME_T_IS_32BIT
EXPECT_SUBTRACTION(-0x7fff'ffff'ffff'ffff, 999'999'995, 1, 999'999'994, (i64)-0x8000'0000'0000'0000, 1);
EXPECT_SUBTRACTION(-0x7fff'ffff'ffff'ffff, 999'999'995, 1, 999'999'995, (i64)-0x8000'0000'0000'0000, 0);
EXPECT_SUBTRACTION(-0x7fff'ffff'ffff'ffff, 999'999'995, 1, 999'999'996, (i64)-0x8000'0000'0000'0000, 0);
#endif
}
TEST_CASE(rounding)
{
EXPECT_EQ(DURATION(2, 800'800'800).to_seconds(), 3);
EXPECT_EQ(DURATION(2, 800'800'800).to_milliseconds(), 2'801);
EXPECT_EQ(DURATION(2, 800'800'800).to_microseconds(), 2'800'801);
EXPECT_EQ(DURATION(2, 800'800'800).to_nanoseconds(), 2'800'800'800);
EXPECT_EQ(DURATION(-2, 800'800'800).to_seconds(), -2);
EXPECT_EQ(DURATION(-2, 800'800'800).to_milliseconds(), -1'200);
EXPECT_EQ(DURATION(-2, 800'800'800).to_microseconds(), -1'199'200);
EXPECT_EQ(DURATION(-2, 800'800'800).to_nanoseconds(), -1'199'199'200);
EXPECT_EQ(DURATION(0, 0).to_seconds(), 0);
EXPECT_EQ(DURATION(0, 0).to_milliseconds(), 0);
EXPECT_EQ(DURATION(0, 0).to_microseconds(), 0);
EXPECT_EQ(DURATION(0, 0).to_nanoseconds(), 0);
EXPECT_EQ(DURATION(0, 1).to_seconds(), 1);
EXPECT_EQ(DURATION(0, 1).to_milliseconds(), 1);
EXPECT_EQ(DURATION(0, 1).to_microseconds(), 1);
EXPECT_EQ(DURATION(0, 1).to_nanoseconds(), 1);
EXPECT_EQ(DURATION(0, -1).to_seconds(), -1);
EXPECT_EQ(DURATION(0, -1).to_milliseconds(), -1);
EXPECT_EQ(DURATION(0, -1).to_microseconds(), -1);
EXPECT_EQ(DURATION(0, -1).to_nanoseconds(), -1);
#ifndef TIME_T_IS_32BIT
EXPECT_EQ(DURATION(-9223372037, 145'224'191).to_nanoseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372037, 145'224'192).to_nanoseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372037, 145'224'193).to_nanoseconds(), -0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036, 854'775'806).to_nanoseconds(), 0x7fff'ffff'ffff'fffe);
EXPECT_EQ(DURATION(9223372036, 854'775'807).to_nanoseconds(), 0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036, 854'775'808).to_nanoseconds(), 0x7fff'ffff'ffff'ffff);
#endif
}
TEST_CASE(truncation)
{
// Sanity
EXPECT_EQ(DURATION(2, 0).to_truncated_seconds(), 2);
EXPECT_EQ(DURATION(-2, 0).to_truncated_seconds(), -2);
EXPECT_EQ(DURATION(2, 800'800'800).to_truncated_seconds(), 2);
EXPECT_EQ(DURATION(2, 800'800'800).to_truncated_milliseconds(), 2'800);
EXPECT_EQ(DURATION(2, 800'800'800).to_truncated_microseconds(), 2'800'800);
EXPECT_EQ(DURATION(-2, -800'800'800).to_truncated_seconds(), -2);
EXPECT_EQ(DURATION(-2, -800'800'800).to_truncated_milliseconds(), -2'800);
EXPECT_EQ(DURATION(-2, -800'800'800).to_truncated_microseconds(), -2'800'800);
// Overflow, seconds
EXPECT_EQ(Duration::min().to_truncated_seconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(Duration::max().to_truncated_seconds(), 0x7fff'ffff'ffff'ffff);
#ifndef TIME_T_IS_32BIT
// Overflow, milliseconds
EXPECT_EQ(DURATION(-9223372036854776, 191'000'000).to_truncated_milliseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372036854776, 192'000'000).to_truncated_milliseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372036854776, 192'000'001).to_truncated_milliseconds(), -0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(-9223372036854776, 193'000'000).to_truncated_milliseconds(), -0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036854775, 806'000'000).to_truncated_milliseconds(), 0x7fff'ffff'ffff'fffe);
EXPECT_EQ(DURATION(9223372036854775, 806'999'999).to_truncated_milliseconds(), 0x7fff'ffff'ffff'fffe);
EXPECT_EQ(DURATION(9223372036854775, 807'000'000).to_truncated_milliseconds(), 0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036854775, 808'000'000).to_truncated_milliseconds(), 0x7fff'ffff'ffff'ffff);
// Overflow, microseconds
EXPECT_EQ(DURATION(-9223372036855, 224'191'000).to_truncated_microseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372036855, 224'192'000).to_truncated_microseconds(), (i64)-0x8000'0000'0000'0000);
EXPECT_EQ(DURATION(-9223372036855, 224'192'001).to_truncated_microseconds(), (i64)-0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(-9223372036855, 224'193'000).to_truncated_microseconds(), (i64)-0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036854, 775'806'000).to_truncated_microseconds(), 0x7fff'ffff'ffff'fffe);
EXPECT_EQ(DURATION(9223372036854, 775'806'999).to_truncated_microseconds(), 0x7fff'ffff'ffff'fffe);
EXPECT_EQ(DURATION(9223372036854, 775'807'000).to_truncated_microseconds(), 0x7fff'ffff'ffff'ffff);
EXPECT_EQ(DURATION(9223372036854, 775'808'000).to_truncated_microseconds(), 0x7fff'ffff'ffff'ffff);
#endif
}
TEST_CASE(is_negative)
{
auto small = Duration::from_nanoseconds(10);
auto large = Duration::from_nanoseconds(15);
auto result = small - large;
EXPECT_EQ(result.to_nanoseconds(), -5);
EXPECT(result.is_negative());
result = large - small;
EXPECT_EQ(result.to_nanoseconds(), 5);
EXPECT(!result.is_negative());
}
struct YearAndDays {
int year;
i64 days;
};
TEST_CASE(years_to_days_since_epoch_points)
{
Array<YearAndDays, 24> test_data = { {
{ 1969, -365 },
{ 1970, 0 },
{ 1971, 365 },
{ 1900, -25567 },
{ 2023, 19358 },
{ 1800, -62091 },
{ 2100, 47482 },
{ 0, -719528 },
{ -1, -719893 },
{ -2, -720258 },
{ -3, -720623 },
{ -4, -720989 },
{ -5, -721354 },
{ -6, -721719 },
{ 4000, 741442 },
{ -10000, -4371953 },
{ 10000, 2932897 },
{ -1000000, -365962028 },
{ 1000000, 364522972 },
{ -5877640, -2147483456 },
{ 5881474, 2147444740 },
// Very important year: https://github.com/SerenityOS/serenity/pull/16760#issuecomment-1369054745
{ -999999, -365961662 },
// The following two values haven't been verified by any other algorithm, but are very close to "year * 365.2425", and prove that there is no UB due to signed overflow:
{ 2147483647, 784351576412 },
{ -2147483648, -784353015833 },
} };
for (auto entry : test_data) {
int year = entry.year;
i64 expected_days = entry.days;
i64 actual_days = years_to_days_since_epoch(year);
EXPECT_EQ(actual_days, expected_days);
}
}
BENCHMARK_CASE(years_to_days_since_epoch_benchmark)
{
// This benchmark takes consistently "0ms" on Linux, and "0ms" on Serenity.
for (size_t i = 0; i < 100; ++i) {
i64 actual_days = years_to_days_since_epoch(-5877640);
(void)actual_days;
EXPECT_EQ(actual_days, -2147483456);
}
}
TEST_CASE(days_since_epoch)
{
EXPECT_EQ(days_since_epoch(1970, 1, 1), 0);
EXPECT_EQ(days_since_epoch(1970, 1, 2), 1);
EXPECT_EQ(days_since_epoch(1970, 2, 1), 31);
EXPECT_EQ(days_since_epoch(1970, 2, 27), 57);
EXPECT_EQ(days_since_epoch(1970, 2, 28), 58);
EXPECT_EQ(days_since_epoch(1970, 2, 29), 59); // doesn't really exist
EXPECT_EQ(days_since_epoch(1970, 3, 1), 59);
EXPECT_EQ(days_since_epoch(1971, 1, 1), 365);
EXPECT_EQ(days_since_epoch(1972, 1, 1), 730);
EXPECT_EQ(days_since_epoch(1972, 2, 1), 761);
EXPECT_EQ(days_since_epoch(1972, 2, 27), 787);
EXPECT_EQ(days_since_epoch(1972, 2, 28), 788);
EXPECT_EQ(days_since_epoch(1972, 2, 29), 789);
EXPECT_EQ(days_since_epoch(1972, 3, 1), 790);
// At least shouldn't crash:
EXPECT_EQ(days_since_epoch(1971, 1, 0), 364);
EXPECT_EQ(days_since_epoch(1971, 0, 1), 365);
EXPECT_EQ(days_since_epoch(1971, 0, 0), 365);
EXPECT_EQ(days_since_epoch(1971, 13, 3), 365);
// I can't easily verify that these values are perfectly exact and correct, but they're close enough.
// Also, for these "years" the most important thing is to avoid crashing (i.e. signed overflow UB).
// Observe that these are very close to the naive guess of 365.2425 days per year.
EXPECT_EQ(days_since_epoch(0, 1, 1), -719528);
EXPECT_EQ(days_since_epoch(-1'000'000, 1, 1), -365962028);
EXPECT_EQ(days_since_epoch(-2'147'483'648, 1, 1), -784353015833); // Guess: 784353015832
EXPECT_EQ(days_since_epoch(1'000'000, 1, 1), 364522972);
EXPECT_EQ(days_since_epoch(2'147'483'647, 1, 1), 784351576412); // Guess: 784351576411
EXPECT_EQ(days_since_epoch(2'147'483'647, 12, 31), 784351576776); // Guess: 784351576777
EXPECT_EQ(days_since_epoch(2'147'483'647, 12, 255), 784351577000);
// FIXME shouldn't crash: EXPECT_EQ(days_since_epoch(2'147'483'647, 255, 255), 784351577000);
// FIXME: Restrict interface to only take sensible types, and ensure callers pass only sensible values for that type.
}
TEST_CASE(div_floor_by)
{
EXPECT_EQ(AK::Detail::floor_div_by<4>(-5), -2);
EXPECT_EQ(AK::Detail::floor_div_by<4>(-4), -1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(-3), -1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(-2), -1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(-1), -1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+0), +0);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+1), +0);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+2), +0);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+3), +0);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+4), +1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+5), +1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+6), +1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+7), +1);
EXPECT_EQ(AK::Detail::floor_div_by<4>(+8), +2);
}
TEST_CASE(mod_zeros_in_range)
{
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 0), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 1), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 2), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 3), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 4), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 5), 2);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(0, 6), 2);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 1), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 2), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 3), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 4), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 5), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(1, 6), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(2, 2), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(2, 3), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(2, 4), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(2, 5), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(2, 6), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(3, 3), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(3, 4), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(3, 5), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(3, 6), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(4, 4), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(4, 5), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(4, 6), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(5, 5), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(5, 6), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(6, 6), 0);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-5, 3), 2);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-4, 3), 2);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-3, 3), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-2, 3), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-1, 3), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(-0, 3), 1);
EXPECT_EQ(AK::Detail::mod_zeros_in_range<4>(+1, 3), 0);
}
TEST_CASE(years_to_days_since_epoch_span)
{
auto test_data_start_year = 1900;
// Data was pre-computed with a slow, but known-correct implementation.
// clang-format off
auto test_data = Array {
-25567, -25202, -24837, -24472, -24107, -23741, -23376, -23011,
-22646, -22280, -21915, -21550, -21185, -20819, -20454, -20089,
-19724, -19358, -18993, -18628, -18263, -17897, -17532, -17167,
-16802, -16436, -16071, -15706, -15341, -14975, -14610, -14245,
-13880, -13514, -13149, -12784, -12419, -12053, -11688, -11323,
-10958, -10592, -10227, -9862, -9497, -9131, -8766, -8401, -8036,
-7670, -7305, -6940, -6575, -6209, -5844, -5479, -5114, -4748, -4383,
-4018, -3653, -3287, -2922, -2557, -2192, -1826, -1461, -1096, -731,
-365, 0, 365, 730, 1096, 1461, 1826, 2191, 2557, 2922, 3287, 3652,
4018, 4383, 4748, 5113, 5479, 5844, 6209, 6574, 6940, 7305, 7670,
8035, 8401, 8766, 9131, 9496, 9862, 10227, 10592, 10957, 11323, 11688,
12053, 12418, 12784, 13149, 13514, 13879, 14245, 14610, 14975, 15340,
15706, 16071, 16436, 16801, 17167, 17532, 17897, 18262, 18628, 18993,
19358, 19723, 20089, 20454, 20819, 21184, 21550, 21915, 22280, 22645,
23011, 23376, 23741, 24106, 24472, 24837, 25202, 25567, 25933, 26298,
26663, 27028, 27394, 27759, 28124, 28489, 28855, 29220, 29585, 29950,
30316, 30681, 31046, 31411, 31777, 32142, 32507, 32872, 33238, 33603,
33968, 34333, 34699, 35064, 35429, 35794, 36160, 36525, 36890, 37255,
37621, 37986, 38351, 38716, 39082, 39447, 39812, 40177, 40543, 40908,
41273, 41638, 42004, 42369, 42734, 43099, 43465, 43830, 44195, 44560,
44926, 45291, 45656, 46021, 46387, 46752, 47117, 47482, 47847, 48212,
48577, 48942, 49308, 49673, 50038, 50403, 50769, 51134, 51499, 51864,
52230, 52595, 52960, 53325, 53691, 54056, 54421, 54786, 55152, 55517,
55882, 56247, 56613, 56978, 57343, 57708, 58074, 58439, 58804, 59169,
59535, 59900, 60265, 60630, 60996, 61361, 61726, 62091, 62457, 62822,
63187, 63552, 63918, 64283, 64648, 65013, 65379, 65744, 66109, 66474,
66840, 67205, 67570, 67935, 68301, 68666, 69031, 69396, 69762, 70127,
70492, 70857, 71223, 71588, 71953, 72318, 72684, 73049, 73414, 73779,
74145, 74510, 74875, 75240, 75606, 75971, 76336, 76701, 77067, 77432,
77797, 78162, 78528, 78893, 79258, 79623, 79989, 80354, 80719, 81084,
81450, 81815, 82180, 82545, 82911, 83276, 83641, 84006, 84371, 84736,
85101, 85466, 85832, 86197, 86562, 86927, 87293, 87658, 88023, 88388,
88754, 89119, 89484, 89849, 90215, 90580, 90945, 91310, 91676, 92041,
92406, 92771, 93137, 93502, 93867, 94232, 94598, 94963, 95328, 95693,
96059, 96424, 96789, 97154, 97520, 97885, 98250, 98615, 98981, 99346,
99711, 100076, 100442, 100807, 101172, 101537, 101903, 102268, 102633,
102998, 103364, 103729, 104094, 104459, 104825, 105190, 105555,
105920, 106286, 106651, 107016, 107381, 107747, 108112, 108477,
108842, 109208, 109573, 109938, 110303, 110669, 111034, 111399,
111764, 112130, 112495, 112860, 113225, 113591, 113956, 114321,
114686, 115052, 115417, 115782, 116147, 116513, 116878, 117243,
117608, 117974, 118339, 118704, 119069, 119435, 119800, 120165,
120530, 120895, 121260, 121625, 121990, 122356, 122721, 123086,
123451, 123817, 124182, 124547, 124912, 125278, 125643, 126008,
126373, 126739, 127104, 127469, 127834, 128200, 128565, 128930,
129295, 129661, 130026, 130391, 130756, 131122, 131487, 131852,
132217, 132583, 132948, 133313, 133678, 134044, 134409, 134774,
135139, 135505, 135870, 136235, 136600, 136966, 137331, 137696,
138061, 138427, 138792, 139157, 139522, 139888, 140253, 140618,
140983, 141349, 141714, 142079, 142444, 142810, 143175, 143540,
143905, 144271, 144636, 145001, 145366, 145732, 146097, 146462,
146827, 147193, 147558, 147923, 148288, 148654, 149019, 149384,
149749, 150115, 150480, 150845, 151210, 151576, 151941, 152306,
152671, 153037, 153402, 153767, 154132, 154498, 154863, 155228,
155593, 155959, 156324, 156689, 157054, 157420, 157785, 158150,
158515, 158881, 159246, 159611, 159976, 160342, 160707, 161072,
161437, 161803, 162168, 162533, 162898, 163264, 163629, 163994,
164359, 164725, 165090, 165455, 165820, 166186, 166551, 166916,
167281, 167647, 168012, 168377, 168742, 169108, 169473, 169838,
170203, 170569, 170934, 171299, 171664, 172030, 172395, 172760,
173125, 173491, 173856, 174221, 174586, 174952, 175317, 175682,
176047, 176413, 176778, 177143, 177508, 177874, 178239, 178604,
178969, 179335, 179700, 180065, 180430, 180796, 181161, 181526,
181891, 182257, 182622, 182987, 183352, 183718, 184083, 184448,
184813, 185179, 185544, 185909, 186274, 186640, 187005, 187370,
187735, 188101, 188466, 188831, 189196, 189562, 189927, 190292,
190657, 191023, 191388, 191753, 192118, 192484, 192849, 193214,
193579, 193944, 194309, 194674, 195039, 195405,
};
// clang-format on
for (size_t offset = 0; offset < test_data.size(); ++offset) {
int year = offset + test_data_start_year;
i64 expected_days = test_data[offset];
i64 actual_days = years_to_days_since_epoch(year);
EXPECT_EQ(actual_days, expected_days);
}
}
TEST_CASE(user_defined_literals)
{
using namespace AK::TimeLiterals;
static_assert(Duration::from_nanoseconds(123) == 123_ns, "Factory is same as UDL");
static_assert(100_ms > 10_ms, "LT UDL");
static_assert(1000_ns == 1_us, "EQ UDL");
static_assert(1_sec > 1_ms, "GT UDL");
static_assert(100_ms >= 100'000_us, "GE UDL (eq)");
static_assert(100_ms >= 99'999_us, "GE UDL (gt)");
static_assert(100_ms <= 100'000_us, "LE UDL (eq)");
static_assert(100_ms <= 100'001_us, "LE UDL (lt)");
static_assert(1_sec != 2_sec, "NE UDL");
}
TEST_CASE(from_iso8601_week)
{
// 1970-W01
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1970, 1).offset_to_epoch(), -259'200, 0);
// First and last weeks of yearEXPECT_DURATION(UnixDateTime::from_iso8601_week(2000, 1).offset_to_epoch(), 946857600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2000, 2).offset_to_epoch(), 947462400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2000, 51).offset_to_epoch(), 977097600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2000, 52).offset_to_epoch(), 977702400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2001, 1).offset_to_epoch(), 978307200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2001, 2).offset_to_epoch(), 978912000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2001, 51).offset_to_epoch(), 1008547200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2001, 52).offset_to_epoch(), 1009152000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2002, 1).offset_to_epoch(), 1009756800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2002, 2).offset_to_epoch(), 1010361600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2002, 51).offset_to_epoch(), 1039996800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2002, 52).offset_to_epoch(), 1040601600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2003, 1).offset_to_epoch(), 1041206400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2003, 2).offset_to_epoch(), 1041811200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2003, 51).offset_to_epoch(), 1071446400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2003, 52).offset_to_epoch(), 1072051200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2004, 1).offset_to_epoch(), 1072656000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2004, 2).offset_to_epoch(), 1073260800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2004, 51).offset_to_epoch(), 1102896000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2004, 52).offset_to_epoch(), 1103500800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2004, 53).offset_to_epoch(), 1104105600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2005, 1).offset_to_epoch(), 1104710400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2005, 2).offset_to_epoch(), 1105315200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2005, 51).offset_to_epoch(), 1134950400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2005, 52).offset_to_epoch(), 1135555200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2006, 1).offset_to_epoch(), 1136160000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2006, 2).offset_to_epoch(), 1136764800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2006, 51).offset_to_epoch(), 1166400000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2006, 52).offset_to_epoch(), 1167004800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2007, 1).offset_to_epoch(), 1167609600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2007, 2).offset_to_epoch(), 1168214400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2007, 51).offset_to_epoch(), 1197849600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2007, 52).offset_to_epoch(), 1198454400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2008, 1).offset_to_epoch(), 1199059200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2008, 2).offset_to_epoch(), 1199664000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2008, 51).offset_to_epoch(), 1229299200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2008, 52).offset_to_epoch(), 1229904000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2009, 1).offset_to_epoch(), 1230508800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2009, 2).offset_to_epoch(), 1231113600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2009, 51).offset_to_epoch(), 1260748800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2009, 52).offset_to_epoch(), 1261353600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2009, 53).offset_to_epoch(), 1261958400, 0);
// Some random weeks
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2064, 25).offset_to_epoch(), 2980800000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1976, 20).offset_to_epoch(), 200534400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2036, 6).offset_to_epoch(), 2085696000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2022, 9).offset_to_epoch(), 1646006400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2049, 19).offset_to_epoch(), 2504217600, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2069, 9).offset_to_epoch(), 3128976000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2015, 46).offset_to_epoch(), 1447027200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2056, 42).offset_to_epoch(), 2738880000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2018, 23).offset_to_epoch(), 1528070400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2047, 2).offset_to_epoch(), 2430432000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2033, 41).offset_to_epoch(), 2012515200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2021, 52).offset_to_epoch(), 1640563200, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1987, 8).offset_to_epoch(), 540432000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1982, 13).offset_to_epoch(), 386208000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1979, 36).offset_to_epoch(), 305164800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2057, 43).offset_to_epoch(), 2770934400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(1988, 35).offset_to_epoch(), 588816000, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2060, 50).offset_to_epoch(), 2869516800, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2013, 14).offset_to_epoch(), 1364774400, 0);
EXPECT_DURATION(UnixDateTime::from_iso8601_week(2005, 52).offset_to_epoch(), 1135555200, 0);
}
TEST_CASE(from_unix_time_parts_common_values)
{
// Non-negative "common" values.
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 0, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 0, 1).offset_to_epoch(), 0, 1'000'000);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 0, 999).offset_to_epoch(), 0, 999'000'000);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 1, 2).offset_to_epoch(), 1, 2'000'000);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 59, 0).offset_to_epoch(), 59, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 1, 0, 0).offset_to_epoch(), 60, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 59, 0, 0).offset_to_epoch(), 3540, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 1, 0, 0, 0).offset_to_epoch(), 3600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 23, 0, 0, 0).offset_to_epoch(), 82800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 2, 0, 0, 0, 0).offset_to_epoch(), 86400, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 2, 1, 0, 0, 0, 0).offset_to_epoch(), 2678400, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 2, 27, 0, 0, 0, 0).offset_to_epoch(), 4924800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 2, 28, 0, 0, 0, 0).offset_to_epoch(), 5011200, 0);
// Note that this day does *not* exist:
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 2, 29, 0, 0, 0, 0).offset_to_epoch(), 5097600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 3, 0, 0, 0, 0, 0).offset_to_epoch(), 5011200, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 3, 1, 0, 0, 0, 0).offset_to_epoch(), 5097600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 3, 2, 0, 0, 0, 0).offset_to_epoch(), 5184000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1971, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 31536000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 63072000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 2, 1, 0, 0, 0, 0).offset_to_epoch(), 65750400, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 2, 27, 0, 0, 0, 0).offset_to_epoch(), 67996800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 2, 28, 0, 0, 0, 0).offset_to_epoch(), 68083200, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 2, 29, 0, 0, 0, 0).offset_to_epoch(), 68169600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1972, 3, 1, 0, 0, 0, 0).offset_to_epoch(), 68256000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(2023, 5, 24, 18, 44, 40, 0).offset_to_epoch(), 1684953880, 0);
}
TEST_CASE(from_unix_time_parts_negative)
{
// Negative "common" values. These aren't really that well-defined, but we must make sure we don't crash.
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 0, 23, 0, 0, 0).offset_to_epoch(), -3600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 0, 24, 0, 0, 0).offset_to_epoch(), 0, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 0, 31, 0, 0, 0, 0).offset_to_epoch(), 0, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 11, 30, 0, 0, 0, 0).offset_to_epoch(), 28771200, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 12, 1, 0, 0, 0, 0).offset_to_epoch(), 28857600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 12, 31, 0, 0, 0, 0).offset_to_epoch(), 31449600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1971, 0, 0, 0, 0, 0, 0).offset_to_epoch(), 31536000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1971, 0, 1, 0, 0, 0, 0).offset_to_epoch(), 31536000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1971, 1, 0, 0, 0, 0, 0).offset_to_epoch(), 31449600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1971, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 31536000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1969, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -31536000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 3, 1, 0, 0, 0, 0).offset_to_epoch(), -57974400, 0);
// Leap day!
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 2, 29, 0, 0, 0, 0).offset_to_epoch(), -58060800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 2, 28, 0, 0, 0, 0).offset_to_epoch(), -58147200, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 2, 27, 0, 0, 0, 0).offset_to_epoch(), -58233600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 2, 1, 0, 0, 0, 0).offset_to_epoch(), -60480000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1968, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -63158400, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1967, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -94694400, 0);
}
TEST_CASE(from_milliseconds)
{
EXPECT_DURATION(Duration::from_milliseconds(0), 0, 0);
EXPECT_DURATION(Duration::from_milliseconds(42), 0, 42'000'000);
EXPECT_DURATION(Duration::from_milliseconds(-1), -1, 999'000'000);
EXPECT_DURATION(Duration::from_milliseconds(-1'000'000'000), -1'000'000, 0);
EXPECT_DURATION(Duration::from_milliseconds(1'000'000'000), 1'000'000, 0);
EXPECT_DURATION(Duration::from_milliseconds(9223372036854775807), 9223372036854775, 807'000'000);
EXPECT_DURATION(Duration::from_milliseconds((i64)-0x8000'0000'0000'0000), -9223372036854776, 192'000'000);
}
TEST_CASE(from_unix_time_parts_overflow)
{
// Negative overflow
// I can't easily verify that these values are perfectly exact and correct, but they're close enough.
// Also, for these "years" the most important thing is to avoid crashing (i.e. signed overflow UB).
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(0, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -62167219200, 0); // Guess: -62167195440, off by 23760 seconds
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(-1'000'000, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -31619119219200, 0); // Guess: -31619119195440, off by the same 23760 seconds
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(-2'147'483'648, 1, 1, 0, 0, 0, 0).offset_to_epoch(), -67768100567971200, 0); // Guess: -67768100567916336, off by 54864 seconds
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(-2'147'483'648, 1, 0, 0, 0, 0, 0).offset_to_epoch(), -67768100568057600, 0); // Guess: -67768100568002736, off by the same 54864 seconds
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(-2'147'483'648, 0, 0, 0, 0, 0, 0).offset_to_epoch(), -67768100567971200, 0);
// Positive overflow
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 0, 65535).offset_to_epoch(), 65, 535'000'000);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 0, 255, 0).offset_to_epoch(), 255, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 0, 255, 0, 0).offset_to_epoch(), 15300, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 1, 255, 0, 0, 0).offset_to_epoch(), 918000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 1, 255, 0, 0, 0, 0).offset_to_epoch(), 21945600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 12, 1, 0, 0, 0, 0).offset_to_epoch(), 28857600, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1970, 255, 1, 0, 0, 0, 0).offset_to_epoch(), 0, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(1'000'000, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 31494784780800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(2'147'483'647, 1, 1, 0, 0, 0, 0).offset_to_epoch(), 67767976201996800, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(2'147'483'647, 12, 255, 0, 0, 0, 0).offset_to_epoch(), 67767976252800000, 0);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(2'147'483'647, 12, 255, 255, 255, 255, 65535).offset_to_epoch(), 67767976253733620, 535'000'000);
EXPECT_DURATION(UnixDateTime::from_unix_time_parts(2'147'483'647, 255, 255, 255, 255, 255, 65535).offset_to_epoch(), 67767976202930420, 535'000'000);
}
TEST_CASE(time_to_string)
{
auto test = [](auto format, auto expected, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second) {
auto result = AK::UnixDateTime::from_unix_time_parts(year, month, day, hour, minute, second, 0).to_string(format, AK::UnixDateTime::LocalTime::No);
VERIFY(!result.is_error());
EXPECT_EQ(expected, result.value());
};
test("%Y/%m/%d %R"sv, "2023/01/23 10:50"sv, 2023, 1, 23, 10, 50, 10);
// two-digit year and century
test("%y %C"sv, "23 20"sv, 2023, 1, 23, 10, 50, 10);
// zero- and space-padded day, and %D shortcut
test("%d %e"sv, "05 5"sv, 2023, 1, 5, 0, 0, 0);
test("%D"sv, "01/23/23"sv, 2023, 1, 23, 0, 0, 0);
// full time and seconds
test("%T"sv, "10:50:10"sv, 2023, 1, 23, 10, 50, 10);
test("%S"sv, "05"sv, 2023, 1, 1, 0, 0, 5);
// 12-hour clock with AM/PM
test("%H %I %p"sv, "00 12 AM"sv, 2023, 1, 5, 0, 0, 0);
test("%H %I %p"sv, "15 03 PM"sv, 2023, 1, 5, 15, 0, 0);
// short/long weekday and month names
test("%a %A"sv, "Mon Monday"sv, 2023, 1, 23, 0, 0, 0);
test("%b %B"sv, "Jan January"sv, 2023, 1, 5, 0, 0, 0);
// numeric weekday and dayofyear
test("%w %j"sv, "1 023"sv, 2023, 1, 23, 0, 0, 0);
// newline, tab and literal '%'
test("%n"sv, "\n"sv, 2023, 1, 1, 0, 0, 0);
test("%t"sv, "\t"sv, 2023, 1, 1, 0, 0, 0);
test("%%"sv, "%"sv, 2023, 1, 1, 0, 0, 0);
}
TEST_CASE(parse_time)
{
auto test = [](auto format, auto time, int year, int month, int day, int hour, int minute, int second = 0) {
auto result = AK::UnixDateTime::parse(format, time);
VERIFY(result.has_value());
auto result_time = result.value().to_timespec();
struct tm tm;
#ifdef AK_OS_WINDOWS
VERIFY(gmtime_r(&result_time.tv_sec, &tm) == 0);
#else
VERIFY(gmtime_r(&result_time.tv_sec, &tm) != nullptr);
#endif
EXPECT_EQ(year, tm.tm_year + 1900);
EXPECT_EQ(month, tm.tm_mon + 1);
EXPECT_EQ(day, tm.tm_mday);
EXPECT_EQ(hour, tm.tm_hour);
EXPECT_EQ(minute, tm.tm_min);
EXPECT_EQ(second, tm.tm_sec);
};
test("%d-%m-%Y %H:%M"sv, "05-01-2023 00:00"sv, 2023, 1, 5, 0, 0);
test("%d-%m-%Y %H:%M GMT"sv, "05-01-2023 00:00 GMT"sv, 2023, 1, 5, 0, 0);
test("%Y/%m/%d %R"sv, "2023/01/23 10:50"sv, 2023, 1, 23, 10, 50);
test("%Y-%m-%d %H:%M"sv, "1999-12-31 23:59"sv, 1999, 12, 31, 23, 59);
test("%Y/%m/%d %R"sv, "1970/01/01 00:00"sv, 1970, 1, 1, 0, 0);
test("%Y/%m/%d %R"sv, "2000/02/29 12:34"sv, 2000, 2, 29, 12, 34); // Leap year
// %T: full time with seconds
test("%Y-%m-%d %T"sv, "2023-01-23 10:50:15"sv, 2023, 1, 23, 10, 50, 15);
// %S: seconds
test("%Y-%m-%d %H:%M:%S"sv, "2023-01-23 10:50:42"sv, 2023, 1, 23, 10, 50, 42);
// %I: 12-hour clock, %p: AM/PM
test("%Y-%m-%d %I:%M %p"sv, "2023-01-23 03:21 PM"sv, 2023, 1, 23, 15, 21, 0);
test("%Y-%m-%d %I:%M %p"sv, "2023-01-23 12:01 AM"sv, 2023, 1, 23, 0, 1, 0);
// %D: shortcut for %m/%d/%y
test("%D %H:%M:%S"sv, "01/23/23 10:50:59"sv, 2023, 1, 23, 10, 50, 59);
// %y: two-digit year, %C: century
test("%y %C %m %d %H:%M:%S"sv, "23 20 01 23 10:50:11"sv, 2023, 1, 23, 10, 50, 11);
// %a/%A: short/long weekday name (parsing ignores names, but test for correct date)
test("%Y-%m-%d %a"sv, "2023-01-23 Mon"sv, 2023, 1, 23, 0, 0, 0);
test("%Y-%m-%d %A"sv, "2023-01-23 Monday"sv, 2023, 1, 23, 0, 0, 0);
// %b/%B: short/long month name (parsing ignores names, but test for correct date)
test("%d %b %Y"sv, "05 Jan 2023"sv, 2023, 1, 5, 0, 0, 0);
test("%d %B %Y"sv, "05 January 2023"sv, 2023, 1, 5, 0, 0, 0);
// %j: day of year
test("%Y %j %H:%M:%S"sv, "2023 023 10:50:12"sv, 2023, 1, 23, 10, 50, 12);
// %w: weekday number (0=Sunday)
test("%Y-%m-%d %w %H:%M:%S"sv, "2023-01-23 1 10:50:13"sv, 2023, 1, 23, 10, 50, 13);
// %n: newline, %t: tab, %%: literal %
test("%Y-%m-%d%n%H:%M:%S"sv, "2023-01-23\n10:50:14"sv, 2023, 1, 23, 10, 50, 14);
test("%Y-%m-%d%t%H:%M:%S"sv, "2023-01-23\t10:50:15"sv, 2023, 1, 23, 10, 50, 15);
test("%Y-%m-%d %% %H:%M:%S"sv, "2023-01-23 % 10:50:16"sv, 2023, 1, 23, 10, 50, 16);
}
TEST_CASE(parse_wildcard_characters)
{
EXPECT(!AK::UnixDateTime::parse("%+"sv, ""sv).has_value());
EXPECT(!AK::UnixDateTime::parse("foo%+"sv, "foo"sv).has_value());
EXPECT(!AK::UnixDateTime::parse("[%*]"sv, "[foo"sv).has_value());
EXPECT(!AK::UnixDateTime::parse("[%*]"sv, "foo]"sv).has_value());
EXPECT(!AK::UnixDateTime::parse("%+%b"sv, "fooJan"sv).has_value());
auto test = [](auto format, auto time, int year, int month, int day) {
auto result = AK::UnixDateTime::parse(format, time);
VERIFY(result.has_value());
auto result_time = result.value().to_timespec();
struct tm tm;
#ifdef AK_OS_WINDOWS
VERIFY(gmtime_r(&result_time.tv_sec, &tm) == 0);
#else
VERIFY(gmtime_r(&result_time.tv_sec, &tm) != nullptr);
#endif
EXPECT_EQ(year, tm.tm_year + 1900);
EXPECT_EQ(month, tm.tm_mon + 1);
EXPECT_EQ(day, tm.tm_mday);
};
test("%Y %+ %m %d"sv, "2023 whf 01 23"sv, 2023, 01, 23);
test("%Y %m %d %+"sv, "2023 01 23 whf"sv, 2023, 01, 23);
test("%Y [%+] %m %d"sv, "2023 [well hello friends!] 01 23"sv, 2023, 01, 23);
test("%Y %m %d [%+]"sv, "2023 01 23 [well hello friends!]"sv, 2023, 01, 23);
}
TEST_CASE(parse_time_from_gmt)
{
// Test parsing with from_gmt = true (GMT time)
auto gmt_result = AK::UnixDateTime::parse("%Y-%m-%d %H:%M:%S"sv,
"2023-01-15 12:00:00"sv, true);
VERIFY(gmt_result.has_value());
// Parse a known GMT time and verify the timestamp
auto test_gmt = AK::UnixDateTime::parse("%Y-%m-%d %H:%M:%S"sv,
"1970-01-01 00:00:00"sv, true);
VERIFY(test_gmt.has_value());
EXPECT_EQ(test_gmt.value().seconds_since_epoch(), 0);
// Test another GMT time
auto test_gmt2 = AK::UnixDateTime::parse("%Y-%m-%d %H:%M:%S"sv,
"1970-01-01 01:00:00"sv, true);
VERIFY(test_gmt2.has_value());
EXPECT_EQ(test_gmt2.value().seconds_since_epoch(), 3600);
// Test with date components
auto test_gmt3 = AK::UnixDateTime::parse("%Y-%m-%d %H:%M:%S"sv,
"2023-06-15 18:30:45"sv, true);
VERIFY(test_gmt3.has_value());
// Verify the parsed time by converting back to tm structure
auto result_time = test_gmt3.value().to_timespec();
struct tm tm;
#ifdef AK_OS_WINDOWS
VERIFY(gmtime_r(&result_time.tv_sec, &tm) == 0);
#else
VERIFY(gmtime_r(&result_time.tv_sec, &tm) != nullptr);
#endif
EXPECT_EQ(tm.tm_year + 1900, 2023);
EXPECT_EQ(tm.tm_mon + 1, 6);
EXPECT_EQ(tm.tm_mday, 15);
EXPECT_EQ(tm.tm_hour, 18);
EXPECT_EQ(tm.tm_min, 30);
EXPECT_EQ(tm.tm_sec, 45);
}