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