diff --git a/docs/chrono/hh_mm_ss.md b/docs/chrono/hh_mm_ss.md index f7744ff1..583e2cba 100644 --- a/docs/chrono/hh_mm_ss.md +++ b/docs/chrono/hh_mm_ss.md @@ -135,4 +135,49 @@ ETL_NOEXCEPT ``` A specialisation of absolute for `etl::chrono::duration`. **Return** -The absolute duration value. \ No newline at end of file +The absolute duration value. + +## 12/24 hour functions +```cpp +ETL_NODISCARD +inline ETL_CONSTEXPR14 +bool is_am(const etl::chrono::hours& h) +ETL_NOEXCEPT +``` +**Description** +Returns `true` if `h` is in the range [0h, 11h] (an am hour). + +--- + +```cpp +ETL_NODISCARD +inline ETL_CONSTEXPR14 +bool is_pm(const etl::chrono::hours& h) +ETL_NOEXCEPT +``` +**Description** +Returns `true` if `h` is in the range [12h, 23h] (a pm hour). + +--- + +```cpp +ETL_NODISCARD +inline ETL_CONSTEXPR14 +etl::chrono::hours make12(const etl::chrono::hours& h) +ETL_NOEXCEPT +``` +**Description** +Returns the 12-hour equivalent of `h` in the range [1h, 12h]. +If `h` is not in the range [0h, 23h], the value returned is unspecified. + +--- + +```cpp +ETL_NODISCARD +inline ETL_CONSTEXPR14 +etl::chrono::hours make24(const etl::chrono::hours& h, bool is_pm) +ETL_NOEXCEPT +``` +**Description** +Returns the 24-hour equivalent of `h`, which is assumed to represent the hour with the indicated am/pm. +If `h` is not in the range [1h, 12h], the value returned is unspecified. \ No newline at end of file diff --git a/docs/chrono/time_point.md b/docs/chrono/time_point.md index dd0bd674..4b9680f8 100644 --- a/docs/chrono/time_point.md +++ b/docs/chrono/time_point.md @@ -100,6 +100,41 @@ ETL_NOEXCEPT **Description** Subtracts a duration. +## Increment/decrement +```cpp +ETL_CONSTEXPR14 time_point& operator ++() +ETL_NOEXCEPT +``` +**Description** +Pre-increments the stored duration by one tick. + +--- + +```cpp +ETL_CONSTEXPR14 time_point operator ++(int) +ETL_NOEXCEPT +``` +**Description** +Post-increments the stored duration by one tick. + +--- + +```cpp +ETL_CONSTEXPR14 time_point& operator --() +ETL_NOEXCEPT +``` +**Description** +Pre-decrements the stored duration by one tick. + +--- + +```cpp +ETL_CONSTEXPR14 time_point operator --(int) +ETL_NOEXCEPT +``` +**Description** +Post-decrements the stored duration by one tick. + ## Constants ```cpp ETL_NODISCARD @@ -180,6 +215,65 @@ If time_point < other, returns -1 else if time_point > other, returns 1 else returns 0 +## Non-member mathematical operators +```cpp +template +ETL_CONSTEXPR14 +etl::chrono::time_point >::type> + operator +(const time_point& lhs, + const etl::chrono::duration& rhs) +ETL_NOEXCEPT +``` +**Description** +Adds a duration to a time_point. +**Return** +A time_point whose duration is the common type of the two. + +--- + +```cpp +template +ETL_CONSTEXPR14 +etl::chrono::time_point, TDuration2>::type> + operator +(const etl::chrono::duration& lhs, + const time_point& rhs) +ETL_NOEXCEPT +``` +**Description** +Adds a duration to a time_point. +**Return** +A time_point whose duration is the common type of the two. + +--- + +```cpp +template +ETL_CONSTEXPR14 +etl::chrono::time_point >::type> + operator -(const time_point& lhs, + const etl::chrono::duration& rhs) +ETL_NOEXCEPT +``` +**Description** +Subtracts a duration from a time_point. +**Return** +A time_point whose duration is the common type of the two. + +--- + +```cpp +template +ETL_CONSTEXPR14 +typename etl::common_type::type + operator -(const time_point& lhs, + const time_point& rhs) +ETL_NOEXCEPT +``` +**Description** +Subtracts one time_point from another. +**Return** +The duration between them as the common type of the two durations. + ## Non-member comparison operators ```cpp template diff --git a/include/etl/private/chrono/hh_mm_ss.h b/include/etl/private/chrono/hh_mm_ss.h index 2777551d..d60b3829 100644 --- a/include/etl/private/chrono/hh_mm_ss.h +++ b/include/etl/private/chrono/hh_mm_ss.h @@ -184,5 +184,64 @@ namespace etl template constexpr int etl::chrono::hh_mm_ss::fractional_width; + + //*********************************************************************** + /// 12/24 hours functions + //*********************************************************************** + + //*********************************************************************** + /// Returns true if h is in the range [0h, 11h] (an am hour). + //*********************************************************************** + ETL_NODISCARD + inline ETL_CONSTEXPR14 bool is_am(const etl::chrono::hours& h) ETL_NOEXCEPT + { + return (h >= etl::chrono::hours(0)) && (h <= etl::chrono::hours(11)); + } + + //*********************************************************************** + /// Returns true if h is in the range [12h, 23h] (a pm hour). + //*********************************************************************** + ETL_NODISCARD + inline ETL_CONSTEXPR14 bool is_pm(const etl::chrono::hours& h) ETL_NOEXCEPT + { + return (h >= etl::chrono::hours(12)) && (h <= etl::chrono::hours(23)); + } + + //*********************************************************************** + /// Returns the 12-hour equivalent of h in the range [1h, 12h]. + /// If h is not in the range [0h, 23h], the value returned is unspecified. + //*********************************************************************** + ETL_NODISCARD + inline ETL_CONSTEXPR14 etl::chrono::hours make12(const etl::chrono::hours& h) ETL_NOEXCEPT + { + if (h == etl::chrono::hours(0)) + { + return etl::chrono::hours(12); + } + else if (h > etl::chrono::hours(12)) + { + return h - etl::chrono::hours(12); + } + + return h; + } + + //*********************************************************************** + /// Returns the 24-hour equivalent of h, which is assumed to represent the + /// hour with the indicated am/pm. + /// If h is not in the range [1h, 12h], the value returned is unspecified. + //*********************************************************************** + ETL_NODISCARD + inline ETL_CONSTEXPR14 etl::chrono::hours make24(const etl::chrono::hours& h, bool is_pm) ETL_NOEXCEPT + { + if (is_pm) + { + return (h == etl::chrono::hours(12)) ? h : (h + etl::chrono::hours(12)); + } + else + { + return (h == etl::chrono::hours(12)) ? etl::chrono::hours(0) : h; + } + } } // namespace chrono } // namespace etl diff --git a/include/etl/private/chrono/time_point.h b/include/etl/private/chrono/time_point.h index 1d122f12..f90f1c61 100644 --- a/include/etl/private/chrono/time_point.h +++ b/include/etl/private/chrono/time_point.h @@ -122,6 +122,48 @@ namespace etl return *this; } + //*************************************************************************** + /// Pre-increments the stored duration by one tick. + //*************************************************************************** + ETL_CONSTEXPR14 time_point& operator++() ETL_NOEXCEPT + { + ++dur; + + return *this; + } + + //*************************************************************************** + /// Post-increments the stored duration by one tick. + //*************************************************************************** + ETL_CONSTEXPR14 time_point operator++(int) ETL_NOEXCEPT + { + time_point temp(*this); + ++dur; + + return temp; + } + + //*************************************************************************** + /// Pre-decrements the stored duration by one tick. + //*************************************************************************** + ETL_CONSTEXPR14 time_point& operator--() ETL_NOEXCEPT + { + --dur; + + return *this; + } + + //*************************************************************************** + /// Post-decrements the stored duration by one tick. + //*************************************************************************** + ETL_CONSTEXPR14 time_point operator--(int) ETL_NOEXCEPT + { + time_point temp(*this); + --dur; + + return temp; + } + //*************************************************************************** /// Returns a time_point with the smallest possible duration. //*************************************************************************** @@ -200,6 +242,59 @@ namespace etl return etl::chrono::time_point(dur); } + //*************************************************************************** + /// Adds a duration to a time_point. + /// Returns a time_point whose duration is the common type of the two. + //*************************************************************************** + template + ETL_CONSTEXPR14 etl::chrono::time_point >::type> + operator+(const time_point& lhs, const etl::chrono::duration& rhs) ETL_NOEXCEPT + { + using common_duration = typename etl::common_type >::type; + using result_time_point = etl::chrono::time_point; + + return result_time_point(lhs.time_since_epoch() + rhs); + } + + //*************************************************************************** + /// Adds a time_point to a duration. + /// Returns a time_point whose duration is the common type of the two. + //*************************************************************************** + template + ETL_CONSTEXPR14 etl::chrono::time_point, TDuration2>::type> + operator+(const etl::chrono::duration& lhs, const time_point& rhs) ETL_NOEXCEPT + { + using common_duration = typename etl::common_type, TDuration2>::type; + using result_time_point = etl::chrono::time_point; + + return result_time_point(lhs + rhs.time_since_epoch()); + } + + //*************************************************************************** + /// Subtracts a duration from a time_point. + /// Returns a time_point whose duration is the common type of the two. + //*************************************************************************** + template + ETL_CONSTEXPR14 etl::chrono::time_point >::type> + operator-(const time_point& lhs, const etl::chrono::duration& rhs) ETL_NOEXCEPT + { + using common_duration = typename etl::common_type >::type; + using result_time_point = etl::chrono::time_point; + + return result_time_point(lhs.time_since_epoch() - rhs); + } + + //*************************************************************************** + /// Subtracts one time_point from another. + /// Returns the duration between them as the common type of the two durations. + //*************************************************************************** + template + ETL_CONSTEXPR14 typename etl::common_type::type operator-(const time_point& lhs, + const time_point& rhs) ETL_NOEXCEPT + { + return lhs.time_since_epoch() - rhs.time_since_epoch(); + } + //*************************************************************************** /// Equality operator //*************************************************************************** diff --git a/test/test_chrono_hh_mm_ss.cpp b/test/test_chrono_hh_mm_ss.cpp index 9e770024..7342964d 100644 --- a/test/test_chrono_hh_mm_ss.cpp +++ b/test/test_chrono_hh_mm_ss.cpp @@ -286,5 +286,86 @@ namespace CHECK_EQUAL(0, time.fractional_width); CHECK_TRUE((std::is_same::precision>::value)); } + + //************************************************************************* + TEST(test_is_am) + { + for (int h = 0; h <= 11; ++h) + { + CHECK_TRUE(Chrono::is_am(Chrono::hours(h))); + } + + for (int h = 12; h <= 23; ++h) + { + CHECK_FALSE(Chrono::is_am(Chrono::hours(h))); + } + } + + //************************************************************************* + TEST(test_is_pm) + { + for (int h = 0; h <= 11; ++h) + { + CHECK_FALSE(Chrono::is_pm(Chrono::hours(h))); + } + + for (int h = 12; h <= 23; ++h) + { + CHECK_TRUE(Chrono::is_pm(Chrono::hours(h))); + } + } + + //************************************************************************* + TEST(test_make12) + { + // Midnight (0h) maps to 12h. + CHECK_EQUAL(12, Chrono::make12(Chrono::hours(0)).count()); + + // 1h..12h are unchanged. + for (int h = 1; h <= 12; ++h) + { + CHECK_EQUAL(h, Chrono::make12(Chrono::hours(h)).count()); + } + + // 13h..23h map to 1h..11h. + for (int h = 13; h <= 23; ++h) + { + CHECK_EQUAL(h - 12, Chrono::make12(Chrono::hours(h)).count()); + } + } + + //************************************************************************* + TEST(test_make24) + { + // am: 12h maps to 0h, 1h..11h are unchanged. + CHECK_EQUAL(0, Chrono::make24(Chrono::hours(12), false).count()); + + for (int h = 1; h <= 11; ++h) + { + CHECK_EQUAL(h, Chrono::make24(Chrono::hours(h), false).count()); + } + + // pm: 12h stays 12h, 1h..11h map to 13h..23h. + CHECK_EQUAL(12, Chrono::make24(Chrono::hours(12), true).count()); + + for (int h = 1; h <= 11; ++h) + { + CHECK_EQUAL(h + 12, Chrono::make24(Chrono::hours(h), true).count()); + } + } + + //************************************************************************* + TEST(test_make12_make24_round_trip) + { + // For every 24-hour value, make12 plus its am/pm flag round-trips via make24. + for (int h = 0; h <= 23; ++h) + { + Chrono::hours h24(h); + bool pm = Chrono::is_pm(h24); + Chrono::hours h12 = Chrono::make12(h24); + + CHECK_EQUAL(h, Chrono::make24(h12, pm).count()); + } + } } } // namespace diff --git a/test/test_chrono_time_point.cpp b/test/test_chrono_time_point.cpp index e49c3791..0bbea37f 100644 --- a/test/test_chrono_time_point.cpp +++ b/test/test_chrono_time_point.cpp @@ -185,6 +185,99 @@ namespace } } + //************************************************************************* + TEST(test_operator_plus_time_point_duration) + { + TimePoint tp{Chrono::hours(10)}; + + // Same duration type. + auto result = tp + Chrono::hours(5); + CHECK_EQUAL(15, result.time_since_epoch().count()); + + // Mixed duration types resolve to the common (finer) type. + auto result_mixed = tp + Chrono::days(1); // 10 hours + 24 hours + CHECK_EQUAL(34, result_mixed.time_since_epoch().count()); + CHECK_TRUE((std::is_same::value)); + } + + //************************************************************************* + TEST(test_operator_plus_duration_time_point) + { + TimePoint tp{Chrono::hours(10)}; + + // Same duration type. + auto result = Chrono::hours(5) + tp; + CHECK_EQUAL(15, result.time_since_epoch().count()); + + // Mixed duration types resolve to the common (finer) type. + auto result_mixed = Chrono::days(1) + tp; // 24 hours + 10 hours + CHECK_EQUAL(34, result_mixed.time_since_epoch().count()); + CHECK_TRUE((std::is_same::value)); + } + + //************************************************************************* + TEST(test_operator_minus_time_point_duration) + { + TimePoint tp{Chrono::hours(50)}; + + // Same duration type. + auto result = tp - Chrono::hours(5); + CHECK_EQUAL(45, result.time_since_epoch().count()); + + // Mixed duration types resolve to the common (finer) type. + auto result_mixed = tp - Chrono::days(1); // 50 hours - 24 hours + CHECK_EQUAL(26, result_mixed.time_since_epoch().count()); + CHECK_TRUE((std::is_same::value)); + } + + //************************************************************************* + TEST(test_operator_minus_time_point_time_point) + { + TimePoint tp1{Chrono::hours(50)}; + TimePoint tp2{Chrono::hours(20)}; + + // Subtracting two time_points yields the duration between them. + auto diff = tp1 - tp2; + CHECK_EQUAL(30, diff.count()); + CHECK_TRUE((std::is_same::value)); + + // Mixed duration types resolve to the common (finer) duration. + Chrono::time_point tp_days{Chrono::days(2)}; // 48 hours + auto diff_mixed = tp1 - tp_days; // 50 hours - 48 hours + CHECK_EQUAL(2, diff_mixed.count()); + CHECK_TRUE((std::is_same::value)); + + // The reverse difference is negative. + auto diff_negative = tp2 - tp1; + CHECK_EQUAL(-30, diff_negative.count()); + } + + //************************************************************************* + TEST(test_increment_decrement_operators) + { + TimePoint tp{Chrono::hours(10)}; + + // Pre-increment. + auto& pre_inc = ++tp; + CHECK_EQUAL(11, tp.time_since_epoch().count()); + CHECK_EQUAL(11, pre_inc.time_since_epoch().count()); + + // Post-increment returns the previous value. + TimePoint post_inc = tp++; + CHECK_EQUAL(11, post_inc.time_since_epoch().count()); + CHECK_EQUAL(12, tp.time_since_epoch().count()); + + // Pre-decrement. + auto& pre_dec = --tp; + CHECK_EQUAL(11, tp.time_since_epoch().count()); + CHECK_EQUAL(11, pre_dec.time_since_epoch().count()); + + // Post-decrement returns the previous value. + TimePoint post_dec = tp--; + CHECK_EQUAL(11, post_dec.time_since_epoch().count()); + CHECK_EQUAL(10, tp.time_since_epoch().count()); + } + #if ETL_USING_ETL_CHRONO //************************************************************************* TEST(test_min_max_time_point)