AK+Tests: Allow creating a Duration from 64-bit floating point seconds

This commit is contained in:
Zaggy1024 2025-10-02 08:58:48 -05:00 committed by Jelle Raaijmakers
parent d3941cd83d
commit aa8c28eb24
Notes: github-actions[bot] 2025-10-28 00:34:01 +00:00
2 changed files with 38 additions and 0 deletions

View file

@ -14,6 +14,7 @@
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/Types.h>
#include <math.h>
#ifdef AK_OS_WINDOWS
# include <time.h>
@ -213,6 +214,19 @@ private:
public:
[[nodiscard]] constexpr static Duration from_seconds(i64 seconds) { return Duration(seconds, 0); }
[[nodiscard]] constexpr static Duration from_seconds_f64(f64 seconds)
{
VERIFY(!isnan(seconds));
if (seconds >= static_cast<f64>(NumericLimits<i64>::max()))
return from_seconds(NumericLimits<i64>::max());
if (seconds <= static_cast<f64>(NumericLimits<i64>::min()))
return from_seconds(NumericLimits<i64>::min());
i64 integer_seconds = static_cast<i64>(seconds);
if (static_cast<f64>(integer_seconds) > seconds)
integer_seconds--;
u32 integer_nanoseconds = static_cast<u32>((seconds - static_cast<f64>(integer_seconds)) * 1'000'000'000);
return Duration(integer_seconds, integer_nanoseconds);
}
[[nodiscard]] constexpr static Duration from_nanoseconds(i64 nanoseconds)
{
i64 seconds = sane_mod(nanoseconds, 1'000'000'000);

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/Macros.h>
#include <LibTest/TestCase.h>
#include <AK/Time.h>
@ -915,3 +916,26 @@ TEST_CASE(formatter_unix_date_time)
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
}
TEST_CASE(from_f64_seconds)
{
constexpr auto max_seconds = Duration::from_seconds(NumericLimits<i64>::max());
EXPECT_EQ(Duration::from_seconds_f64(NumericLimits<float>::max()), max_seconds);
auto smaller_float = nextafterf(NumericLimits<float>::max(), 0.0f);
EXPECT_EQ(Duration::from_seconds_f64(smaller_float), max_seconds);
auto max_representable_float = nextafterf(static_cast<float>(NumericLimits<i64>::max()), 0.0f);
constexpr auto max_representable_float_as_integer = 9223371487098961920LL;
EXPECT_EQ(Duration::from_seconds_f64(max_representable_float), Duration::from_seconds(max_representable_float_as_integer));
constexpr auto min_seconds = Duration::from_seconds(NumericLimits<i64>::min());
EXPECT_EQ(Duration::from_seconds_f64(NumericLimits<float>::lowest()), min_seconds);
EXPECT_EQ(Duration::from_seconds_f64(-smaller_float), min_seconds);
EXPECT_EQ(Duration::from_seconds_f64(-max_representable_float), Duration::from_seconds(-max_representable_float_as_integer));
EXPECT_EQ(Duration::from_seconds_f64(1.5f), Duration::from_milliseconds(1500));
EXPECT_EQ(Duration::from_seconds_f64(205321.25f), Duration::from_milliseconds(205321250));
EXPECT_EQ(Duration::from_seconds_f64(-0.25f), Duration::from_milliseconds(-250));
EXPECT_EQ(Duration::from_seconds_f64(-1.75f), Duration::from_milliseconds(-1750));
EXPECT_DEATH("Converting float NaN seconds", (void)Duration::from_seconds_f64(NAN));
}