add more struct timespec/Time formatters
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Mon, 5 Feb 2018 13:49:28 +0000 (14:49 +0100)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 27 Mar 2019 09:31:38 +0000 (10:31 +0100)
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
src/timefunc.hxx
test/test_timefunc.cpp

index f111763..0d2ee5d 100644 (file)
@@ -24,6 +24,7 @@ on this file might be covered by the GNU General Public License.
  *
  */
 
+#include <cstdio>
 #include <errno.h>
 #include <string>
 #include <sstream>
@@ -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<std::string>
+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>
+    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<int> (this->value.tv_sec));
     }
 
-    boost::optional<std::string>
+    std::string
     Time::format_full_time (void) const
     { return ::format_full_time (this->value.tv_sec); }
 
-    boost::optional<std::string>
+    std::string
     Time::format_date (void) const
     { return ::format_date (this->value.tv_sec); }
 
index 159d0ec..5fd4911 100644 (file)
@@ -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<std::string> format_min_sec_msec (const struct timespec &ts);
+
 boost::optional<struct tm> 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<std::string> make_nice_time (void) const;
-            boost::optional<std::string> format_full_time (void) const;
-            boost::optional<std::string> 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<std::string>
+            format_min_sec_msec (void) const
+            { return ::format_min_sec_msec (this->value); }
 
     }; /* [class Time] */
 
index d286e50..827d128 100644 (file)
@@ -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);