Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / timefunc.hxx
... / ...
CommitLineData
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20/** @file
21 * @brief time related functions.
22 *
23 * @copyright Copyright © 2001-2018 by Intra2net AG
24 */
25
26#ifndef __TIMEFUNC_HXX
27#define __TIMEFUNC_HXX
28
29#include <climits>
30#include <errno.h>
31#include <list>
32#include <string>
33#include <cstdlib>
34#include <algorithm>
35
36#include <boost/optional.hpp>
37
38#include <week.hpp>
39
40#include "stringfunc.hxx"
41
42#if __cplusplus >= 201103
43# define CONSTEXPR constexpr
44# define NOEXCEPT noexcept
45#else
46# define CONSTEXPR
47# define NOEXCEPT
48#endif
49
50#define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
51
52double prec_time(void);
53
54time_t date_to_seconds(const std::string &date);
55
56std::string make_nice_time(int seconds);
57std::string format_full_time(time_t seconds);
58std::string format_date(time_t seconds);
59std::string format_iso8601(const struct tm &tm, const bool date=true,
60 const bool time=true, const bool tz=true);
61std::string format_iso8601(time_t t, const bool utc=true,
62 const bool date=true, const bool time=true,
63 const bool tz=true);
64
65inline std::string format_iso8601(const struct timespec &ts, const bool utc=true,
66 const bool date=true, const bool time=true,
67 const bool tz=true)
68{ return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
69
70inline std::string format_sec_msec (const struct timespec &ts)
71{
72 return I2n::to_string (ts.tv_sec) + "s "
73 + I2n::to_string (ts.tv_nsec / 1000000) + "ms"
74 ;
75}
76
77boost::optional<std::string> format_min_sec_msec (const struct timespec &ts);
78
79boost::optional<struct tm> scan_iso8601 (const char *s,
80 const bool date=true, const bool time=true,
81 const bool tz=true) NOEXCEPT;
82inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
83 const bool date=true,
84 const bool time=true,
85 const bool tz=true) NOEXCEPT
86{ return scan_iso8601 (s.c_str (), date, time, tz); }
87
88
89void seconds_to_hour_minute(int seconds, int *hour, int *minute);
90void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
91std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
92
93inline std::string output_hour_minute_from_seconds(int seconds)
94{
95 int hour, minute;
96 split_daysec(seconds,&hour,&minute);
97 return output_hour_minute(hour,minute);
98}
99
100std::string get_month_name(unsigned char month);
101
102/**
103 * @brief structure representing a single (half-open) interval.
104 */
105class Interval
106{
107 public:
108 Interval()
109 : m_lower_bound(0)
110 , m_upper_bound(0)
111 , m_weak_mark(0)
112 , m_changed(false)
113 {
114 } //
115
116 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
117 : m_lower_bound(start)
118 , m_upper_bound(end)
119 , m_weak_mark(weak_mark)
120 , m_changed(false)
121 {
122 } //
123
124
125 void clear();
126
127 bool is_valid() const
128 {
129 return m_lower_bound <= m_upper_bound;
130 } // eo is_valid() const
131
132 bool empty() const
133 {
134 return m_lower_bound == m_upper_bound;
135 } // eo empty() const
136
137
138 unsigned int lower_bound() const { return m_lower_bound; }
139 unsigned int upper_bound() const { return m_upper_bound; }
140
141 int weak_mark() const { return m_weak_mark; }
142
143 bool changed() const { return m_changed; }
144
145
146 bool operator== (const Interval& other) const
147 {
148 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
149 } // eo operator==(const Interval&)
150
151
152 bool operator!=(const Interval& other) const
153 {
154 return not (*this == other);
155 } // eo operator!=(const Interval&)
156
157
158 /**
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.
162 */
163 bool operator<(const Interval& other) const
164 {
165 return m_lower_bound < other.m_lower_bound;
166 } // eo operator<(const Interval&)
167
168
169 bool intersects(const Interval& other) const;
170 bool contains(const Interval& other) const;
171
172
173 protected:
174
175 friend class Intervals;
176
177 unsigned int m_lower_bound;
178 unsigned int m_upper_bound;
179
180 int m_weak_mark;
181 bool m_changed;
182
183}; // eo Interval
184
185
186
187/**
188 * @brief structure representing a combination of single disjoint (half open) intervals.
189 *
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.
193 *
194 * @note the list is sorted by the start; lower comes first.
195 *
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.
198 *
199 * @internal
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!!
203 */
204class Intervals
205{
206 public:
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;
212
213 public:
214 Intervals();
215
216 void add(const Interval& new_frame);
217 void sub(const Interval& new_frame);
218
219 void clear();
220
221 const_iterator begin() const { return m_intervals.begin(); }
222 const_iterator end() const { return m_intervals.end(); }
223
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(); }
227
228 size_type size() const { return m_intervals.size(); }
229
230 bool intersects(const Interval& other) const;
231 bool intersects(const Intervals& other) const;
232
233 bool contains(const Interval& other) const;
234 bool contains(const Intervals& other) const;
235
236 bool contains_exact(const Interval& other) const;
237
238 bool operator==(const Intervals& other) const;
239 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
240
241 Intervals& operator+=(const Interval& other);
242 Intervals& operator-=(const Interval& other);
243
244 Intervals& operator+=(const Intervals& other);
245 Intervals& operator-=(const Intervals& other);
246
247 protected:
248
249 std::list< Interval > m_intervals;
250
251}; // eo Intervals
252
253
254/*
255** clock funcs:
256*/
257
258
259bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
260long long monotonic_clock_gettime_nano();
261
262bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
263
264namespace I2n {
265
266namespace clock {
267
268 class conversion_error : public std::exception
269 {
270 public:
271 const int err;
272 const std::string context;
273
274 conversion_error (const int err, const std::string &context)
275 : err (err)
276 , context (context)
277 { }
278
279 virtual ~conversion_error (void) throw() { };
280
281 operator std::string (void)
282 {
283 return std::string ("errno=") + I2n::to_string (this->err)
284 + " [" + this->context + "]";
285 }
286 };
287
288 namespace {
289
290 /* helper for ctor initializer list; we still lack aggregate initializers */
291 struct timespec
292 timespec_of_parts (const time_t sec, const long nsec)
293 {
294 struct timespec ret = { sec, nsec};
295
296 return ret;
297 }
298
299 } /* [namespace] */
300
301 namespace type {
302 /*
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.
306 */
307 enum id {
308 mono, /* CLOCK_MONOTONIC_COARSE */
309 real, /* CLOCK_REALIME_COARSE */
310 boot, /* CLOCK_BOOTTIME */
311 cpu, /* CLOCK_CPUTIME_* */
312 };
313
314 /*
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
317 */
318 enum variant {
319 dflt, /* all */
320 exact, /* mono, real: not (*_COARSE) */
321 raw, /* mono: _RAW */
322 process, /* cpu: *_PROCESS_* */
323 thread, /* cpu: *_THREAD_* */
324 };
325
326 } /* [namespace type] */
327
328
329 class Time {
330
331 private:
332 struct timespec value;
333
334 public:
335 enum type::id id;
336 enum type::variant variant;
337 int err;
338
339 private:
340 /*
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.
345 *
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.
352 */
353 inline void
354 carry_nsec (void)
355 {
356# if LONG_BIT > 32
357 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
358 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
359 {
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;
363 }
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;
368 }
369
370 while (this->value.tv_nsec < 0) {
371 this->value.tv_sec -= 1;
372 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
373 }
374 }
375
376 /* ctors *************************************************************/
377 public:
378
379 Time (const enum type::id id = type::mono,
380 const enum type::variant var = type::dflt) NOEXCEPT;
381
382 inline Time (const Time &t) NOEXCEPT
383 : value (t.value)
384 , id (t.id)
385 , variant (t.variant)
386 , err (t.err)
387 { }
388
389 inline
390 Time (const time_t sec,
391 const long nsec = 0,
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))
396 , id (id)
397 , variant (var)
398 , err (err)
399 { this->carry_nsec (); }
400
401 explicit
402 Time (const struct tm &tm,
403 const enum type::id id = type::mono,
404 const enum type::variant var = type::dflt);
405
406 /* value read access *************************************************/
407 public:
408
409 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
410 { return this->value; }
411
412 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
413 { return this->value.tv_sec; }
414
415 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
416 { return this->value.tv_nsec; }
417
418 inline CONSTEXPR const long get_msec (void) const NOEXCEPT
419 { return this->get_nsec () / 1000000; }
420
421 int64_t as_nanosec (void) const NOEXCEPT;
422
423 long as_nanosec_L (void) const NOEXCEPT;
424
425 /* value write access ************************************************/
426 public:
427
428 inline void
429 swap (Time &t) NOEXCEPT
430 {
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 );
435 }
436
437 Time &operator= (Time t) NOEXCEPT;
438
439 Time &operator= (struct timespec ts) NOEXCEPT;
440
441 inline void
442 set (const struct timespec &ts) NOEXCEPT
443 {
444 this->value = ts;
445 this->carry_nsec ();
446 }
447
448 inline void
449 set (const time_t sec,
450 const long nsec,
451 const enum type::id id = type::mono,
452 const enum type::variant var = type::dflt) NOEXCEPT
453 {
454 this->value.tv_sec = sec;
455 this->value.tv_nsec = nsec;
456 this->id = id;
457 this->variant = var;
458
459 this->carry_nsec ();
460 }
461
462 bool set (void) NOEXCEPT;
463
464 void unset (void) NOEXCEPT;
465
466 /* arithmetic ********************************************************/
467 public:
468
469 Time &add (const time_t sec, const long nsec) NOEXCEPT;
470
471 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
472
473 inline Time &add (const Time &t2) NOEXCEPT
474 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
475
476 inline Time &add (const time_t t2) NOEXCEPT
477 { return this->add (t2, 0L); };
478
479 inline Time &subtract (const Time &t2) NOEXCEPT
480 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
481
482 inline Time &subtract (const time_t t2) NOEXCEPT
483 { return this->subtract (t2, 0L); };
484
485 Time &scale (const int64_t factor) NOEXCEPT;
486
487 Time &divide (const int64_t divisor) NOEXCEPT;
488
489 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
490
491 inline Time
492 difference (const Time &t) NOEXCEPT
493 { return (*this < t) ? t - *this : *this - t; }
494
495 /* overloads *********************************************************/
496 public:
497
498 inline Time
499 operator+ (const Time &t2) const NOEXCEPT
500 { return Time (*this).add (t2); }
501
502 inline Time
503 operator+ (const time_t t2) const NOEXCEPT
504 { return Time (*this).add (t2); }
505
506 inline Time &
507 operator+= (const Time &t2) NOEXCEPT
508 { return this->add (t2); }
509
510 inline Time &
511 operator+= (const time_t t2) NOEXCEPT
512 { return this->add (t2); }
513
514 inline Time
515 operator- (const Time &t2) const NOEXCEPT
516 { return Time (*this).subtract (t2); }
517
518 inline Time
519 operator- (const time_t t2) const NOEXCEPT
520 { return Time (*this).subtract (t2); }
521
522 inline Time &
523 operator-= (const Time &t2) NOEXCEPT
524 { return this->subtract (t2); }
525
526 inline Time &
527 operator-= (const time_t t2) NOEXCEPT
528 { return this->subtract (t2); }
529
530 inline Time
531 operator* (const int64_t factor) const NOEXCEPT
532 { return Time (*this).scale (factor); }
533
534 inline Time &
535 operator*= (const int64_t factor) NOEXCEPT
536 { return this->scale (factor); }
537
538 inline Time
539 operator/ (const int64_t divisor) const NOEXCEPT
540 { return Time (*this).divide (divisor); }
541
542 inline Time &
543 operator/= (const int64_t divisor) NOEXCEPT
544 { return this->divide (divisor); }
545
546 friend CONSTEXPR bool
547 operator== (const Time &t1, const Time &t2) NOEXCEPT;
548
549 friend CONSTEXPR bool
550 operator< (const Time &t1, const Time &t2) NOEXCEPT;
551
552 friend CONSTEXPR bool
553 operator> (const Time &t1, const Time &t2) NOEXCEPT;
554
555 friend std::ostream &
556 operator<< (std::ostream &os, const Time &t);
557
558 /* formatting ********************************************************/
559 public:
560
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;
566
567 std::string make_nice_time (void) const;
568 std::string format_full_time (void) const;
569 std::string format_date (void) const;
570
571 inline std::string
572 format_sec_msec (void) const
573 { return ::format_sec_msec (this->value); }
574
575 inline boost::optional<std::string>
576 format_min_sec_msec (void) const
577 { return ::format_min_sec_msec (this->value); }
578
579 }; /* [class Time] */
580
581 inline Time
582 operator+ (const time_t t1, const Time &t2) NOEXCEPT
583 { return Time (t1) + t2; }
584
585 inline Time
586 operator- (const time_t t1, const Time &t2) NOEXCEPT
587 { return Time (t1) - t2; }
588
589 inline Time
590 operator* (const time_t t1, const Time &t2) NOEXCEPT
591 { return t2 * t1; }
592
593 int compare (const Time &t1, const Time &t2) NOEXCEPT;
594
595 /*
596 * comparison for equality also considers the clock type;
597 */
598 inline CONSTEXPR bool
599 operator== (const Time &t1, const Time &t2) NOEXCEPT
600 {
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
604 ;
605 }
606
607 /* these ignore the *id* and *variant* fields */
608 inline CONSTEXPR bool
609 operator< (const Time &t1, const Time &t2) NOEXCEPT
610 {
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)
614 ;
615 }
616
617 /* these ignore the *id* and *variant* fields */
618 inline CONSTEXPR bool
619 operator> (const Time &t1, const Time &t2) NOEXCEPT
620 {
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)
624 ;
625 }
626
627 inline std::ostream &
628 operator<< (std::ostream &os, const Time &t)
629 {
630 os << I2n::to_string (t.value.tv_sec) << "s, "
631 << I2n::to_string (t.value.tv_nsec) << "ns"
632 ;
633
634 return os;
635 }
636
637 boost::optional<Time>
638 now (const enum type::id id = type::mono,
639 const enum type::variant var = type::dflt) NOEXCEPT;
640
641 Time
642 zero (const enum type::id id = type::mono,
643 const enum type::variant var = type::dflt) NOEXCEPT;
644
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;
652
653 template <typename ContT>
654 Time
655 mean (const ContT &data)
656 {
657 Time sum (0, 0);
658
659 if (data.size () == 0) {
660 return sum;
661 }
662
663 for (typename ContT::const_iterator it = data.begin ();
664 it != data.end (); ++it)
665 {
666 sum += *it;
667 };
668
669 return sum.divide (static_cast<int64_t> (data.size ()));
670 };
671
672 template <typename ContT>
673 Time
674 median (const ContT &data)
675 {
676 if (data.size () == 0) {
677 return zero ();
678 }
679 if (data.size () == 1) {
680 return *data.begin ();
681 }
682
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 ());
686
687 return sorted [data.size () / 2];
688 };
689
690} /* [namespace clock] */
691
692} /* [namespace I2n] */
693
694
695#endif