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
41 #include <sys/timeb.h>
43 #include <timefunc.hxx>
47 // define missing POSIX.1b constants...
49 #ifndef CLOCK_REALTIME
50 #define CLOCK_REALTIME 0
52 #ifndef CLOCK_MONOTONIC
53 #define CLOCK_MONOTONIC 1
60 double prec_time(void)
67 ret=tb.time+(static_cast<float>(tb.millitm)/1000);
72 // converts ISO-DATE: 2003-06-13
73 time_t date_to_seconds(const std::string &date)
76 int year = -1, month = -1, day = -1;
78 string::size_type pos = date.find("-");
79 if (pos == string::npos)
82 istringstream in(string(date,0,pos));
86 string dstr(date, pos+1);
87 if ((pos = dstr.find("-")) == string::npos)
91 in.str(string(dstr, 0, pos));
96 in.str(string(dstr, pos+1));
99 if (year < 0 || month == -1 || day == -1)
103 memset(&tm_struct, 0, sizeof(struct tm));
104 tm_struct.tm_year = year;
105 tm_struct.tm_mon = month;
106 tm_struct.tm_mday = day;
107 tm_struct.tm_isdst = -1;
109 rtn = mktime (&tm_struct);
113 string make_nice_time(int seconds)
117 int days=seconds/86400;
121 split_daysec(seconds,&hours,&minutes,&seconds);
124 out << days << " " << i18n_plural("day", "days", days) << ", ";
127 out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
132 string format_full_time(time_t seconds)
137 if (localtime_r((time_t *)&seconds, &ta) == NULL)
138 memset (&ta, 0, sizeof(struct tm));
140 strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
144 string format_date(time_t seconds)
149 if (localtime_r((time_t *)&seconds, &ta) == NULL)
150 memset (&ta, 0, sizeof(struct tm));
152 strftime (buf, 49, "%d.%m.%Y", &ta);
156 void seconds_to_hour_minute(int seconds, int *hour, int *minute)
160 while (seconds >= 3600) {
166 if (minute != NULL) {
168 while (seconds >= 60) {
176 * Split seconds into hours, minutes and seconds
177 * @param [in] daysec Seconds since start of day
178 * @param [out] outhours hours
179 * @param [out] outminutes minutes
180 * @param [out] outseconds seconds
182 void split_daysec(int daysec, int *outhours, int *outminutes, int *outseconds)
184 int hours=daysec/3600;
187 int minutes=daysec/60;
200 std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
204 if (hour >= 0 && hour < 10)
208 if (!h_for_00 || minute != 0 || seconds > 0)
211 if (minute >= 0 && minute < 10)
221 if (seconds > 0 && seconds < 10)
229 string get_month_name(unsigned char month)
234 rtn = i18n("January");
237 rtn = i18n("February");
255 rtn = i18n("August");
258 rtn = i18n("September");
261 rtn = i18n("October");
264 rtn = i18n("November");
267 rtn = i18n("December");
272 out << i18n("Illegal month:") << " " << month;
282 ** implementaion of Interval
287 * @brief clears the interval (make it empty).
289 void Interval::clear()
291 m_lower_bound = m_upper_bound = 0;
292 } // eo Interval::clear()
296 * @brief tests if there is some overlapping with another interval
297 * @param other the other interval
298 * @return @a true if the two intervals have a non empty intersection.
300 bool Interval::intersects(const Interval& other) const
303 // // other start within this:
304 (other.m_lower_bound >= m_lower_bound and other.m_lower_bound < m_upper_bound )
305 // // other end within this:
306 or (other.m_upper_bound > m_lower_bound and other.m_upper_bound <= m_upper_bound )
307 // // other contains this
308 or (other.m_lower_bound <= m_lower_bound and other.m_upper_bound >= m_upper_bound )
310 } // eo Interval::intersects(const Interval&)
314 * @brief tests if the current interval (fully) contains another one.
315 * @param other the other interval.
316 * @return @a true if the current interval fully contains the other interval.
318 bool Interval::contains(const Interval& other) const
320 return (other.m_lower_bound >= m_lower_bound)
321 and (other.m_upper_bound <= m_upper_bound)
323 } // eo Interval::contains(const Interval& other) const
327 ** implementation of Intervals:
331 Intervals::Intervals()
333 } // eo Intervals::Intervals
336 void Intervals::clear()
339 } // eo Intervals::clear()
342 * @brief tests if one of the intervals of the list intersects with the given interval.
343 * @param other the interval to check for intersection.
344 * @return @a true if there is an intersection.
346 bool Intervals::intersects(const Interval& other) const
348 for(const_iterator it= begin();
352 if ( it->intersects(other) )
358 } // eo Intervals::intersects(const Interval&) const
362 * @brief tests if we have at least one intersection with another Intervals instance.
363 * @param other the other instance.
364 * @return @a true if there is an intersection.
366 bool Intervals::intersects(const Intervals& other) const
368 for(const_iterator it= begin();
372 if ( other.intersects( *it ) )
378 } // eo Intervals::intersects(const Intervals&) const
382 * @brief adds a new interval to the list.
383 * @param new_frame the new interval.
385 * Adds the interval to the list and joins overlapping intervals.
387 * @internal complexity O(n).
389 void Intervals::add(const Interval& new_frame)
391 if (not new_frame.is_valid() or new_frame.empty())
393 // well... we will not insert invalid or empty frames!
396 for (IntervalList::iterator it= m_intervals.begin();
397 it != m_intervals.end();
400 Interval& current_frame = *it;
401 if ( new_frame.m_lower_bound > current_frame.m_upper_bound )
403 // new_frame begins later than current end; go on:
406 // at this point: the begin of the new frame is less then the current end.
407 // now let's determine how we can insert the new frame:
409 if ( new_frame.m_upper_bound < current_frame.m_lower_bound )
411 // new disjoint frame; insert it before the current frame:
412 m_intervals.insert( it, new_frame );
416 // at this point: the end of the new frame is >= current begin.
417 if ( new_frame.m_upper_bound <= current_frame.m_upper_bound )
419 // the end of the new frame is within our current frame; we need to combine
420 if (new_frame.m_lower_bound < current_frame.m_lower_bound)
422 // the new interval starts earlier; we need to adjust our current frame:
423 current_frame.m_lower_bound = new_frame.m_lower_bound;
424 current_frame.m_changed = true;
426 // NOTE no "else" part needed since in that case our current frame already
427 // contains the new one!
432 // at this point: end of new frame > end of current frame
433 // so we need to extend the current frame; at least the end.
434 // But we need to deal with intersects of following frames... *sigh*
436 // first the simple part: let's see if we need to move the start:
437 if ( new_frame.m_lower_bound < current_frame.m_lower_bound)
439 // yes, we need to move the start:
440 current_frame.m_lower_bound = new_frame.m_lower_bound;
441 current_frame.m_changed= true;
444 // now let's extend the end:
445 current_frame.m_upper_bound = new_frame.m_upper_bound;
446 current_frame.m_changed = true;
448 // well... let's walk through the following frames; looking for more joins...:
449 IntervalList::iterator it2 = it;
450 while( ++(it2=it) != m_intervals.end()
451 and current_frame.m_upper_bound >= it2->m_lower_bound
454 Interval next_frame= *it2;
455 if ( current_frame.m_upper_bound < next_frame.m_upper_bound )
457 // in this case our end is within the next frame.
459 current_frame.m_upper_bound = next_frame.m_upper_bound;
461 // and remove the next frame since the current frame contains it (now):
462 m_intervals.erase(it2);
467 // at this point: new frame starts later than the last frame ends
468 // append the new frame:
469 m_intervals.push_back( new_frame );
470 } // eo Intervals::add(const Interval&)
474 * @brief subtracts a time interval from the list.
475 * @param del_frame the time interval to subtract.
477 * removes the time interval from the list; cut off parts from or remove existing
478 * intervals if they overlap.
480 * @internal complexity O(n).
482 void Intervals::sub(const Interval& del_frame)
484 if (not del_frame.is_valid() or del_frame.empty() )
488 for (IntervalList::iterator it= m_intervals.begin();
489 it != m_intervals.end();
492 Interval& current_frame = *it;
493 if ( del_frame.m_lower_bound >= current_frame.m_upper_bound )
495 // del_frame begins later than current end; go on:
499 // at this point: the begin of the del frame is less then the current end.
500 if ( del_frame.m_upper_bound < current_frame.m_lower_bound )
502 // end is before our start; nothing to do.
505 // at this point: the end of the del frame is >= current begin.
506 if ( del_frame.m_upper_bound < current_frame.m_upper_bound )
508 // del frame end point is within our interval.
509 if ( del_frame.m_lower_bound > current_frame.m_lower_bound)
511 // the del frame is within our interval... we need to split:
512 m_intervals.insert(it, Interval( current_frame.m_lower_bound, del_frame.m_lower_bound ) );
514 // adjust start of current frame:
515 if (current_frame.m_lower_bound < del_frame.m_upper_bound)
517 current_frame.m_lower_bound= del_frame.m_upper_bound;
518 current_frame.m_changed= true;
523 // at this point the end of the del frame is >= current end
524 if ( del_frame.m_lower_bound > current_frame.m_lower_bound )
526 // a part of the current interval needs to be preserved..
528 current_frame.m_upper_bound= del_frame.m_lower_bound;
529 current_frame.m_changed= true;
530 // and continue with the next interval:
534 // at this point; the whole frame needs to be deleted..
535 if ( it == m_intervals.begin())
537 m_intervals.erase(it);
538 it= m_intervals.begin();
542 IntervalList::iterator it2= it++;
543 m_intervals.erase(it2);
546 } // eo Intervals::sub(const Interval&)
550 * @brief returns if we contain an interval.
551 * @param other the interval to check.
552 * @return @a true if we cover the given interval, too.
554 bool Intervals::contains(const Interval& other) const
556 for(const_iterator it= begin();
560 if ( it->contains( other ))
566 } // eo Intervals::contains(const Interval&) const
570 * @brief returns if we contain an exact interval.
571 * @param other the interval to check.
572 * @return @a true if we axactly contains the given interval.
574 * @note thsi differs from contain in the way, that we return only @a true
575 * iff we have the given interval in our list; not only cover it.
577 bool Intervals::contains_exact(const Interval& other) const
579 for(const_iterator it= begin();
589 } // eo Intervals::contains_exact(const Interval&)const
593 * @brief returns if we contain another interval combination.
594 * @param other the intervals to check.
595 * @return @a true if we cover the given intervals, too.
597 * @internal we rely on the fact that the lists are sorted and contain
598 * disjoint intervals.
600 * So this method has a complexity of O(n).
602 bool Intervals::contains(const Intervals& other) const
604 const_iterator my_it= begin();
605 const_iterator other_it= other.begin();
606 while( my_it != end() and other_it!= other.end() )
608 // seek the first interval which contains the lower bound of the current other interval
609 while (my_it != end()
610 and my_it->m_lower_bound > other_it->m_lower_bound
611 and other_it->m_lower_bound >= my_it->m_upper_bound
620 if (not my_it->contains( *other_it ))
622 // if we don't contain the current other; we're done:
625 //else check the next other interval:
628 return (other_it == other.end());
629 } // eo Intervals::contains(const Intervals&) const
633 * @brief combines to interval combinates for equality
634 * @param other the other instance.
635 * @return @a true if the other is equal to the current.
637 * @internal since the lists are sorted, we compare the interval lists.
638 * Thus we have a complexity of O(n).
640 bool Intervals::operator==(const Intervals& other) const
642 // since we keep sorted lists: just compare the lists :-)
643 return m_intervals == other.m_intervals;
644 } // eo Intervals::operator==(const Intervals&)
647 Intervals& Intervals::operator+=(const Interval& other)
651 } // eo operator+=(const Interval&)
654 Intervals& Intervals::operator-=(const Interval& other)
658 } // eo operator-=(const Interval&)
662 * @brief adds the intervals of a second instance to us.
663 * @param other the other instance.
664 * @return self reference (allow chaining).
666 * @internal since we do simple loops over the other and our intervals
667 * we have a complexity of O(n^2).
669 * @todo optimize if complexity becomes a problem.
671 Intervals& Intervals::operator+=(const Intervals& other)
673 for(const_iterator it= other.begin();
680 } // eo operator+=(const Intervals&)
684 * @brief subtracts the intervals of a second instance from us.
685 * @param other the other instance.
686 * @return self reference (allow chaining).
688 * @internal since we do simple loops over the other and our intervals
689 * we have a complexity of O(n^2).
691 * @todo optimize if complexity becomes a problem.
693 Intervals& Intervals::operator-=(const Intervals& other)
701 for(const_iterator it= other.begin();
709 } // eo operator-=(const Intervals&)
719 * @brief fetches the value from the monotonic clock source.
720 * @param[out] seconds the seconds.
721 * @param[out] nano_seconds the nano seconds.
722 * @return @a true if the clock was successfully read.
724 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
726 struct timespec tp[1];
727 int res= clock_gettime (CLOCK_MONOTONIC, tp);
731 nano_seconds= tp->tv_nsec;
734 } // eo monotonic_clock_gettime(long int&,long int&)
738 * @brief fetches the value from the monotonic clock source.
739 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
741 long long monotonic_clock_gettime_nano()
744 long int nano_seconds;
747 if (monotonic_clock_gettime(seconds,nano_seconds))
758 * @brief fetches the value from the monotonic clock source.
759 * @param[out] seconds the seconds.
760 * @param[out] nano_seconds the nano seconds.
761 * @return @a true if the clock was successfully read.
763 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
765 struct timespec tp[1];
766 int res= clock_gettime(CLOCK_REALTIME, tp);
770 nano_seconds= tp->tv_nsec;
773 } // eo realtime_clock_gettime(long int&,long int&)
777 * There is a discrepancy of one input character
778 * due to the lack of sign handling in strptime(3):
780 * - strftime(3) needs the year specified as %5Y to account for the
782 * - strptime(3) will not parse the leading dash with that format
783 * but apart from that it works well.
789 * max: -YYYYYYYYYY-MM-DDThh:mm:ssZ+zzzz ⇒ 32
790 * That is assuming the year in broken down time is an int we
791 * need to reserve ten decimal places.
793 // static_assert (sizeof (((struct tm *)NULL)->tm_year) == 4);
794 static const size_t bufsize = 33;
806 * Unfortunately the glibc strptime(3) on the Intranator trips over
807 * the length specifier in field descriptors so we can’t reuse the
808 * formatters here. This problem is fixed in newer glibc. For the time
809 * being we keep two tables of formatters and choose the appropriate
813 static const char *const formatter [ISO8601_SIZE] =
814 { /* [iso8601::d ] = */ "%4Y-%m-%d",
815 /* [iso8601::t ] = */ "%T",
816 /* [iso8601::tz ] = */ "%TZ%z",
817 /* [iso8601::dt ] = */ "%4Y-%m-%dT%T",
818 /* [iso8601::dtz] = */ "%4Y-%m-%dT%TZ%z",
821 static const char *const scanner [ISO8601_SIZE] =
822 { /* [iso8601::d ] = */ "%Y-%m-%d",
823 /* [iso8601::t ] = */ "%T",
824 /* [iso8601::tz ] = */ "%TZ%z",
825 /* [iso8601::dt ] = */ "%Y-%m-%dT%T",
826 /* [iso8601::dtz] = */ "%Y-%m-%dT%TZ%z",
829 static inline const char *
830 pick_fmt (const bool date, const bool time, const bool tz, const bool scan=false)
832 const char *const *table = scan ? iso8601::scanner : iso8601::formatter;
833 enum iso8601::kind format = iso8601::dtz;
838 format = iso8601::dtz;
840 format = iso8601::dt;
845 } else if (time && tz) {
846 format = iso8601::tz;
848 format = iso8601::t; /* default to %T */
851 return table [format];
859 static inline int flip_tm_year (const int y)
860 { return (y + 1900) * -1 - 1900; }
864 * @brief Format a time structure according to ISO-8601, e. g.
865 * “2018-01-09T10:40:00Z+0100”; see \c strftime(3) for
868 * @param tm Time to format as broken-down \c struct tm.
869 * @param date Include the day part ([-]YYYY-MM-DD).
870 * @param time Include the time part (hh:mm:ss).
871 * @param tz Include the timezone ([±]ZZZZ); only needed if
872 * \c time is requested as well.
874 * @return The formatted timestamp.
876 std::string format_iso8601 (const struct tm &tm, const bool date,
877 const bool time, const bool tz)
880 char buf [iso8601::bufsize] = { 0 };
881 char *start = &buf [0];
882 const char *format = iso8601::pick_fmt (date, time, tz);
884 memcpy (&tmp, &tm, sizeof (tmp));
886 if (tmp.tm_year < -1900) { /* negative year */
889 tmp.tm_year = flip_tm_year (tmp.tm_year);
893 * The sign is *always* handled above so the formatted string here
894 * is always one character shorter.
896 if (strftime (start, iso8601::bufsize-1, format, &tmp) == 0)
898 return std::string ();
901 buf [iso8601::bufsize-1] = '\0'; /* Just in case. */
903 return std::string (buf);
906 typedef struct tm * (*time_breakdown_fn) (const time_t *, struct tm *);
909 * @brief Format a UNIX timestamp according to ISO-8601. Converts
910 * to broken down time first.
912 * @param t Time to format as broken-down \c struct tm.
913 * @param date Include the day part ([-]YYYY-MM-DD).
914 * @param time Include the time part (hh:mm:ss).
915 * @param tz Include the timezone ([±]ZZZZ); only heeded if
916 * \c time is requested as well.
918 * @return The formatted timestamp.
920 std::string format_iso8601 (time_t t, const bool utc, const bool date,
921 const bool time, const bool tz)
923 time_breakdown_fn breakdown = utc ? gmtime_r : localtime_r;
927 if (breakdown (&t, &tm) == NULL) {
928 return std::string ("error analyzing timestamp: ") + strerror (errno);
931 return format_iso8601 (tm, date, time, tz);
935 * @brief Read a ISO-8601 formatted date stamp into broken down time.
937 * @param s String containing the timestamp.
939 * @return \c boost::none if the input string was \c NULL or malformed,
940 * an optional \c struct tm with the extracted values otherwise.
942 boost::optional<struct tm>
943 scan_iso8601 (const char *s,
944 const bool date, const bool time, const bool tz) NOEXCEPT
947 const char *format = iso8601::pick_fmt (date, time, tz, true);
948 const char *start = s;
949 bool negyear = false;
961 * Contrary to what the man page indicates, strptime(3) is *not*
962 * the inverse operation of strftime(3)! The later correctly formats
963 * negative year numbers with the %F modifier wheres the former trips
964 * over the sign character.
976 memset (&tm, 0, sizeof (tm));
978 if (strptime (start, format, &tm) == NULL) {
983 tm.tm_year = flip_tm_year (tm.tm_year);
990 * @brief Format a \c struct timespec in the schema established by
991 * time(1): “3m14.159s”.
993 * @param ts The time spec to format.
995 * @return \c boost:none in case of error during formatting, an optional
996 * \c std::string otherwise.
998 boost::optional<std::string>
999 format_min_sec_msec (const struct timespec &ts)
1001 char ms [4] = { '\0', '\0', '\0', '\0' };
1003 if (snprintf (ms, 4, "%.3ld", ts.tv_nsec / 1000000) < 0) {
1007 const time_t min = ts.tv_sec / 60;
1008 const time_t sec = ts.tv_sec - min * 60;
1010 return I2n::to_string (min) + "m"
1011 + I2n::to_string (sec) + "."
1022 static inline clockid_t
1023 clockid_of_flags (const enum type::id id,
1024 const enum type::variant var) NOEXCEPT
1026 clockid_t cid = CLOCK_MONOTONIC_COARSE;
1037 cid = CLOCK_MONOTONIC_RAW;
1041 cid = CLOCK_MONOTONIC;
1049 if (var == type::exact) {
1050 cid = CLOCK_REALTIME;
1052 cid = CLOCK_REALTIME_COARSE;
1058 if (var & type::exact) {
1059 cid = CLOCK_BOOTTIME;
1065 if (var == type::thread) {
1066 cid = CLOCK_THREAD_CPUTIME_ID;
1068 cid = CLOCK_PROCESS_CPUTIME_ID;
1077 static const struct timespec zero_time = { 0, 0 };
1081 Time::Time (const enum type::id id,
1082 const enum type::variant var) NOEXCEPT
1090 * Ctor from *struct tm*. On 32 bit systems the conversion to *time_t* will
1091 * fail with years outside the range from epoch to 2038.
1093 Time::Time (const struct tm &tm,
1094 const enum type::id id,
1095 const enum type::variant var)
1097 struct tm tmp_tm; /* dummy for mktime(3) */
1100 memcpy (&tmp_tm, &tm, sizeof (tmp_tm));
1103 const time_t t = mktime (&tmp_tm);
1104 if (t == - 1) { /* Glibc does not set errno on out-of-range here! */
1105 const char *datestr = asctime (&tm);
1106 throw conversion_error (errno,
1107 std::string ("mktime: from struct tm {")
1108 + std::string (datestr, 0, strlen(datestr)-1)
1112 tmp_time = Time (t, 0l, id, var);
1114 this->swap (tmp_time);
1118 Time::as_nanosec (void) const NOEXCEPT
1120 return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
1121 + this->value.tv_nsec;
1125 Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
1126 { return static_cast<long>(this->as_nanosec ()); }
1129 Time::operator= (Time t2) NOEXCEPT
1137 Time::operator= (struct timespec ts) NOEXCEPT
1139 std::swap (this->value, ts);
1140 this->id = clock::type::mono;
1141 this->variant = clock::type::dflt;
1148 Time::unset (void) NOEXCEPT
1149 { this->value = zero_time; }
1152 Time::set (void) NOEXCEPT
1154 struct timespec now;
1157 if (clock_gettime (clockid_of_flags (this->id, this->variant), &now)
1172 Time::add (const time_t sec, const long nsec) NOEXCEPT
1174 this->value.tv_sec += sec;
1175 this->value.tv_nsec += nsec;
1177 this->carry_nsec ();
1183 Time::subtract (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::scale (const int64_t factor) NOEXCEPT
1196 this->value.tv_sec *= factor;
1197 this->value.tv_nsec *= factor;
1199 this->carry_nsec ();
1205 * Below division code purposely does not attempt to handle divide-
1206 * by-zero just as any other C++ division function does. It is up to
1207 * the caller to ensure that the divisor is not zero.
1210 Time::divide (const int64_t divisor) NOEXCEPT
1212 const long sec = static_cast<long> (this->value.tv_sec );
1213 int64_t nsec = static_cast<int64_t> (this->value.tv_nsec);
1214 const ldiv_t div = ldiv (sec, divisor);
1217 nsec += div.rem * TIME_CONST_FACTOR_NANO;
1222 this->value.tv_sec = static_cast<time_t> (div.quot);
1223 this->value.tv_nsec = static_cast<long> (nsec);
1225 this->carry_nsec ();
1230 boost::optional<std::string>
1231 Time::format_iso8601 (const bool utc,
1234 const bool tz) const
1236 time_breakdown_fn breakdown = utc ? gmtime_r : localtime_r;
1239 if (breakdown (&this->value.tv_sec, &tm) == NULL) {
1243 return ::format_iso8601 (tm, date, time, tz);
1247 Time::make_nice_time (void) const
1249 /* XXX the cast below results in loss of precision with 64 bit time_t! */
1250 return ::make_nice_time (static_cast<int> (this->value.tv_sec));
1254 Time::format_full_time (void) const
1255 { return ::format_full_time (this->value.tv_sec); }
1258 Time::format_date (void) const
1259 { return ::format_date (this->value.tv_sec); }
1261 boost::optional<Time>
1262 now (const enum type::id id, const enum type::variant var) NOEXCEPT
1274 zero (const enum type::id id, const enum type::variant var) NOEXCEPT
1275 { return Time (id, var); }
1278 compare (const Time &t1, const Time &t2) NOEXCEPT
1280 if (t1.value.tv_sec < t2.value.tv_sec) {
1284 if (t1.value.tv_sec > t2.value.tv_sec) {
1288 if (t1.value.tv_nsec < t2.value.tv_nsec) {
1292 if (t1.value.tv_nsec > t2.value.tv_nsec) {
1299 boost::optional<Time>
1300 time_of_iso8601 (const std::string &s,
1304 const enum type::id id,
1305 const enum type::variant var) NOEXCEPT
1307 boost::optional<struct tm> tm = scan_iso8601 (s, date, time, tz);
1314 return Time (*tm, id, var);
1316 catch (conversion_error &_unused) { }
1321 } /* [namespace clock] */
1323 } /* [namespace I2n] */