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