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