use separate directives for time formatting and scanning
[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>
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);
63inline std::string format_iso8601(const struct timespec ts, const bool utc=true,
64 const bool date=true, const bool time=true,
65 const bool tz=true)
66{ return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
67
2795e39c
PG
68boost::optional<struct tm> scan_iso8601 (const char *s,
69 const bool date=true, const bool time=true,
70 const bool tz=true) NOEXCEPT;
71inline boost::optional<struct tm> scan_iso8601 (const std::string &s,
72 const bool date=true,
73 const bool time=true,
74 const bool tz=true) NOEXCEPT
75{ return scan_iso8601 (s.c_str (), date, time, tz); }
76
77
87869870 78void seconds_to_hour_minute(int seconds, int *hour, int *minute);
c0368918
GE
79void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
80std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
2c66f490
GE
81
82inline std::string output_hour_minute_from_seconds(int seconds)
83{
84 int hour, minute;
c0368918 85 split_daysec(seconds,&hour,&minute);
2c66f490
GE
86 return output_hour_minute(hour,minute);
87}
e93545dd 88
4e157d1d
TJ
89std::string get_month_name(unsigned char month);
90
1b5dfd98
TJ
91/**
92 * @brief structure representing a single (half-open) interval.
93 */
94class Interval
95{
96 public:
97 Interval()
98 : m_lower_bound(0)
99 , m_upper_bound(0)
80f30818
TJ
100 , m_weak_mark(0)
101 , m_changed(false)
1b5dfd98
TJ
102 {
103 } //
104
80f30818 105 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
1b5dfd98
TJ
106 : m_lower_bound(start)
107 , m_upper_bound(end)
80f30818
TJ
108 , m_weak_mark(weak_mark)
109 , m_changed(false)
1b5dfd98
TJ
110 {
111 } //
112
d181c3bc
TJ
113
114 void clear();
115
1b5dfd98
TJ
116 bool is_valid() const
117 {
118 return m_lower_bound <= m_upper_bound;
119 } // eo is_valid() const
120
121 bool empty() const
122 {
123 return m_lower_bound == m_upper_bound;
124 } // eo empty() const
125
126
127 unsigned int lower_bound() const { return m_lower_bound; }
128 unsigned int upper_bound() const { return m_upper_bound; }
129
80f30818
TJ
130 int weak_mark() const { return m_weak_mark; }
131
132 bool changed() const { return m_changed; }
133
1b5dfd98
TJ
134
135 bool operator== (const Interval& other) const
136 {
137 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
138 } // eo operator==(const Interval&)
139
140
ebc3b584
TJ
141 bool operator!=(const Interval& other) const
142 {
143 return not (*this == other);
144 } // eo operator!=(const Interval&)
145
146
1b5dfd98
TJ
147 /**
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.
151 */
152 bool operator<(const Interval& other) const
153 {
154 return m_lower_bound < other.m_lower_bound;
155 } // eo operator<(const Interval&)
156
157
158 bool intersects(const Interval& other) const;
159 bool contains(const Interval& other) const;
160
161
162 protected:
163
164 friend class Intervals;
165
166 unsigned int m_lower_bound;
167 unsigned int m_upper_bound;
168
80f30818
TJ
169 int m_weak_mark;
170 bool m_changed;
171
1b5dfd98
TJ
172}; // eo Interval
173
174
175
176/**
177 * @brief structure representing a combination of single disjoint (half open) intervals.
178 *
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.
182 *
183 * @note the list is sorted by the start; lower comes first.
184 *
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.
187 *
188 * @internal
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!!
192 */
193class Intervals
194{
195 public:
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;
201
202 public:
203 Intervals();
204
205 void add(const Interval& new_frame);
206 void sub(const Interval& new_frame);
207
d181c3bc 208 void clear();
1b5dfd98
TJ
209
210 const_iterator begin() const { return m_intervals.begin(); }
211 const_iterator end() const { return m_intervals.end(); }
212
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(); }
216
217 size_type size() const { return m_intervals.size(); }
218
219 bool intersects(const Interval& other) const;
220 bool intersects(const Intervals& other) const;
221
222 bool contains(const Interval& other) const;
223 bool contains(const Intervals& other) const;
224
e156de7c
TJ
225 bool contains_exact(const Interval& other) const;
226
1b5dfd98 227 bool operator==(const Intervals& other) const;
ebc3b584 228 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
1b5dfd98
TJ
229
230 Intervals& operator+=(const Interval& other);
231 Intervals& operator-=(const Interval& other);
232
233 Intervals& operator+=(const Intervals& other);
234 Intervals& operator-=(const Intervals& other);
235
236 protected:
237
238 std::list< Interval > m_intervals;
239
240}; // eo Intervals
241
242
96d0be2e
TJ
243/*
244** clock funcs:
245*/
246
247
248bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
b7e17426 249long long monotonic_clock_gettime_nano();
96d0be2e
TJ
250
251bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
252
8b5814e2
PG
253namespace I2n {
254
255namespace clock {
256
e36ca33c
PG
257 namespace {
258
259 /* helper for ctor initializer list; we still lack aggregate initializers */
260 struct timespec
261 timespec_of_parts (const time_t sec, const long nsec)
262 {
263 struct timespec ret = { sec, nsec};
264
265 return ret;
266 }
267
268 } /* [namespace] */
269
8b5814e2
PG
270 namespace type {
271 /*
272 * represent the clock id options from clock_gettime(2) as
273 * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
274 * everywhere since that’s what we want in most cases.
275 */
276 enum id {
277 mono, /* CLOCK_MONOTONIC_COARSE */
278 real, /* CLOCK_REALIME_COARSE */
279 boot, /* CLOCK_BOOTTIME */
280 cpu, /* CLOCK_CPUTIME_* */
281 };
282
283 /*
284 * for clocks that support it: non-coarse or raw variants; if a variant
285 * does not apply to a given clock, it is ignored
286 */
287 enum variant {
288 dflt, /* all */
289 exact, /* mono, real: not (*_COARSE) */
290 raw, /* mono: _RAW */
291 process, /* cpu: *_PROCESS_* */
292 thread, /* cpu: *_THREAD_* */
293 };
294
295 } /* [namespace type] */
296
297
298 class Time {
299
300 private:
e36ca33c 301 struct timespec value;
8b5814e2
PG
302
303 public:
e36ca33c
PG
304 enum type::id id;
305 enum type::variant variant;
306 int err;
307
308 private:
309 /*
310 * Handle decimal part (nanosecond) overflow; this is performed
311 * after arithmetic operations and whenever we there is the
312 * possibility of unsanitized input for example in constructors
313 * from other types and suchlike.
314 *
315 * POSIX defines the ns part as *long*. Technically, that means
316 * that on machines where *sizeof long* equals *sizeof int*, it can
317 * represent only up to arund 2.1 seconds. In this range, the loop
318 * version is most likely faster than division. However, since in
319 * practice *long* is 8 bytes just about anywhere, we have to
320 * handle greater dividends first.
321 */
322 inline void
323 carry_nsec (void)
324 {
325# if LONG_BIT > 32
326 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
327 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
328 {
329 const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
330 this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
331 this->value.tv_sec += sec;
332 }
333# endif /* [LONG_BIT > 32] */
334 while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
335 this->value.tv_sec += 1;
336 this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
337 }
338
339 while (this->value.tv_nsec < 0) {
340 this->value.tv_sec -= 1;
341 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
342 }
343 }
8b5814e2
PG
344
345 /* ctors *************************************************************/
346 public:
347
348 Time (const enum type::id id = type::mono,
e36ca33c
PG
349 const enum type::variant var = type::dflt) NOEXCEPT;
350
351 inline Time (const Time &t) NOEXCEPT
352 : value (t.value)
353 , id (t.id)
354 , variant (t.variant)
355 , err (t.err)
356 { }
357
358 inline Time (const time_t sec,
359 const long nsec = 0,
360 const enum type::id id = type::mono,
361 const enum type::variant var = type::dflt,
362 const int err = 0) NOEXCEPT
363 : value (timespec_of_parts (sec, nsec))
364 , id (id)
365 , variant (var)
366 , err (err)
367 { this->carry_nsec (); }
368
2795e39c
PG
369 Time (const struct tm &tm,
370 const enum type::id id = type::mono,
371 const enum type::variant var = type::dflt) NOEXCEPT;
372
e36ca33c 373 /* value read access *************************************************/
8b5814e2
PG
374 public:
375
e36ca33c 376 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
8b5814e2
PG
377 { return this->value; }
378
e36ca33c
PG
379 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
380 { return this->value.tv_sec; }
8b5814e2 381
e36ca33c 382 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
8b5814e2
PG
383 { return this->value.tv_nsec; }
384
e36ca33c 385 int64_t as_nanosec (void) const NOEXCEPT;
8b5814e2 386
e36ca33c 387 long as_nanosec_L (void) const NOEXCEPT;
8b5814e2 388
e36ca33c 389 /* value write access ************************************************/
8b5814e2
PG
390 public:
391
392 inline void
e36ca33c
PG
393 swap (Time &t) NOEXCEPT
394 {
395 std::swap (this->value , t.value );
396 std::swap (this->id , t.id );
397 std::swap (this->variant, t.variant);
398 std::swap (this->err , t.err );
399 }
400
401 Time &operator= (Time t) NOEXCEPT;
402
403 Time &operator= (struct timespec ts) NOEXCEPT;
8b5814e2
PG
404
405 inline void
e36ca33c
PG
406 set (const struct timespec &ts) NOEXCEPT
407 {
408 this->value = ts;
409 this->carry_nsec ();
410 }
411
412 inline void
413 set (const time_t sec,
414 const long nsec,
415 const enum type::id id = type::mono,
416 const enum type::variant var = type::dflt) NOEXCEPT
8b5814e2
PG
417 {
418 this->value.tv_sec = sec;
419 this->value.tv_nsec = nsec;
e36ca33c
PG
420 this->id = id;
421 this->variant = var;
422
423 this->carry_nsec ();
424 }
8b5814e2 425
e36ca33c
PG
426 bool set (void) NOEXCEPT;
427
428 void unset (void) NOEXCEPT;
429
430 /* arithmetic ********************************************************/
431 public:
8b5814e2 432
e36ca33c
PG
433 Time &add (const time_t sec, const long nsec) NOEXCEPT;
434
435 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
436
437 inline Time &add (const Time &t2) NOEXCEPT
438 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
439
440 inline Time &add (const time_t t2) NOEXCEPT
441 { return this->add (t2, 0L); };
442
443 inline Time &subtract (const Time &t2) NOEXCEPT
444 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
445
446 inline Time &subtract (const time_t t2) NOEXCEPT
447 { return this->subtract (t2, 0L); };
448
c42fd3b3
PG
449 Time &scale (const int64_t factor) NOEXCEPT;
450
451 Time &divide (const int64_t divisor) NOEXCEPT;
e36ca33c
PG
452
453 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
454
455 inline Time
456 difference (const Time &t) NOEXCEPT
457 { return (*this < t) ? t - *this : *this - t; }
458
459 /* overloads *********************************************************/
460 public:
461
462 inline Time
463 operator+ (const Time &t2) const NOEXCEPT
464 { return Time (*this).add (t2); }
465
466 inline Time
467 operator+ (const time_t t2) const NOEXCEPT
468 { return Time (*this).add (t2); }
469
470 inline Time &
471 operator+= (const Time &t2) NOEXCEPT
472 { return this->add (t2); }
473
474 inline Time &
475 operator+= (const time_t t2) NOEXCEPT
476 { return this->add (t2); }
477
478 inline Time
479 operator- (const Time &t2) const NOEXCEPT
480 { return Time (*this).subtract (t2); }
481
482 inline Time
483 operator- (const time_t t2) const NOEXCEPT
484 { return Time (*this).subtract (t2); }
485
486 inline Time &
487 operator-= (const Time &t2) NOEXCEPT
488 { return this->subtract (t2); }
489
490 inline Time &
491 operator-= (const time_t t2) NOEXCEPT
492 { return this->subtract (t2); }
493
494 inline Time
c42fd3b3 495 operator* (const int64_t factor) const NOEXCEPT
e36ca33c
PG
496 { return Time (*this).scale (factor); }
497
498 inline Time &
c42fd3b3 499 operator*= (const int64_t factor) NOEXCEPT
e36ca33c
PG
500 { return this->scale (factor); }
501
c42fd3b3
PG
502 inline Time
503 operator/ (const int64_t divisor) const NOEXCEPT
504 { return Time (*this).divide (divisor); }
505
506 inline Time &
507 operator/= (const int64_t divisor) NOEXCEPT
508 { return this->divide (divisor); }
509
e36ca33c
PG
510 friend CONSTEXPR bool
511 operator== (const Time &t1, const Time &t2) NOEXCEPT;
512
513 friend CONSTEXPR bool
514 operator< (const Time &t1, const Time &t2) NOEXCEPT;
515
516 friend CONSTEXPR bool
517 operator> (const Time &t1, const Time &t2) NOEXCEPT;
518
519 friend std::ostream &
520 operator<< (std::ostream &os, const Time &t);
8b5814e2 521
72acd54c
PG
522 /* formatting ********************************************************/
523 public:
524
525 boost::optional<std::string>
526 format_iso8601 (const bool utc = true,
527 const bool date = true,
528 const bool time = true,
529 const bool tz = true) const;
530
531 boost::optional<std::string> make_nice_time (void) const;
532 boost::optional<std::string> format_full_time (void) const;
533 boost::optional<std::string> format_date (void) const;
534
8b5814e2
PG
535 }; /* [class Time] */
536
e36ca33c
PG
537 inline Time
538 operator+ (const time_t t1, const Time &t2) NOEXCEPT
539 { return Time (t1) + t2; }
540
541 inline Time
542 operator- (const time_t t1, const Time &t2) NOEXCEPT
543 { return Time (t1) - t2; }
544
c42fd3b3
PG
545 inline Time
546 operator* (const time_t t1, const Time &t2) NOEXCEPT
547 { return t2 * t1; }
548
e36ca33c
PG
549 int compare (const Time &t1, const Time &t2) NOEXCEPT;
550
551 /*
552 * comparison for equality also considers the clock type;
553 */
554 inline CONSTEXPR bool
555 operator== (const Time &t1, const Time &t2) NOEXCEPT
556 {
557 return t1.id == t2.id && t1.variant == t2.variant
558 && t1.value.tv_sec == t2.value.tv_sec
559 && t1.value.tv_nsec == t2.value.tv_nsec
560 ;
561 }
562
563 /* these ignore the *id* and *variant* fields */
564 inline CONSTEXPR bool
565 operator< (const Time &t1, const Time &t2) NOEXCEPT
566 {
567 return t1.value.tv_sec < t2.value.tv_sec
568 || ( t1.value.tv_sec == t2.value.tv_sec
569 && t1.value.tv_nsec < t2.value.tv_nsec)
570 ;
571 }
572
573 /* these ignore the *id* and *variant* fields */
574 inline CONSTEXPR bool
575 operator> (const Time &t1, const Time &t2) NOEXCEPT
576 {
577 return t1.value.tv_sec > t2.value.tv_sec
578 || ( t1.value.tv_sec == t2.value.tv_sec
579 && t1.value.tv_nsec > t2.value.tv_nsec)
580 ;
581 }
582
583 inline std::ostream &
584 operator<< (std::ostream &os, const Time &t)
585 {
586 os << I2n::to_string (t.value.tv_sec) << "ms, "
587 << I2n::to_string (t.value.tv_nsec) << "ns"
588 ;
589
590 return os;
591 }
592
8b5814e2
PG
593 boost::optional<Time>
594 now (const enum type::id id = type::mono,
e36ca33c
PG
595 const enum type::variant var = type::dflt) NOEXCEPT;
596
597 Time
598 zero (const enum type::id id = type::mono,
599 const enum type::variant var = type::dflt) NOEXCEPT;
8b5814e2 600
2795e39c
PG
601 boost::optional<Time>
602 time_of_iso8601 (const std::string &s,
603 const bool date = true,
604 const bool time = true,
605 const bool tz = true,
606 const enum type::id id = type::real,
607 const enum type::variant var = type::dflt) NOEXCEPT;
608
c42fd3b3
PG
609 template <typename ContT>
610 Time
611 mean (const ContT &data)
612 {
613 Time sum (0, 0);
614
615 if (data.size () == 0) {
616 return sum;
617 }
618
619 for (typename ContT::const_iterator it = data.begin ();
620 it != data.end (); ++it)
621 {
622 sum += *it;
623 };
624
625 return sum.divide (static_cast<int64_t> (data.size ()));
626 };
627
628 template <typename ContT>
629 Time
630 median (const ContT &data)
631 {
632 if (data.size () == 0) {
633 return zero ();
634 }
635 if (data.size () == 1) {
636 return *data.begin ();
637 }
638
639 std::vector<typename ContT::value_type> sorted;
640 std::copy (data.begin (), data.end (), std::back_inserter (sorted));
641 std::sort (sorted.begin (), sorted.end ());
642
643 return sorted [data.size () / 2];
644 };
645
8b5814e2
PG
646} /* [namespace clock] */
647
648} /* [namespace I2n] */
1b5dfd98
TJ
649
650
e93545dd 651#endif