unit test for Tribool
[libi2ncommon] / src / timefunc.cpp
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 *
23 * @copyright Copyright © 2001-2008 by Intra2net AG
1b5dfd98
TJ
24 *
25 */
26
e93545dd
GE
27#include <string>
28#include <sstream>
29#include <iostream>
30#include <iomanip>
f1499910
GE
31#include <bitset>
32#include <stdexcept>
1b5dfd98
TJ
33#include <iterator>
34#include <algorithm>
e93545dd
GE
35
36#include <time.h>
96d0be2e 37#include <unistd.h>
5efd35b1 38#include <string.h>
e93545dd 39#include <sys/timeb.h>
96d0be2e 40#include <sys/syscall.h>
e93545dd
GE
41
42#include <timefunc.hxx>
43#include <i18n.h>
44
96d0be2e
TJ
45
46// define missing POSIX.1b constants...
47
48#ifndef CLOCK_REALTIME
49#define CLOCK_REALTIME 0
50#endif
51#ifndef CLOCK_MONOTONIC
52#define CLOCK_MONOTONIC 1
53#endif
54
55
56
e93545dd
GE
57using namespace std;
58
59double prec_time(void)
60{
61 struct timeb tb;
62 double ret;
63
64 ftime(&tb);
65
66 ret=tb.time+(static_cast<float>(tb.millitm)/1000);
67
68 return ret;
69}
70
71// converts ISO-DATE: 2003-06-13
72int date_to_seconds(const std::string &date)
73{
74 int rtn = -1, year = -1, month = -1, day = -1;
75
76 string::size_type pos = date.find("-");
77 if (pos == string::npos)
78 return rtn;
79
80 istringstream in(string(date,0,pos));
81 in >> year;
82 year -= 1900;
83
84 string dstr(date, pos+1);
85 if ((pos = dstr.find("-")) == string::npos)
86 return rtn;
87
88 in.clear();
89 in.str(string(dstr, 0, pos));
90 in >> month;
91 month -= 1;
92
93 in.clear();
94 in.str(string(dstr, pos+1));
95 in >> day;
96
97 if (year < 0 || month == -1 || day == -1)
98 return rtn;
4cf3676b 99
e93545dd 100 struct tm tm_struct;
4cf3676b 101 memset(&tm_struct, 0, sizeof(struct tm));
e93545dd
GE
102 tm_struct.tm_year = year;
103 tm_struct.tm_mon = month;
104 tm_struct.tm_mday = day;
105 tm_struct.tm_isdst = -1;
106
107 rtn = mktime (&tm_struct);
108 return rtn;
109}
110
111string make_nice_time(int seconds)
112{
113 ostringstream out;
114
115 int days=seconds/86400;
116 seconds%=86400;
117
c0368918
GE
118 int hours,minutes;
119 split_daysec(seconds,&hours,&minutes,&seconds);
120
e93545dd
GE
121 if (days==1)
122 out << i18n("1 day") << ", ";
123 else if (days>1)
124 out << days << ' ' << i18n("days") << ", ";
125
126 out << setfill('0');
127 out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
128
129 return out.str();
130}
131
132string format_full_time(int seconds)
133{
134 char buf[50];
135 memset (buf, 0, 50);
532d6b3a
TJ
136 struct tm ta;
137 if (localtime_r((time_t *)&seconds, &ta) == NULL)
138 memset (&ta, 0, sizeof(struct tm));
e93545dd 139
532d6b3a 140 strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
e93545dd
GE
141 return string(buf);
142}
f1499910 143
87869870
GE
144void seconds_to_hour_minute(int seconds, int *hour, int *minute)
145{
146 if (hour != NULL) {
147 *hour = 0;
148 while (seconds >= 3600) {
149 seconds-=3600;
150 (*hour)++;
151 }
152 }
153
154 if (minute != NULL) {
155 *minute = 0;
156 while (seconds >= 60) {
157 seconds-=60;
158 (*minute)++;
159 }
160 }
161}
162
c0368918
GE
163/**
164 * Split seconds into hours, minutes and seconds
165 * @param [in] daysec Seconds since start of day
166 * @param [out] outhours hours
167 * @param [out] outminutes minutes
168 * @param [out] outseconds seconds
169 */
170void split_daysec(int daysec, int *outhours, int *outminutes, int *outseconds)
171{
172 int hours=daysec/3600;
173 daysec%=3600;
174
175 int minutes=daysec/60;
176 daysec%=60;
177
178 if (outhours)
179 *outhours=hours;
180
181 if (outminutes)
182 *outminutes=minutes;
183
184 if (outseconds)
185 *outseconds=daysec;
186}
187
188std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
2c66f490
GE
189{
190 ostringstream out;
191
192 if (hour >= 0 && hour < 10)
193 out << '0';
194 out << hour;
195
c0368918 196 if (!h_for_00 || minute != 0 || seconds > 0)
2c66f490
GE
197 {
198 out << ':';
fe223928 199 if (minute >= 0 && minute < 10)
2c66f490
GE
200 out << '0';
201 out << minute;
202 }
203 else
204 out << 'h';
205
c0368918
GE
206 if (seconds > 0)
207 {
208 out << ':';
209 if (seconds > 0 && seconds < 10)
210 out << '0';
211 out << seconds;
212 }
213
2c66f490
GE
214 return out.str();
215}
4e157d1d
TJ
216
217string get_month_name(unsigned char month)
218{
219 string rtn;
220 switch(month) {
221 case 1:
222 rtn = i18n("January");
223 break;
224 case 2:
225 rtn = i18n("February");
226 break;
227 case 3:
228 rtn = i18n("March");
229 break;
230 case 4:
231 rtn = i18n("April");
232 break;
233 case 5:
234 rtn = i18n("May");
235 break;
236 case 6:
237 rtn = i18n("June");
238 break;
239 case 7:
240 rtn = i18n("July");
241 break;
242 case 8:
243 rtn = i18n("August");
244 break;
245 case 9:
246 rtn = i18n("September");
247 break;
248 case 10:
249 rtn = i18n("October");
250 break;
251 case 11:
252 rtn = i18n("November");
253 break;
254 case 12:
255 rtn = i18n("December");
256 break;
257 default:
258 {
259 ostringstream out;
260 out << i18n("Illegal month:") << " " << month;
261 rtn = out.str();
262 }
263 }
264
265 return rtn;
266}
1b5dfd98
TJ
267
268
269/*
270** implementaion of Interval
271*/
272
d181c3bc
TJ
273
274/**
275 * @brief clears the interval (make it empty).
276 */
277void Interval::clear()
278{
279 m_lower_bound = m_upper_bound = 0;
280} // eo Interval::clear()
281
282
1b5dfd98
TJ
283/**
284 * @brief tests if there is some overlapping with another interval
285 * @param other the other interval
286 * @return @a true if the two intervals have a non empty intersection.
287 */
288bool Interval::intersects(const Interval& other) const
289{
290 return
291 // // other start within this:
292 (other.m_lower_bound >= m_lower_bound and other.m_lower_bound < m_upper_bound )
293 // // other end within this:
294 or (other.m_upper_bound > m_lower_bound and other.m_upper_bound <= m_upper_bound )
295 // // other contains this
296 or (other.m_lower_bound <= m_lower_bound and other.m_upper_bound >= m_upper_bound )
297 ;
298} // eo Interval::intersects(const Interval&)
299
300
301/**
302 * @brief tests if the current interval (fully) contains another one.
303 * @param other the other interval.
304 * @return @a true if the current interval fully contains the other interval.
305 */
306bool Interval::contains(const Interval& other) const
307{
308 return (other.m_lower_bound >= m_lower_bound)
309 and (other.m_upper_bound <= m_upper_bound)
310 ;
311} // eo Interval::contains(const Interval& other) const
312
313
314/*
315** implementation of Intervals:
316*/
317
318
319Intervals::Intervals()
320{
321} // eo Intervals::Intervals
322
323
d181c3bc
TJ
324void Intervals::clear()
325{
326 m_intervals.clear();
327} // eo Intervals::clear()
328
1b5dfd98
TJ
329/**
330 * @brief tests if one of the intervals of the list intersects with the given interval.
331 * @param other the interval to check for intersection.
332 * @return @a true if there is an intersection.
333 */
334bool Intervals::intersects(const Interval& other) const
335{
336 for(const_iterator it= begin();
337 it != end();
338 ++it)
339 {
340 if ( it->intersects(other) )
341 {
342 return true;
343 }
344 }
345 return false;
346} // eo Intervals::intersects(const Interval&) const
347
348
349/**
350 * @brief tests if we have at least one intersection with another Intervals instance.
351 * @param other the other instance.
352 * @return @a true if there is an intersection.
353 */
354bool Intervals::intersects(const Intervals& other) const
355{
356 for(const_iterator it= begin();
357 it != end();
358 ++it)
359 {
360 if ( other.intersects( *it ) )
361 {
362 return true;
363 }
364 }
365 return false;
366} // eo Intervals::intersects(const Intervals&) const
367
368
369/**
370 * @brief adds a new interval to the list.
371 * @param new_frame the new interval.
372 *
373 * Adds the interval to the list and joins overlapping intervals.
ebc3b584
TJ
374 *
375 * @internal complexity O(n).
1b5dfd98
TJ
376 */
377void Intervals::add(const Interval& new_frame)
378{
379 if (not new_frame.is_valid() or new_frame.empty())
380 {
381 // well... we will not insert invalid or empty frames!
382 return;
383 }
384 for (IntervalList::iterator it= m_intervals.begin();
385 it != m_intervals.end();
386 ++it)
387 {
388 Interval& current_frame = *it;
389 if ( new_frame.m_lower_bound > current_frame.m_upper_bound )
390 {
391 // new_frame begins later than current end; go on:
392 continue;
393 }
394 // at this point: the begin of the new frame is less then the current end.
395 // now let's determine how we can insert the new frame:
396
397 if ( new_frame.m_upper_bound < current_frame.m_lower_bound )
398 {
399 // new disjoint frame; insert it before the current frame:
400 m_intervals.insert( it, new_frame );
401 // and we are done.
402 return;
403 }
404 // at this point: the end of the new frame is >= current begin.
405 if ( new_frame.m_upper_bound <= current_frame.m_upper_bound )
406 {
407 // the end of the new frame is within our current frame; we need to combine
408 if (new_frame.m_lower_bound < current_frame.m_lower_bound)
409 {
410 // the new interval starts earlier; we need to adjust our current frame:
411 current_frame.m_lower_bound = new_frame.m_lower_bound;
80f30818 412 current_frame.m_changed = true;
1b5dfd98
TJ
413 }
414 // NOTE no "else" part needed since in that case our current frame already
415 // contains the new one!
416
417 // we are done:
418 return;
419 }
420 // at this point: end of new frame > end of current frame
421 // so we need to extend the current frame; at least the end.
422 // But we need to deal with intersects of following frames... *sigh*
423
424 // first the simple part: let's see if we need to move the start:
425 if ( new_frame.m_lower_bound < current_frame.m_lower_bound)
426 {
427 // yes, we need to move the start:
428 current_frame.m_lower_bound = new_frame.m_lower_bound;
80f30818 429 current_frame.m_changed= true;
1b5dfd98
TJ
430 }
431
432 // now let's extend the end:
433 current_frame.m_upper_bound = new_frame.m_upper_bound;
80f30818 434 current_frame.m_changed = true;
1b5dfd98
TJ
435
436 // well... let's walk through the following frames; looking for more joins...:
437 IntervalList::iterator it2 = it;
438 while( ++(it2=it) != m_intervals.end()
439 and current_frame.m_upper_bound >= it2->m_lower_bound
440 )
441 {
442 Interval next_frame= *it2;
443 if ( current_frame.m_upper_bound < next_frame.m_upper_bound )
444 {
445 // in this case our end is within the next frame.
446 // adjust our end.
447 current_frame.m_upper_bound = next_frame.m_upper_bound;
448 }
449 // and remove the next frame since the current frame contains it (now):
450 m_intervals.erase(it2);
451 }
452 // we are done!
453 return;
454 }
455 // at this point: new frame starts later than the last frame ends
456 // append the new frame:
457 m_intervals.push_back( new_frame );
458} // eo Intervals::add(const Interval&)
459
460
461/**
462 * @brief subtracts a time interval from the list.
463 * @param del_frame the time interval to subtract.
464 *
465 * removes the time interval from the list; cut off parts from or remove existing
466 * intervals if they overlap.
ebc3b584
TJ
467 *
468 * @internal complexity O(n).
1b5dfd98
TJ
469 */
470void Intervals::sub(const Interval& del_frame)
471{
472 if (not del_frame.is_valid() or del_frame.empty() )
473 {
474 return;
475 }
476 for (IntervalList::iterator it= m_intervals.begin();
477 it != m_intervals.end();
478 )
479 {
480 Interval& current_frame = *it;
481 if ( del_frame.m_lower_bound >= current_frame.m_upper_bound )
482 {
483 // del_frame begins later than current end; go on:
484 ++it;
485 continue;
486 }
487 // at this point: the begin of the del frame is less then the current end.
488 if ( del_frame.m_upper_bound < current_frame.m_lower_bound )
489 {
490 // end is before our start; nothing to do.
491 return;
492 }
493 // at this point: the end of the del frame is >= current begin.
494 if ( del_frame.m_upper_bound < current_frame.m_upper_bound )
495 {
496 // del frame end point is within our interval.
497 if ( del_frame.m_lower_bound > current_frame.m_lower_bound)
498 {
499 // the del frame is within our interval... we need to split:
500 m_intervals.insert(it, Interval( current_frame.m_lower_bound, del_frame.m_lower_bound ) );
501 }
502 // adjust start of current frame:
80f30818
TJ
503 if (current_frame.m_lower_bound < del_frame.m_upper_bound)
504 {
505 current_frame.m_lower_bound= del_frame.m_upper_bound;
506 current_frame.m_changed= true;
507 }
1b5dfd98
TJ
508 // and we are done!
509 return;
510 }
511 // at this point the end of the del frame is >= current end
512 if ( del_frame.m_lower_bound > current_frame.m_lower_bound )
513 {
514 // a part of the current interval needs to be preserved..
515 // move the end.
516 current_frame.m_upper_bound= del_frame.m_lower_bound;
80f30818 517 current_frame.m_changed= true;
1b5dfd98
TJ
518 // and continue with the next interval:
519 ++it;
520 continue;
521 }
522 // at this point; the whole frame needs to be deleted..
523 if ( it == m_intervals.begin())
524 {
525 m_intervals.erase(it);
526 it= m_intervals.begin();
527 }
528 else
529 {
530 IntervalList::iterator it2= it++;
531 m_intervals.erase(it2);
532 }
533 }
534} // eo Intervals::sub(const Interval&)
535
536
537/**
538 * @brief returns if we contain an interval.
539 * @param other the interval to check.
540 * @return @a true if we cover the given interval, too.
541 */
542bool Intervals::contains(const Interval& other) const
543{
544 for(const_iterator it= begin();
545 it != end();
546 ++it)
547 {
548 if ( it->contains( other ))
549 {
550 return true;
551 }
552 }
553 return false;
554} // eo Intervals::contains(const Interval&) const
555
556
557/**
e156de7c
TJ
558 * @brief returns if we contain an exact interval.
559 * @param other the interval to check.
560 * @return @a true if we axactly contains the given interval.
561 *
562 * @note thsi differs from contain in the way, that we return only @a true
563 * iff we have the given interval in our list; not only cover it.
564 */
565bool Intervals::contains_exact(const Interval& other) const
566{
567 for(const_iterator it= begin();
568 it != end();
569 ++it)
570 {
571 if ( *it == other)
572 {
573 return true;
574 }
575 }
576 return false;
577} // eo Intervals::contains_exact(const Interval&)const
578
579
580/**
1b5dfd98
TJ
581 * @brief returns if we contain another interval combination.
582 * @param other the intervals to check.
583 * @return @a true if we cover the given intervals, too.
584 *
585 * @internal we rely on the fact that the lists are sorted and contain
586 * disjoint intervals.
ebc3b584
TJ
587 *
588 * So this method has a complexity of O(n).
1b5dfd98
TJ
589 */
590bool Intervals::contains(const Intervals& other) const
591{
592 const_iterator my_it= begin();
593 const_iterator other_it= other.begin();
594 while( my_it != end() and other_it!= other.end() )
595 {
596 // seek the first interval which contains the lower bound of the current other interval
597 while (my_it != end()
598 and my_it->m_lower_bound > other_it->m_lower_bound
599 and other_it->m_lower_bound >= my_it->m_upper_bound
600 )
601 {
602 ++my_it;
603 }
604 if (my_it == end())
605 {
606 break;
607 }
608 if (not my_it->contains( *other_it ))
609 {
610 // if we don't contain the current other; we're done:
611 return false;
612 }
613 //else check the next other interval:
614 ++other_it;
615 }
616 return (other_it == other.end());
ebc3b584 617} // eo Intervals::contains(const Intervals&) const
1b5dfd98
TJ
618
619
ebc3b584
TJ
620/**
621 * @brief combines to interval combinates for equality
622 * @param other the other instance.
623 * @return @a true if the other is equal to the current.
624 *
625 * @internal since the lists are sorted, we compare the interval lists.
626 * Thus we have a complexity of O(n).
627 */
1b5dfd98
TJ
628bool Intervals::operator==(const Intervals& other) const
629{
630 // since we keep sorted lists: just compare the lists :-)
631 return m_intervals == other.m_intervals;
632} // eo Intervals::operator==(const Intervals&)
633
634
635Intervals& Intervals::operator+=(const Interval& other)
636{
637 add(other);
638 return *this;
639} // eo operator+=(const Interval&)
640
641
642Intervals& Intervals::operator-=(const Interval& other)
643{
644 sub(other);
645 return *this;
646} // eo operator-=(const Interval&)
647
648
ebc3b584
TJ
649/**
650 * @brief adds the intervals of a second instance to us.
651 * @param other the other instance.
652 * @return self reference (allow chaining).
653 *
654 * @internal since we do simple loops over the other and our intervals
655 * we have a complexity of O(n^2).
656 *
657 * @todo optimize if complexity becomes a problem.
658 */
1b5dfd98
TJ
659Intervals& Intervals::operator+=(const Intervals& other)
660{
661 for(const_iterator it= other.begin();
662 it != other.end();
663 ++it)
664 {
665 add( *it );
666 }
667 return *this;
668} // eo operator+=(const Intervals&)
669
670
ebc3b584
TJ
671/**
672 * @brief subtracts the intervals of a second instance from us.
673 * @param other the other instance.
674 * @return self reference (allow chaining).
675 *
676 * @internal since we do simple loops over the other and our intervals
677 * we have a complexity of O(n^2).
678 *
679 * @todo optimize if complexity becomes a problem.
680 */
1b5dfd98
TJ
681Intervals& Intervals::operator-=(const Intervals& other)
682{
683 if (&other == this)
684 {
685 m_intervals.clear();
686 }
687 else
688 {
689 for(const_iterator it= other.begin();
690 it != other.end();
691 ++it)
692 {
693 sub( *it );
694 }
695 }
696 return *this;
697} // eo operator-=(const Intervals&)
96d0be2e
TJ
698
699
700
701/*
702** clock funcs:
703*/
704
705
706/**
707 * @brief fetches the value from the monotonic clock source.
708 * @param[out] seconds the seconds.
709 * @param[out] nano_seconds the nano seconds.
710 * @return @a true if the clock was successfully read.
711 */
712bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
713{
714 struct timespec tp[1];
715 int res= ::syscall(__NR_clock_gettime, CLOCK_MONOTONIC, tp);
716 if (0 == res)
717 {
718 seconds= tp->tv_sec;
719 nano_seconds= tp->tv_nsec;
720 }
721 return (res==0);
722} // eo monotonic_clock_gettime(long int&,long int&)
723
724
725/**
726 * @brief fetches the value from the monotonic clock source.
b7e17426
GE
727 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
728 */
729long long monotonic_clock_gettime_nano()
730{
731 long int seconds;
732 long int nano_seconds;
733 long long nano=0;
734
735 if (monotonic_clock_gettime(seconds,nano_seconds))
736 {
737 nano=seconds;
738 nano*=1000000000LL;
739 nano+=nano_seconds;
740 }
741
742 return nano;
743}
744
745/**
746 * @brief fetches the value from the monotonic clock source.
96d0be2e
TJ
747 * @param[out] seconds the seconds.
748 * @param[out] nano_seconds the nano seconds.
749 * @return @a true if the clock was successfully read.
750 */
751bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
752{
753 struct timespec tp[1];
754 int res= ::syscall(__NR_clock_gettime, CLOCK_REALTIME, tp);
755 if (0 == res)
756 {
757 seconds= tp->tv_sec;
758 nano_seconds= tp->tv_nsec;
759 }
760 return (res==0);
761} // eo realtime_clock_gettime(long int&,long int&)
762
763