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