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