Fix output unit for Time::operator<<
[libi2ncommon] / src / timefunc.hxx
index 1b9df92..3cb34ad 100644 (file)
@@ -30,6 +30,7 @@ on this file might be covered by the GNU General Public License.
 #include <errno.h>
 #include <list>
 #include <string>
+#include <cstdlib>
 
 #include <boost/optional.hpp>
 
@@ -59,11 +60,31 @@ 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;
+inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
+                                                const bool date=true,
+                                                const bool time=true,
+                                                const bool tz=true) NOEXCEPT
+{ return scan_iso8601 (s.c_str (), date, time, tz); }
+
+
 void seconds_to_hour_minute(int seconds, int *hour, int *minute);
 void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
 std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
@@ -243,6 +264,26 @@ namespace I2n {
 
 namespace clock {
 
+    class conversion_error : public std::exception
+    {
+        public:
+            const int         err;
+            const std::string context;
+
+            conversion_error (const int err, const std::string &context)
+                : err     (err)
+                , context (context)
+            { }
+
+            virtual ~conversion_error (void) throw() { };
+
+            operator std::string (void)
+            {
+                return std::string ("errno=") + I2n::to_string (this->err)
+                     + " [" + this->context + "]";
+            }
+    };
+
     namespace {
 
         /* helper for ctor initializer list; we still lack aggregate initializers */
@@ -303,7 +344,7 @@ namespace clock {
              *
              * POSIX defines the ns part as *long*. Technically, that means
              * that on machines where *sizeof long* equals *sizeof int*, it can
-             * represent only up to arund 2.1 seconds. In this range, the loop
+             * represent only up to around 2.1 seconds. In this range, the loop
              * version is most likely faster than division. However, since in
              * practice *long* is 8 bytes just about anywhere, we have to
              * handle greater dividends first.
@@ -344,17 +385,23 @@ namespace clock {
                 , err     (t.err)
             { }
 
-            inline Time (const time_t sec,
-                         const long               nsec = 0,
-                         const enum type::id      id   = type::mono,
-                         const enum type::variant var  = type::dflt,
-                         const int                err  = 0) NOEXCEPT
+            inline
+            Time (const time_t sec,
+                  const long               nsec = 0,
+                  const enum type::id      id   = type::mono,
+                  const enum type::variant var  = type::dflt,
+                  const int                err  = 0) NOEXCEPT
                 : value   (timespec_of_parts (sec, nsec))
                 , id      (id)
                 , variant (var)
                 , err     (err)
             { this->carry_nsec (); }
 
+            explicit
+            Time (const struct tm          &tm,
+                  const enum type::id       id  = type::mono,
+                  const enum type::variant  var = type::dflt);
+
         /* value read access *************************************************/
         public:
 
@@ -367,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;
@@ -431,7 +481,9 @@ namespace clock {
             inline Time &subtract (const time_t t2) NOEXCEPT
             { return this->subtract (t2, 0L); };
 
-            Time &scale (const time_t factor) NOEXCEPT;
+            Time &scale (const int64_t factor) NOEXCEPT;
+
+            Time &divide (const int64_t divisor) NOEXCEPT;
 
             friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
 
@@ -475,13 +527,21 @@ namespace clock {
             { return this->subtract (t2); }
 
             inline Time
-            operator* (const time_t factor) const NOEXCEPT
+            operator* (const int64_t factor) const NOEXCEPT
             { return Time (*this).scale (factor); }
 
             inline Time &
-            operator*= (const time_t factor) NOEXCEPT
+            operator*= (const int64_t factor) NOEXCEPT
             { return this->scale (factor); }
 
+            inline Time
+            operator/ (const int64_t divisor) const NOEXCEPT
+            { return Time (*this).divide (divisor); }
+
+            inline Time &
+            operator/= (const int64_t divisor) NOEXCEPT
+            { return this->divide (divisor); }
+
             friend CONSTEXPR bool
             operator== (const Time &t1, const Time &t2) NOEXCEPT;
 
@@ -503,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] */
 
@@ -517,6 +585,10 @@ namespace clock {
     operator- (const time_t t1, const Time &t2) NOEXCEPT
     { return Time (t1) - t2; }
 
+    inline Time
+    operator* (const time_t t1, const Time &t2) NOEXCEPT
+    { return t2 * t1; }
+
     int compare (const Time &t1, const Time &t2) NOEXCEPT;
 
     /*
@@ -554,7 +626,7 @@ namespace clock {
     inline std::ostream &
     operator<< (std::ostream &os, const Time &t)
     {
-        os << I2n::to_string (t.value.tv_sec)  << "ms, "
+        os << I2n::to_string (t.value.tv_sec)  << "s, "
            << I2n::to_string (t.value.tv_nsec) << "ns"
            ;
 
@@ -569,6 +641,51 @@ namespace clock {
     zero (const enum type::id      id  = type::mono,
           const enum type::variant var = type::dflt) NOEXCEPT;
 
+    boost::optional<Time>
+    time_of_iso8601 (const std::string        &s,
+                     const bool                date = true,
+                     const bool                time = true,
+                     const bool                tz   = true,
+                     const enum type::id       id   = type::real,
+                     const enum type::variant  var  = type::dflt) NOEXCEPT;
+
+    template <typename ContT>
+    Time
+    mean (const ContT &data)
+    {
+        Time sum (0, 0);
+
+        if (data.size () == 0) {
+            return sum;
+        }
+
+        for (typename ContT::const_iterator it = data.begin ();
+             it != data.end (); ++it)
+        {
+            sum += *it;
+        };
+
+        return sum.divide (static_cast<int64_t> (data.size ()));
+    };
+
+    template <typename ContT>
+    Time
+    median (const ContT &data)
+    {
+        if (data.size () == 0) {
+            return zero ();
+        }
+        if (data.size () == 1) {
+            return *data.begin ();
+        }
+
+        std::vector<typename ContT::value_type> sorted;
+        std::copy (data.begin (), data.end (), std::back_inserter (sorted));
+        std::sort (sorted.begin (), sorted.end ());
+
+        return sorted [data.size () / 2];
+    };
+
 } /* [namespace clock] */
 
 } /* [namespace I2n] */