increase libi2ncommon version as it is incompatible after dividing it by licenses...
[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>
5efd35b1 22#include <string.h>
e93545dd 23#include <sys/timeb.h>
96d0be2e 24#include <sys/syscall.h>
e93545dd
GE
25
26#include <timefunc.hxx>
27#include <i18n.h>
28
96d0be2e
TJ
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
e93545dd
GE
41using namespace std;
42
43double 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
56int 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
95string 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
119string 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}
f1499910 128
87869870
GE
129void 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
1344894d 148std::string output_hour_minute(int hour, int minute, bool h_for_00)
2c66f490
GE
149{
150 ostringstream out;
151
152 if (hour >= 0 && hour < 10)
153 out << '0';
154 out << hour;
155
1344894d 156 if (!h_for_00 || minute != 0)
2c66f490
GE
157 {
158 out << ':';
fe223928 159 if (minute >= 0 && minute < 10)
2c66f490
GE
160 out << '0';
161 out << minute;
162 }
163 else
164 out << 'h';
165
166 return out.str();
167}
4e157d1d
TJ
168
169string 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}
1b5dfd98
TJ
219
220
221/*
222** implementaion of Interval
223*/
224
d181c3bc
TJ
225
226/**
227 * @brief clears the interval (make it empty).
228 */
229void Interval::clear()
230{
231 m_lower_bound = m_upper_bound = 0;
232} // eo Interval::clear()
233
234
1b5dfd98
TJ
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 */
240bool 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 */
258bool 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
271Intervals::Intervals()
272{
273} // eo Intervals::Intervals
274
275
d181c3bc
TJ
276void Intervals::clear()
277{
278 m_intervals.clear();
279} // eo Intervals::clear()
280
1b5dfd98
TJ
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 */
286bool 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 */
306bool 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.
ebc3b584
TJ
326 *
327 * @internal complexity O(n).
1b5dfd98
TJ
328 */
329void 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;
80f30818 364 current_frame.m_changed = true;
1b5dfd98
TJ
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;
80f30818 381 current_frame.m_changed= true;
1b5dfd98
TJ
382 }
383
384 // now let's extend the end:
385 current_frame.m_upper_bound = new_frame.m_upper_bound;
80f30818 386 current_frame.m_changed = true;
1b5dfd98
TJ
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.
ebc3b584
TJ
419 *
420 * @internal complexity O(n).
1b5dfd98
TJ
421 */
422void 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:
80f30818
TJ
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 }
1b5dfd98
TJ
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;
80f30818 469 current_frame.m_changed= true;
1b5dfd98
TJ
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 */
494bool 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/**
e156de7c
TJ
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 */
517bool 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/**
1b5dfd98
TJ
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.
ebc3b584
TJ
539 *
540 * So this method has a complexity of O(n).
1b5dfd98
TJ
541 */
542bool 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());
ebc3b584 569} // eo Intervals::contains(const Intervals&) const
1b5dfd98
TJ
570
571
ebc3b584
TJ
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 */
1b5dfd98
TJ
580bool 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
587Intervals& Intervals::operator+=(const Interval& other)
588{
589 add(other);
590 return *this;
591} // eo operator+=(const Interval&)
592
593
594Intervals& Intervals::operator-=(const Interval& other)
595{
596 sub(other);
597 return *this;
598} // eo operator-=(const Interval&)
599
600
ebc3b584
TJ
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 */
1b5dfd98
TJ
611Intervals& 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
ebc3b584
TJ
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 */
1b5dfd98
TJ
633Intervals& 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&)
96d0be2e
TJ
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 */
664bool 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.
b7e17426
GE
679 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
680 */
681long 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.
96d0be2e
TJ
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 */
703bool 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