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
35 #include <boost/optional.hpp>
39 #include "stringfunc.hxx"
41 #if __cplusplus >= 201103
42 # define CONSTEXPR constexpr
43 # define NOEXCEPT noexcept
49 #define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
51 double prec_time(void);
53 time_t date_to_seconds(const std::string &date);
55 std::string make_nice_time(int seconds);
56 std::string format_full_time(time_t seconds);
57 std::string format_date(time_t seconds);
58 std::string format_iso8601(const struct tm &tm, const bool date=true,
59 const bool time=true, const bool tz=true);
60 std::string format_iso8601(time_t t, const bool utc=true,
61 const bool date=true, const bool time=true,
64 inline std::string format_iso8601(const struct timespec &ts, const bool utc=true,
65 const bool date=true, const bool time=true,
67 { return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
69 inline std::string format_sec_msec (const struct timespec &ts)
71 return I2n::to_string (ts.tv_sec) + "s "
72 + I2n::to_string (ts.tv_nsec / 1000000) + "ms"
76 boost::optional<std::string> format_min_sec_msec (const struct timespec &ts);
78 boost::optional<struct tm> scan_iso8601 (const char *s,
79 const bool date=true, const bool time=true,
80 const bool tz=true) NOEXCEPT;
81 inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
84 const bool tz=true) NOEXCEPT
85 { return scan_iso8601 (s.c_str (), date, time, tz); }
88 void seconds_to_hour_minute(int seconds, int *hour, int *minute);
89 void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
90 std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
92 inline std::string output_hour_minute_from_seconds(int seconds)
95 split_daysec(seconds,&hour,&minute);
96 return output_hour_minute(hour,minute);
99 std::string get_month_name(unsigned char month);
102 * @brief structure representing a single (half-open) interval.
115 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
116 : m_lower_bound(start)
118 , m_weak_mark(weak_mark)
126 bool is_valid() const
128 return m_lower_bound <= m_upper_bound;
129 } // eo is_valid() const
133 return m_lower_bound == m_upper_bound;
134 } // eo empty() const
137 unsigned int lower_bound() const { return m_lower_bound; }
138 unsigned int upper_bound() const { return m_upper_bound; }
140 int weak_mark() const { return m_weak_mark; }
142 bool changed() const { return m_changed; }
145 bool operator== (const Interval& other) const
147 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
148 } // eo operator==(const Interval&)
151 bool operator!=(const Interval& other) const
153 return not (*this == other);
154 } // eo operator!=(const Interval&)
158 * @brief less operator. compares only the start times!
159 * @param other the other interval to compare with.
160 * @return @a true if the current start is less than the other start.
162 bool operator<(const Interval& other) const
164 return m_lower_bound < other.m_lower_bound;
165 } // eo operator<(const Interval&)
168 bool intersects(const Interval& other) const;
169 bool contains(const Interval& other) const;
174 friend class Intervals;
176 unsigned int m_lower_bound;
177 unsigned int m_upper_bound;
187 * @brief structure representing a combination of single disjoint (half open) intervals.
189 * Basic idea is that this structure provides an interface for adding and
190 * subtracting single intervals and keeps the internal list of intervals as
191 * a list of disjoint intervals.
193 * @note the list is sorted by the start; lower comes first.
195 * @note the class provides some methods similar to STL container classes;
196 * i.e. it can be used with (at least some) STL algorithms.
199 * we use a std::list for the intervals; this means we don't invalidate all
200 * iterators when we insert or delete within loops...
201 * And we use that fact!!
206 typedef std::list< Interval > IntervalList;
207 typedef IntervalList::value_type value_type;
208 typedef IntervalList::const_iterator const_iterator;
209 typedef IntervalList::const_iterator iterator; // we allow only const...
210 typedef IntervalList::size_type size_type;
215 void add(const Interval& new_frame);
216 void sub(const Interval& new_frame);
220 const_iterator begin() const { return m_intervals.begin(); }
221 const_iterator end() const { return m_intervals.end(); }
223 bool empty() const { return m_intervals.empty(); }
224 const Interval& front() const { return m_intervals.front(); }
225 const Interval& back() const { return m_intervals.back(); }
227 size_type size() const { return m_intervals.size(); }
229 bool intersects(const Interval& other) const;
230 bool intersects(const Intervals& other) const;
232 bool contains(const Interval& other) const;
233 bool contains(const Intervals& other) const;
235 bool contains_exact(const Interval& other) const;
237 bool operator==(const Intervals& other) const;
238 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
240 Intervals& operator+=(const Interval& other);
241 Intervals& operator-=(const Interval& other);
243 Intervals& operator+=(const Intervals& other);
244 Intervals& operator-=(const Intervals& other);
248 std::list< Interval > m_intervals;
258 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
259 long long monotonic_clock_gettime_nano();
261 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
267 class conversion_error : public std::exception
271 const std::string context;
273 conversion_error (const int err, const std::string &context)
278 virtual ~conversion_error (void) throw() { };
280 operator std::string (void)
282 return std::string ("errno=") + I2n::to_string (this->err)
283 + " [" + this->context + "]";
289 /* helper for ctor initializer list; we still lack aggregate initializers */
291 timespec_of_parts (const time_t sec, const long nsec)
293 struct timespec ret = { sec, nsec};
302 * represent the clock id options from clock_gettime(2) as
303 * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
304 * everywhere since that’s what we want in most cases.
307 mono, /* CLOCK_MONOTONIC_COARSE */
308 real, /* CLOCK_REALIME_COARSE */
309 boot, /* CLOCK_BOOTTIME */
310 cpu, /* CLOCK_CPUTIME_* */
314 * for clocks that support it: non-coarse or raw variants; if a variant
315 * does not apply to a given clock, it is ignored
319 exact, /* mono, real: not (*_COARSE) */
320 raw, /* mono: _RAW */
321 process, /* cpu: *_PROCESS_* */
322 thread, /* cpu: *_THREAD_* */
325 } /* [namespace type] */
331 struct timespec value;
335 enum type::variant variant;
340 * Handle decimal part (nanosecond) overflow; this is performed
341 * after arithmetic operations and whenever we there is the
342 * possibility of unsanitized input for example in constructors
343 * from other types and suchlike.
345 * POSIX defines the ns part as *long*. Technically, that means
346 * that on machines where *sizeof long* equals *sizeof int*, it can
347 * represent only up to around 2.1 seconds. In this range, the loop
348 * version is most likely faster than division. However, since in
349 * practice *long* is 8 bytes just about anywhere, we have to
350 * handle greater dividends first.
356 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
357 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
359 const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
360 this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
361 this->value.tv_sec += sec;
363 # endif /* [LONG_BIT > 32] */
364 while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
365 this->value.tv_sec += 1;
366 this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
369 while (this->value.tv_nsec < 0) {
370 this->value.tv_sec -= 1;
371 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
375 /* ctors *************************************************************/
378 Time (const enum type::id id = type::mono,
379 const enum type::variant var = type::dflt) NOEXCEPT;
381 inline Time (const Time &t) NOEXCEPT
384 , variant (t.variant)
389 Time (const time_t sec,
391 const enum type::id id = type::mono,
392 const enum type::variant var = type::dflt,
393 const int err = 0) NOEXCEPT
394 : value (timespec_of_parts (sec, nsec))
398 { this->carry_nsec (); }
401 Time (const struct tm &tm,
402 const enum type::id id = type::mono,
403 const enum type::variant var = type::dflt);
405 /* value read access *************************************************/
408 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
409 { return this->value; }
411 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
412 { return this->value.tv_sec; }
414 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
415 { return this->value.tv_nsec; }
417 inline CONSTEXPR const long get_msec (void) const NOEXCEPT
418 { return this->get_nsec () / 1000000; }
420 int64_t as_nanosec (void) const NOEXCEPT;
422 long as_nanosec_L (void) const NOEXCEPT;
424 /* value write access ************************************************/
428 swap (Time &t) NOEXCEPT
430 std::swap (this->value , t.value );
431 std::swap (this->id , t.id );
432 std::swap (this->variant, t.variant);
433 std::swap (this->err , t.err );
436 Time &operator= (Time t) NOEXCEPT;
438 Time &operator= (struct timespec ts) NOEXCEPT;
441 set (const struct timespec &ts) NOEXCEPT
448 set (const time_t sec,
450 const enum type::id id = type::mono,
451 const enum type::variant var = type::dflt) NOEXCEPT
453 this->value.tv_sec = sec;
454 this->value.tv_nsec = nsec;
461 bool set (void) NOEXCEPT;
463 void unset (void) NOEXCEPT;
465 /* arithmetic ********************************************************/
468 Time &add (const time_t sec, const long nsec) NOEXCEPT;
470 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
472 inline Time &add (const Time &t2) NOEXCEPT
473 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
475 inline Time &add (const time_t t2) NOEXCEPT
476 { return this->add (t2, 0L); };
478 inline Time &subtract (const Time &t2) NOEXCEPT
479 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
481 inline Time &subtract (const time_t t2) NOEXCEPT
482 { return this->subtract (t2, 0L); };
484 Time &scale (const int64_t factor) NOEXCEPT;
486 Time ÷ (const int64_t divisor) NOEXCEPT;
488 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
491 difference (const Time &t) NOEXCEPT
492 { return (*this < t) ? t - *this : *this - t; }
494 /* overloads *********************************************************/
498 operator+ (const Time &t2) const NOEXCEPT
499 { return Time (*this).add (t2); }
502 operator+ (const time_t t2) const NOEXCEPT
503 { return Time (*this).add (t2); }
506 operator+= (const Time &t2) NOEXCEPT
507 { return this->add (t2); }
510 operator+= (const time_t t2) NOEXCEPT
511 { return this->add (t2); }
514 operator- (const Time &t2) const NOEXCEPT
515 { return Time (*this).subtract (t2); }
518 operator- (const time_t t2) const NOEXCEPT
519 { return Time (*this).subtract (t2); }
522 operator-= (const Time &t2) NOEXCEPT
523 { return this->subtract (t2); }
526 operator-= (const time_t t2) NOEXCEPT
527 { return this->subtract (t2); }
530 operator* (const int64_t factor) const NOEXCEPT
531 { return Time (*this).scale (factor); }
534 operator*= (const int64_t factor) NOEXCEPT
535 { return this->scale (factor); }
538 operator/ (const int64_t divisor) const NOEXCEPT
539 { return Time (*this).divide (divisor); }
542 operator/= (const int64_t divisor) NOEXCEPT
543 { return this->divide (divisor); }
545 friend CONSTEXPR bool
546 operator== (const Time &t1, const Time &t2) NOEXCEPT;
548 friend CONSTEXPR bool
549 operator< (const Time &t1, const Time &t2) NOEXCEPT;
551 friend CONSTEXPR bool
552 operator> (const Time &t1, const Time &t2) NOEXCEPT;
554 friend std::ostream &
555 operator<< (std::ostream &os, const Time &t);
557 /* formatting ********************************************************/
560 boost::optional<std::string>
561 format_iso8601 (const bool utc = true,
562 const bool date = true,
563 const bool time = true,
564 const bool tz = true) const;
566 std::string make_nice_time (void) const;
567 std::string format_full_time (void) const;
568 std::string format_date (void) const;
571 format_sec_msec (void) const
572 { return ::format_sec_msec (this->value); }
574 inline boost::optional<std::string>
575 format_min_sec_msec (void) const
576 { return ::format_min_sec_msec (this->value); }
578 }; /* [class Time] */
581 operator+ (const time_t t1, const Time &t2) NOEXCEPT
582 { return Time (t1) + t2; }
585 operator- (const time_t t1, const Time &t2) NOEXCEPT
586 { return Time (t1) - t2; }
589 operator* (const time_t t1, const Time &t2) NOEXCEPT
592 int compare (const Time &t1, const Time &t2) NOEXCEPT;
595 * comparison for equality also considers the clock type;
597 inline CONSTEXPR bool
598 operator== (const Time &t1, const Time &t2) NOEXCEPT
600 return t1.id == t2.id && t1.variant == t2.variant
601 && t1.value.tv_sec == t2.value.tv_sec
602 && t1.value.tv_nsec == t2.value.tv_nsec
606 /* these ignore the *id* and *variant* fields */
607 inline CONSTEXPR bool
608 operator< (const Time &t1, const Time &t2) NOEXCEPT
610 return t1.value.tv_sec < t2.value.tv_sec
611 || ( t1.value.tv_sec == t2.value.tv_sec
612 && t1.value.tv_nsec < t2.value.tv_nsec)
616 /* these ignore the *id* and *variant* fields */
617 inline CONSTEXPR bool
618 operator> (const Time &t1, const Time &t2) NOEXCEPT
620 return t1.value.tv_sec > t2.value.tv_sec
621 || ( t1.value.tv_sec == t2.value.tv_sec
622 && t1.value.tv_nsec > t2.value.tv_nsec)
626 inline std::ostream &
627 operator<< (std::ostream &os, const Time &t)
629 os << I2n::to_string (t.value.tv_sec) << "s, "
630 << I2n::to_string (t.value.tv_nsec) << "ns"
636 boost::optional<Time>
637 now (const enum type::id id = type::mono,
638 const enum type::variant var = type::dflt) NOEXCEPT;
641 zero (const enum type::id id = type::mono,
642 const enum type::variant var = type::dflt) NOEXCEPT;
644 boost::optional<Time>
645 time_of_iso8601 (const std::string &s,
646 const bool date = true,
647 const bool time = true,
648 const bool tz = true,
649 const enum type::id id = type::real,
650 const enum type::variant var = type::dflt) NOEXCEPT;
652 template <typename ContT>
654 mean (const ContT &data)
658 if (data.size () == 0) {
662 for (typename ContT::const_iterator it = data.begin ();
663 it != data.end (); ++it)
668 return sum.divide (static_cast<int64_t> (data.size ()));
671 template <typename ContT>
673 median (const ContT &data)
675 if (data.size () == 0) {
678 if (data.size () == 1) {
679 return *data.begin ();
682 std::vector<typename ContT::value_type> sorted;
683 std::copy (data.begin (), data.end (), std::back_inserter (sorted));
684 std::sort (sorted.begin (), sorted.end ());
686 return sorted [data.size () / 2];
689 } /* [namespace clock] */
691 } /* [namespace I2n] */