From 2d3bba9e01b59e99c5656faa57029fc4f20ada93 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Thu, 8 Aug 2024 22:43:42 +0300 Subject: [PATCH] utils: more duration types and shorter uptime string --- code/espurna/datetime.h | 11 +++++---- code/espurna/types.h | 10 +++++--- code/espurna/utils.cpp | 38 +++++++++++++++++++++++------- code/test/unit/src/utils/utils.cpp | 23 ++++++++++++++++++ 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/code/espurna/datetime.h b/code/espurna/datetime.h index 91e57af1..c303329f 100644 --- a/code/espurna/datetime.h +++ b/code/espurna/datetime.h @@ -19,10 +19,13 @@ Copyright (C) 2024 by Maxim Prokhorov namespace espurna { namespace datetime { -using Days = std::chrono::duration >; -using Hours = std::chrono::duration >; -using Minutes = std::chrono::duration >; -using Seconds = std::chrono::duration; +using rep_type = time_t; + +using Seconds = std::chrono::duration; +using Minutes = std::chrono::duration >; +using Hours = std::chrono::duration >; +using Days = std::chrono::duration >; +using Weeks = std::chrono::duration >; // TODO import std::chrono::{floor,ceil,trunc} diff --git a/code/espurna/types.h b/code/espurna/types.h index 350c1273..72cf84e0 100644 --- a/code/espurna/types.h +++ b/code/espurna/types.h @@ -27,9 +27,13 @@ using Milliseconds = std::chrono::duration; // Our own helper types, a lot of things are based off of the `millis()` // (and it can be seamlessly used with any Core functions accepting u32 millisecond inputs) -using Seconds = std::chrono::duration >; -using Minutes = std::chrono::duration >; -using Hours = std::chrono::duration >; +using rep_type = uint32_t; + +using Seconds = std::chrono::duration >; +using Minutes = std::chrono::duration >; +using Hours = std::chrono::duration >; +using Days = std::chrono::duration >; +using Weeks = std::chrono::duration >; } // namespace duration diff --git a/code/espurna/utils.cpp b/code/espurna/utils.cpp index 379d414e..0ef78e30 100644 --- a/code/espurna/utils.cpp +++ b/code/espurna/utils.cpp @@ -132,17 +132,39 @@ bool tryParseIdPath(espurna::StringView value, size_t limit, size_t& out) { return false; } +static void prettyDurationImpl(char suffix, String& out, espurna::duration::rep_type value) { + if (value > 0) { + if (out.length()) { + out += ' '; + } + + out += String(value) + suffix; + } +} + +template +static void prettyDurationAppend(char suffix, String& out, espurna::duration::Seconds& seconds) { + const auto value = std::chrono::duration_cast(seconds); + prettyDurationImpl(suffix, out, value.count()); + seconds -= value; +} + String prettyDuration(espurna::duration::Seconds seconds) { - time_t timestamp = static_cast(seconds.count()); - tm spec; - gmtime_r(×tamp, &spec); + String out; - char buffer[64]; - sprintf_P(buffer, PSTR("%02dy %02dd %02dh %02dm %02ds"), - (spec.tm_year - 70), spec.tm_yday, spec.tm_hour, - spec.tm_min, spec.tm_sec); + if (seconds > seconds.zero()) { + using namespace espurna::duration; + prettyDurationAppend('w', out, seconds); + prettyDurationAppend('d', out, seconds); + prettyDurationAppend('h', out, seconds); + prettyDurationAppend('m', out, seconds); - return String(buffer); + prettyDurationImpl('s', out, seconds.count()); + } else { + out += "0s"; + } + + return out; } // ----------------------------------------------------------------------------- diff --git a/code/test/unit/src/utils/utils.cpp b/code/test/unit/src/utils/utils.cpp index 783fe424..e5c37acc 100644 --- a/code/test/unit/src/utils/utils.cpp +++ b/code/test/unit/src/utils/utils.cpp @@ -9,6 +9,28 @@ namespace espurna { namespace test { namespace { +void test_pretty_duration() { + const duration::Seconds one = + duration::Days{5} + + duration::Hours{15} + + duration::Minutes{30} + + duration::Seconds{45}; + + TEST_ASSERT_EQUAL_STRING("5d 15h 30m 45s", + prettyDuration(one).c_str()); + + const duration::Seconds two = + duration::Days{5} + + duration::Hours{15}; + + TEST_ASSERT_EQUAL_STRING("5d 15h", + prettyDuration(two).c_str()); + + const auto three = duration::Seconds{0}; + TEST_ASSERT_EQUAL_STRING("0s", + prettyDuration(three).c_str()); +} + void test_parse_unsigned_result() { const auto result = parseUnsigned(""); using Value = std::is_same; @@ -62,6 +84,7 @@ void test_parse_unsigned_prefix() { int main(int, char**) { UNITY_BEGIN(); using namespace espurna::test; + RUN_TEST(test_pretty_duration); RUN_TEST(test_parse_unsigned_result); RUN_TEST(test_parse_unsigned_value); RUN_TEST(test_parse_unsigned_overflow);