Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / timefunc.hxx
CommitLineData
0e23f538
TJ
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*/
1b5dfd98
TJ
20/** @file
21 * @brief time related functions.
22 *
d70f7269 23 * @copyright Copyright © 2001-2018 by Intra2net AG
1b5dfd98 24 */
e93545dd
GE
25
26#ifndef __TIMEFUNC_HXX
27#define __TIMEFUNC_HXX
28
e36ca33c 29#include <climits>
8b5814e2 30#include <errno.h>
1b5dfd98 31#include <list>
e36ca33c 32#include <string>
c42fd3b3 33#include <cstdlib>
6d9ab467 34#include <algorithm>
1b5dfd98 35
8b5814e2
PG
36#include <boost/optional.hpp>
37
0c7e72d7 38#include <week.hpp>
f1499910 39
e36ca33c
PG
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
e93545dd
GE
52double prec_time(void);
53
dad9e26f 54time_t date_to_seconds(const std::string &date);
e93545dd
GE
55
56std::string make_nice_time(int seconds);
7839bd53 57std::string format_full_time(time_t seconds);
25f3d405 58std::string format_date(time_t seconds);
d70f7269
PG
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);
9f39641d
PG
64
65inline std::string format_iso8601(const struct timespec &ts, const bool utc=true,
d70f7269
PG
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
9f39641d
PG
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
2795e39c
PG
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
87869870 89void seconds_to_hour_minute(int seconds, int *hour, int *minute);
c0368918
GE
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);
2c66f490
GE
92
93inline std::string output_hour_minute_from_seconds(int seconds)
94{
95 int hour, minute;
c0368918 96 split_daysec(seconds,&hour,&minute);
2c66f490
GE
97 return output_hour_minute(hour,minute);
98}
e93545dd 99
4e157d1d
TJ
100std::string get_month_name(unsigned char month);
101
1b5dfd98
TJ
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)
80f30818
TJ
111 , m_weak_mark(0)
112 , m_changed(false)
1b5dfd98
TJ
113 {
114 } //
115
80f30818 116 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
1b5dfd98
TJ
117 : m_lower_bound(start)
118 , m_upper_bound(end)
80f30818
TJ
119 , m_weak_mark(weak_mark)
120 , m_changed(false)
1b5dfd98
TJ
121 {
122 } //
123
d181c3bc
TJ
124
125 void clear();
126
1b5dfd98
TJ
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
80f30818
TJ
141 int weak_mark() const { return m_weak_mark; }
142
143 bool changed() const { return m_changed; }
144
1b5dfd98
TJ
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
ebc3b584
TJ
152 bool operator!=(const Interval& other) const
153 {
154 return not (*this == other);
155 } // eo operator!=(const Interval&)
156
157
1b5dfd98
TJ
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
80f30818
TJ
180 int m_weak_mark;
181 bool m_changed;
182
1b5dfd98
TJ
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
d181c3bc 219 void clear();
1b5dfd98
TJ
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
e156de7c
TJ
236 bool contains_exact(const Interval& other) const;
237
1b5dfd98 238 bool operator==(const Intervals& other) const;
ebc3b584 239 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
1b5dfd98
TJ
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
96d0be2e
TJ
254/*
255** clock funcs:
256*/
257
258
259bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
b7e17426 260long long monotonic_clock_gettime_nano();
96d0be2e
TJ
261
262bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
263
8b5814e2
PG
264namespace I2n {
265
266namespace clock {
267
cf960f73
PG
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
e36ca33c
PG
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
8b5814e2
PG
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:
e36ca33c 332 struct timespec value;
8b5814e2
PG
333
334 public:
e36ca33c
PG
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
fe377737 348 * represent only up to around 2.1 seconds. In this range, the loop
e36ca33c
PG
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 }
8b5814e2
PG
375
376 /* ctors *************************************************************/
377 public:
378
379 Time (const enum type::id id = type::mono,
e36ca33c
PG
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
cf960f73
PG
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
e36ca33c
PG
395 : value (timespec_of_parts (sec, nsec))
396 , id (id)
397 , variant (var)
398 , err (err)
399 { this->carry_nsec (); }
400
cf960f73 401 explicit
2795e39c
PG
402 Time (const struct tm &tm,
403 const enum type::id id = type::mono,
cf960f73 404 const enum type::variant var = type::dflt);
2795e39c 405
e36ca33c 406 /* value read access *************************************************/
8b5814e2
PG
407 public:
408
e36ca33c 409 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
8b5814e2
PG
410 { return this->value; }
411
e36ca33c
PG
412 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
413 { return this->value.tv_sec; }
8b5814e2 414
e36ca33c 415 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
8b5814e2
PG
416 { return this->value.tv_nsec; }
417
9f39641d
PG
418 inline CONSTEXPR const long get_msec (void) const NOEXCEPT
419 { return this->get_nsec () / 1000000; }
420
e36ca33c 421 int64_t as_nanosec (void) const NOEXCEPT;
8b5814e2 422
e36ca33c 423 long as_nanosec_L (void) const NOEXCEPT;
8b5814e2 424
e36ca33c 425 /* value write access ************************************************/
8b5814e2
PG
426 public:
427
428 inline void
e36ca33c
PG
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;
8b5814e2
PG
440
441 inline void
e36ca33c
PG
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
8b5814e2
PG
453 {
454 this->value.tv_sec = sec;
455 this->value.tv_nsec = nsec;
e36ca33c
PG
456 this->id = id;
457 this->variant = var;
458
459 this->carry_nsec ();
460 }
8b5814e2 461
e36ca33c
PG
462 bool set (void) NOEXCEPT;
463
464 void unset (void) NOEXCEPT;
465
466 /* arithmetic ********************************************************/
467 public:
8b5814e2 468
e36ca33c
PG
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
c42fd3b3
PG
485 Time &scale (const int64_t factor) NOEXCEPT;
486
487 Time &divide (const int64_t divisor) NOEXCEPT;
e36ca33c
PG
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
c42fd3b3 531 operator* (const int64_t factor) const NOEXCEPT
e36ca33c
PG
532 { return Time (*this).scale (factor); }
533
534 inline Time &
c42fd3b3 535 operator*= (const int64_t factor) NOEXCEPT
e36ca33c
PG
536 { return this->scale (factor); }
537
c42fd3b3
PG
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
e36ca33c
PG
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);
8b5814e2 557
72acd54c
PG
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
9f39641d
PG
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); }
72acd54c 578
8b5814e2
PG
579 }; /* [class Time] */
580
e36ca33c
PG
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
c42fd3b3
PG
589 inline Time
590 operator* (const time_t t1, const Time &t2) NOEXCEPT
591 { return t2 * t1; }
592
e36ca33c
PG
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 {
f8ebfa53 630 os << I2n::to_string (t.value.tv_sec) << "s, "
e36ca33c
PG
631 << I2n::to_string (t.value.tv_nsec) << "ns"
632 ;
633
634 return os;
635 }
636
8b5814e2
PG
637 boost::optional<Time>
638 now (const enum type::id id = type::mono,
e36ca33c
PG
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;
8b5814e2 644
2795e39c
PG
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
c42fd3b3
PG
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
8b5814e2
PG
690} /* [namespace clock] */
691
692} /* [namespace I2n] */
1b5dfd98
TJ
693
694
e93545dd 695#endif