-/***************************************************************************
- timecvt.hxx - description
- -------------------
- begin : Fri May 11 2001
- copyright : (C) 2001 by STYLETEC
- email : info@styletec.de
- ***************************************************************************/
+/*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
+/** @file
+ * @brief time related functions.
+ *
+ * @copyright Copyright © 2001-2018 by Intra2net AG
+ */
#ifndef __TIMEFUNC_HXX
#define __TIMEFUNC_HXX
-#include <bitset>
+#include <climits>
+#include <errno.h>
+#include <list>
+#include <string>
+#include <cstdlib>
+
+#include <boost/optional.hpp>
+
+#include <week.hpp>
+
+#include "stringfunc.hxx"
+
+#if __cplusplus >= 201103
+# define CONSTEXPR constexpr
+# define NOEXCEPT noexcept
+#else
+# define CONSTEXPR
+# define NOEXCEPT
+#endif
+
+#define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
double prec_time(void);
-int date_to_seconds(const std::string &date);
+time_t date_to_seconds(const std::string &date);
std::string make_nice_time(int seconds);
-std::string format_full_time(int seconds);
+std::string format_full_time(time_t seconds);
+std::string format_date(time_t seconds);
+std::string format_iso8601(const struct tm &tm, const bool date=true,
+ const bool time=true, const bool tz=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,
+ 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);
-std::string output_hour_minute(int hour, int minute, bool h_for_00=true);
+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);
inline std::string output_hour_minute_from_seconds(int seconds)
{
int hour, minute;
- seconds_to_hour_minute(seconds,&hour,&minute);
+ split_daysec(seconds,&hour,&minute);
return output_hour_minute(hour,minute);
}
-class WEEK
+std::string get_month_name(unsigned char month);
+
+/**
+ * @brief structure representing a single (half-open) interval.
+ */
+class Interval
{
- private:
- std::bitset<7> days;
+ public:
+ Interval()
+ : m_lower_bound(0)
+ , m_upper_bound(0)
+ , m_weak_mark(0)
+ , m_changed(false)
+ {
+ } //
+
+ Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
+ : m_lower_bound(start)
+ , m_upper_bound(end)
+ , m_weak_mark(weak_mark)
+ , m_changed(false)
+ {
+ } //
+
+
+ void clear();
+
+ bool is_valid() const
+ {
+ return m_lower_bound <= m_upper_bound;
+ } // eo is_valid() const
+
+ bool empty() const
+ {
+ return m_lower_bound == m_upper_bound;
+ } // eo empty() const
+
+
+ unsigned int lower_bound() const { return m_lower_bound; }
+ unsigned int upper_bound() const { return m_upper_bound; }
+
+ int weak_mark() const { return m_weak_mark; }
+
+ bool changed() const { return m_changed; }
+
+
+ bool operator== (const Interval& other) const
+ {
+ return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
+ } // eo operator==(const Interval&)
+
+
+ bool operator!=(const Interval& other) const
+ {
+ return not (*this == other);
+ } // eo operator!=(const Interval&)
+
+
+ /**
+ * @brief less operator. compares only the start times!
+ * @param other the other interval to compare with.
+ * @return @a true if the current start is less than the other start.
+ */
+ bool operator<(const Interval& other) const
+ {
+ return m_lower_bound < other.m_lower_bound;
+ } // eo operator<(const Interval&)
+
+
+ bool intersects(const Interval& other) const;
+ bool contains(const Interval& other) const;
+
+
+ protected:
+
+ friend class Intervals;
+
+ unsigned int m_lower_bound;
+ unsigned int m_upper_bound;
+ int m_weak_mark;
+ bool m_changed;
+
+}; // eo Interval
+
+
+
+/**
+ * @brief structure representing a combination of single disjoint (half open) intervals.
+ *
+ * Basic idea is that this structure provides an interface for adding and
+ * subtracting single intervals and keeps the internal list of intervals as
+ * a list of disjoint intervals.
+ *
+ * @note the list is sorted by the start; lower comes first.
+ *
+ * @note the class provides some methods similar to STL container classes;
+ * i.e. it can be used with (at least some) STL algorithms.
+ *
+ * @internal
+ * we use a std::list for the intervals; this means we don't invalidate all
+ * iterators when we insert or delete within loops...
+ * And we use that fact!!
+ */
+class Intervals
+{
public:
- enum WEEKDAY { SU=0, MO=1, TU=2, WE=3, TH=4, FR=5, SA=6 };
-
- // throws out_of_range if illegal week
- WEEK(const std::string& daystring);
-
- WEEK(const std::bitset<7> &days)
- : days(days)
+ typedef std::list< Interval > IntervalList;
+ typedef IntervalList::value_type value_type;
+ typedef IntervalList::const_iterator const_iterator;
+ typedef IntervalList::const_iterator iterator; // we allow only const...
+ typedef IntervalList::size_type size_type;
+
+ public:
+ Intervals();
+
+ void add(const Interval& new_frame);
+ void sub(const Interval& new_frame);
+
+ void clear();
+
+ const_iterator begin() const { return m_intervals.begin(); }
+ const_iterator end() const { return m_intervals.end(); }
+
+ bool empty() const { return m_intervals.empty(); }
+ const Interval& front() const { return m_intervals.front(); }
+ const Interval& back() const { return m_intervals.back(); }
+
+ size_type size() const { return m_intervals.size(); }
+
+ bool intersects(const Interval& other) const;
+ bool intersects(const Intervals& other) const;
+
+ bool contains(const Interval& other) const;
+ bool contains(const Intervals& other) const;
+
+ bool contains_exact(const Interval& other) const;
+
+ bool operator==(const Intervals& other) const;
+ bool operator!=(const Intervals& other) const { return not (*this == other) ; }
+
+ Intervals& operator+=(const Interval& other);
+ Intervals& operator-=(const Interval& other);
+
+ Intervals& operator+=(const Intervals& other);
+ Intervals& operator-=(const Intervals& other);
+
+ protected:
+
+ std::list< Interval > m_intervals;
+
+}; // eo Intervals
+
+
+/*
+** clock funcs:
+*/
+
+
+bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
+long long monotonic_clock_gettime_nano();
+
+bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
+
+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)
{ }
-
- WEEK()
+
+ 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 */
+ struct timespec
+ timespec_of_parts (const time_t sec, const long nsec)
+ {
+ struct timespec ret = { sec, nsec};
+
+ return ret;
+ }
+
+ } /* [namespace] */
+
+ namespace type {
+ /*
+ * represent the clock id options from clock_gettime(2) as
+ * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
+ * everywhere since that’s what we want in most cases.
+ */
+ enum id {
+ mono, /* CLOCK_MONOTONIC_COARSE */
+ real, /* CLOCK_REALIME_COARSE */
+ boot, /* CLOCK_BOOTTIME */
+ cpu, /* CLOCK_CPUTIME_* */
+ };
+
+ /*
+ * for clocks that support it: non-coarse or raw variants; if a variant
+ * does not apply to a given clock, it is ignored
+ */
+ enum variant {
+ dflt, /* all */
+ exact, /* mono, real: not (*_COARSE) */
+ raw, /* mono: _RAW */
+ process, /* cpu: *_PROCESS_* */
+ thread, /* cpu: *_THREAD_* */
+ };
+
+ } /* [namespace type] */
+
+
+ class Time {
+
+ private:
+ struct timespec value;
+
+ public:
+ enum type::id id;
+ enum type::variant variant;
+ int err;
+
+ private:
+ /*
+ * Handle decimal part (nanosecond) overflow; this is performed
+ * after arithmetic operations and whenever we there is the
+ * possibility of unsanitized input for example in constructors
+ * from other types and suchlike.
+ *
+ * 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 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.
+ */
+ inline void
+ carry_nsec (void)
+ {
+# if LONG_BIT > 32
+ if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
+ || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
+ {
+ const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
+ this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
+ this->value.tv_sec += sec;
+ }
+# endif /* [LONG_BIT > 32] */
+ while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
+ this->value.tv_sec += 1;
+ this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
+ }
+
+ while (this->value.tv_nsec < 0) {
+ this->value.tv_sec -= 1;
+ this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
+ }
+ }
+
+ /* ctors *************************************************************/
+ public:
+
+ Time (const enum type::id id = type::mono,
+ const enum type::variant var = type::dflt) NOEXCEPT;
+
+ inline Time (const Time &t) NOEXCEPT
+ : value (t.value)
+ , id (t.id)
+ , variant (t.variant)
+ , err (t.err)
{ }
-
- void clear()
- { days.reset(); }
-
- operator std::bitset<7>() const
- { return days; }
-
- std::string get_daystring() const;
- std::string get_displaystring() const;
- std::string get_netfilterstring() const;
-
- static std::string get_day_display(WEEKDAY day);
- static std::string get_english_display(WEEKDAY day);
-};
+
+ 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:
+
+ inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
+ { return this->value; }
+
+ inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
+ { return this->value.tv_sec; }
+
+ 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;
+
+ /* value write access ************************************************/
+ public:
+
+ inline void
+ swap (Time &t) NOEXCEPT
+ {
+ std::swap (this->value , t.value );
+ std::swap (this->id , t.id );
+ std::swap (this->variant, t.variant);
+ std::swap (this->err , t.err );
+ }
+
+ Time &operator= (Time t) NOEXCEPT;
+
+ Time &operator= (struct timespec ts) NOEXCEPT;
+
+ inline void
+ set (const struct timespec &ts) NOEXCEPT
+ {
+ this->value = ts;
+ this->carry_nsec ();
+ }
+
+ inline void
+ set (const time_t sec,
+ const long nsec,
+ const enum type::id id = type::mono,
+ const enum type::variant var = type::dflt) NOEXCEPT
+ {
+ this->value.tv_sec = sec;
+ this->value.tv_nsec = nsec;
+ this->id = id;
+ this->variant = var;
+
+ this->carry_nsec ();
+ }
+
+ bool set (void) NOEXCEPT;
+
+ void unset (void) NOEXCEPT;
+
+ /* arithmetic ********************************************************/
+ public:
+
+ Time &add (const time_t sec, const long nsec) NOEXCEPT;
+
+ Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
+
+ inline Time &add (const Time &t2) NOEXCEPT
+ { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
+
+ inline Time &add (const time_t t2) NOEXCEPT
+ { return this->add (t2, 0L); };
+
+ inline Time &subtract (const Time &t2) NOEXCEPT
+ { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
+
+ inline Time &subtract (const time_t t2) NOEXCEPT
+ { return this->subtract (t2, 0L); };
+
+ Time &scale (const int64_t factor) NOEXCEPT;
+
+ Time ÷ (const int64_t divisor) NOEXCEPT;
+
+ friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
+
+ inline Time
+ difference (const Time &t) NOEXCEPT
+ { return (*this < t) ? t - *this : *this - t; }
+
+ /* overloads *********************************************************/
+ public:
+
+ inline Time
+ operator+ (const Time &t2) const NOEXCEPT
+ { return Time (*this).add (t2); }
+
+ inline Time
+ operator+ (const time_t t2) const NOEXCEPT
+ { return Time (*this).add (t2); }
+
+ inline Time &
+ operator+= (const Time &t2) NOEXCEPT
+ { return this->add (t2); }
+
+ inline Time &
+ operator+= (const time_t t2) NOEXCEPT
+ { return this->add (t2); }
+
+ inline Time
+ operator- (const Time &t2) const NOEXCEPT
+ { return Time (*this).subtract (t2); }
+
+ inline Time
+ operator- (const time_t t2) const NOEXCEPT
+ { return Time (*this).subtract (t2); }
+
+ inline Time &
+ operator-= (const Time &t2) NOEXCEPT
+ { return this->subtract (t2); }
+
+ inline Time &
+ operator-= (const time_t t2) NOEXCEPT
+ { return this->subtract (t2); }
+
+ inline Time
+ operator* (const int64_t factor) const NOEXCEPT
+ { return Time (*this).scale (factor); }
+
+ inline Time &
+ 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;
+
+ friend CONSTEXPR bool
+ operator< (const Time &t1, const Time &t2) NOEXCEPT;
+
+ friend CONSTEXPR bool
+ operator> (const Time &t1, const Time &t2) NOEXCEPT;
+
+ friend std::ostream &
+ operator<< (std::ostream &os, const Time &t);
+
+ /* formatting ********************************************************/
+ public:
+
+ boost::optional<std::string>
+ format_iso8601 (const bool utc = true,
+ const bool date = true,
+ const bool time = true,
+ const bool tz = true) 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] */
+
+ inline Time
+ 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 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;
+
+ /*
+ * comparison for equality also considers the clock type;
+ */
+ inline CONSTEXPR bool
+ operator== (const Time &t1, const Time &t2) NOEXCEPT
+ {
+ return t1.id == t2.id && t1.variant == t2.variant
+ && t1.value.tv_sec == t2.value.tv_sec
+ && t1.value.tv_nsec == t2.value.tv_nsec
+ ;
+ }
+
+ /* these ignore the *id* and *variant* fields */
+ inline CONSTEXPR bool
+ operator< (const Time &t1, const Time &t2) NOEXCEPT
+ {
+ return t1.value.tv_sec < t2.value.tv_sec
+ || ( t1.value.tv_sec == t2.value.tv_sec
+ && t1.value.tv_nsec < t2.value.tv_nsec)
+ ;
+ }
+
+ /* these ignore the *id* and *variant* fields */
+ inline CONSTEXPR bool
+ operator> (const Time &t1, const Time &t2) NOEXCEPT
+ {
+ return t1.value.tv_sec > t2.value.tv_sec
+ || ( t1.value.tv_sec == t2.value.tv_sec
+ && t1.value.tv_nsec > t2.value.tv_nsec)
+ ;
+ }
+
+ inline std::ostream &
+ operator<< (std::ostream &os, const Time &t)
+ {
+ os << I2n::to_string (t.value.tv_sec) << "s, "
+ << I2n::to_string (t.value.tv_nsec) << "ns"
+ ;
+
+ return os;
+ }
+
+ boost::optional<Time>
+ now (const enum type::id id = type::mono,
+ const enum type::variant var = type::dflt) NOEXCEPT;
+
+ Time
+ 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] */
+
#endif