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