add ISO-8601 formatters to timefunc
[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>
1b5dfd98 33
8b5814e2
PG
34#include <boost/optional.hpp>
35
0c7e72d7 36#include <week.hpp>
f1499910 37
e36ca33c
PG
38#include "stringfunc.hxx"
39
40#if __cplusplus >= 201103
41# define CONSTEXPR constexpr
42# define NOEXCEPT noexcept
43#else
44# define CONSTEXPR
45# define NOEXCEPT
46#endif
47
48#define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000)
49
e93545dd
GE
50double prec_time(void);
51
dad9e26f 52time_t date_to_seconds(const std::string &date);
e93545dd
GE
53
54std::string make_nice_time(int seconds);
7839bd53 55std::string format_full_time(time_t seconds);
25f3d405 56std::string format_date(time_t seconds);
d70f7269
PG
57std::string format_iso8601(const struct tm &tm, const bool date=true,
58 const bool time=true, const bool tz=true);
59std::string format_iso8601(time_t t, const bool utc=true,
60 const bool date=true, const bool time=true,
61 const bool tz=true);
62inline std::string format_iso8601(const struct timespec ts, const bool utc=true,
63 const bool date=true, const bool time=true,
64 const bool tz=true)
65{ return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
66
87869870 67void seconds_to_hour_minute(int seconds, int *hour, int *minute);
c0368918
GE
68void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
69std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
2c66f490
GE
70
71inline std::string output_hour_minute_from_seconds(int seconds)
72{
73 int hour, minute;
c0368918 74 split_daysec(seconds,&hour,&minute);
2c66f490
GE
75 return output_hour_minute(hour,minute);
76}
e93545dd 77
4e157d1d
TJ
78std::string get_month_name(unsigned char month);
79
1b5dfd98
TJ
80/**
81 * @brief structure representing a single (half-open) interval.
82 */
83class Interval
84{
85 public:
86 Interval()
87 : m_lower_bound(0)
88 , m_upper_bound(0)
80f30818
TJ
89 , m_weak_mark(0)
90 , m_changed(false)
1b5dfd98
TJ
91 {
92 } //
93
80f30818 94 Interval( unsigned int start, unsigned int end, int weak_mark= 0 )
1b5dfd98
TJ
95 : m_lower_bound(start)
96 , m_upper_bound(end)
80f30818
TJ
97 , m_weak_mark(weak_mark)
98 , m_changed(false)
1b5dfd98
TJ
99 {
100 } //
101
d181c3bc
TJ
102
103 void clear();
104
1b5dfd98
TJ
105 bool is_valid() const
106 {
107 return m_lower_bound <= m_upper_bound;
108 } // eo is_valid() const
109
110 bool empty() const
111 {
112 return m_lower_bound == m_upper_bound;
113 } // eo empty() const
114
115
116 unsigned int lower_bound() const { return m_lower_bound; }
117 unsigned int upper_bound() const { return m_upper_bound; }
118
80f30818
TJ
119 int weak_mark() const { return m_weak_mark; }
120
121 bool changed() const { return m_changed; }
122
1b5dfd98
TJ
123
124 bool operator== (const Interval& other) const
125 {
126 return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound;
127 } // eo operator==(const Interval&)
128
129
ebc3b584
TJ
130 bool operator!=(const Interval& other) const
131 {
132 return not (*this == other);
133 } // eo operator!=(const Interval&)
134
135
1b5dfd98
TJ
136 /**
137 * @brief less operator. compares only the start times!
138 * @param other the other interval to compare with.
139 * @return @a true if the current start is less than the other start.
140 */
141 bool operator<(const Interval& other) const
142 {
143 return m_lower_bound < other.m_lower_bound;
144 } // eo operator<(const Interval&)
145
146
147 bool intersects(const Interval& other) const;
148 bool contains(const Interval& other) const;
149
150
151 protected:
152
153 friend class Intervals;
154
155 unsigned int m_lower_bound;
156 unsigned int m_upper_bound;
157
80f30818
TJ
158 int m_weak_mark;
159 bool m_changed;
160
1b5dfd98
TJ
161}; // eo Interval
162
163
164
165/**
166 * @brief structure representing a combination of single disjoint (half open) intervals.
167 *
168 * Basic idea is that this structure provides an interface for adding and
169 * subtracting single intervals and keeps the internal list of intervals as
170 * a list of disjoint intervals.
171 *
172 * @note the list is sorted by the start; lower comes first.
173 *
174 * @note the class provides some methods similar to STL container classes;
175 * i.e. it can be used with (at least some) STL algorithms.
176 *
177 * @internal
178 * we use a std::list for the intervals; this means we don't invalidate all
179 * iterators when we insert or delete within loops...
180 * And we use that fact!!
181 */
182class Intervals
183{
184 public:
185 typedef std::list< Interval > IntervalList;
186 typedef IntervalList::value_type value_type;
187 typedef IntervalList::const_iterator const_iterator;
188 typedef IntervalList::const_iterator iterator; // we allow only const...
189 typedef IntervalList::size_type size_type;
190
191 public:
192 Intervals();
193
194 void add(const Interval& new_frame);
195 void sub(const Interval& new_frame);
196
d181c3bc 197 void clear();
1b5dfd98
TJ
198
199 const_iterator begin() const { return m_intervals.begin(); }
200 const_iterator end() const { return m_intervals.end(); }
201
202 bool empty() const { return m_intervals.empty(); }
203 const Interval& front() const { return m_intervals.front(); }
204 const Interval& back() const { return m_intervals.back(); }
205
206 size_type size() const { return m_intervals.size(); }
207
208 bool intersects(const Interval& other) const;
209 bool intersects(const Intervals& other) const;
210
211 bool contains(const Interval& other) const;
212 bool contains(const Intervals& other) const;
213
e156de7c
TJ
214 bool contains_exact(const Interval& other) const;
215
1b5dfd98 216 bool operator==(const Intervals& other) const;
ebc3b584 217 bool operator!=(const Intervals& other) const { return not (*this == other) ; }
1b5dfd98
TJ
218
219 Intervals& operator+=(const Interval& other);
220 Intervals& operator-=(const Interval& other);
221
222 Intervals& operator+=(const Intervals& other);
223 Intervals& operator-=(const Intervals& other);
224
225 protected:
226
227 std::list< Interval > m_intervals;
228
229}; // eo Intervals
230
231
96d0be2e
TJ
232/*
233** clock funcs:
234*/
235
236
237bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
b7e17426 238long long monotonic_clock_gettime_nano();
96d0be2e
TJ
239
240bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
241
8b5814e2
PG
242namespace I2n {
243
244namespace clock {
245
e36ca33c
PG
246 namespace {
247
248 /* helper for ctor initializer list; we still lack aggregate initializers */
249 struct timespec
250 timespec_of_parts (const time_t sec, const long nsec)
251 {
252 struct timespec ret = { sec, nsec};
253
254 return ret;
255 }
256
257 } /* [namespace] */
258
8b5814e2
PG
259 namespace type {
260 /*
261 * represent the clock id options from clock_gettime(2) as
262 * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used
263 * everywhere since that’s what we want in most cases.
264 */
265 enum id {
266 mono, /* CLOCK_MONOTONIC_COARSE */
267 real, /* CLOCK_REALIME_COARSE */
268 boot, /* CLOCK_BOOTTIME */
269 cpu, /* CLOCK_CPUTIME_* */
270 };
271
272 /*
273 * for clocks that support it: non-coarse or raw variants; if a variant
274 * does not apply to a given clock, it is ignored
275 */
276 enum variant {
277 dflt, /* all */
278 exact, /* mono, real: not (*_COARSE) */
279 raw, /* mono: _RAW */
280 process, /* cpu: *_PROCESS_* */
281 thread, /* cpu: *_THREAD_* */
282 };
283
284 } /* [namespace type] */
285
286
287 class Time {
288
289 private:
e36ca33c 290 struct timespec value;
8b5814e2
PG
291
292 public:
e36ca33c
PG
293 enum type::id id;
294 enum type::variant variant;
295 int err;
296
297 private:
298 /*
299 * Handle decimal part (nanosecond) overflow; this is performed
300 * after arithmetic operations and whenever we there is the
301 * possibility of unsanitized input for example in constructors
302 * from other types and suchlike.
303 *
304 * POSIX defines the ns part as *long*. Technically, that means
305 * that on machines where *sizeof long* equals *sizeof int*, it can
306 * represent only up to arund 2.1 seconds. In this range, the loop
307 * version is most likely faster than division. However, since in
308 * practice *long* is 8 bytes just about anywhere, we have to
309 * handle greater dividends first.
310 */
311 inline void
312 carry_nsec (void)
313 {
314# if LONG_BIT > 32
315 if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO
316 || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO)
317 {
318 const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO;
319 this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO;
320 this->value.tv_sec += sec;
321 }
322# endif /* [LONG_BIT > 32] */
323 while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) {
324 this->value.tv_sec += 1;
325 this->value.tv_nsec -= TIME_CONST_FACTOR_NANO;
326 }
327
328 while (this->value.tv_nsec < 0) {
329 this->value.tv_sec -= 1;
330 this->value.tv_nsec += TIME_CONST_FACTOR_NANO;
331 }
332 }
8b5814e2
PG
333
334 /* ctors *************************************************************/
335 public:
336
337 Time (const enum type::id id = type::mono,
e36ca33c
PG
338 const enum type::variant var = type::dflt) NOEXCEPT;
339
340 inline Time (const Time &t) NOEXCEPT
341 : value (t.value)
342 , id (t.id)
343 , variant (t.variant)
344 , err (t.err)
345 { }
346
347 inline Time (const time_t sec,
348 const long nsec = 0,
349 const enum type::id id = type::mono,
350 const enum type::variant var = type::dflt,
351 const int err = 0) NOEXCEPT
352 : value (timespec_of_parts (sec, nsec))
353 , id (id)
354 , variant (var)
355 , err (err)
356 { this->carry_nsec (); }
357
358 /* value read access *************************************************/
8b5814e2
PG
359 public:
360
e36ca33c 361 inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT
8b5814e2
PG
362 { return this->value; }
363
e36ca33c
PG
364 inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT
365 { return this->value.tv_sec; }
8b5814e2 366
e36ca33c 367 inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT
8b5814e2
PG
368 { return this->value.tv_nsec; }
369
e36ca33c 370 int64_t as_nanosec (void) const NOEXCEPT;
8b5814e2 371
e36ca33c 372 long as_nanosec_L (void) const NOEXCEPT;
8b5814e2 373
e36ca33c 374 /* value write access ************************************************/
8b5814e2
PG
375 public:
376
377 inline void
e36ca33c
PG
378 swap (Time &t) NOEXCEPT
379 {
380 std::swap (this->value , t.value );
381 std::swap (this->id , t.id );
382 std::swap (this->variant, t.variant);
383 std::swap (this->err , t.err );
384 }
385
386 Time &operator= (Time t) NOEXCEPT;
387
388 Time &operator= (struct timespec ts) NOEXCEPT;
8b5814e2
PG
389
390 inline void
e36ca33c
PG
391 set (const struct timespec &ts) NOEXCEPT
392 {
393 this->value = ts;
394 this->carry_nsec ();
395 }
396
397 inline void
398 set (const time_t sec,
399 const long nsec,
400 const enum type::id id = type::mono,
401 const enum type::variant var = type::dflt) NOEXCEPT
8b5814e2
PG
402 {
403 this->value.tv_sec = sec;
404 this->value.tv_nsec = nsec;
e36ca33c
PG
405 this->id = id;
406 this->variant = var;
407
408 this->carry_nsec ();
409 }
8b5814e2 410
e36ca33c
PG
411 bool set (void) NOEXCEPT;
412
413 void unset (void) NOEXCEPT;
414
415 /* arithmetic ********************************************************/
416 public:
8b5814e2 417
e36ca33c
PG
418 Time &add (const time_t sec, const long nsec) NOEXCEPT;
419
420 Time &subtract (const time_t sec, const long nsec) NOEXCEPT;
421
422 inline Time &add (const Time &t2) NOEXCEPT
423 { return this->add (t2.value.tv_sec, t2.value.tv_nsec); }
424
425 inline Time &add (const time_t t2) NOEXCEPT
426 { return this->add (t2, 0L); };
427
428 inline Time &subtract (const Time &t2) NOEXCEPT
429 { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); }
430
431 inline Time &subtract (const time_t t2) NOEXCEPT
432 { return this->subtract (t2, 0L); };
433
434 Time &scale (const time_t factor) NOEXCEPT;
435
436 friend int compare (const Time &t1, const Time &t2) NOEXCEPT;
437
438 inline Time
439 difference (const Time &t) NOEXCEPT
440 { return (*this < t) ? t - *this : *this - t; }
441
442 /* overloads *********************************************************/
443 public:
444
445 inline Time
446 operator+ (const Time &t2) const NOEXCEPT
447 { return Time (*this).add (t2); }
448
449 inline Time
450 operator+ (const time_t t2) const NOEXCEPT
451 { return Time (*this).add (t2); }
452
453 inline Time &
454 operator+= (const Time &t2) NOEXCEPT
455 { return this->add (t2); }
456
457 inline Time &
458 operator+= (const time_t t2) NOEXCEPT
459 { return this->add (t2); }
460
461 inline Time
462 operator- (const Time &t2) const NOEXCEPT
463 { return Time (*this).subtract (t2); }
464
465 inline Time
466 operator- (const time_t t2) const NOEXCEPT
467 { return Time (*this).subtract (t2); }
468
469 inline Time &
470 operator-= (const Time &t2) NOEXCEPT
471 { return this->subtract (t2); }
472
473 inline Time &
474 operator-= (const time_t t2) NOEXCEPT
475 { return this->subtract (t2); }
476
477 inline Time
478 operator* (const time_t factor) const NOEXCEPT
479 { return Time (*this).scale (factor); }
480
481 inline Time &
482 operator*= (const time_t factor) NOEXCEPT
483 { return this->scale (factor); }
484
485 friend CONSTEXPR bool
486 operator== (const Time &t1, const Time &t2) NOEXCEPT;
487
488 friend CONSTEXPR bool
489 operator< (const Time &t1, const Time &t2) NOEXCEPT;
490
491 friend CONSTEXPR bool
492 operator> (const Time &t1, const Time &t2) NOEXCEPT;
493
494 friend std::ostream &
495 operator<< (std::ostream &os, const Time &t);
8b5814e2
PG
496
497 }; /* [class Time] */
498
e36ca33c
PG
499 inline Time
500 operator+ (const time_t t1, const Time &t2) NOEXCEPT
501 { return Time (t1) + t2; }
502
503 inline Time
504 operator- (const time_t t1, const Time &t2) NOEXCEPT
505 { return Time (t1) - t2; }
506
507 int compare (const Time &t1, const Time &t2) NOEXCEPT;
508
509 /*
510 * comparison for equality also considers the clock type;
511 */
512 inline CONSTEXPR bool
513 operator== (const Time &t1, const Time &t2) NOEXCEPT
514 {
515 return t1.id == t2.id && t1.variant == t2.variant
516 && t1.value.tv_sec == t2.value.tv_sec
517 && t1.value.tv_nsec == t2.value.tv_nsec
518 ;
519 }
520
521 /* these ignore the *id* and *variant* fields */
522 inline CONSTEXPR bool
523 operator< (const Time &t1, const Time &t2) NOEXCEPT
524 {
525 return t1.value.tv_sec < t2.value.tv_sec
526 || ( t1.value.tv_sec == t2.value.tv_sec
527 && t1.value.tv_nsec < t2.value.tv_nsec)
528 ;
529 }
530
531 /* these ignore the *id* and *variant* fields */
532 inline CONSTEXPR bool
533 operator> (const Time &t1, const Time &t2) NOEXCEPT
534 {
535 return t1.value.tv_sec > t2.value.tv_sec
536 || ( t1.value.tv_sec == t2.value.tv_sec
537 && t1.value.tv_nsec > t2.value.tv_nsec)
538 ;
539 }
540
541 inline std::ostream &
542 operator<< (std::ostream &os, const Time &t)
543 {
544 os << I2n::to_string (t.value.tv_sec) << "ms, "
545 << I2n::to_string (t.value.tv_nsec) << "ns"
546 ;
547
548 return os;
549 }
550
8b5814e2
PG
551 boost::optional<Time>
552 now (const enum type::id id = type::mono,
e36ca33c
PG
553 const enum type::variant var = type::dflt) NOEXCEPT;
554
555 Time
556 zero (const enum type::id id = type::mono,
557 const enum type::variant var = type::dflt) NOEXCEPT;
8b5814e2
PG
558
559} /* [namespace clock] */
560
561} /* [namespace I2n] */
1b5dfd98
TJ
562
563
e93545dd 564#endif