Skip to content

Commit

Permalink
fix: wrong wrapping in time_of_day::operator-.
Browse files Browse the repository at this point in the history
  • Loading branch information
ashigeru committed Jul 26, 2024
1 parent 625bbca commit ad142ac
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 9 deletions.
26 changes: 17 additions & 9 deletions include/takatori/datetime/time_of_day.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ class time_of_day {
/// @brief time offset type.
using difference_type = std::chrono::nanoseconds;

/// @brief the max value.
static constexpr time_unit max_value {
std::chrono::duration_cast<time_unit>(second_unit { 86400 }) - time_unit { 1 },
/// @brief the modulo of the day in the time unit.
static constexpr time_unit modulo {
std::chrono::duration_cast<time_unit>(second_unit { 86'400 } ),
};

/// @brief the max value.
static constexpr time_unit max_value { modulo - time_unit { 1 }, };

/**
* @brief creates a new instance which represents 00:00:00 of day.
*/
Expand All @@ -56,11 +59,13 @@ class time_of_day {
std::uint32_t hour,
std::uint32_t minute,
std::uint32_t second,
time_unit subsecond = time_unit::zero()) noexcept
: elapsed_(std::chrono::duration<std::uint64_t, std::chrono::hours::period>(hour)
+ std::chrono::duration<std::uint64_t, std::chrono::minutes::period>(minute)
+ std::chrono::duration<std::uint64_t, std::chrono::seconds::period>(second)
+ subsecond)
time_unit subsecond = time_unit::zero()) noexcept:
time_of_day {
std::chrono::duration<std::uint64_t, std::chrono::hours::period>(hour)
+ std::chrono::duration<std::uint64_t, std::chrono::minutes::period>(minute)
+ std::chrono::duration<std::uint64_t, std::chrono::seconds::period>(second)
+ subsecond
}
{}

/**
Expand Down Expand Up @@ -145,7 +150,10 @@ class time_of_day {
* @return the computed time
*/
inline constexpr time_of_day operator+(time_of_day a, time_of_day::difference_type b) noexcept {
return time_of_day { a.time_since_epoch() + b };
constexpr auto signed_modulo = std::chrono::duration_cast<time_of_day::difference_type>(time_of_day::modulo);
auto b_normalized = std::chrono::duration_cast<time_of_day::time_unit>(signed_modulo + b % signed_modulo);
auto r_normalized = (a.time_since_epoch() + b_normalized) % time_of_day::modulo;
return time_of_day { r_normalized };
}

/**
Expand Down
18 changes: 18 additions & 0 deletions test/takatori/datetime/time_of_day_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ TEST_F(time_of_day_test, hms) {
EXPECT_EQ(d.subsecond(), c::milliseconds(789));
}

TEST_F(time_of_day_test, plus_difference_in_range) {
time_of_day a { 1, 0, 0 };
auto r = a + std::chrono::hours { 2 };
EXPECT_EQ(r.time_since_epoch(), std::chrono::hours { 3 });
}

TEST_F(time_of_day_test, plus_difference_wrap_positive) {
time_of_day a { 12, 0, 0 };
auto r = a + std::chrono::hours { 13 };
EXPECT_EQ(r.time_since_epoch(), std::chrono::hours { 1 });
}

TEST_F(time_of_day_test, plus_difference_wrap_negative) {
time_of_day a { 12, 0, 0 };
auto r = a + std::chrono::hours { -13 };
EXPECT_EQ(r.time_since_epoch(), std::chrono::hours { 23 });
}

TEST_F(time_of_day_test, output) {
time_of_day d { 12, 34, 56, unit { 789'000'000 } };
std::cout << d << std::endl;
Expand Down

0 comments on commit ad142ac

Please sign in to comment.