From 9f39641d5b3f1666900eb7b7be88236711078ff6 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 5 Feb 2018 14:49:28 +0100 Subject: [PATCH] add more struct timespec/Time formatters Add formatters for durations: * format_sec_msec: ``1s 337ms'', and * format_min_sec_msec: ``1m3.370s'' (following time(1)). Also only use string option types when there is actually an error path under our control (e. g. with snprintf(3)). (NB the omnipresent to_string() does not propagate formatting errors upward so the wrappers we have for it return a plain string.) --- src/timefunc.cpp | 33 ++++++++++++++++++++++++++++++--- src/timefunc.hxx | 29 +++++++++++++++++++++++++---- test/test_timefunc.cpp | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/src/timefunc.cpp b/src/timefunc.cpp index f111763..0d2ee5d 100644 --- a/src/timefunc.cpp +++ b/src/timefunc.cpp @@ -24,6 +24,7 @@ on this file might be covered by the GNU General Public License. * */ +#include #include #include #include @@ -982,6 +983,32 @@ scan_iso8601 (const char *s, return tm; } +/** + * @brief Format a \c struct timespec in the schema established by + * time(1): “3m14.159s”. + * + * @param ts The time spec to format. + * + * @return \c boost:none in case of error during formatting, an optional + * \c std::string otherwise. + */ +boost::optional +format_min_sec_msec (const struct timespec &ts) +{ + char ms [4] = { '\0', '\0', '\0', '\0' }; + + if (snprintf (ms, 4, "%0.3ld", ts.tv_nsec / 1000000) < 0) { + return boost::none; + } + + const time_t min = ts.tv_sec / 60; + const time_t sec = ts.tv_sec - min * 60; + + return I2n::to_string (min) + "m" + + I2n::to_string (sec) + "." + + ms + "s" + ; +} namespace I2n { @@ -1213,18 +1240,18 @@ namespace clock { return ::format_iso8601 (tm, date, time, tz); } - boost::optional + std::string Time::make_nice_time (void) const { /* XXX the cast below results in loss of precision with 64 bit time_t! */ return ::make_nice_time (static_cast (this->value.tv_sec)); } - boost::optional + std::string Time::format_full_time (void) const { return ::format_full_time (this->value.tv_sec); } - boost::optional + std::string Time::format_date (void) const { return ::format_date (this->value.tv_sec); } diff --git a/src/timefunc.hxx b/src/timefunc.hxx index 159d0ec..5fd4911 100644 --- a/src/timefunc.hxx +++ b/src/timefunc.hxx @@ -60,11 +60,21 @@ std::string format_iso8601(const struct tm &tm, const bool date=true, std::string format_iso8601(time_t t, const bool utc=true, const bool date=true, const bool time=true, const bool tz=true); -inline std::string format_iso8601(const struct timespec ts, const bool utc=true, + +inline std::string format_iso8601(const struct timespec &ts, const bool utc=true, const bool date=true, const bool time=true, const bool tz=true) { return format_iso8601 (ts.tv_sec, utc, date, time, tz); } +inline std::string format_sec_msec (const struct timespec &ts) +{ + return I2n::to_string (ts.tv_sec) + "s " + + I2n::to_string (ts.tv_nsec / 1000000) + "ms" + ; +} + +boost::optional format_min_sec_msec (const struct timespec &ts); + boost::optional scan_iso8601 (const char *s, const bool date=true, const bool time=true, const bool tz=true) NOEXCEPT; @@ -404,6 +414,9 @@ namespace clock { inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT { return this->value.tv_nsec; } + inline CONSTEXPR const long get_msec (void) const NOEXCEPT + { return this->get_nsec () / 1000000; } + int64_t as_nanosec (void) const NOEXCEPT; long as_nanosec_L (void) const NOEXCEPT; @@ -550,9 +563,17 @@ namespace clock { const bool time = true, const bool tz = true) const; - boost::optional make_nice_time (void) const; - boost::optional format_full_time (void) const; - boost::optional format_date (void) const; + std::string make_nice_time (void) const; + std::string format_full_time (void) const; + std::string format_date (void) const; + + inline std::string + format_sec_msec (void) const + { return ::format_sec_msec (this->value); } + + inline boost::optional + format_min_sec_msec (void) const + { return ::format_min_sec_msec (this->value); } }; /* [class Time] */ diff --git a/test/test_timefunc.cpp b/test/test_timefunc.cpp index d286e50..827d128 100644 --- a/test/test_timefunc.cpp +++ b/test/test_timefunc.cpp @@ -975,6 +975,42 @@ BOOST_AUTO_TEST_SUITE(Clock) BOOST_CHECK_GT( t2, *t1); } + BOOST_AUTO_TEST_CASE(Format_sec_msec) + { + I2n::clock::Time t1 (42, 42); + I2n::clock::Time t2 ( 4, 242424242); + I2n::clock::Time t3 ( 0, 133713371); + I2n::clock::Time t4 ( 0, 0); + + std::string s1 = t1.format_sec_msec (); + std::string s2 = t2.format_sec_msec (); + std::string s3 = t3.format_sec_msec (); + std::string s4 = t4.format_sec_msec (); + + BOOST_CHECK_EQUAL("42s 0ms" , s1); + BOOST_CHECK_EQUAL( "4s 242ms", s2); + BOOST_CHECK_EQUAL( "0s 133ms", s3); + BOOST_CHECK_EQUAL( "0s 0ms" , s4); + } + + BOOST_AUTO_TEST_CASE(Format_min_sec_msec) + { + I2n::clock::Time t1 (42*60 + 42, 42); + I2n::clock::Time t2 ( 4*60 + 42, 242424242); + I2n::clock::Time t3 ( 0*60 + 42, 133713371); + I2n::clock::Time t4 ( 0 + 0, 0); + + std::string s1 = *t1.format_min_sec_msec (); + std::string s2 = *t2.format_min_sec_msec (); + std::string s3 = *t3.format_min_sec_msec (); + std::string s4 = *t4.format_min_sec_msec (); + + BOOST_CHECK_EQUAL("42m42.000s", s1); + BOOST_CHECK_EQUAL( "4m42.242s", s2); + BOOST_CHECK_EQUAL( "0m42.133s", s3); + BOOST_CHECK_EQUAL( "0m0.000s", s4); + } + BOOST_AUTO_TEST_CASE(FormatISO8601_T) { I2n::clock::Time t (42, 42); -- 1.7.1