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