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