implement basic operations over class Time
[libi2ncommon] / src / timefunc.cpp
1 /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19 */
20 /** @file
21  * @brief time related functions.
22  *
23  * @copyright Copyright © 2001-2008 by Intra2net AG
24  *
25  */
26
27 #include <string>
28 #include <sstream>
29 #include <iostream>
30 #include <iomanip>
31 #include <bitset>
32 #include <stdexcept>
33 #include <iterator>
34 #include <algorithm>
35
36 #include <time.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sys/timeb.h>
40
41 #include <timefunc.hxx>
42 #include <i18n.h>
43
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
56 using namespace std;
57
58 double 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
71 time_t date_to_seconds(const std::string &date)
72 {
73     time_t rtn = 0;
74     int year = -1, month = -1, day = -1;
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;
99
100     struct tm tm_struct;
101     memset(&tm_struct, 0, sizeof(struct tm));
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
111 string make_nice_time(int seconds)
112 {
113     ostringstream out;
114
115     int days=seconds/86400;
116     seconds%=86400;
117
118     int hours,minutes;
119     split_daysec(seconds,&hours,&minutes,&seconds);
120     
121     if (days>0)
122         out << days << " " << i18n_plural("day", "days", days) << ", ";
123
124     out << setfill('0');
125     out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
126
127     return out.str();
128 }
129
130 string format_full_time(time_t seconds)
131 {
132     char buf[50];
133     memset (buf, 0, 50);
134     struct tm ta;
135     if (localtime_r((time_t *)&seconds, &ta) == NULL)
136         memset (&ta, 0, sizeof(struct tm));
137
138     strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
139     return string(buf);
140 }
141
142 string 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
154 void 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
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     */
180 void 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
198 std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
199 {
200     ostringstream out;
201     
202     if (hour >= 0 && hour < 10)
203         out << '0';
204     out << hour;
205     
206     if (!h_for_00 || minute != 0 || seconds > 0)
207     {
208         out << ':';
209         if (minute >= 0 && minute < 10)
210             out << '0';
211         out << minute;
212     }
213     else
214         out << 'h';
215
216     if (seconds > 0)
217     {
218         out << ':';
219         if (seconds > 0 && seconds < 10)
220             out << '0';
221         out << seconds;
222     }
223
224     return out.str();
225 }
226
227 string 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 }
277
278
279 /*
280 ** implementaion of Interval
281 */
282
283
284 /**
285  * @brief clears the interval (make it empty).
286  */
287 void Interval::clear()
288 {
289     m_lower_bound = m_upper_bound = 0;
290 } // eo Interval::clear()
291
292
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  */
298 bool 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  */
316 bool 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
329 Intervals::Intervals()
330 {
331 } // eo Intervals::Intervals
332
333
334 void Intervals::clear()
335 {
336     m_intervals.clear();
337 } // eo Intervals::clear()
338
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  */
344 bool 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  */
364 bool 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.
384  *
385  * @internal complexity O(n).
386  */
387 void 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;
422                 current_frame.m_changed = true;
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;
439             current_frame.m_changed= true;
440         }
441
442         // now let's extend the end:
443         current_frame.m_upper_bound = new_frame.m_upper_bound;
444         current_frame.m_changed = true;
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.
477  *
478  * @internal complexity O(n).
479  */
480 void 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:
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             }
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;
527             current_frame.m_changed= true;
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  */
552 bool 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 /**
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  */
575 bool 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 /**
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.
597  *
598  * So this method has a complexity of O(n).
599  */
600 bool 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());
627 } // eo Intervals::contains(const Intervals&) const
628
629
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  */
638 bool 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
645 Intervals& Intervals::operator+=(const Interval& other)
646 {
647     add(other);
648     return *this;
649 } // eo operator+=(const Interval&)
650
651
652 Intervals& Intervals::operator-=(const Interval& other)
653 {
654     sub(other);
655     return *this;
656 } // eo operator-=(const Interval&)
657
658
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  */
669 Intervals& 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
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  */
691 Intervals& 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&)
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  */
722 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
723 {
724     struct timespec tp[1];
725     int res= clock_gettime (CLOCK_MONOTONIC, tp);
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.
737  * @return the time since system start in nanoseconds, 0 if read was unsuccessful
738  */
739 long 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.
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  */
761 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
762 {
763     struct timespec tp[1];
764     int res= clock_gettime(CLOCK_REALTIME, tp);
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
774 namespace I2n {
775
776 namespace clock {
777
778     namespace {
779
780         static inline clockid_t
781         clockid_of_flags (const enum type::id      id,
782                           const enum type::variant var) NOEXCEPT
783         {
784             clockid_t cid = CLOCK_MONOTONIC_COARSE;
785
786             switch (id) {
787
788                 default:
789                 case type::mono: {
790                     switch (var) {
791                         default: {
792                             break;
793                         }
794                         case type::raw: {
795                             cid = CLOCK_MONOTONIC_RAW;
796                             break;
797                         }
798                         case type::exact: {
799                             cid = CLOCK_MONOTONIC;
800                             break;
801                         }
802                     }
803                     break;
804                 }
805
806                 case type::real: {
807                     if (var == type::exact) {
808                         cid = CLOCK_REALTIME;
809                     } else {
810                         cid = CLOCK_REALTIME_COARSE;
811                     }
812                     break;
813                 }
814
815                 case type::boot: {
816                     if (var & type::exact) {
817                         cid = CLOCK_BOOTTIME;
818                     }
819                     break;
820                 }
821
822                 case type::cpu: {
823                     if (var == type::thread) {
824                         cid = CLOCK_THREAD_CPUTIME_ID;
825                     } else {
826                         cid = CLOCK_PROCESS_CPUTIME_ID;
827                     }
828                     break;
829                 }
830             } /* [switch id] */
831
832             return cid;
833         }
834
835         static const struct timespec zero_time = { 0, 0 };
836
837     } /* [namespace] */
838
839     Time::Time (const enum type::id id,
840                 const enum type::variant var) NOEXCEPT
841         : value   (zero_time)
842         , id      (id)
843         , variant (var)
844         , err     (0)
845     { }
846
847     int64_t
848     Time::as_nanosec (void) const NOEXCEPT
849     {
850         return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
851              + this->value.tv_nsec;
852     }
853
854     long
855     Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
856     { return static_cast<long>(this->as_nanosec ()); }
857
858     Time &
859     Time::operator= (Time t2) NOEXCEPT
860     {
861         this->swap (t2);
862
863         return *this;
864     }
865
866     Time &
867     Time::operator= (struct timespec ts) NOEXCEPT
868     {
869         std::swap (this->value, ts);
870         this->id      = clock::type::mono;
871         this->variant = clock::type::dflt;
872         this->err     = 0;
873
874         return *this;
875     }
876
877     void
878     Time::unset (void) NOEXCEPT
879     { this->value = zero_time; }
880
881     bool
882     Time::set (void) NOEXCEPT
883     {
884         struct timespec now;
885
886         errno = 0;
887         if (clock_gettime (clockid_of_flags (this->id, this->variant), &now)
888             == -1)
889         {
890             this->err = errno;
891             this->unset ();
892
893             return false;
894         }
895         this->err   = 0;
896         this->value = now;
897
898         return true;
899     }
900
901     Time &
902     Time::add (const time_t sec, const long nsec) NOEXCEPT
903     {
904         this->value.tv_sec  += sec;
905         this->value.tv_nsec += nsec;
906
907         this->carry_nsec ();
908
909         return *this;
910     }
911
912     Time &
913     Time::subtract (const time_t sec, const long nsec) NOEXCEPT
914     {
915         this->value.tv_sec  -= sec;
916         this->value.tv_nsec -= nsec;
917
918         this->carry_nsec ();
919
920         return *this;
921     }
922
923     Time &
924     Time::scale (const time_t factor) NOEXCEPT
925     {
926         this->value.tv_sec  *= factor;
927         this->value.tv_nsec *= factor;
928
929         this->carry_nsec ();
930
931         return *this;
932     }
933
934     boost::optional<Time>
935     now (const enum type::id id, const enum type::variant var) NOEXCEPT
936     {
937         Time ret (id, var);
938
939         if (!ret.set ()) {
940             return boost::none;
941         }
942
943         return ret;
944     }
945
946     Time
947     zero (const enum type::id id, const enum type::variant var) NOEXCEPT
948     { return Time (id, var); }
949
950     int
951     compare (const Time &t1, const Time &t2) NOEXCEPT
952     {
953         if (t1.value.tv_sec < t2.value.tv_sec) {
954             return -1;
955         }
956
957         if (t1.value.tv_sec > t2.value.tv_sec) {
958             return 1;
959         }
960
961         if (t1.value.tv_nsec < t2.value.tv_nsec) {
962             return -1;
963         }
964
965         if (t1.value.tv_nsec > t2.value.tv_nsec) {
966             return 1;
967         }
968
969         return 0;
970     }
971
972 } /* [namespace clock] */
973
974 } /* [namespace I2n] */
975