2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
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.
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.
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.
21 * @brief time related functions.
23 * @copyright Copyright © 2001-2008 by Intra2net AG
42 #include <timefunc.hxx>
48 double prec_time(void)
50 struct timespec ts = { 0 };
53 if (clock_gettime(CLOCK_REALTIME_COARSE, &ts) == -1) {
54 /* Something’s wrong on the kernel end! */
58 ret = static_cast<double>(ts.tv_sec);
59 ret += static_cast<double>(ts.tv_nsec)
60 / static_cast<double>(TIME_CONST_FACTOR_NANO);
65 // converts ISO-DATE: 2003-06-13
66 time_t date_to_seconds(const std::string &date)
69 int year = -1, month = -1, day = -1;
71 string::size_type pos = date.find("-");
72 if (pos == string::npos)
75 istringstream in(string(date,0,pos));
79 string dstr(date, pos+1);
80 if ((pos = dstr.find("-")) == string::npos)
84 in.str(string(dstr, 0, pos));
89 in.str(string(dstr, pos+1));
92 if (year < 0 || month == -1 || day == -1)
96 memset(&tm_struct, 0, sizeof(struct tm));
97 tm_struct.tm_year = year;
98 tm_struct.tm_mon = month;
99 tm_struct.tm_mday = day;
100 tm_struct.tm_isdst = -1;
102 rtn = mktime (&tm_struct);
106 string make_nice_time(int seconds)
110 int days=seconds/86400;
114 split_daysec(seconds,&hours,&minutes,&seconds);
117 out << days << " " << i18n_plural("day", "days", days) << ", ";
120 out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
125 string format_full_time(time_t seconds)
130 if (localtime_r((time_t *)&seconds, &ta) == NULL)
131 memset (&ta, 0, sizeof(struct tm));
133 strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
137 string format_date(time_t seconds)
142 if (localtime_r((time_t *)&seconds, &ta) == NULL)
143 memset (&ta, 0, sizeof(struct tm));
145 strftime (buf, 49, "%d.%m.%Y", &ta);
149 void seconds_to_hour_minute(int seconds, int *hour, int *minute)
153 while (seconds >= 3600) {
159 if (minute != NULL) {
161 while (seconds >= 60) {
169 * Split seconds into hours, minutes and seconds
170 * @param [in] daysec Seconds since start of day
171 * @param [out] outhours hours
172 * @param [out] outminutes minutes
173 * @param [out] outseconds seconds
175 void split_daysec(int daysec, int *outhours, int *outminutes, int *outseconds)
177 int hours=daysec/3600;
180 int minutes=daysec/60;
193 std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
197 if (hour >= 0 && hour < 10)
201 if (!h_for_00 || minute != 0 || seconds > 0)
204 if (minute >= 0 && minute < 10)
214 if (seconds > 0 && seconds < 10)
222 string get_month_name(unsigned char month)
227 rtn = i18n("January");
230 rtn = i18n("February");
248 rtn = i18n("August");
251 rtn = i18n("September");
254 rtn = i18n("October");
257 rtn = i18n("November");
260 rtn = i18n("December");
265 out << i18n("Illegal month:") << " " << month;
275 ** implementaion of Interval
280 * @brief clears the interval (make it empty).
282 void Interval::clear()
284 m_lower_bound = m_upper_bound = 0;
285 } // eo Interval::clear()
289 * @brief tests if there is some overlapping with another interval
290 * @param other the other interval
291 * @return @a true if the two intervals have a non empty intersection.
293 bool Interval::intersects(const Interval& other) const
296 // // other start within this:
297 (other.m_lower_bound >= m_lower_bound and other.m_lower_bound < m_upper_bound )
298 // // other end within this:
299 or (other.m_upper_bound > m_lower_bound and other.m_upper_bound <= m_upper_bound )
300 // // other contains this
301 or (other.m_lower_bound <= m_lower_bound and other.m_upper_bound >= m_upper_bound )
303 } // eo Interval::intersects(const Interval&)
307 * @brief tests if the current interval (fully) contains another one.
308 * @param other the other interval.
309 * @return @a true if the current interval fully contains the other interval.
311 bool Interval::contains(const Interval& other) const
313 return (other.m_lower_bound >= m_lower_bound)
314 and (other.m_upper_bound <= m_upper_bound)
316 } // eo Interval::contains(const Interval& other) const
320 ** implementation of Intervals:
324 Intervals::Intervals()
326 } // eo Intervals::Intervals
329 void Intervals::clear()
332 } // eo Intervals::clear()
335 * @brief tests if one of the intervals of the list intersects with the given interval.
336 * @param other the interval to check for intersection.
337 * @return @a true if there is an intersection.
339 bool Intervals::intersects(const Interval& other) const
341 for(const_iterator it= begin();
345 if ( it->intersects(other) )
351 } // eo Intervals::intersects(const Interval&) const
355 * @brief tests if we have at least one intersection with another Intervals instance.
356 * @param other the other instance.
357 * @return @a true if there is an intersection.
359 bool Intervals::intersects(const Intervals& other) const
361 for(const_iterator it= begin();
365 if ( other.intersects( *it ) )
371 } // eo Intervals::intersects(const Intervals&) const
375 * @brief adds a new interval to the list.
376 * @param new_frame the new interval.
378 * Adds the interval to the list and joins overlapping intervals.
380 * @internal complexity O(n).
382 void Intervals::add(const Interval& new_frame)
384 if (not new_frame.is_valid() or new_frame.empty())
386 // well... we will not insert invalid or empty frames!
389 for (IntervalList::iterator it= m_intervals.begin();
390 it != m_intervals.end();
393 Interval& current_frame = *it;
394 if ( new_frame.m_lower_bound > current_frame.m_upper_bound )
396 // new_frame begins later than current end; go on:
399 // at this point: the begin of the new frame is less then the current end.
400 // now let's determine how we can insert the new frame:
402 if ( new_frame.m_upper_bound < current_frame.m_lower_bound )
404 // new disjoint frame; insert it before the current frame:
405 m_intervals.insert( it, new_frame );
409 // at this point: the end of the new frame is >= current begin.
410 if ( new_frame.m_upper_bound <= current_frame.m_upper_bound )
412 // the end of the new frame is within our current frame; we need to combine
413 if (new_frame.m_lower_bound < current_frame.m_lower_bound)
415 // the new interval starts earlier; we need to adjust our current frame:
416 current_frame.m_lower_bound = new_frame.m_lower_bound;
417 current_frame.m_changed = true;
419 // NOTE no "else" part needed since in that case our current frame already
420 // contains the new one!
425 // at this point: end of new frame > end of current frame
426 // so we need to extend the current frame; at least the end.
427 // But we need to deal with intersects of following frames... *sigh*
429 // first the simple part: let's see if we need to move the start:
430 if ( new_frame.m_lower_bound < current_frame.m_lower_bound)
432 // yes, we need to move the start:
433 current_frame.m_lower_bound = new_frame.m_lower_bound;
434 current_frame.m_changed= true;
437 // now let's extend the end:
438 current_frame.m_upper_bound = new_frame.m_upper_bound;
439 current_frame.m_changed = true;
441 // well... let's walk through the following frames; looking for more joins...:
442 IntervalList::iterator it2 = it;
443 while( ++(it2=it) != m_intervals.end()
444 and current_frame.m_upper_bound >= it2->m_lower_bound
447 Interval next_frame= *it2;
448 if ( current_frame.m_upper_bound < next_frame.m_upper_bound )
450 // in this case our end is within the next frame.
452 current_frame.m_upper_bound = next_frame.m_upper_bound;
454 // and remove the next frame since the current frame contains it (now):
455 m_intervals.erase(it2);
460 // at this point: new frame starts later than the last frame ends
461 // append the new frame:
462 m_intervals.push_back( new_frame );
463 } // eo Intervals::add(const Interval&)
467 * @brief subtracts a time interval from the list.
468 * @param del_frame the time interval to subtract.
470 * removes the time interval from the list; cut off parts from or remove existing
471 * intervals if they overlap.
473 * @internal complexity O(n).
475 void Intervals::sub(const Interval& del_frame)
477 if (not del_frame.is_valid() or del_frame.empty() )
481 for (IntervalList::iterator it= m_intervals.begin();
482 it != m_intervals.end();
485 Interval& current_frame = *it;
486 if ( del_frame.m_lower_bound >= current_frame.m_upper_bound )
488 // del_frame begins later than current end; go on:
492 // at this point: the begin of the del frame is less then the current end.
493 if ( del_frame.m_upper_bound < current_frame.m_lower_bound )
495 // end is before our start; nothing to do.
498 // at this point: the end of the del frame is >= current begin.
499 if ( del_frame.m_upper_bound < current_frame.m_upper_bound )
501 // del frame end point is within our interval.
502 if ( del_frame.m_lower_bound > current_frame.m_lower_bound)
504 // the del frame is within our interval... we need to split:
505 m_intervals.insert(it, Interval( current_frame.m_lower_bound, del_frame.m_lower_bound ) );
507 // adjust start of current frame:
508 if (current_frame.m_lower_bound < del_frame.m_upper_bound)
510 current_frame.m_lower_bound= del_frame.m_upper_bound;
511 current_frame.m_changed= true;
516 // at this point the end of the del frame is >= current end
517 if ( del_frame.m_lower_bound > current_frame.m_lower_bound )
519 // a part of the current interval needs to be preserved..
521 current_frame.m_upper_bound= del_frame.m_lower_bound;
522 current_frame.m_changed= true;
523 // and continue with the next interval:
527 // at this point; the whole frame needs to be deleted..
528 if ( it == m_intervals.begin())
530 m_intervals.erase(it);
531 it= m_intervals.begin();
535 IntervalList::iterator it2= it++;
536 m_intervals.erase(it2);
539 } // eo Intervals::sub(const Interval&)
543 * @brief returns if we contain an interval.
544 * @param other the interval to check.
545 * @return @a true if we cover the given interval, too.
547 bool Intervals::contains(const Interval& other) const
549 for(const_iterator it= begin();
553 if ( it->contains( other ))
559 } // eo Intervals::contains(const Interval&) const
563 * @brief returns if we contain an exact interval.
564 * @param other the interval to check.
565 * @return @a true if we axactly contains the given interval.
567 * @note thsi differs from contain in the way, that we return only @a true
568 * iff we have the given interval in our list; not only cover it.
570 bool Intervals::contains_exact(const Interval& other) const
572 for(const_iterator it= begin();
582 } // eo Intervals::contains_exact(const Interval&)const
586 * @brief returns if we contain another interval combination.
587 * @param other the intervals to check.
588 * @return @a true if we cover the given intervals, too.
590 * @internal we rely on the fact that the lists are sorted and contain
591 * disjoint intervals.
593 * So this method has a complexity of O(n).
595 bool Intervals::contains(const Intervals& other) const
597 const_iterator my_it= begin();
598 const_iterator other_it= other.begin();
599 while( my_it != end() and other_it!= other.end() )
601 // seek the first interval which contains the lower bound of the current other interval
602 while (my_it != end()
603 and my_it->m_lower_bound > other_it->m_lower_bound
604 and other_it->m_lower_bound >= my_it->m_upper_bound
613 if (not my_it->contains( *other_it ))
615 // if we don't contain the current other; we're done:
618 //else check the next other interval:
621 return (other_it == other.end());
622 } // eo Intervals::contains(const Intervals&) const
626 * @brief combines to interval combinates for equality
627 * @param other the other instance.
628 * @return @a true if the other is equal to the current.
630 * @internal since the lists are sorted, we compare the interval lists.
631 * Thus we have a complexity of O(n).
633 bool Intervals::operator==(const Intervals& other) const
635 // since we keep sorted lists: just compare the lists :-)
636 return m_intervals == other.m_intervals;
637 } // eo Intervals::operator==(const Intervals&)
640 Intervals& Intervals::operator+=(const Interval& other)
644 } // eo operator+=(const Interval&)
647 Intervals& Intervals::operator-=(const Interval& other)
651 } // eo operator-=(const Interval&)
655 * @brief adds the intervals of a second instance to us.
656 * @param other the other instance.
657 * @return self reference (allow chaining).
659 * @internal since we do simple loops over the other and our intervals
660 * we have a complexity of O(n^2).
662 * @todo optimize if complexity becomes a problem.
664 Intervals& Intervals::operator+=(const Intervals& other)
666 for(const_iterator it= other.begin();
673 } // eo operator+=(const Intervals&)
677 * @brief subtracts the intervals of a second instance from us.
678 * @param other the other instance.
679 * @return self reference (allow chaining).
681 * @internal since we do simple loops over the other and our intervals
682 * we have a complexity of O(n^2).
684 * @todo optimize if complexity becomes a problem.
686 Intervals& Intervals::operator-=(const Intervals& other)
694 for(const_iterator it= other.begin();
702 } // eo operator-=(const Intervals&)
712 * @brief fetches the value from the monotonic clock source.
713 * @param[out] seconds the seconds.
714 * @param[out] nano_seconds the nano seconds.
715 * @return @a true if the clock was successfully read.
717 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
719 struct timespec tp[1];
720 int res= clock_gettime (CLOCK_MONOTONIC, tp);
724 nano_seconds= tp->tv_nsec;
727 } // eo monotonic_clock_gettime(long int&,long int&)
731 * @brief fetches the value from the monotonic clock source.
732 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
734 long long monotonic_clock_gettime_nano()
737 long int nano_seconds;
740 if (monotonic_clock_gettime(seconds,nano_seconds))
751 * @brief fetches the value from the monotonic clock source.
752 * @param[out] seconds the seconds.
753 * @param[out] nano_seconds the nano seconds.
754 * @return @a true if the clock was successfully read.
756 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
758 struct timespec tp[1];
759 int res= clock_gettime(CLOCK_REALTIME, tp);
763 nano_seconds= tp->tv_nsec;
766 } // eo realtime_clock_gettime(long int&,long int&)
770 * There is a discrepancy of one input character
771 * due to the lack of sign handling in strptime(3):
773 * - strftime(3) needs the year specified as %5Y to account for the
775 * - strptime(3) will not parse the leading dash with that format
776 * but apart from that it works well.
782 * max: -YYYYYYYYYY-MM-DDThh:mm:ssZ+zzzz ⇒ 32
783 * That is assuming the year in broken down time is an int we
784 * need to reserve ten decimal places.
786 // static_assert (sizeof (((struct tm *)NULL)->tm_year) == 4);
787 static const size_t bufsize = 33;
799 * Unfortunately the glibc strptime(3) on the Intranator trips over
800 * the length specifier in field descriptors so we can’t reuse the
801 * formatters here. This problem is fixed in newer glibc. For the time
802 * being we keep two tables of formatters and choose the appropriate
806 static const char *const formatter [ISO8601_SIZE] =
807 { /* [iso8601::d ] = */ "%4Y-%m-%d",
808 /* [iso8601::t ] = */ "%T",
809 /* [iso8601::tz ] = */ "%TZ%z",
810 /* [iso8601::dt ] = */ "%4Y-%m-%dT%T",
811 /* [iso8601::dtz] = */ "%4Y-%m-%dT%TZ%z",
814 static const char *const scanner [ISO8601_SIZE] =
815 { /* [iso8601::d ] = */ "%Y-%m-%d",
816 /* [iso8601::t ] = */ "%T",
817 /* [iso8601::tz ] = */ "%TZ%z",
818 /* [iso8601::dt ] = */ "%Y-%m-%dT%T",
819 /* [iso8601::dtz] = */ "%Y-%m-%dT%TZ%z",
822 static inline const char *
823 pick_fmt (const bool date, const bool time, const bool tz, const bool scan=false)
825 const char *const *table = scan ? iso8601::scanner : iso8601::formatter;
826 enum iso8601::kind format = iso8601::dtz;
831 format = iso8601::dtz;
833 format = iso8601::dt;
838 } else if (time && tz) {
839 format = iso8601::tz;
841 format = iso8601::t; /* default to %T */
844 return table [format];
852 static inline int flip_tm_year (const int y)
853 { return (y + 1900) * -1 - 1900; }
857 * @brief Format a time structure according to ISO-8601, e. g.
858 * “2018-01-09T10:40:00Z+0100”; see \c strftime(3) for
861 * @param tm Time to format as broken-down \c struct tm.
862 * @param date Include the day part ([-]YYYY-MM-DD).
863 * @param time Include the time part (hh:mm:ss).
864 * @param tz Include the timezone ([±]ZZZZ); only needed if
865 * \c time is requested as well.
867 * @return The formatted timestamp.
869 std::string format_iso8601 (const struct tm &tm, const bool date,
870 const bool time, const bool tz)
873 char buf [iso8601::bufsize] = { 0 };
874 char *start = &buf [0];
875 const char *format = iso8601::pick_fmt (date, time, tz);
877 memcpy (&tmp, &tm, sizeof (tmp));
879 if (tmp.tm_year < -1900) { /* negative year */
882 tmp.tm_year = flip_tm_year (tmp.tm_year);
886 * The sign is *always* handled above so the formatted string here
887 * is always one character shorter.
889 if (strftime (start, iso8601::bufsize-1, format, &tmp) == 0)
891 return std::string ();
894 buf [iso8601::bufsize-1] = '\0'; /* Just in case. */
896 return std::string (buf);
899 typedef struct tm * (*time_breakdown_fn) (const time_t *, struct tm *);
902 * @brief Format a UNIX timestamp according to ISO-8601. Converts
903 * to broken down time first.
905 * @param t Time to format as broken-down \c struct tm.
906 * @param date Include the day part ([-]YYYY-MM-DD).
907 * @param time Include the time part (hh:mm:ss).
908 * @param tz Include the timezone ([±]ZZZZ); only heeded if
909 * \c time is requested as well.
911 * @return The formatted timestamp.
913 std::string format_iso8601 (time_t t, const bool utc, const bool date,
914 const bool time, const bool tz)
916 time_breakdown_fn breakdown = utc ? gmtime_r : localtime_r;
920 if (breakdown (&t, &tm) == NULL) {
921 return std::string ("error analyzing timestamp: ") + strerror (errno);
924 return format_iso8601 (tm, date, time, tz);
928 * @brief Read a ISO-8601 formatted date stamp into broken down time.
930 * @param s String containing the timestamp.
932 * @return \c boost::none if the input string was \c NULL or malformed,
933 * an optional \c struct tm with the extracted values otherwise.
935 boost::optional<struct tm>
936 scan_iso8601 (const char *s,
937 const bool date, const bool time, const bool tz) NOEXCEPT
940 const char *format = iso8601::pick_fmt (date, time, tz, true);
941 const char *start = s;
942 bool negyear = false;
954 * Contrary to what the man page indicates, strptime(3) is *not*
955 * the inverse operation of strftime(3)! The later correctly formats
956 * negative year numbers with the %F modifier wheres the former trips
957 * over the sign character.
969 memset (&tm, 0, sizeof (tm));
971 if (strptime (start, format, &tm) == NULL) {
976 tm.tm_year = flip_tm_year (tm.tm_year);
983 * @brief Format a \c struct timespec in the schema established by
984 * time(1): “3m14.159s”.
986 * @param ts The time spec to format.
988 * @return \c boost:none in case of error during formatting, an optional
989 * \c std::string otherwise.
991 boost::optional<std::string>
992 format_min_sec_msec (const struct timespec &ts)
994 char ms [4] = { '\0', '\0', '\0', '\0' };
996 if (snprintf (ms, 4, "%.3ld", ts.tv_nsec / 1000000) < 0) {
1000 const time_t min = ts.tv_sec / 60;
1001 const time_t sec = ts.tv_sec - min * 60;
1003 return I2n::to_string (min) + "m"
1004 + I2n::to_string (sec) + "."
1016 * @brief <b>For internal use only</b>. Translates clock
1017 * specification flags to kernel clock types.
1019 * @param id Master clock id: \c mono, \c real, \c boot, or \c
1021 * @param var Variant of clock if appropriate: \c raw, \c exact, \c
1022 * process, or \c thread. Use \c dflt for the base
1025 * @return The clock id for using with kernel APIs.
1027 static inline clockid_t
1028 clockid_of_flags (const enum type::id id,
1029 const enum type::variant var) NOEXCEPT
1031 clockid_t cid = CLOCK_MONOTONIC_COARSE;
1042 cid = CLOCK_MONOTONIC_RAW;
1046 cid = CLOCK_MONOTONIC;
1054 if (var == type::exact) {
1055 cid = CLOCK_REALTIME;
1057 cid = CLOCK_REALTIME_COARSE;
1063 cid = CLOCK_BOOTTIME;
1068 if (var == type::thread) {
1069 cid = CLOCK_THREAD_CPUTIME_ID;
1071 cid = CLOCK_PROCESS_CPUTIME_ID;
1080 static const struct timespec zero_time = { 0, 0 };
1084 Time::Time (const enum type::id id,
1085 const enum type::variant var) NOEXCEPT
1093 * Ctor from *struct tm*. On 32 bit systems the conversion to *time_t* will
1094 * fail with years outside the range from epoch to 2038.
1096 Time::Time (const struct tm &tm,
1097 const enum type::id id,
1098 const enum type::variant var)
1100 struct tm tmp_tm; /* dummy for mktime(3) */
1103 memcpy (&tmp_tm, &tm, sizeof (tmp_tm));
1106 const time_t t = mktime (&tmp_tm);
1107 if (t == - 1) { /* Glibc does not set errno on out-of-range here! */
1108 const char *datestr = asctime (&tm);
1109 throw conversion_error (errno,
1110 std::string ("mktime: from struct tm {")
1111 + std::string (datestr, 0, strlen(datestr)-1)
1115 tmp_time = Time (t, 0l, id, var);
1117 this->swap (tmp_time);
1121 Time::as_nanosec (void) const NOEXCEPT
1123 return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
1124 + this->value.tv_nsec;
1128 Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
1129 { return static_cast<long>(this->as_nanosec ()); }
1132 Time::operator= (Time t2) NOEXCEPT
1140 * @note This operator is an up-assignment from a type containing less
1141 * information than the structure assigned from. Since the
1142 * operator can only be two valued we must normalize the remaining
1143 * fields to the default clock. When assigning from non-default
1144 * clocks, use the appropriate constructor and pass it the desired
1145 * id and variant so as to assign the result.
1148 Time::operator= (struct timespec ts) NOEXCEPT
1150 std::swap (this->value, ts);
1151 this->id = clock::type::mono;
1152 this->variant = clock::type::dflt;
1159 Time::unset (void) NOEXCEPT
1160 { this->value = zero_time; }
1163 Time::set (void) NOEXCEPT
1165 struct timespec now;
1168 if (clock_gettime (clockid_of_flags (this->id, this->variant), &now)
1183 Time::add (const time_t sec, const long nsec) NOEXCEPT
1185 this->value.tv_sec += sec;
1186 this->value.tv_nsec += nsec;
1188 this->carry_nsec ();
1194 Time::subtract (const time_t sec, const long nsec) NOEXCEPT
1196 this->value.tv_sec -= sec;
1197 this->value.tv_nsec -= nsec;
1199 this->carry_nsec ();
1205 Time::scale (const int64_t factor) NOEXCEPT
1207 this->value.tv_sec *= factor;
1208 this->value.tv_nsec *= factor;
1210 this->carry_nsec ();
1216 * Below division code purposely does not attempt to handle divide-
1217 * by-zero just as any other C++ division function does. It is up to
1218 * the caller to ensure that the divisor is not zero.
1221 Time::divide (const int64_t divisor) NOEXCEPT
1223 const long sec = static_cast<long> (this->value.tv_sec );
1224 int64_t nsec = static_cast<int64_t> (this->value.tv_nsec);
1225 const ldiv_t div = ldiv (sec, divisor);
1228 nsec += div.rem * TIME_CONST_FACTOR_NANO;
1233 this->value.tv_sec = static_cast<time_t> (div.quot);
1234 this->value.tv_nsec = static_cast<long> (nsec);
1236 this->carry_nsec ();
1242 * @brief Format timestamp according to the ISO standard rules.
1244 * @param utc Whether to normalize the timestamp to UTC or local time.
1245 * @param date Whether to include the date (%F).
1246 * @param time Whether to include the time (%T).
1247 * @param tz Whether to include the UTC offset (%z).
1249 * @return \c none if the formatting operation failed, the
1250 * formatted timestamp otherwise.
1252 * @note The standard allows for extending the format using
1253 * a fractional component. However, this is subject to
1254 * local conventions so we don’t support it. For more
1255 * than seconds granularity use a better suited format
1256 * like LDAP Generalized time instead.
1258 boost::optional<std::string>
1259 Time::format_iso8601 (const bool utc,
1262 const bool tz) const
1264 time_breakdown_fn breakdown = utc ? gmtime_r : localtime_r;
1267 if (breakdown (&this->value.tv_sec, &tm) == NULL) {
1271 return ::format_iso8601 (tm, date, time, tz);
1275 Time::make_nice_time (void) const
1277 /* XXX the cast below results in loss of precision with 64 bit time_t! */
1278 return ::make_nice_time (static_cast<int> (this->value.tv_sec));
1282 Time::format_full_time (void) const
1283 { return ::format_full_time (this->value.tv_sec); }
1286 Time::format_date (void) const
1287 { return ::format_date (this->value.tv_sec); }
1290 * @brief Obtain the current time wrt. the given
1293 * @param id Clock id.
1294 * @param var Clock variant.
1296 * @return \c none if the underlying \c clock_gettime() operation
1297 * failed, a fully initialized \c struct Time otherwise.
1299 boost::optional<Time>
1300 now (const enum type::id id, const enum type::variant var) NOEXCEPT
1312 zero (const enum type::id id, const enum type::variant var) NOEXCEPT
1313 { return Time (id, var); }
1316 * @brief Standard three-way comparison for \c struct Time
1317 * relying on strict total ordering.
1319 * @param t1 Comparand.
1320 * @param t2 Comparand.
1322 * @return -1, 0, 1 depending on whether t1 is less-than, equal,
1323 * or greater than t2.
1325 * @note This should be used to implement the spaceship operator
1326 * (P0515R0) when we get a new compiler.
1329 compare (const Time &t1, const Time &t2) NOEXCEPT
1331 if (t1.value.tv_sec < t2.value.tv_sec) {
1335 if (t1.value.tv_sec > t2.value.tv_sec) {
1339 if (t1.value.tv_nsec < t2.value.tv_nsec) {
1343 if (t1.value.tv_nsec > t2.value.tv_nsec) {
1351 * @brief Interpret string as timestamp according to the ISO
1354 * This is the inverse operation of \c format_iso8601().
1356 * @param s Input string to read. The entire string is interpreted
1357 * and it must not contain any trailing data.
1358 * @param date Whether to parse the date (%F).
1359 * @param time Whether to parse the time (%T).
1360 * @param tz Whether to parse the UTC offset (%z).
1361 * @param id Clock id to assign the result.
1362 * @param var Clock variant to assign the result.
1364 * @return \c none if the input could not be parsed according to
1365 * ISO rules, a \c struct Time otherwise.
1367 boost::optional<Time>
1368 time_of_iso8601 (const std::string &s,
1372 const enum type::id id,
1373 const enum type::variant var) NOEXCEPT
1375 boost::optional<struct tm> tm = scan_iso8601 (s, date, time, tz);
1382 return Time (*tm, id, var);
1384 catch (conversion_error &_unused) { }
1389 } /* [namespace clock] */
1391 } /* [namespace I2n] */