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