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
39 #include <sys/timeb.h>
41 #include <timefunc.hxx>
45 // define missing POSIX.1b constants...
47 #ifndef CLOCK_REALTIME
48 #define CLOCK_REALTIME 0
50 #ifndef CLOCK_MONOTONIC
51 #define CLOCK_MONOTONIC 1
58 double prec_time(void)
65 ret=tb.time+(static_cast<float>(tb.millitm)/1000);
70 // converts ISO-DATE: 2003-06-13
71 time_t date_to_seconds(const std::string &date)
74 int year = -1, month = -1, day = -1;
76 string::size_type pos = date.find("-");
77 if (pos == string::npos)
80 istringstream in(string(date,0,pos));
84 string dstr(date, pos+1);
85 if ((pos = dstr.find("-")) == string::npos)
89 in.str(string(dstr, 0, pos));
94 in.str(string(dstr, pos+1));
97 if (year < 0 || month == -1 || day == -1)
101 memset(&tm_struct, 0, sizeof(struct tm));
102 tm_struct.tm_year = year;
103 tm_struct.tm_mon = month;
104 tm_struct.tm_mday = day;
105 tm_struct.tm_isdst = -1;
107 rtn = mktime (&tm_struct);
111 string make_nice_time(int seconds)
115 int days=seconds/86400;
119 split_daysec(seconds,&hours,&minutes,&seconds);
122 out << days << " " << i18n_plural("day", "days", days) << ", ";
125 out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
130 string format_full_time(time_t seconds)
135 if (localtime_r((time_t *)&seconds, &ta) == NULL)
136 memset (&ta, 0, sizeof(struct tm));
138 strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
142 string format_date(time_t seconds)
147 if (localtime_r((time_t *)&seconds, &ta) == NULL)
148 memset (&ta, 0, sizeof(struct tm));
150 strftime (buf, 49, "%d.%m.%Y", &ta);
154 void seconds_to_hour_minute(int seconds, int *hour, int *minute)
158 while (seconds >= 3600) {
164 if (minute != NULL) {
166 while (seconds >= 60) {
174 * Split seconds into hours, minutes and seconds
175 * @param [in] daysec Seconds since start of day
176 * @param [out] outhours hours
177 * @param [out] outminutes minutes
178 * @param [out] outseconds seconds
180 void split_daysec(int daysec, int *outhours, int *outminutes, int *outseconds)
182 int hours=daysec/3600;
185 int minutes=daysec/60;
198 std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
202 if (hour >= 0 && hour < 10)
206 if (!h_for_00 || minute != 0 || seconds > 0)
209 if (minute >= 0 && minute < 10)
219 if (seconds > 0 && seconds < 10)
227 string get_month_name(unsigned char month)
232 rtn = i18n("January");
235 rtn = i18n("February");
253 rtn = i18n("August");
256 rtn = i18n("September");
259 rtn = i18n("October");
262 rtn = i18n("November");
265 rtn = i18n("December");
270 out << i18n("Illegal month:") << " " << month;
280 ** implementaion of Interval
285 * @brief clears the interval (make it empty).
287 void Interval::clear()
289 m_lower_bound = m_upper_bound = 0;
290 } // eo Interval::clear()
294 * @brief tests if there is some overlapping with another interval
295 * @param other the other interval
296 * @return @a true if the two intervals have a non empty intersection.
298 bool Interval::intersects(const Interval& other) const
301 // // other start within this:
302 (other.m_lower_bound >= m_lower_bound and other.m_lower_bound < m_upper_bound )
303 // // other end within this:
304 or (other.m_upper_bound > m_lower_bound and other.m_upper_bound <= m_upper_bound )
305 // // other contains this
306 or (other.m_lower_bound <= m_lower_bound and other.m_upper_bound >= m_upper_bound )
308 } // eo Interval::intersects(const Interval&)
312 * @brief tests if the current interval (fully) contains another one.
313 * @param other the other interval.
314 * @return @a true if the current interval fully contains the other interval.
316 bool Interval::contains(const Interval& other) const
318 return (other.m_lower_bound >= m_lower_bound)
319 and (other.m_upper_bound <= m_upper_bound)
321 } // eo Interval::contains(const Interval& other) const
325 ** implementation of Intervals:
329 Intervals::Intervals()
331 } // eo Intervals::Intervals
334 void Intervals::clear()
337 } // eo Intervals::clear()
340 * @brief tests if one of the intervals of the list intersects with the given interval.
341 * @param other the interval to check for intersection.
342 * @return @a true if there is an intersection.
344 bool Intervals::intersects(const Interval& other) const
346 for(const_iterator it= begin();
350 if ( it->intersects(other) )
356 } // eo Intervals::intersects(const Interval&) const
360 * @brief tests if we have at least one intersection with another Intervals instance.
361 * @param other the other instance.
362 * @return @a true if there is an intersection.
364 bool Intervals::intersects(const Intervals& other) const
366 for(const_iterator it= begin();
370 if ( other.intersects( *it ) )
376 } // eo Intervals::intersects(const Intervals&) const
380 * @brief adds a new interval to the list.
381 * @param new_frame the new interval.
383 * Adds the interval to the list and joins overlapping intervals.
385 * @internal complexity O(n).
387 void Intervals::add(const Interval& new_frame)
389 if (not new_frame.is_valid() or new_frame.empty())
391 // well... we will not insert invalid or empty frames!
394 for (IntervalList::iterator it= m_intervals.begin();
395 it != m_intervals.end();
398 Interval& current_frame = *it;
399 if ( new_frame.m_lower_bound > current_frame.m_upper_bound )
401 // new_frame begins later than current end; go on:
404 // at this point: the begin of the new frame is less then the current end.
405 // now let's determine how we can insert the new frame:
407 if ( new_frame.m_upper_bound < current_frame.m_lower_bound )
409 // new disjoint frame; insert it before the current frame:
410 m_intervals.insert( it, new_frame );
414 // at this point: the end of the new frame is >= current begin.
415 if ( new_frame.m_upper_bound <= current_frame.m_upper_bound )
417 // the end of the new frame is within our current frame; we need to combine
418 if (new_frame.m_lower_bound < current_frame.m_lower_bound)
420 // the new interval starts earlier; we need to adjust our current frame:
421 current_frame.m_lower_bound = new_frame.m_lower_bound;
422 current_frame.m_changed = true;
424 // NOTE no "else" part needed since in that case our current frame already
425 // contains the new one!
430 // at this point: end of new frame > end of current frame
431 // so we need to extend the current frame; at least the end.
432 // But we need to deal with intersects of following frames... *sigh*
434 // first the simple part: let's see if we need to move the start:
435 if ( new_frame.m_lower_bound < current_frame.m_lower_bound)
437 // yes, we need to move the start:
438 current_frame.m_lower_bound = new_frame.m_lower_bound;
439 current_frame.m_changed= true;
442 // now let's extend the end:
443 current_frame.m_upper_bound = new_frame.m_upper_bound;
444 current_frame.m_changed = true;
446 // well... let's walk through the following frames; looking for more joins...:
447 IntervalList::iterator it2 = it;
448 while( ++(it2=it) != m_intervals.end()
449 and current_frame.m_upper_bound >= it2->m_lower_bound
452 Interval next_frame= *it2;
453 if ( current_frame.m_upper_bound < next_frame.m_upper_bound )
455 // in this case our end is within the next frame.
457 current_frame.m_upper_bound = next_frame.m_upper_bound;
459 // and remove the next frame since the current frame contains it (now):
460 m_intervals.erase(it2);
465 // at this point: new frame starts later than the last frame ends
466 // append the new frame:
467 m_intervals.push_back( new_frame );
468 } // eo Intervals::add(const Interval&)
472 * @brief subtracts a time interval from the list.
473 * @param del_frame the time interval to subtract.
475 * removes the time interval from the list; cut off parts from or remove existing
476 * intervals if they overlap.
478 * @internal complexity O(n).
480 void Intervals::sub(const Interval& del_frame)
482 if (not del_frame.is_valid() or del_frame.empty() )
486 for (IntervalList::iterator it= m_intervals.begin();
487 it != m_intervals.end();
490 Interval& current_frame = *it;
491 if ( del_frame.m_lower_bound >= current_frame.m_upper_bound )
493 // del_frame begins later than current end; go on:
497 // at this point: the begin of the del frame is less then the current end.
498 if ( del_frame.m_upper_bound < current_frame.m_lower_bound )
500 // end is before our start; nothing to do.
503 // at this point: the end of the del frame is >= current begin.
504 if ( del_frame.m_upper_bound < current_frame.m_upper_bound )
506 // del frame end point is within our interval.
507 if ( del_frame.m_lower_bound > current_frame.m_lower_bound)
509 // the del frame is within our interval... we need to split:
510 m_intervals.insert(it, Interval( current_frame.m_lower_bound, del_frame.m_lower_bound ) );
512 // adjust start of current frame:
513 if (current_frame.m_lower_bound < del_frame.m_upper_bound)
515 current_frame.m_lower_bound= del_frame.m_upper_bound;
516 current_frame.m_changed= true;
521 // at this point the end of the del frame is >= current end
522 if ( del_frame.m_lower_bound > current_frame.m_lower_bound )
524 // a part of the current interval needs to be preserved..
526 current_frame.m_upper_bound= del_frame.m_lower_bound;
527 current_frame.m_changed= true;
528 // and continue with the next interval:
532 // at this point; the whole frame needs to be deleted..
533 if ( it == m_intervals.begin())
535 m_intervals.erase(it);
536 it= m_intervals.begin();
540 IntervalList::iterator it2= it++;
541 m_intervals.erase(it2);
544 } // eo Intervals::sub(const Interval&)
548 * @brief returns if we contain an interval.
549 * @param other the interval to check.
550 * @return @a true if we cover the given interval, too.
552 bool Intervals::contains(const Interval& other) const
554 for(const_iterator it= begin();
558 if ( it->contains( other ))
564 } // eo Intervals::contains(const Interval&) const
568 * @brief returns if we contain an exact interval.
569 * @param other the interval to check.
570 * @return @a true if we axactly contains the given interval.
572 * @note thsi differs from contain in the way, that we return only @a true
573 * iff we have the given interval in our list; not only cover it.
575 bool Intervals::contains_exact(const Interval& other) const
577 for(const_iterator it= begin();
587 } // eo Intervals::contains_exact(const Interval&)const
591 * @brief returns if we contain another interval combination.
592 * @param other the intervals to check.
593 * @return @a true if we cover the given intervals, too.
595 * @internal we rely on the fact that the lists are sorted and contain
596 * disjoint intervals.
598 * So this method has a complexity of O(n).
600 bool Intervals::contains(const Intervals& other) const
602 const_iterator my_it= begin();
603 const_iterator other_it= other.begin();
604 while( my_it != end() and other_it!= other.end() )
606 // seek the first interval which contains the lower bound of the current other interval
607 while (my_it != end()
608 and my_it->m_lower_bound > other_it->m_lower_bound
609 and other_it->m_lower_bound >= my_it->m_upper_bound
618 if (not my_it->contains( *other_it ))
620 // if we don't contain the current other; we're done:
623 //else check the next other interval:
626 return (other_it == other.end());
627 } // eo Intervals::contains(const Intervals&) const
631 * @brief combines to interval combinates for equality
632 * @param other the other instance.
633 * @return @a true if the other is equal to the current.
635 * @internal since the lists are sorted, we compare the interval lists.
636 * Thus we have a complexity of O(n).
638 bool Intervals::operator==(const Intervals& other) const
640 // since we keep sorted lists: just compare the lists :-)
641 return m_intervals == other.m_intervals;
642 } // eo Intervals::operator==(const Intervals&)
645 Intervals& Intervals::operator+=(const Interval& other)
649 } // eo operator+=(const Interval&)
652 Intervals& Intervals::operator-=(const Interval& other)
656 } // eo operator-=(const Interval&)
660 * @brief adds the intervals of a second instance to us.
661 * @param other the other instance.
662 * @return self reference (allow chaining).
664 * @internal since we do simple loops over the other and our intervals
665 * we have a complexity of O(n^2).
667 * @todo optimize if complexity becomes a problem.
669 Intervals& Intervals::operator+=(const Intervals& other)
671 for(const_iterator it= other.begin();
678 } // eo operator+=(const Intervals&)
682 * @brief subtracts the intervals of a second instance from us.
683 * @param other the other instance.
684 * @return self reference (allow chaining).
686 * @internal since we do simple loops over the other and our intervals
687 * we have a complexity of O(n^2).
689 * @todo optimize if complexity becomes a problem.
691 Intervals& Intervals::operator-=(const Intervals& other)
699 for(const_iterator it= other.begin();
707 } // eo operator-=(const Intervals&)
717 * @brief fetches the value from the monotonic clock source.
718 * @param[out] seconds the seconds.
719 * @param[out] nano_seconds the nano seconds.
720 * @return @a true if the clock was successfully read.
722 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
724 struct timespec tp[1];
725 int res= clock_gettime (CLOCK_MONOTONIC, tp);
729 nano_seconds= tp->tv_nsec;
732 } // eo monotonic_clock_gettime(long int&,long int&)
736 * @brief fetches the value from the monotonic clock source.
737 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
739 long long monotonic_clock_gettime_nano()
742 long int nano_seconds;
745 if (monotonic_clock_gettime(seconds,nano_seconds))
756 * @brief fetches the value from the monotonic clock source.
757 * @param[out] seconds the seconds.
758 * @param[out] nano_seconds the nano seconds.
759 * @return @a true if the clock was successfully read.
761 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
763 struct timespec tp[1];
764 int res= clock_gettime(CLOCK_REALTIME, tp);
768 nano_seconds= tp->tv_nsec;
771 } // eo realtime_clock_gettime(long int&,long int&)
780 static inline clockid_t
781 clockid_of_flags (const enum type::id id,
782 const enum type::variant var) NOEXCEPT
784 clockid_t cid = CLOCK_MONOTONIC_COARSE;
795 cid = CLOCK_MONOTONIC_RAW;
799 cid = CLOCK_MONOTONIC;
807 if (var == type::exact) {
808 cid = CLOCK_REALTIME;
810 cid = CLOCK_REALTIME_COARSE;
816 if (var & type::exact) {
817 cid = CLOCK_BOOTTIME;
823 if (var == type::thread) {
824 cid = CLOCK_THREAD_CPUTIME_ID;
826 cid = CLOCK_PROCESS_CPUTIME_ID;
835 static const struct timespec zero_time = { 0, 0 };
839 Time::Time (const enum type::id id,
840 const enum type::variant var) NOEXCEPT
848 Time::as_nanosec (void) const NOEXCEPT
850 return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
851 + this->value.tv_nsec;
855 Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
856 { return static_cast<long>(this->as_nanosec ()); }
859 Time::operator= (Time t2) NOEXCEPT
867 Time::operator= (struct timespec ts) NOEXCEPT
869 std::swap (this->value, ts);
870 this->id = clock::type::mono;
871 this->variant = clock::type::dflt;
878 Time::unset (void) NOEXCEPT
879 { this->value = zero_time; }
882 Time::set (void) NOEXCEPT
887 if (clock_gettime (clockid_of_flags (this->id, this->variant), &now)
902 Time::add (const time_t sec, const long nsec) NOEXCEPT
904 this->value.tv_sec += sec;
905 this->value.tv_nsec += nsec;
913 Time::subtract (const time_t sec, const long nsec) NOEXCEPT
915 this->value.tv_sec -= sec;
916 this->value.tv_nsec -= nsec;
924 Time::scale (const time_t factor) NOEXCEPT
926 this->value.tv_sec *= factor;
927 this->value.tv_nsec *= factor;
934 boost::optional<Time>
935 now (const enum type::id id, const enum type::variant var) NOEXCEPT
947 zero (const enum type::id id, const enum type::variant var) NOEXCEPT
948 { return Time (id, var); }
951 compare (const Time &t1, const Time &t2) NOEXCEPT
953 if (t1.value.tv_sec < t2.value.tv_sec) {
957 if (t1.value.tv_sec > t2.value.tv_sec) {
961 if (t1.value.tv_nsec < t2.value.tv_nsec) {
965 if (t1.value.tv_nsec > t2.value.tv_nsec) {
972 } /* [namespace clock] */
974 } /* [namespace I2n] */