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,
63 inline std::string format_iso8601(const struct timespec ts, const bool utc=true,
64 const bool date=true, const bool time=true,
66 { return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
68 boost::optional<struct tm> scan_iso8601 (const char *s,
69 const bool date=true, const bool time=true,
70 const bool tz=true) NOEXCEPT;
71 inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
74 const bool tz=true) NOEXCEPT
75 { return scan_iso8601 (s.c_str (), date, time, tz); }
78 void seconds_to_hour_minute(int seconds, int *hour, int *minute);
79 void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
80 std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
82 inline std::string output_hour_minute_from_seconds(int seconds)
85 split_daysec(seconds,&hour,&minute);
86 return output_hour_minute(hour,minute);
89 std::string get_month_name(unsigned char month);
92 * @brief structure representing a single (half-open) interval.
105 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
106 : m_lower_bound(start)
108 , m_weak_mark(weak_mark)
116 bool is_valid() const
118 return m_lower_bound <= m_upper_bound;
119 } // eo is_valid() const
123 return m_lower_bound == m_upper_bound;
124 } // eo empty() const
127 unsigned int lower_bound() const { return m_lower_bound; }
128 unsigned int upper_bound() const { return m_upper_bound; }
130 int weak_mark() const { return m_weak_mark; }
132 bool changed() const { return m_changed; }
135 bool operator== (const Interval& other) const
137 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
138 } // eo operator==(const Interval&)
141 bool operator!=(const Interval& other) const
143 return not (*this == other);
144 } // eo operator!=(const Interval&)
148 * @brief less operator. compares only the start times!
149 * @param other the other interval to compare with.
150 * @return @a true if the current start is less than the other start.
152 bool operator<(const Interval& other) const
154 return m_lower_bound < other.m_lower_bound;
155 } // eo operator<(const Interval&)
158 bool intersects(const Interval& other) const;
159 bool contains(const Interval& other) const;
164 friend class Intervals;
166 unsigned int m_lower_bound;
167 unsigned int m_upper_bound;
177 * @brief structure representing a combination of single disjoint (half open) intervals.
179 * Basic idea is that this structure provides an interface for adding and
180 * subtracting single intervals and keeps the internal list of intervals as
181 * a list of disjoint intervals.
183 * @note the list is sorted by the start; lower comes first.
185 * @note the class provides some methods similar to STL container classes;
186 * i.e. it can be used with (at least some) STL algorithms.
189 * we use a std::list for the intervals; this means we don't invalidate all
190 * iterators when we insert or delete within loops...
191 * And we use that fact!!
196 typedef std::list< Interval > IntervalList;
197 typedef IntervalList::value_type value_type;
198 typedef IntervalList::const_iterator const_iterator;
199 typedef IntervalList::const_iterator iterator; // we allow only const...
200 typedef IntervalList::size_type size_type;
205 void add(const Interval& new_frame);
206 void sub(const Interval& new_frame);
210 const_iterator begin() const { return m_intervals.begin(); }
211 const_iterator end() const { return m_intervals.end(); }
213 bool empty() const { return m_intervals.empty(); }
214 const Interval& front() const { return m_intervals.front(); }
215 const Interval& back() const { return m_intervals.back(); }
217 size_type size() const { return m_intervals.size(); }
219 bool intersects(const Interval& other) const;
220 bool intersects(const Intervals& other) const;
222 bool contains(const Interval& other) const;
223 bool contains(const Intervals& other) const;
225 bool contains_exact(const Interval& other) const;
227 bool operator==(const Intervals& other) const;
228 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
230 Intervals& operator+=(const Interval& other);
231 Intervals& operator-=(const Interval& other);
233 Intervals& operator+=(const Intervals& other);
234 Intervals& operator-=(const Intervals& other);
238 std::list< Interval > m_intervals;
248 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
249 long long monotonic_clock_gettime_nano();
251 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
257 class conversion_error : public std::exception
261 const std::string context;
263 conversion_error (const int err, const std::string &context)
268 virtual ~conversion_error (void) throw() { };
270 operator std::string (void)
272 return std::string ("errno=") + I2n::to_string (this->err)
273 + " [" + this->context + "]";
279 /* helper for ctor initializer list; we still lack aggregate initializers */
281 timespec_of_parts (const time_t sec, const long nsec)
283 struct timespec ret = { sec, nsec};
292 * represent the clock id options from clock_gettime(2) as
293 * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
294 * everywhere since that’s what we want in most cases.
297 mono, /* CLOCK_MONOTONIC_COARSE */
298 real, /* CLOCK_REALIME_COARSE */
299 boot, /* CLOCK_BOOTTIME */
300 cpu, /* CLOCK_CPUTIME_* */
304 * for clocks that support it: non-coarse or raw variants; if a variant
305 * does not apply to a given clock, it is ignored
309 exact, /* mono, real: not (*_COARSE) */
310 raw, /* mono: _RAW */
311 process, /* cpu: *_PROCESS_* */
312 thread, /* cpu: *_THREAD_* */
315 } /* [namespace type] */
321 struct timespec value;
325 enum type::variant variant;
330 * Handle decimal part (nanosecond) overflow; this is performed
331 * after arithmetic operations and whenever we there is the
332 * possibility of unsanitized input for example in constructors
333 * from other types and suchlike.
335 * POSIX defines the ns part as *long*. Technically, that means
336 * that on machines where *sizeof long* equals *sizeof int*, it can
337 * represent only up to arund 2.1 seconds. In this range, the loop
338 * version is most likely faster than division. However, since in
339 * practice *long* is 8 bytes just about anywhere, we have to
340 * handle greater dividends first.
346 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
347 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
349 const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
350 this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
351 this->value.tv_sec += sec;
353 # endif /* [LONG_BIT > 32] */
354 while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
355 this->value.tv_sec += 1;
356 this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
359 while (this->value.tv_nsec < 0) {
360 this->value.tv_sec -= 1;
361 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
365 /* ctors *************************************************************/
368 Time (const enum type::id id = type::mono,
369 const enum type::variant var = type::dflt) NOEXCEPT;
371 inline Time (const Time &t) NOEXCEPT
374 , variant (t.variant)
379 Time (const time_t sec,
381 const enum type::id id = type::mono,
382 const enum type::variant var = type::dflt,
383 const int err = 0) NOEXCEPT
384 : value (timespec_of_parts (sec, nsec))
388 { this->carry_nsec (); }
391 Time (const struct tm &tm,
392 const enum type::id id = type::mono,
393 const enum type::variant var = type::dflt);
395 /* value read access *************************************************/
398 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
399 { return this->value; }
401 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
402 { return this->value.tv_sec; }
404 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
405 { return this->value.tv_nsec; }
407 int64_t as_nanosec (void) const NOEXCEPT;
409 long as_nanosec_L (void) const NOEXCEPT;
411 /* value write access ************************************************/
415 swap (Time &t) NOEXCEPT
417 std::swap (this->value , t.value );
418 std::swap (this->id , t.id );
419 std::swap (this->variant, t.variant);
420 std::swap (this->err , t.err );
423 Time &operator= (Time t) NOEXCEPT;
425 Time &operator= (struct timespec ts) NOEXCEPT;
428 set (const struct timespec &ts) NOEXCEPT
435 set (const time_t sec,
437 const enum type::id id = type::mono,
438 const enum type::variant var = type::dflt) NOEXCEPT
440 this->value.tv_sec = sec;
441 this->value.tv_nsec = nsec;
448 bool set (void) NOEXCEPT;
450 void unset (void) NOEXCEPT;
452 /* arithmetic ********************************************************/
455 Time &add (const time_t sec, const long nsec) NOEXCEPT;
457 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
459 inline Time &add (const Time &t2) NOEXCEPT
460 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
462 inline Time &add (const time_t t2) NOEXCEPT
463 { return this->add (t2, 0L); };
465 inline Time &subtract (const Time &t2) NOEXCEPT
466 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
468 inline Time &subtract (const time_t t2) NOEXCEPT
469 { return this->subtract (t2, 0L); };
471 Time &scale (const int64_t factor) NOEXCEPT;
473 Time ÷ (const int64_t divisor) NOEXCEPT;
475 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
478 difference (const Time &t) NOEXCEPT
479 { return (*this < t) ? t - *this : *this - t; }
481 /* overloads *********************************************************/
485 operator+ (const Time &t2) const NOEXCEPT
486 { return Time (*this).add (t2); }
489 operator+ (const time_t t2) const NOEXCEPT
490 { return Time (*this).add (t2); }
493 operator+= (const Time &t2) NOEXCEPT
494 { return this->add (t2); }
497 operator+= (const time_t t2) NOEXCEPT
498 { return this->add (t2); }
501 operator- (const Time &t2) const NOEXCEPT
502 { return Time (*this).subtract (t2); }
505 operator- (const time_t t2) const NOEXCEPT
506 { return Time (*this).subtract (t2); }
509 operator-= (const Time &t2) NOEXCEPT
510 { return this->subtract (t2); }
513 operator-= (const time_t t2) NOEXCEPT
514 { return this->subtract (t2); }
517 operator* (const int64_t factor) const NOEXCEPT
518 { return Time (*this).scale (factor); }
521 operator*= (const int64_t factor) NOEXCEPT
522 { return this->scale (factor); }
525 operator/ (const int64_t divisor) const NOEXCEPT
526 { return Time (*this).divide (divisor); }
529 operator/= (const int64_t divisor) NOEXCEPT
530 { return this->divide (divisor); }
532 friend CONSTEXPR bool
533 operator== (const Time &t1, const Time &t2) NOEXCEPT;
535 friend CONSTEXPR bool
536 operator< (const Time &t1, const Time &t2) NOEXCEPT;
538 friend CONSTEXPR bool
539 operator> (const Time &t1, const Time &t2) NOEXCEPT;
541 friend std::ostream &
542 operator<< (std::ostream &os, const Time &t);
544 /* formatting ********************************************************/
547 boost::optional<std::string>
548 format_iso8601 (const bool utc = true,
549 const bool date = true,
550 const bool time = true,
551 const bool tz = true) const;
553 boost::optional<std::string> make_nice_time (void) const;
554 boost::optional<std::string> format_full_time (void) const;
555 boost::optional<std::string> format_date (void) const;
557 }; /* [class Time] */
560 operator+ (const time_t t1, const Time &t2) NOEXCEPT
561 { return Time (t1) + t2; }
564 operator- (const time_t t1, const Time &t2) NOEXCEPT
565 { return Time (t1) - t2; }
568 operator* (const time_t t1, const Time &t2) NOEXCEPT
571 int compare (const Time &t1, const Time &t2) NOEXCEPT;
574 * comparison for equality also considers the clock type;
576 inline CONSTEXPR bool
577 operator== (const Time &t1, const Time &t2) NOEXCEPT
579 return t1.id == t2.id && t1.variant == t2.variant
580 && t1.value.tv_sec == t2.value.tv_sec
581 && t1.value.tv_nsec == t2.value.tv_nsec
585 /* these ignore the *id* and *variant* fields */
586 inline CONSTEXPR bool
587 operator< (const Time &t1, const Time &t2) NOEXCEPT
589 return t1.value.tv_sec < t2.value.tv_sec
590 || ( t1.value.tv_sec == t2.value.tv_sec
591 && t1.value.tv_nsec < t2.value.tv_nsec)
595 /* these ignore the *id* and *variant* fields */
596 inline CONSTEXPR bool
597 operator> (const Time &t1, const Time &t2) NOEXCEPT
599 return t1.value.tv_sec > t2.value.tv_sec
600 || ( t1.value.tv_sec == t2.value.tv_sec
601 && t1.value.tv_nsec > t2.value.tv_nsec)
605 inline std::ostream &
606 operator<< (std::ostream &os, const Time &t)
608 os << I2n::to_string (t.value.tv_sec) << "ms, "
609 << I2n::to_string (t.value.tv_nsec) << "ns"
615 boost::optional<Time>
616 now (const enum type::id id = type::mono,
617 const enum type::variant var = type::dflt) NOEXCEPT;
620 zero (const enum type::id id = type::mono,
621 const enum type::variant var = type::dflt) NOEXCEPT;
623 boost::optional<Time>
624 time_of_iso8601 (const std::string &s,
625 const bool date = true,
626 const bool time = true,
627 const bool tz = true,
628 const enum type::id id = type::real,
629 const enum type::variant var = type::dflt) NOEXCEPT;
631 template <typename ContT>
633 mean (const ContT &data)
637 if (data.size () == 0) {
641 for (typename ContT::const_iterator it = data.begin ();
642 it != data.end (); ++it)
647 return sum.divide (static_cast<int64_t> (data.size ()));
650 template <typename ContT>
652 median (const ContT &data)
654 if (data.size () == 0) {
657 if (data.size () == 1) {
658 return *data.begin ();
661 std::vector<typename ContT::value_type> sorted;
662 std::copy (data.begin (), data.end (), std::back_inserter (sorted));
663 std::sort (sorted.begin (), sorted.end ());
665 return sorted [data.size () / 2];
668 } /* [namespace clock] */
670 } /* [namespace I2n] */