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