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