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