Fix iconv include directory
[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
c0368918
GE
102 int hours,minutes;
103 split_daysec(seconds,&hours,&minutes,&seconds);
104
e93545dd
GE
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
116string 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}
f1499910 125
87869870
GE
126void 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
c0368918
GE
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 */
152void 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
170std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
2c66f490
GE
171{
172 ostringstream out;
173
174 if (hour >= 0 && hour < 10)
175 out << '0';
176 out << hour;
177
c0368918 178 if (!h_for_00 || minute != 0 || seconds > 0)
2c66f490
GE
179 {
180 out << ':';
fe223928 181 if (minute >= 0 && minute < 10)
2c66f490
GE
182 out << '0';
183 out << minute;
184 }
185 else
186 out << 'h';
187
c0368918
GE
188 if (seconds > 0)
189 {
190 out << ':';
191 if (seconds > 0 && seconds < 10)
192 out << '0';
193 out << seconds;
194 }
195
2c66f490
GE
196 return out.str();
197}
4e157d1d
TJ
198
199string 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}
1b5dfd98
TJ
249
250
251/*
252** implementaion of Interval
253*/
254
d181c3bc
TJ
255
256/**
257 * @brief clears the interval (make it empty).
258 */
259void Interval::clear()
260{
261 m_lower_bound = m_upper_bound = 0;
262} // eo Interval::clear()
263
264
1b5dfd98
TJ
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 */
270bool 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 */
288bool 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
301Intervals::Intervals()
302{
303} // eo Intervals::Intervals
304
305
d181c3bc
TJ
306void Intervals::clear()
307{
308 m_intervals.clear();
309} // eo Intervals::clear()
310
1b5dfd98
TJ
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 */
316bool 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 */
336bool 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.
ebc3b584
TJ
356 *
357 * @internal complexity O(n).
1b5dfd98
TJ
358 */
359void 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;
80f30818 394 current_frame.m_changed = true;
1b5dfd98
TJ
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;
80f30818 411 current_frame.m_changed= true;
1b5dfd98
TJ
412 }
413
414 // now let's extend the end:
415 current_frame.m_upper_bound = new_frame.m_upper_bound;
80f30818 416 current_frame.m_changed = true;
1b5dfd98
TJ
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.
ebc3b584
TJ
449 *
450 * @internal complexity O(n).
1b5dfd98
TJ
451 */
452void 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:
80f30818
TJ
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 }
1b5dfd98
TJ
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;
80f30818 499 current_frame.m_changed= true;
1b5dfd98
TJ
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 */
524bool 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/**
e156de7c
TJ
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 */
547bool 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/**
1b5dfd98
TJ
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.
ebc3b584
TJ
569 *
570 * So this method has a complexity of O(n).
1b5dfd98
TJ
571 */
572bool 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());
ebc3b584 599} // eo Intervals::contains(const Intervals&) const
1b5dfd98
TJ
600
601
ebc3b584
TJ
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 */
1b5dfd98
TJ
610bool 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
617Intervals& Intervals::operator+=(const Interval& other)
618{
619 add(other);
620 return *this;
621} // eo operator+=(const Interval&)
622
623
624Intervals& Intervals::operator-=(const Interval& other)
625{
626 sub(other);
627 return *this;
628} // eo operator-=(const Interval&)
629
630
ebc3b584
TJ
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 */
1b5dfd98
TJ
641Intervals& 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
ebc3b584
TJ
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 */
1b5dfd98
TJ
663Intervals& 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&)
96d0be2e
TJ
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 */
694bool 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.
b7e17426
GE
709 * @return the time since system start in nanoseconds, 0 if read was unsuccessful
710 */
711long 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.
96d0be2e
TJ
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 */
733bool 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