add precautions for old glibc
[libi2ncommon] / test / test_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 unit test for time related functions.
22  *
23  * @copyright Copyright © 2001-2008 by Intra2net AG
24  *
25  */
26 #include <features.h>
27 #if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 23)
28 /*
29  * Ancient glibc (pre 2015) has a defective implementation of strptime(3)
30  * that doesn’t handle the ‘Z’ modifier of ISO8601 to indicate UTC. It also
31  * parses fractional timezones only partially so e. g. “+11:11” is treated
32  * as “+1100”.
33  */
34 #   define GLIBC_STRPTIME_LACKS_Z
35 #endif
36
37 #define BOOST_TEST_DYN_LINK
38 #include <boost/test/unit_test.hpp>
39
40 #include <timefunc.hxx>
41 #include <filefunc.hxx>
42
43 #include <unistd.h>
44 #include <set>
45 #include <iostream>
46
47 using namespace std;
48 using namespace I2n;
49 using namespace I2n::Time;
50
51 class TestTimeFuncFixture
52 {
53 protected:
54    typedef std::list< std::string > StringList;
55    std::set<std::string>  used_check_files;
56    std::string tz; /* save and restore TZ from envp */
57
58    std::string get_check_file_path(std::string tag)
59    {
60       std::string result;
61       result= "__unittest__" + tag + ".dat";
62       used_check_files.insert(result);
63       return result;
64    } // eo get_check_file_path
65
66    void remove_check_files()
67    {
68       for (std::set<std::string>::iterator it= used_check_files.begin();
69             it != used_check_files.end();
70             ++it)
71       {
72          std::string filepath(*it);
73          if (path_exists(filepath))
74          {
75             unlink(filepath);
76          }
77          //TODO
78       }
79       used_check_files.clear();
80    } // eo remove_check_files
81
82    void set_tz (const std::string &tzname)
83    {
84         errno = 0;
85         if (setenv ("TZ", tzname.c_str (), 1) == -1)
86         {
87             std::cerr
88                 << "error setting environment 'TZ': [" << tzname << "]"
89                 << std::endl
90                 ;
91             return;
92         }
93
94         tzset ();
95    }
96
97    inline void set_utc (void)
98    {
99        this->set_tz ("UTC");
100    }
101
102 public:
103     TestTimeFuncFixture()
104         : tz (secure_getenv ("TZ") ?: "")
105     {
106     }
107
108     ~TestTimeFuncFixture()
109     {
110         remove_check_files();
111
112         errno = 0;
113         if (setenv ("TZ", this->tz.c_str (), 1) == -1)
114         {
115             std::cerr
116                 << "error cleaning up environment 'TZ': [" << this->tz << "]"
117                 << std::endl
118                 ;
119         }
120         else
121         {
122             tzset();
123         }
124     }
125 };
126
127 BOOST_FIXTURE_TEST_SUITE(TestTimeFunc, TestTimeFuncFixture)
128
129 BOOST_AUTO_TEST_CASE(AddIntervalsDisjoint)
130 {
131     Intervals intervals;
132
133     intervals.add( Interval( 10, 100 ) );
134     intervals.add( Interval( 600, 620 ) );
135
136     BOOST_CHECK_EQUAL( false, intervals.empty() );
137     BOOST_CHECK_EQUAL( 2u, intervals.size() );
138
139     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
140     BOOST_CHECK_EQUAL( 100u, intervals.front().upper_bound() );
141
142     BOOST_CHECK_EQUAL( 600u, intervals.back().lower_bound() );
143     BOOST_CHECK_EQUAL( 620u, intervals.back().upper_bound() );
144 } // eo AddIntervalsDisjoint()
145
146
147
148 BOOST_AUTO_TEST_CASE(AddIntervalsInclude)
149 {
150     Intervals intervals;
151
152     intervals.add( Interval( 10, 100 ) );
153     intervals.add( Interval( 10, 80 ) );
154
155     BOOST_CHECK_EQUAL( false, intervals.empty() );
156     BOOST_CHECK_EQUAL( 1u, intervals.size() );
157
158     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
159     BOOST_CHECK_EQUAL( 100u, intervals.front().upper_bound() );
160     BOOST_CHECK_EQUAL( false, intervals.front().changed() );
161 } // eo AddIntervalsInclude()
162
163
164
165 BOOST_AUTO_TEST_CASE(AddIntervalsEmbrace)
166 {
167     Intervals intervals;
168
169     intervals.add( Interval( 10, 100 ) );
170     intervals.add( Interval( 5, 120 ) );
171
172     BOOST_CHECK_EQUAL( false, intervals.empty() );
173     BOOST_CHECK_EQUAL( 1u, intervals.size() );
174
175     BOOST_CHECK_EQUAL( 5u, intervals.front().lower_bound() );
176     BOOST_CHECK_EQUAL( 120u, intervals.front().upper_bound() );
177     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
178 } // eo AddIntervalsEmbrace()
179
180
181
182 BOOST_AUTO_TEST_CASE(AddIntervalsJoin1)
183 {
184     Intervals intervals;
185
186     intervals.add( Interval( 10, 100 ) );
187     intervals.add( Interval( 60, 120 ) );
188
189     BOOST_CHECK_EQUAL( false, intervals.empty() );
190     BOOST_CHECK_EQUAL( 1u, intervals.size() );
191
192     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
193     BOOST_CHECK_EQUAL( 120u, intervals.front().upper_bound() );
194     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
195 } // eo AddIntervalsJoin1()
196
197
198
199 BOOST_AUTO_TEST_CASE(AddIntervalsJoin1b)
200 {
201     Intervals intervals;
202
203     intervals.add( Interval( 10, 100 ) );
204     intervals.add( Interval( 100, 120 ) );
205
206     BOOST_CHECK_EQUAL( false, intervals.empty() );
207     BOOST_CHECK_EQUAL( 1u, intervals.size() );
208
209     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
210     BOOST_CHECK_EQUAL( 120u, intervals.front().upper_bound() );
211     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
212 } // eo AddIntervalsJoin1b()
213
214
215
216 BOOST_AUTO_TEST_CASE(AddIntervalsJoin2)
217 {
218     Intervals intervals;
219
220     intervals.add( Interval( 10, 100 ) );
221     intervals.add( Interval( 200, 250 ) );
222
223     BOOST_CHECK_EQUAL( false, intervals.empty() );
224     BOOST_CHECK_EQUAL( 2u, intervals.size() );
225
226     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
227     BOOST_CHECK_EQUAL( 100u, intervals.front().upper_bound() );
228     BOOST_CHECK_EQUAL( 200u, intervals.back().lower_bound() );
229     BOOST_CHECK_EQUAL( 250u, intervals.back().upper_bound() );
230
231     // now add the gap; the intervals should collapse to one covering all:
232     intervals.add( Interval(100, 200) );
233
234     BOOST_CHECK_EQUAL( false, intervals.empty() );
235     BOOST_CHECK_EQUAL( 1u, intervals.size() );
236
237     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
238     BOOST_CHECK_EQUAL( 250u, intervals.front().upper_bound() );
239     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
240 } // eo AddIntervalsJoin2()
241
242
243
244 BOOST_AUTO_TEST_CASE(SubIntervalsDisjoint)
245 {
246     Intervals intervals;
247
248     intervals.add( Interval(10, 100) );
249     intervals.sub( Interval(0, 10) );
250
251     BOOST_CHECK_EQUAL( false, intervals.empty() );
252     BOOST_CHECK_EQUAL( 1u, intervals.size() );
253
254     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
255     BOOST_CHECK_EQUAL( 100u, intervals.front().upper_bound() );
256     BOOST_CHECK_EQUAL( false, intervals.front().changed() );
257 } // eo SubIntervalsDisjoint()
258
259
260
261 BOOST_AUTO_TEST_CASE(SubIntervalsExact)
262 {
263     Intervals intervals;
264
265     intervals.add( Interval(10, 100) );
266     intervals.sub( Interval(10, 100) );
267
268     BOOST_CHECK_EQUAL( true, intervals.empty() );
269     BOOST_CHECK_EQUAL( 0u, intervals.size() );
270 } // eo SubIntervalsExact()
271
272
273
274 BOOST_AUTO_TEST_CASE(SubIntervalsSplit1)
275 {
276     Intervals intervals;
277
278     intervals.add( Interval(10, 100) );
279     intervals.sub( Interval(20, 40) );
280
281     BOOST_CHECK_EQUAL( false, intervals.empty() );
282     BOOST_CHECK_EQUAL( 2u, intervals.size() );
283
284     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
285     BOOST_CHECK_EQUAL( 20u, intervals.front().upper_bound() );
286
287     BOOST_CHECK_EQUAL( 40u, intervals.back().lower_bound() );
288     BOOST_CHECK_EQUAL( 100u, intervals.back().upper_bound() );
289     BOOST_CHECK_EQUAL( false, intervals.front().changed() );
290     BOOST_CHECK_EQUAL( true, intervals.back().changed() );
291 } // eo SubIntervalsSplit1()
292
293
294 BOOST_AUTO_TEST_CASE(SubIntervalsCutFront)
295 {
296     Intervals intervals;
297
298     intervals.add( Interval(10, 100) );
299     intervals.sub( Interval(10, 20) );
300
301     BOOST_CHECK_EQUAL( false, intervals.empty() );
302     BOOST_CHECK_EQUAL( 1u, intervals.size() );
303
304     BOOST_CHECK_EQUAL( 20u, intervals.front().lower_bound() );
305     BOOST_CHECK_EQUAL( 100u, intervals.front().upper_bound() );
306     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
307 } // eo SubIntervalsCutFront()
308
309
310 BOOST_AUTO_TEST_CASE(SubIntervalsCutBack)
311 {
312     Intervals intervals;
313
314     intervals.add( Interval(10, 100) );
315     intervals.sub( Interval(87, 100) );
316
317     BOOST_CHECK_EQUAL( false, intervals.empty() );
318     BOOST_CHECK_EQUAL( 1u, intervals.size() );
319
320     BOOST_CHECK_EQUAL( 10u, intervals.front().lower_bound() );
321     BOOST_CHECK_EQUAL( 87u, intervals.front().upper_bound() );
322     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
323 } // eo SubIntervalsCutBack()
324
325
326
327 BOOST_AUTO_TEST_CASE(SubIntervalsCutMore)
328 {
329     Intervals intervals;
330
331     intervals.add( Interval( 10, 100) );
332     intervals.add( Interval(110, 200) );
333     intervals.add( Interval(210, 300) );
334
335     // this should remove the first 2 intervals and cut the third:
336     intervals.sub( Interval(8, 220) );
337
338     BOOST_CHECK_EQUAL( false, intervals.empty() );
339     BOOST_CHECK_EQUAL( 1u, intervals.size() );
340
341     BOOST_CHECK_EQUAL( 220u, intervals.front().lower_bound() );
342     BOOST_CHECK_EQUAL( 300u, intervals.front().upper_bound() );
343     BOOST_CHECK_EQUAL( true, intervals.front().changed() );
344 } // eo SubIntervalsCutMore()
345
346
347 BOOST_AUTO_TEST_CASE(IntervalComparisons)
348 {
349     Intervals intervals1;
350     Intervals intervals2;
351
352     intervals1.add( Interval( 10, 120) );
353
354     intervals2.add( Interval( 10, 110 ) );
355     intervals2.add( Interval( 100, 120 ) );
356
357     BOOST_CHECK_EQUAL( 1u, intervals2.size() );
358
359     BOOST_CHECK( intervals1 == intervals2 );
360     BOOST_CHECK_EQUAL( true, intervals1.contains( intervals2 ));
361     BOOST_CHECK_EQUAL( true, intervals2.contains( intervals1 ));
362
363     intervals2.sub( Interval( 40, 50) );
364
365     BOOST_CHECK( intervals1 != intervals2 );
366     BOOST_CHECK_EQUAL( true, intervals1.contains( intervals2 ));
367     BOOST_CHECK_EQUAL( false, intervals2.contains( intervals1 ));
368 } // eo IntervalComparisons()
369
370
371
372 BOOST_AUTO_TEST_CASE(MonotonicClock)
373 {
374     long sec0, nsec0;
375     long sec1, nsec1;
376
377     bool res = monotonic_clock_gettime(sec0,nsec0);
378     BOOST_CHECK_EQUAL( true, res );
379
380     usleep(250000);
381     res= monotonic_clock_gettime(sec1,nsec1);
382     BOOST_CHECK_EQUAL( true, res);
383
384     long delta_sec = sec1 - sec0;
385     long delta_nsec= nsec1 - nsec0;
386
387     long delta_millisec= ( delta_nsec / 1000000L) + delta_sec * 1000L;
388
389     BOOST_CHECK( delta_millisec >= 250 - /*fuzz*/ 1);
390     BOOST_CHECK( delta_millisec < 300 );
391 } // eo MonotonicClock()
392
393 BOOST_AUTO_TEST_CASE(WeekInvalid)
394 {
395     Week week("99999999");
396     BOOST_CHECK_EQUAL(false, week.is_valid());
397     BOOST_CHECK_EQUAL(string(""), week.get_displaystring());
398 }
399
400 BOOST_AUTO_TEST_CASE(WeekDisplayString1)
401 {
402     Week week("");
403     BOOST_CHECK_EQUAL(true, week.is_valid());
404     BOOST_CHECK_EQUAL(string(""), week.get_displaystring());
405 }
406
407 BOOST_AUTO_TEST_CASE(WeekDisplayString2)
408 {
409     Week week("0123456");
410     BOOST_CHECK_EQUAL(true, week.is_valid());
411     BOOST_CHECK_EQUAL(string("Mon-Sun"), week.get_displaystring());
412 }
413
414 BOOST_AUTO_TEST_CASE(WeekDisplayString3)
415 {
416     Week week("123456");
417     BOOST_CHECK_EQUAL(true, week.is_valid());
418     BOOST_CHECK_EQUAL(string("Mon-Sat"), week.get_displaystring());
419 }
420
421 BOOST_AUTO_TEST_CASE(WeekDisplayString4)
422 {
423     Week week("012345");
424     BOOST_CHECK_EQUAL(true, week.is_valid());
425     BOOST_CHECK_EQUAL(string("Mon-Fri, Sun"), week.get_displaystring());
426 }
427
428 BOOST_AUTO_TEST_CASE(WeekDisplayString5)
429 {
430     Week week("1256");
431     BOOST_CHECK_EQUAL(true, week.is_valid());
432     BOOST_CHECK_EQUAL(string("Mon, Tue, Fri, Sat"), week.get_displaystring());
433 }
434
435 BOOST_AUTO_TEST_CASE(WeekDisplayString6)
436 {
437     Week week("0246");
438     BOOST_CHECK_EQUAL(true, week.is_valid());
439     BOOST_CHECK_EQUAL(string("Tue, Thu, Sat, Sun"), week.get_displaystring());
440 }
441
442 BOOST_AUTO_TEST_CASE(WeekDisplayString7)
443 {
444     Week week("135");
445     BOOST_CHECK_EQUAL(true, week.is_valid());
446     BOOST_CHECK_EQUAL(string("Mon, Wed, Fri"), week.get_displaystring());
447 }
448
449 BOOST_AUTO_TEST_CASE(WeekDisplayString8)
450 {
451     Week week("15");
452     BOOST_CHECK_EQUAL(true, week.is_valid());
453     BOOST_CHECK_EQUAL(string("Mon, Fri"), week.get_displaystring());
454 }
455
456 BOOST_AUTO_TEST_CASE(WeekDisplayString9)
457 {
458     Week week("06");
459     BOOST_CHECK_EQUAL(true, week.is_valid());
460     BOOST_CHECK_EQUAL(string("Sat, Sun"), week.get_displaystring());
461 }
462
463 BOOST_AUTO_TEST_CASE(WeekDisplayString10)
464 {
465     Week week("056");
466     BOOST_CHECK_EQUAL(true, week.is_valid());
467     BOOST_CHECK_EQUAL(string("Fri-Sun"), week.get_displaystring());
468 }
469
470 BOOST_AUTO_TEST_CASE(WeekDisplayString11)
471 {
472     Week week("0");
473     BOOST_CHECK_EQUAL(true, week.is_valid());
474     BOOST_CHECK_EQUAL(string("Sun"), week.get_displaystring());
475 }
476
477 BOOST_AUTO_TEST_CASE(WeekDisplayString12)
478 {
479     Week week("6");
480     BOOST_CHECK_EQUAL(true, week.is_valid());
481     BOOST_CHECK_EQUAL(string("Sat"), week.get_displaystring());
482 }
483
484 BOOST_AUTO_TEST_CASE(WeekDisplayString13)
485 {
486     Week week("123");
487     BOOST_CHECK_EQUAL(true, week.is_valid());
488     BOOST_CHECK_EQUAL(string("Mon-Wed"), week.get_displaystring());
489 }
490
491 BOOST_AUTO_TEST_CASE(FormatFullTime)
492 {
493     this->set_tz ("CET");
494     time_t seconds = 1318844005;
495
496     BOOST_CHECK_EQUAL("17.10.2011 11:33", format_full_time(seconds));
497 }
498
499 BOOST_AUTO_TEST_CASE(DateToSeconds1)
500 {
501     this->set_tz ("CET");
502     // no DST
503     BOOST_CHECK_EQUAL(1325372400, date_to_seconds("2012-01-01"));
504 }
505
506 BOOST_AUTO_TEST_CASE(DateToSeconds2)
507 {
508     this->set_tz ("CET");
509     // DST
510     BOOST_CHECK_EQUAL(1341093600, date_to_seconds("2012-07-01"));
511 }
512
513 BOOST_AUTO_TEST_CASE(FormatISO8601_T)
514 {
515     const time_t moment = 1515492684;
516     BOOST_CHECK_EQUAL("10:11:24",
517                       format_iso8601 (moment, true, false, true, false));
518 }
519
520 BOOST_AUTO_TEST_CASE(FormatISO8601_TZ_local)
521 {
522     this->set_tz ("CET");
523     const time_t moment = 1515492684;
524     BOOST_CHECK_EQUAL("11:11:24+0100",
525                       format_iso8601 (moment, false, false, true, true));
526 }
527
528 BOOST_AUTO_TEST_CASE(FormatISO8601_TZ)
529 {
530     const time_t moment = 1515492684;
531     BOOST_CHECK_EQUAL("10:11:24+0000",
532                       format_iso8601 (moment, true, false, true, true));
533 }
534
535 BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_local)
536 {
537     this->set_tz ("CET");
538     const time_t moment = 1515492684;
539     BOOST_CHECK_EQUAL("2018-01-09T11:11:24+0100",
540                       format_iso8601 (moment, false, true, true, true));
541 }
542
543 BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ)
544 {
545     const time_t moment = 1515492684;
546     BOOST_CHECK_EQUAL("2018-01-09T10:11:24+0000",
547                       format_iso8601 (moment, true, true, true, true));
548 }
549
550 BOOST_AUTO_TEST_CASE(FormatISO8601_DT)
551 {
552     const time_t moment = 1515492684;
553     BOOST_CHECK_EQUAL("2018-01-09T10:11:24",
554                       format_iso8601 (moment, true, true, true, false));
555 }
556
557 BOOST_AUTO_TEST_CASE(FormatISO8601_D)
558 {
559     const time_t moment = 1515492684;
560     BOOST_CHECK_EQUAL("2018-01-09",
561                       format_iso8601 (moment, true, true, false, false));
562 }
563
564 BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_struct_tm)
565 {
566     struct tm helau;
567     helau.tm_sec    = 11;
568     helau.tm_min    = 11;
569     helau.tm_hour   = 11;
570     helau.tm_mday   = 11;
571     helau.tm_mon    = 10;
572     helau.tm_year   = 2018 - 1900;
573     helau.tm_wday   = 0;
574     helau.tm_yday   = 315;
575     helau.tm_isdst  = 0;
576     helau.tm_gmtoff = 0;
577     helau.tm_zone   = NULL;
578
579     BOOST_CHECK_EQUAL("2018-11-11T11:11:11+0000",
580                       format_iso8601 (helau, true, true, true));
581 }
582
583 BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_struct_timespec)
584 {
585     struct timespec ts = { 1541934671, 11 };
586
587     BOOST_CHECK_EQUAL("2018-11-11T11:11:11+0000",
588                       format_iso8601 (ts, true, true, true, true));
589 }
590
591 BOOST_AUTO_TEST_SUITE(Clock)
592
593     BOOST_AUTO_TEST_CASE(ctor_simple)
594     {
595         I2n::clock::Time t;
596
597         BOOST_CHECK_EQUAL(t.get_sec  (), 0);
598         BOOST_CHECK_EQUAL(t.get_nsec (), 0);
599     }
600
601     BOOST_AUTO_TEST_CASE(ctor_type)
602     {
603         I2n::clock::Time t1 (I2n::clock::type::real);
604         I2n::clock::Time t2 (I2n::clock::type::mono);
605         I2n::clock::Time t3 (I2n::clock::type::boot);
606         I2n::clock::Time t4 (I2n::clock::type::cpu);
607
608         BOOST_CHECK_EQUAL(t1.get_sec  (), 0);
609         BOOST_CHECK_EQUAL(t1.get_nsec (), 0);
610
611         BOOST_CHECK_EQUAL(t2.get_sec  (), 0);
612         BOOST_CHECK_EQUAL(t2.get_nsec (), 0);
613
614         BOOST_CHECK_EQUAL(t3.get_sec  (), 0);
615         BOOST_CHECK_EQUAL(t3.get_nsec (), 0);
616
617         BOOST_CHECK_EQUAL(t4.get_sec  (), 0);
618         BOOST_CHECK_EQUAL(t4.get_nsec (), 0);
619     }
620
621     BOOST_AUTO_TEST_CASE(ctor_variant)
622     {
623         I2n::clock::Time tmc (I2n::clock::type::mono);
624         I2n::clock::Time tmr (I2n::clock::type::mono, I2n::clock::type::raw);
625         I2n::clock::Time tme (I2n::clock::type::mono, I2n::clock::type::exact);
626
627         I2n::clock::Time trc (I2n::clock::type::real);
628         I2n::clock::Time tre (I2n::clock::type::real, I2n::clock::type::exact);
629
630         I2n::clock::Time tb (I2n::clock::type::boot);
631
632         I2n::clock::Time tcp (I2n::clock::type::cpu);
633         I2n::clock::Time tct (I2n::clock::type::cpu, I2n::clock::type::thread);
634
635         BOOST_CHECK_EQUAL(tmc.get_sec  (), 0); /* MONO */
636         BOOST_CHECK_EQUAL(tmc.get_nsec (), 0);
637
638         BOOST_CHECK_EQUAL(tmr.get_sec  (), 0);
639         BOOST_CHECK_EQUAL(tmr.get_nsec (), 0);
640
641         BOOST_CHECK_EQUAL(tme.get_sec  (), 0);
642         BOOST_CHECK_EQUAL(tme.get_nsec (), 0);
643
644         BOOST_CHECK_EQUAL(trc.get_sec  (), 0); /* REAL */
645         BOOST_CHECK_EQUAL(trc.get_nsec (), 0);
646
647         BOOST_CHECK_EQUAL(tre.get_sec  (), 0);
648         BOOST_CHECK_EQUAL(tre.get_nsec (), 0);
649
650         BOOST_CHECK_EQUAL(tb.get_sec  (), 0); /* BOOT */
651         BOOST_CHECK_EQUAL(tb.get_nsec (), 0);
652
653         BOOST_CHECK_EQUAL(tcp.get_sec  (), 0); /* CPU */
654         BOOST_CHECK_EQUAL(tcp.get_nsec (), 0);
655
656         BOOST_CHECK_EQUAL(tct.get_sec  (), 0);
657         BOOST_CHECK_EQUAL(tct.get_nsec (), 0);
658     }
659
660     BOOST_AUTO_TEST_CASE(initializer_now)
661     {
662         boost::optional<I2n::clock::Time> t = I2n::clock::now ();
663
664         BOOST_CHECK(t);
665         BOOST_CHECK_GT(t->get_sec (), 0);
666         BOOST_CHECK_EQUAL(t->err, 0);
667     }
668
669     BOOST_AUTO_TEST_CASE(initializer_zero)
670     {
671         I2n::clock::Time stundenull = I2n::clock::zero ();
672
673         BOOST_CHECK_EQUAL(stundenull.get_sec  (), 0);
674         BOOST_CHECK_EQUAL(stundenull.get_nsec (), 0);
675         BOOST_CHECK_EQUAL(stundenull.err, 0);
676     }
677
678     BOOST_AUTO_TEST_CASE(member_set_now)
679     {
680         I2n::clock::Time t;
681
682         BOOST_CHECK(t.set ());
683
684         BOOST_CHECK_NE(t.get_sec (), 0);
685     }
686
687     BOOST_AUTO_TEST_CASE(member_set_value)
688     {
689         I2n::clock::Time t;
690
691         t.set (42, 42);
692
693         BOOST_CHECK_EQUAL(t.get_sec  (), 42);
694         BOOST_CHECK_EQUAL(t.get_nsec (), 42);
695     }
696
697     BOOST_AUTO_TEST_CASE(member_set_value_type)
698     {
699         I2n::clock::Time t;
700
701         t.set (42, 42, I2n::clock::type::real, I2n::clock::type::exact);
702
703         BOOST_CHECK_EQUAL(t.get_sec  (), 42);
704         BOOST_CHECK_EQUAL(t.get_nsec (), 42);
705     }
706
707     BOOST_AUTO_TEST_CASE(member_add_parts)
708     {
709         I2n::clock::Time t;
710
711         t.set (42, 42);
712         t.add (2187, 2187);
713
714         BOOST_CHECK_EQUAL(t.get_sec  (), 2229);
715         BOOST_CHECK_EQUAL(t.get_nsec (), 2229);
716     }
717
718     BOOST_AUTO_TEST_CASE(member_sub_parts)
719     {
720         I2n::clock::Time t;
721
722         t.set (2, 0L);
723         t.subtract (1, 1L);
724
725         BOOST_CHECK_EQUAL(t.get_sec  (), 0);
726         BOOST_CHECK_EQUAL(t.get_nsec (), 999999999);
727     }
728
729     BOOST_AUTO_TEST_CASE(member_sub_Time)
730     {
731         I2n::clock::Time t1;
732         I2n::clock::Time t2;
733
734         t1.set (42, 42L);
735         t2.set (42,  0L);
736
737         t1.subtract (t2);
738
739         BOOST_CHECK_EQUAL(t1.get_sec  (),  0);
740         BOOST_CHECK_EQUAL(t1.get_nsec (), 42L);
741     }
742
743     BOOST_AUTO_TEST_CASE(member_diff)
744     {
745         static const time_t five = 5 * 365 * 24 * 3600;
746
747         I2n::clock::Time t1 (42, 1337);
748         I2n::clock::Time t2 = t1 + five;;
749         I2n::clock::Time t3 = t1 - five;;
750
751         BOOST_CHECK_EQUAL(t2, I2n::clock::Time ((time_t)42 + five, 1337));
752         BOOST_CHECK_EQUAL(t3, I2n::clock::Time ((time_t)42 - five, 1337));
753         BOOST_CHECK_EQUAL(t1.difference (t3), t3.difference (t1));
754         BOOST_CHECK_EQUAL(t3.difference (t3), t3.difference (t3));
755     }
756
757     BOOST_AUTO_TEST_CASE(op_copyassign)
758     {
759         I2n::clock::Time t1;
760         I2n::clock::Time t2;
761
762         BOOST_CHECK(t1.set ());
763
764         t2 = t1;
765
766         BOOST_CHECK_EQUAL(t1.get_sec  (), t2.get_sec  ());
767         BOOST_CHECK_EQUAL(t1.get_nsec (), t2.get_nsec ());
768     }
769
770     BOOST_AUTO_TEST_CASE(op_equal)
771     {
772         I2n::clock::Time t1;
773         I2n::clock::Time t2;
774
775         BOOST_CHECK(t1.set ());
776         t2 = t1;
777
778         BOOST_CHECK_EQUAL(t1, t2);
779     }
780
781     BOOST_AUTO_TEST_CASE(op_add_Time)
782     {
783         I2n::clock::Time t1;
784         I2n::clock::Time t2;
785         I2n::clock::Time tsum;
786
787         t1.set (2187, 2187);
788         t2.set (1337, 1337);
789         tsum = t1 + t2;
790
791         BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
792         BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
793     }
794
795     BOOST_AUTO_TEST_CASE(op_add_Time_carry)
796     {
797         I2n::clock::Time t1;
798         I2n::clock::Time t2;
799         I2n::clock::Time tsum;
800
801         t1.set (2187, 2187);
802 # if LONG_BIT == 32
803         t2.set (1300,  2L * 1000 * 1000 * 1000 + 1337);
804 # else
805         t2.set (1300, 37L * 1000 * 1000 * 1000 + 1337);
806 # endif
807
808         tsum = t1 + t2;
809
810 # if LONG_BIT == 32
811         BOOST_CHECK_EQUAL(tsum.get_sec  (), 3489);
812         BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
813 # else
814         BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
815         BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
816 # endif
817     }
818
819     BOOST_AUTO_TEST_CASE(op_add_time_t)
820     {
821         I2n::clock::Time t1 (2187, 2187);
822         time_t           t2 = 1337;
823         I2n::clock::Time tsum;
824
825         tsum = t1 + t2;
826
827         BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
828         BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
829     }
830
831     BOOST_AUTO_TEST_CASE(op_add_time_t_external)
832     {
833         time_t           t1 = 1337;
834         I2n::clock::Time t2 (2187, 2187);
835         I2n::clock::Time tsum;
836
837         tsum = t1 + t2;
838
839         BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
840         BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
841     }
842
843     BOOST_AUTO_TEST_CASE(op_incr_Time)
844     {
845         I2n::clock::Time t1 (2187, 2187);
846         I2n::clock::Time t2 (1337, 1337);
847
848         t1 += t2;
849
850         BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
851         BOOST_CHECK_EQUAL(t1.get_nsec (), 3524);
852     }
853
854     BOOST_AUTO_TEST_CASE(op_incr_time_t)
855     {
856         I2n::clock::Time t1 (2187, 2187);
857         time_t           t2 = 1337;
858
859         t1 += t2;
860
861         BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
862         BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
863     }
864
865     BOOST_AUTO_TEST_CASE(op_subtract_Time)
866     {
867         I2n::clock::Time t1;
868         I2n::clock::Time t2;
869         I2n::clock::Time tdiff;
870
871         t1.set (2187, 2187);
872         t2.set (1337, 1337);
873         tdiff = t1 - t2;
874
875         BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
876         BOOST_CHECK_EQUAL(tdiff.get_nsec (), 850);
877     }
878
879     BOOST_AUTO_TEST_CASE(op_subtract_time_t)
880     {
881         I2n::clock::Time t1 (2187, 2187);
882         time_t           t2 = 1337;
883         I2n::clock::Time tdiff;
884
885         tdiff = t1 - t2;
886
887         BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
888         BOOST_CHECK_EQUAL(tdiff.get_nsec (), 2187);
889     }
890
891     BOOST_AUTO_TEST_CASE(op_subtract_time_t_external)
892     {
893         time_t           t1 = 1337;
894         I2n::clock::Time t2 (2187, 2187);
895         I2n::clock::Time tdiff;
896
897         tdiff = t1 - t2;
898
899         BOOST_CHECK_EQUAL(tdiff.get_sec  (), -851);
900         BOOST_CHECK_EQUAL(tdiff.get_nsec (), 999997813);
901     }
902
903     BOOST_AUTO_TEST_CASE(op_decr_Time)
904     {
905         I2n::clock::Time t1 (2187, 2187);
906         I2n::clock::Time t2 (1337, 1337);
907
908         t1 -= t2;
909
910         BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
911         BOOST_CHECK_EQUAL(t1.get_nsec (), 850);
912     }
913
914     BOOST_AUTO_TEST_CASE(op_decr_time_t)
915     {
916         I2n::clock::Time t1 (2187, 2187);
917         time_t           t2 = 1337;
918
919         t1 -= t2;
920
921         BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
922         BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
923     }
924
925     BOOST_AUTO_TEST_CASE(op_mult_scale)
926     {
927         I2n::clock::Time t1;
928         I2n::clock::Time t2;
929
930         t1.set (1, 1);
931         t2 = t1 * 42;
932
933         BOOST_CHECK_EQUAL(t2.get_sec  (), 42);
934         BOOST_CHECK_EQUAL(t2.get_nsec (), 42);
935     }
936
937     BOOST_AUTO_TEST_CASE(op_mult_mutate)
938     {
939         I2n::clock::Time t1 (  42, 42);
940         I2n::clock::Time t2 (1337,  0);
941
942         t1 *=   2;
943         t2 *= -10;
944
945         BOOST_CHECK_EQUAL(t1.get_sec  (),     84);
946         BOOST_CHECK_EQUAL(t1.get_nsec (),     84);
947         BOOST_CHECK_EQUAL(t2.get_sec  (), -13370);
948     }
949
950     BOOST_AUTO_TEST_CASE(op_mult_scale_carry)
951     {
952         I2n::clock::Time t1;
953         I2n::clock::Time t2;
954
955         t1.set (1, 500 * 1000 * 1000);
956         t2 = t1 * 3;
957
958         BOOST_CHECK_EQUAL(t2.get_sec  (),  4);
959         BOOST_CHECK_EQUAL(t2.get_nsec (),  500 * 1000 * 1000);
960     }
961
962     BOOST_AUTO_TEST_CASE(op_equals)
963     {
964         I2n::clock::Time t1;
965         I2n::clock::Time t2;
966
967         t1.set (50, 50);
968         t2.set (50, 50);
969
970         BOOST_CHECK_EQUAL(t1, t2);
971     }
972
973     BOOST_AUTO_TEST_CASE(compare_equal)
974     {
975         I2n::clock::Time t1;
976         I2n::clock::Time t2;
977
978         t1.set (42, 42);
979         t2.set (42, 42);
980
981         BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), 0);
982     }
983
984     BOOST_AUTO_TEST_CASE(compare_equal_type)
985     {
986         I2n::clock::Time t1 (42, 42, I2n::clock::type::real);
987         I2n::clock::Time t2 (42, 42, I2n::clock::type::cpu);
988         I2n::clock::Time t3 (42,  0, I2n::clock::type::real);
989         I2n::clock::Time t4 (42, 42, I2n::clock::type::real);
990
991         BOOST_CHECK_NE(t1, t2);
992         BOOST_CHECK_NE(t1, t3);
993         BOOST_CHECK_EQUAL(t1, t4);
994     }
995
996     BOOST_AUTO_TEST_CASE(compare_ne_sec)
997     {
998         I2n::clock::Time t1;
999         I2n::clock::Time t2;
1000
1001         t1.set (  42, 42);
1002         t2.set (1337, 42);
1003
1004         BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
1005         BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
1006     }
1007
1008     BOOST_AUTO_TEST_CASE(compare_ne_nsec)
1009     {
1010         I2n::clock::Time t1;
1011         I2n::clock::Time t2;
1012
1013         t1.set (42,   42);
1014         t2.set (42, 1337);
1015
1016         BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
1017         BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
1018     }
1019
1020     BOOST_AUTO_TEST_CASE(compare_ne_both)
1021     {
1022         I2n::clock::Time t1;
1023         I2n::clock::Time t2;
1024
1025         t1.set (42, 2187);
1026         t2.set (23, 1337);
1027
1028         BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2),  1);
1029         BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1), -1);
1030     }
1031
1032     BOOST_AUTO_TEST_CASE(op_ineq_sec)
1033     {
1034         I2n::clock::Time t1 (1337);
1035         I2n::clock::Time t2 (2187);
1036
1037         BOOST_CHECK_LT(t1, t2);
1038         BOOST_CHECK_GT(t2, t1);
1039     }
1040
1041     BOOST_AUTO_TEST_CASE(op_ineq_nsec)
1042     {
1043         I2n::clock::Time t1 (1337, 23);
1044         I2n::clock::Time t2 (1337, 42);
1045
1046         BOOST_CHECK_LT(t1, t2);
1047         BOOST_CHECK_GT(t2, t1);
1048     }
1049
1050     BOOST_AUTO_TEST_CASE(op_ineq_both)
1051     {
1052         I2n::clock::Time t1 (2187, 23);
1053         I2n::clock::Time t2 (1337, 42);
1054
1055         BOOST_CHECK_LT(t2, t1);
1056         BOOST_CHECK_GT(t1, t2);
1057     }
1058
1059     BOOST_AUTO_TEST_CASE(op_eq_time_t)
1060     {
1061         boost::optional<I2n::clock::Time> t1  = I2n::clock::now ();
1062         const time_t                      t2  = time (NULL); /* race here */
1063
1064         *t1 -= (time_t)42;
1065
1066         BOOST_CHECK_NE(*t1,  t2);
1067         BOOST_CHECK_LT(*t1,  t2);
1068         BOOST_CHECK_GT( t2, *t1);
1069     }
1070
1071     BOOST_AUTO_TEST_CASE(Format_sec_msec)
1072     {
1073         I2n::clock::Time t1 (42, 42);
1074         I2n::clock::Time t2 ( 4, 242424242);
1075         I2n::clock::Time t3 ( 0, 133713371);
1076         I2n::clock::Time t4 ( 0, 0);
1077
1078         std::string s1 = t1.format_sec_msec ();
1079         std::string s2 = t2.format_sec_msec ();
1080         std::string s3 = t3.format_sec_msec ();
1081         std::string s4 = t4.format_sec_msec ();
1082
1083         BOOST_CHECK_EQUAL("42s 0ms"  , s1);
1084         BOOST_CHECK_EQUAL( "4s 242ms", s2);
1085         BOOST_CHECK_EQUAL( "0s 133ms", s3);
1086         BOOST_CHECK_EQUAL( "0s 0ms"  , s4);
1087     }
1088
1089     BOOST_AUTO_TEST_CASE(Format_min_sec_msec)
1090     {
1091         I2n::clock::Time t1 (42*60 + 42, 42);
1092         I2n::clock::Time t2 ( 4*60 + 42, 242424242);
1093         I2n::clock::Time t3 ( 0*60 + 42, 133713371);
1094         I2n::clock::Time t4 (    0 +  0,  0);
1095
1096         std::string s1 = *t1.format_min_sec_msec ();
1097         std::string s2 = *t2.format_min_sec_msec ();
1098         std::string s3 = *t3.format_min_sec_msec ();
1099         std::string s4 = *t4.format_min_sec_msec ();
1100
1101         BOOST_CHECK_EQUAL("42m42.000s", s1);
1102         BOOST_CHECK_EQUAL( "4m42.242s", s2);
1103         BOOST_CHECK_EQUAL( "0m42.133s", s3);
1104         BOOST_CHECK_EQUAL(  "0m0.000s", s4);
1105     }
1106
1107     BOOST_AUTO_TEST_CASE(FormatISO8601_T)
1108     {
1109         I2n::clock::Time t (42, 42);
1110         boost::optional<std::string> s = t.format_iso8601 (true, false, true, false);
1111
1112         BOOST_CHECK_EQUAL("00:00:42", *s);
1113     }
1114
1115     BOOST_AUTO_TEST_CASE(FormatISO8601_DT)
1116     {
1117         I2n::clock::Time t (1541934671, 0);
1118         boost::optional<std::string> s = t.format_iso8601 (true, true, true, false);
1119
1120         BOOST_CHECK_EQUAL("2018-11-11T11:11:11", *s);
1121     }
1122
1123     BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ)
1124     {
1125         I2n::clock::Time t (1541934671, 0);
1126         boost::optional<std::string> s = t.format_iso8601 (true, true, true, true);
1127
1128         BOOST_CHECK_EQUAL("2018-11-11T11:11:11+0000", *s);
1129     }
1130
1131     BOOST_AUTO_TEST_CASE(Format_make_nice_time)
1132     {
1133         I2n::clock::Time t (111111, 0);
1134         boost::optional<std::string> s = t.make_nice_time ();
1135
1136         BOOST_CHECK_EQUAL("1 day, 06:51:51", *s);
1137     }
1138
1139     BOOST_AUTO_TEST_CASE(Format_format_full_time)
1140     {
1141         I2n::clock::Time t (1541934671, 0);
1142         /*
1143          * brr, the old formatters use localtime without a way to opt out of
1144          * it!
1145          */
1146         this->set_utc ();
1147         boost::optional<std::string> s = t.format_full_time ();
1148
1149         BOOST_CHECK_EQUAL("11.11.2018 11:11", *s);
1150     }
1151
1152     BOOST_AUTO_TEST_CASE(Format_format_date)
1153     {
1154         I2n::clock::Time t (1541934671, 0);
1155         boost::optional<std::string> s = t.format_date ();
1156
1157         BOOST_CHECK_EQUAL("11.11.2018", *s);
1158     }
1159
1160     BOOST_AUTO_TEST_CASE(FromString_iso8601_full)
1161     {
1162         const std::string in1 ("0001-01-01T00:00:00+0000");
1163         const std::string in2 ("2018-11-11T11:11:11+0000");
1164
1165         this->set_utc ();
1166
1167         boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1);
1168         boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2);
1169
1170 # if LONG_BIT == 32
1171         BOOST_CHECK(!t1);
1172 # else
1173         BOOST_CHECK(t1);
1174         BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1);
1175 # endif
1176
1177         BOOST_CHECK(t2);
1178         BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2);
1179     }
1180
1181     BOOST_AUTO_TEST_CASE(FromString_iso8601_full_negyear)
1182     {
1183         const std::string in1 ("-0001-01-01T00:00:00+0000");
1184         const std::string in2 ("-2018-11-11T11:11:11+0000");
1185
1186         this->set_utc ();
1187
1188         boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1);
1189         boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2);
1190
1191 # if LONG_BIT == 32
1192         BOOST_CHECK(!t1);
1193         BOOST_CHECK(!t2);
1194 # else
1195         BOOST_CHECK(t1);
1196         BOOST_CHECK(t2);
1197         BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1);
1198         BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2);
1199 # endif
1200     }
1201
1202 # ifndef GLIBC_STRPTIME_LACKS_Z
1203     BOOST_AUTO_TEST_CASE(FromString_iso8601_Z)
1204     {
1205         const std::string in1 ("2019-04-25T13:41:47+0000");
1206         const std::string in2 ("2019-04-25T13:41:47Z");
1207
1208         this->set_utc ();
1209         boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1, true, true, true);
1210         boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2, true, true, true);
1211
1212         BOOST_CHECK(t1);
1213         BOOST_CHECK(t2);
1214
1215         BOOST_CHECK_EQUAL(*t1, *t2);
1216         BOOST_CHECK_EQUAL(*t1->format_iso8601 (), *t2->format_iso8601 ());
1217         BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in1);
1218     }
1219 # endif
1220
1221     BOOST_AUTO_TEST_CASE(FromString_iso8601_partial)
1222     {
1223         const std::string in1 ("2018-11-11T11:11:11");
1224         const std::string in2 ("2018-11-11");
1225
1226         this->set_utc ();
1227
1228         boost::optional<I2n::clock::Time> t1 =
1229             I2n::clock::time_of_iso8601 (in1, true, true, false);
1230         boost::optional<I2n::clock::Time> t2 =
1231             I2n::clock::time_of_iso8601 (in2, true, false, false);
1232
1233         BOOST_CHECK(t1);
1234         BOOST_CHECK(t2);
1235         /*
1236          * We test for the difference here which is zero if the number is
1237          * correct but causes the difference from the expected value to be
1238          * printed in case the test fails.
1239          */
1240         BOOST_CHECK_EQUAL(*t1->format_iso8601 (true,  true,  true, false), in1);
1241         BOOST_CHECK_EQUAL(*t2->format_iso8601 (true,  true, false, false), in2);
1242     }
1243
1244     BOOST_AUTO_TEST_CASE(FromString_iso8601_offset)
1245     {
1246         const std::string in1 ("2019-04-25T13:41:47Z");
1247         const std::string in2 ("2019-04-25T13:41:47+0200"); /* = UTC(in1 + 2h) */
1248         const std::string in3 ("2019-04-25T15:41:47+0000"); /* = UTC(in2) */
1249
1250         this->set_utc ();
1251         boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1, true, true, true);
1252         boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2, true, true, true);
1253         boost::optional<I2n::clock::Time> t3 = I2n::clock::time_of_iso8601 (in3, true, true, true);
1254
1255 # ifdef GLIBC_STRPTIME_LACKS_Z
1256         BOOST_CHECK(!t1);
1257 # else
1258         BOOST_CHECK(t1);
1259 # endif
1260         BOOST_CHECK(t2);
1261         BOOST_CHECK(t3);
1262
1263 # ifndef GLIBC_STRPTIME_LACKS_Z
1264         BOOST_CHECK_EQUAL(*t1->format_iso8601 (), "2019-04-25T13:41:47+0000");
1265         BOOST_CHECK_EQUAL(t1->get_sec (), 1556199707);
1266 # endif
1267         BOOST_CHECK_EQUAL(*t2->format_iso8601 (), "2019-04-25T15:41:47+0000");
1268 # ifndef GLIBC_STRPTIME_LACKS_Z
1269         BOOST_CHECK_EQUAL(t2->get_sec (), t1->get_sec () + 2 * 60 * 60);
1270 # endif
1271         BOOST_CHECK_EQUAL(*t2, *t3);
1272         BOOST_CHECK_EQUAL(*t3->format_iso8601 (), "2019-04-25T15:41:47+0000");
1273     }
1274
1275     BOOST_AUTO_TEST_CASE(FromString_iso8601_tzdiff)
1276     {
1277         const std::string in ("2019-04-26T13:45:02+0000");
1278
1279         this->set_tz ("UTC");
1280         boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in, true, true, false);
1281
1282         this->set_tz ("CET");
1283         boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in, true, true, false);
1284
1285         BOOST_CHECK_EQUAL(*t1->format_iso8601 (true, true, true, true), in);
1286         BOOST_CHECK_EQUAL(*t2->format_iso8601 (true, true, true, true), "2019-04-26T13:45:02+0000");
1287     }
1288
1289     BOOST_AUTO_TEST_CASE(FromString_iso8601_32bit_time_t_err)
1290     {
1291         const std::string timeless ("11:11:11");
1292         boost::optional<I2n::clock::Time> untimely = boost::none;
1293
1294         this->set_utc ();
1295
1296         untimely = I2n::clock::time_of_iso8601 (timeless, false, true, false);
1297
1298 # if LONG_BIT == 32
1299         BOOST_CHECK(!untimely);
1300 # else
1301         BOOST_CHECK(untimely);
1302         BOOST_CHECK_EQUAL(*untimely->format_iso8601 (true, false,  true, false),
1303                           timeless);
1304 # endif
1305     }
1306
1307     BOOST_AUTO_TEST_CASE(Ctor_32bit_time_t_err)
1308     {
1309         boost::optional<std::string> threw = boost::none;
1310
1311         struct tm tm;
1312         memset (&tm, 0, sizeof (tm));
1313
1314         tm.tm_sec    = 11;
1315         tm.tm_min    = 11;
1316         tm.tm_hour   = 11;
1317         tm.tm_mday   = 11;
1318         tm.tm_mon    = 10;
1319         tm.tm_year   = -789;
1320         tm.tm_gmtoff = 0;
1321
1322         try {
1323             I2n::clock::Time untimely (tm);
1324         } catch (I2n::clock::conversion_error &exn) {
1325             threw = std::string (exn);
1326         }
1327
1328
1329 # if LONG_BIT == 32
1330         BOOST_CHECK_EQUAL(*threw,
1331                           "errno=0 [mktime: from struct tm {Sun Nov 11 11:11:11 1111}]");
1332 # else
1333         BOOST_CHECK(!threw);
1334 # endif
1335     }
1336
1337     BOOST_AUTO_TEST_CASE(containers_list)
1338     {
1339         std::list<I2n::clock::Time> ts;
1340
1341         ts.push_back (I2n::clock::zero ());
1342         ts.push_back (I2n::clock::zero ());
1343
1344         BOOST_CHECK_EQUAL(ts.size (), 2);
1345     }
1346
1347     BOOST_AUTO_TEST_CASE(containers_vec)
1348     {
1349         std::vector<I2n::clock::Time> ts;
1350
1351         ts.push_back (I2n::clock::zero ());
1352         ts.push_back (I2n::clock::zero ());
1353
1354         BOOST_CHECK_EQUAL(ts.size (), 2);
1355     }
1356
1357     BOOST_AUTO_TEST_CASE(containers_set)
1358     {
1359         std::set<I2n::clock::Time> ts;
1360
1361         ts.insert (I2n::clock::zero ());
1362         ts.insert (I2n::clock::Time (42, 2187));
1363         ts.insert (I2n::clock::zero ());
1364
1365         BOOST_CHECK_EQUAL(ts.size (), 2);
1366     }
1367
1368     BOOST_AUTO_TEST_CASE(containers_list_mean)
1369     {
1370         std::list<I2n::clock::Time> ts;
1371
1372         ts.push_back (I2n::clock::Time (42, 42));
1373         ts.push_back (I2n::clock::Time (1337, 1337));
1374
1375         BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
1376                           I2n::clock::Time (689, 500000689));
1377     }
1378
1379     BOOST_AUTO_TEST_CASE(containers_list_mean_zero)
1380     {
1381         std::list<I2n::clock::Time> ts;
1382
1383         ts.push_back (I2n::clock::Time (0, 0));
1384         ts.push_back (I2n::clock::Time (0, 0));
1385         ts.push_back (I2n::clock::Time (0, 0));
1386         ts.push_back (I2n::clock::Time (0, 0));
1387
1388         BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
1389                           I2n::clock::zero ());
1390     }
1391
1392     BOOST_AUTO_TEST_CASE(containers_list_mean_empty)
1393     {
1394         std::list<I2n::clock::Time> ts;
1395
1396         BOOST_CHECK_EQUAL(I2n::clock::mean (ts), I2n::clock::Time (0, 0));
1397     }
1398
1399     BOOST_AUTO_TEST_CASE(containers_set_mean)
1400     {
1401         std::set<I2n::clock::Time> ts;
1402
1403         ts.insert (I2n::clock::Time (42));
1404         ts.insert (I2n::clock::Time (1337));
1405         ts.insert (I2n::clock::Time (2187));
1406
1407         BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
1408                           I2n::clock::Time (1188, 666666666));
1409     }
1410
1411     BOOST_AUTO_TEST_CASE(containers_set_median_empty)
1412     {
1413         std::set<I2n::clock::Time> ts;
1414
1415         BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0, 0));
1416     }
1417
1418     BOOST_AUTO_TEST_CASE(containers_set_median_one)
1419     {
1420         std::set<I2n::clock::Time> ts;
1421
1422         ts.insert (I2n::clock::Time (42, 0));
1423
1424         BOOST_CHECK_EQUAL(I2n::clock::median (ts),
1425                           I2n::clock::Time (42, 0));
1426     }
1427
1428     BOOST_AUTO_TEST_CASE(containers_set_median_multi)
1429     {
1430         std::set<I2n::clock::Time> ts;
1431
1432         ts.insert (I2n::clock::Time (42));
1433         ts.insert (I2n::clock::Time (1337));
1434         ts.insert (I2n::clock::Time (2187));
1435
1436         BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337));
1437     }
1438
1439     BOOST_AUTO_TEST_CASE(containers_vec_median_multi)
1440     {
1441         std::vector<I2n::clock::Time> ts;
1442
1443         ts.push_back (I2n::clock::Time (42));
1444         ts.push_back (I2n::clock::Time (1337));
1445         ts.push_back (I2n::clock::Time (2187));
1446
1447         BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337));
1448     }
1449
1450     BOOST_AUTO_TEST_CASE(containers_list_median_multi)
1451     {
1452         std::list<I2n::clock::Time> ts;
1453
1454         ts.push_back (I2n::clock::Time (42));
1455         ts.push_back (I2n::clock::Time (1337));
1456         ts.push_back (I2n::clock::Time (2187));
1457         ts.push_back (I2n::clock::Time (0xdead));
1458         ts.push_back (I2n::clock::Time (0xbeef));
1459
1460         BOOST_CHECK_EQUAL(I2n::clock::median (ts),
1461                           I2n::clock::Time (2187));
1462     }
1463
1464     BOOST_AUTO_TEST_CASE(containers_list_median_multi_evensize)
1465     {
1466         std::list<I2n::clock::Time> ts;
1467
1468         ts.push_back (I2n::clock::Time (42));
1469         ts.push_back (I2n::clock::Time (1337));
1470         ts.push_back (I2n::clock::Time (2187));
1471         ts.push_back (I2n::clock::Time (0xf00d));
1472         ts.push_back (I2n::clock::Time (0xfeed));
1473         ts.push_back (I2n::clock::Time (0xdeadf0e));
1474
1475         BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0xf00d));
1476     }
1477
1478 BOOST_AUTO_TEST_SUITE_END() /* [Clock] */
1479
1480 BOOST_AUTO_TEST_SUITE_END()