2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
21 * @brief time related functions.
23 * @copyright Copyright © 2001-2018 by Intra2net AG
26 #ifndef __TIMEFUNC_HXX
27 #define __TIMEFUNC_HXX
36 #include <boost/optional.hpp>
40 #include "stringfunc.hxx"
42 #if __cplusplus >= 201103
43 # define CONSTEXPR constexpr
44 # define NOEXCEPT noexcept
50 #define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
52 double prec_time(void);
54 time_t date_to_seconds(const std::string &date);
56 std::string make_nice_time(int seconds);
57 std::string format_full_time(time_t seconds);
58 std::string format_date(time_t seconds);
59 std::string format_iso8601(const struct tm &tm, const bool date=true,
60 const bool time=true, const bool tz=true);
61 std::string format_iso8601(time_t t, const bool utc=true,
62 const bool date=true, const bool time=true,
65 inline std::string format_iso8601(const struct timespec &ts, const bool utc=true,
66 const bool date=true, const bool time=true,
68 { return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
70 inline std::string format_sec_msec (const struct timespec &ts)
72 return I2n::to_string (ts.tv_sec) + "s "
73 + I2n::to_string (ts.tv_nsec / 1000000) + "ms"
77 boost::optional<std::string> format_min_sec_msec (const struct timespec &ts);
79 boost::optional<struct tm> scan_iso8601 (const char *s,
80 const bool date=true, const bool time=true,
81 const bool tz=true) NOEXCEPT;
82 inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
85 const bool tz=true) NOEXCEPT
86 { return scan_iso8601 (s.c_str (), date, time, tz); }
89 void seconds_to_hour_minute(int seconds, int *hour, int *minute);
90 void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
91 std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
93 inline std::string output_hour_minute_from_seconds(int seconds)
96 split_daysec(seconds,&hour,&minute);
97 return output_hour_minute(hour,minute);
100 std::string get_month_name(unsigned char month);
103 * @brief structure representing a single (half-open) interval.
116 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
117 : m_lower_bound(start)
119 , m_weak_mark(weak_mark)
127 bool is_valid() const
129 return m_lower_bound <= m_upper_bound;
130 } // eo is_valid() const
134 return m_lower_bound == m_upper_bound;
135 } // eo empty() const
138 unsigned int lower_bound() const { return m_lower_bound; }
139 unsigned int upper_bound() const { return m_upper_bound; }
141 int weak_mark() const { return m_weak_mark; }
143 bool changed() const { return m_changed; }
146 bool operator== (const Interval& other) const
148 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
149 } // eo operator==(const Interval&)
152 bool operator!=(const Interval& other) const
154 return not (*this == other);
155 } // eo operator!=(const Interval&)
159 * @brief less operator. compares only the start times!
160 * @param other the other interval to compare with.
161 * @return @a true if the current start is less than the other start.
163 bool operator<(const Interval& other) const
165 return m_lower_bound < other.m_lower_bound;
166 } // eo operator<(const Interval&)
169 bool intersects(const Interval& other) const;
170 bool contains(const Interval& other) const;
175 friend class Intervals;
177 unsigned int m_lower_bound;
178 unsigned int m_upper_bound;
188 * @brief structure representing a combination of single disjoint (half open) intervals.
190 * Basic idea is that this structure provides an interface for adding and
191 * subtracting single intervals and keeps the internal list of intervals as
192 * a list of disjoint intervals.
194 * @note the list is sorted by the start; lower comes first.
196 * @note the class provides some methods similar to STL container classes;
197 * i.e. it can be used with (at least some) STL algorithms.
200 * we use a std::list for the intervals; this means we don't invalidate all
201 * iterators when we insert or delete within loops...
202 * And we use that fact!!
207 typedef std::list< Interval > IntervalList;
208 typedef IntervalList::value_type value_type;
209 typedef IntervalList::const_iterator const_iterator;
210 typedef IntervalList::const_iterator iterator; // we allow only const...
211 typedef IntervalList::size_type size_type;
216 void add(const Interval& new_frame);
217 void sub(const Interval& new_frame);
221 const_iterator begin() const { return m_intervals.begin(); }
222 const_iterator end() const { return m_intervals.end(); }
224 bool empty() const { return m_intervals.empty(); }
225 const Interval& front() const { return m_intervals.front(); }
226 const Interval& back() const { return m_intervals.back(); }
228 size_type size() const { return m_intervals.size(); }
230 bool intersects(const Interval& other) const;
231 bool intersects(const Intervals& other) const;
233 bool contains(const Interval& other) const;
234 bool contains(const Intervals& other) const;
236 bool contains_exact(const Interval& other) const;
238 bool operator==(const Intervals& other) const;
239 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
241 Intervals& operator+=(const Interval& other);
242 Intervals& operator-=(const Interval& other);
244 Intervals& operator+=(const Intervals& other);
245 Intervals& operator-=(const Intervals& other);
249 std::list< Interval > m_intervals;
259 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
260 long long monotonic_clock_gettime_nano();
262 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
268 class conversion_error : public std::exception
272 const std::string context;
274 conversion_error (const int err, const std::string &context)
279 virtual ~conversion_error (void) throw() { };
281 operator std::string (void)
283 return std::string ("errno=") + I2n::to_string (this->err)
284 + " [" + this->context + "]";
290 /* helper for ctor initializer list; we still lack aggregate initializers */
292 timespec_of_parts (const time_t sec, const long nsec)
294 struct timespec ret = { sec, nsec};
303 * represent the clock id options from clock_gettime(2) as
304 * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
305 * everywhere since that’s what we want in most cases.
308 mono, /* CLOCK_MONOTONIC_COARSE */
309 real, /* CLOCK_REALIME_COARSE */
310 boot, /* CLOCK_BOOTTIME */
311 cpu, /* CLOCK_CPUTIME_* */
315 * for clocks that support it: non-coarse or raw variants; if a variant
316 * does not apply to a given clock, it is ignored
320 exact, /* mono, real: not (*_COARSE) */
321 raw, /* mono: _RAW */
322 process, /* cpu: *_PROCESS_* */
323 thread, /* cpu: *_THREAD_* */
326 } /* [namespace type] */
332 struct timespec value;
336 enum type::variant variant;
341 * Handle decimal part (nanosecond) overflow; this is performed
342 * after arithmetic operations and whenever we there is the
343 * possibility of unsanitized input for example in constructors
344 * from other types and suchlike.
346 * POSIX defines the ns part as *long*. Technically, that means
347 * that on machines where *sizeof long* equals *sizeof int*, it can
348 * represent only up to around 2.1 seconds. In this range, the loop
349 * version is most likely faster than division. However, since in
350 * practice *long* is 8 bytes just about anywhere, we have to
351 * handle greater dividends first.
357 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
358 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
360 const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
361 this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
362 this->value.tv_sec += sec;
364 # endif /* [LONG_BIT > 32] */
365 while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
366 this->value.tv_sec += 1;
367 this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
370 while (this->value.tv_nsec < 0) {
371 this->value.tv_sec -= 1;
372 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
376 /* ctors *************************************************************/
379 Time (const enum type::id id = type::mono,
380 const enum type::variant var = type::dflt) NOEXCEPT;
382 inline Time (const Time &t) NOEXCEPT
385 , variant (t.variant)
390 Time (const time_t sec,
392 const enum type::id id = type::mono,
393 const enum type::variant var = type::dflt,
394 const int err = 0) NOEXCEPT
395 : value (timespec_of_parts (sec, nsec))
399 { this->carry_nsec (); }
402 Time (const struct tm &tm,
403 const enum type::id id = type::mono,
404 const enum type::variant var = type::dflt);
406 /* value read access *************************************************/
409 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
410 { return this->value; }
412 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
413 { return this->value.tv_sec; }
415 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
416 { return this->value.tv_nsec; }
418 inline CONSTEXPR const long get_msec (void) const NOEXCEPT
419 { return this->get_nsec () / 1000000; }
421 int64_t as_nanosec (void) const NOEXCEPT;
423 long as_nanosec_L (void) const NOEXCEPT;
425 /* value write access ************************************************/
429 swap (Time &t) NOEXCEPT
431 std::swap (this->value , t.value );
432 std::swap (this->id , t.id );
433 std::swap (this->variant, t.variant);
434 std::swap (this->err , t.err );
437 Time &operator= (Time t) NOEXCEPT;
439 Time &operator= (struct timespec ts) NOEXCEPT;
442 set (const struct timespec &ts) NOEXCEPT
449 set (const time_t sec,
451 const enum type::id id = type::mono,
452 const enum type::variant var = type::dflt) NOEXCEPT
454 this->value.tv_sec = sec;
455 this->value.tv_nsec = nsec;
462 bool set (void) NOEXCEPT;
464 void unset (void) NOEXCEPT;
466 /* arithmetic ********************************************************/
469 Time &add (const time_t sec, const long nsec) NOEXCEPT;
471 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
473 inline Time &add (const Time &t2) NOEXCEPT
474 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
476 inline Time &add (const time_t t2) NOEXCEPT
477 { return this->add (t2, 0L); };
479 inline Time &subtract (const Time &t2) NOEXCEPT
480 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
482 inline Time &subtract (const time_t t2) NOEXCEPT
483 { return this->subtract (t2, 0L); };
485 Time &scale (const int64_t factor) NOEXCEPT;
487 Time ÷ (const int64_t divisor) NOEXCEPT;
489 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
492 difference (const Time &t) NOEXCEPT
493 { return (*this < t) ? t - *this : *this - t; }
495 /* overloads *********************************************************/
499 operator+ (const Time &t2) const NOEXCEPT
500 { return Time (*this).add (t2); }
503 operator+ (const time_t t2) const NOEXCEPT
504 { return Time (*this).add (t2); }
507 operator+= (const Time &t2) NOEXCEPT
508 { return this->add (t2); }
511 operator+= (const time_t t2) NOEXCEPT
512 { return this->add (t2); }
515 operator- (const Time &t2) const NOEXCEPT
516 { return Time (*this).subtract (t2); }
519 operator- (const time_t t2) const NOEXCEPT
520 { return Time (*this).subtract (t2); }
523 operator-= (const Time &t2) NOEXCEPT
524 { return this->subtract (t2); }
527 operator-= (const time_t t2) NOEXCEPT
528 { return this->subtract (t2); }
531 operator* (const int64_t factor) const NOEXCEPT
532 { return Time (*this).scale (factor); }
535 operator*= (const int64_t factor) NOEXCEPT
536 { return this->scale (factor); }
539 operator/ (const int64_t divisor) const NOEXCEPT
540 { return Time (*this).divide (divisor); }
543 operator/= (const int64_t divisor) NOEXCEPT
544 { return this->divide (divisor); }
546 friend CONSTEXPR bool
547 operator== (const Time &t1, const Time &t2) NOEXCEPT;
549 friend CONSTEXPR bool
550 operator< (const Time &t1, const Time &t2) NOEXCEPT;
552 friend CONSTEXPR bool
553 operator> (const Time &t1, const Time &t2) NOEXCEPT;
555 friend std::ostream &
556 operator<< (std::ostream &os, const Time &t);
558 /* formatting ********************************************************/
561 boost::optional<std::string>
562 format_iso8601 (const bool utc = true,
563 const bool date = true,
564 const bool time = true,
565 const bool tz = true) const;
567 std::string make_nice_time (void) const;
568 std::string format_full_time (void) const;
569 std::string format_date (void) const;
572 format_sec_msec (void) const
573 { return ::format_sec_msec (this->value); }
575 inline boost::optional<std::string>
576 format_min_sec_msec (void) const
577 { return ::format_min_sec_msec (this->value); }
579 }; /* [class Time] */
582 operator+ (const time_t t1, const Time &t2) NOEXCEPT
583 { return Time (t1) + t2; }
586 operator- (const time_t t1, const Time &t2) NOEXCEPT
587 { return Time (t1) - t2; }
590 operator* (const time_t t1, const Time &t2) NOEXCEPT
593 int compare (const Time &t1, const Time &t2) NOEXCEPT;
596 * comparison for equality also considers the clock type;
598 inline CONSTEXPR bool
599 operator== (const Time &t1, const Time &t2) NOEXCEPT
601 return t1.id == t2.id && t1.variant == t2.variant
602 && t1.value.tv_sec == t2.value.tv_sec
603 && t1.value.tv_nsec == t2.value.tv_nsec
607 /* these ignore the *id* and *variant* fields */
608 inline CONSTEXPR bool
609 operator< (const Time &t1, const Time &t2) NOEXCEPT
611 return t1.value.tv_sec < t2.value.tv_sec
612 || ( t1.value.tv_sec == t2.value.tv_sec
613 && t1.value.tv_nsec < t2.value.tv_nsec)
617 /* these ignore the *id* and *variant* fields */
618 inline CONSTEXPR bool
619 operator> (const Time &t1, const Time &t2) NOEXCEPT
621 return t1.value.tv_sec > t2.value.tv_sec
622 || ( t1.value.tv_sec == t2.value.tv_sec
623 && t1.value.tv_nsec > t2.value.tv_nsec)
627 inline std::ostream &
628 operator<< (std::ostream &os, const Time &t)
630 os << I2n::to_string (t.value.tv_sec) << "s, "
631 << I2n::to_string (t.value.tv_nsec) << "ns"
637 boost::optional<Time>
638 now (const enum type::id id = type::mono,
639 const enum type::variant var = type::dflt) NOEXCEPT;
642 zero (const enum type::id id = type::mono,
643 const enum type::variant var = type::dflt) NOEXCEPT;
645 boost::optional<Time>
646 time_of_iso8601 (const std::string &s,
647 const bool date = true,
648 const bool time = true,
649 const bool tz = true,
650 const enum type::id id = type::real,
651 const enum type::variant var = type::dflt) NOEXCEPT;
653 template <typename ContT>
655 mean (const ContT &data)
659 if (data.size () == 0) {
663 for (typename ContT::const_iterator it = data.begin ();
664 it != data.end (); ++it)
669 return sum.divide (static_cast<int64_t> (data.size ()));
672 template <typename ContT>
674 median (const ContT &data)
676 if (data.size () == 0) {
679 if (data.size () == 1) {
680 return *data.begin ();
683 std::vector<typename ContT::value_type> sorted;
684 std::copy (data.begin (), data.end (), std::back_inserter (sorted));
685 std::sort (sorted.begin (), sorted.end ());
687 return sorted [data.size () / 2];
690 } /* [namespace clock] */
692 } /* [namespace I2n] */