Merge branch 'timefunc-new'
[libi2ncommon] / test / test_timefunc.cpp
index 58dcaf5..885bb67 100644 (file)
@@ -32,6 +32,7 @@ on this file might be covered by the GNU General Public License.
 
 #include <unistd.h>
 #include <set>
+#include <iostream>
 
 using namespace std;
 using namespace I2n;
@@ -42,6 +43,7 @@ class TestTimeFuncFixture
 protected:
    typedef std::list< std::string > StringList;
    std::set<std::string>  used_check_files;
+   std::string tz; /* save and restore TZ from envp */
 
    std::string get_check_file_path(std::string tag)
    {
@@ -67,14 +69,43 @@ protected:
       used_check_files.clear();
    } // eo remove_check_files
 
+   void set_utc (void)
+   {
+        errno = 0;
+        if (setenv ("TZ", "UTC", 1) == -1)
+        {
+            std::cerr
+                << "error setting environment 'TZ': [" << this->tz << "]"
+                << std::endl
+                ;
+            return;
+        }
+
+        tzset ();
+   }
+
 public:
     TestTimeFuncFixture()
+        : tz (secure_getenv ("TZ") ?: "")
     {
     }
 
     ~TestTimeFuncFixture()
     {
         remove_check_files();
+
+        errno = 0;
+        if (setenv ("TZ", this->tz.c_str (), 1) == -1)
+        {
+            std::cerr
+                << "error cleaning up environment 'TZ': [" << this->tz << "]"
+                << std::endl
+                ;
+        }
+        else
+        {
+            tzset();
+        }
     }
 };
 
@@ -461,5 +492,905 @@ BOOST_AUTO_TEST_CASE(DateToSeconds2)
     BOOST_CHECK_EQUAL(1341093600, date_to_seconds("2012-07-01"));
 }
 
+BOOST_AUTO_TEST_CASE(FormatISO8601_T)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("10:11:24",
+                      format_iso8601 (moment, true, false, true, false));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_TZ_local)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("11:11:24Z+0100",
+                      format_iso8601 (moment, false, false, true, true));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_TZ)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("10:11:24Z+0000",
+                      format_iso8601 (moment, true, false, true, true));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_local)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("2018-01-09T11:11:24Z+0100",
+                      format_iso8601 (moment, false, true, true, true));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("2018-01-09T10:11:24Z+0000",
+                      format_iso8601 (moment, true, true, true, true));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_DT)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("2018-01-09T10:11:24",
+                      format_iso8601 (moment, true, true, true, false));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_D)
+{
+    const time_t moment = 1515492684;
+    BOOST_CHECK_EQUAL("2018-01-09",
+                      format_iso8601 (moment, true, true, false, false));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_struct_tm)
+{
+    struct tm helau;
+    helau.tm_sec    = 11;
+    helau.tm_min    = 11;
+    helau.tm_hour   = 11;
+    helau.tm_mday   = 11;
+    helau.tm_mon    = 10;
+    helau.tm_year   = 2018 - 1900;
+    helau.tm_wday   = 0;
+    helau.tm_yday   = 315;
+    helau.tm_isdst  = 0;
+    helau.tm_gmtoff = 0;
+    helau.tm_zone   = NULL;
+
+    BOOST_CHECK_EQUAL("2018-11-11T11:11:11Z+0000",
+                      format_iso8601 (helau, true, true, true));
+}
+
+BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ_struct_timespec)
+{
+    struct timespec ts = { 1541934671, 11 };
+
+    BOOST_CHECK_EQUAL("2018-11-11T11:11:11Z+0000",
+                      format_iso8601 (ts, true, true, true, true));
+}
+
+BOOST_AUTO_TEST_SUITE(Clock)
+
+    BOOST_AUTO_TEST_CASE(ctor_simple)
+    {
+        I2n::clock::Time t;
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(ctor_type)
+    {
+        I2n::clock::Time t1 (I2n::clock::type::real);
+        I2n::clock::Time t2 (I2n::clock::type::mono);
+        I2n::clock::Time t3 (I2n::clock::type::boot);
+        I2n::clock::Time t4 (I2n::clock::type::cpu);
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(t2.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t2.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(t3.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t3.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(t4.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t4.get_nsec (), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(ctor_variant)
+    {
+        I2n::clock::Time tmc (I2n::clock::type::mono);
+        I2n::clock::Time tmr (I2n::clock::type::mono, I2n::clock::type::raw);
+        I2n::clock::Time tme (I2n::clock::type::mono, I2n::clock::type::exact);
+
+        I2n::clock::Time trc (I2n::clock::type::real);
+        I2n::clock::Time tre (I2n::clock::type::real, I2n::clock::type::exact);
+
+        I2n::clock::Time tb (I2n::clock::type::boot);
+
+        I2n::clock::Time tcp (I2n::clock::type::cpu);
+        I2n::clock::Time tct (I2n::clock::type::cpu, I2n::clock::type::thread);
+
+        BOOST_CHECK_EQUAL(tmc.get_sec  (), 0); /* MONO */
+        BOOST_CHECK_EQUAL(tmc.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tmr.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(tmr.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tme.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(tme.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(trc.get_sec  (), 0); /* REAL */
+        BOOST_CHECK_EQUAL(trc.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tre.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(tre.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tb.get_sec  (), 0); /* BOOT */
+        BOOST_CHECK_EQUAL(tb.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tcp.get_sec  (), 0); /* CPU */
+        BOOST_CHECK_EQUAL(tcp.get_nsec (), 0);
+
+        BOOST_CHECK_EQUAL(tct.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(tct.get_nsec (), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(initializer_now)
+    {
+        boost::optional<I2n::clock::Time> t = I2n::clock::now ();
+
+        BOOST_CHECK(t);
+        BOOST_CHECK_GT(t->get_sec (), 0);
+        BOOST_CHECK_EQUAL(t->err, 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(initializer_zero)
+    {
+        I2n::clock::Time stundenull = I2n::clock::zero ();
+
+        BOOST_CHECK_EQUAL(stundenull.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(stundenull.get_nsec (), 0);
+        BOOST_CHECK_EQUAL(stundenull.err, 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_now)
+    {
+        I2n::clock::Time t;
+
+        BOOST_CHECK(t.set ());
+
+        BOOST_CHECK_NE(t.get_sec (), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_value)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_set_value_type)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42, I2n::clock::type::real, I2n::clock::type::exact);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_add_parts)
+    {
+        I2n::clock::Time t;
+
+        t.set (42, 42);
+        t.add (2187, 2187);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 2229);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 2229);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_sub_parts)
+    {
+        I2n::clock::Time t;
+
+        t.set (2, 0L);
+        t.subtract (1, 1L);
+
+        BOOST_CHECK_EQUAL(t.get_sec  (), 0);
+        BOOST_CHECK_EQUAL(t.get_nsec (), 999999999);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_sub_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 42L);
+        t2.set (42,  0L);
+
+        t1.subtract (t2);
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (),  0);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 42L);
+    }
+
+    BOOST_AUTO_TEST_CASE(member_diff)
+    {
+        static const time_t five = 5 * 365 * 24 * 3600;
+
+        I2n::clock::Time t1 (42, 1337);
+        I2n::clock::Time t2 = t1 + five;;
+        I2n::clock::Time t3 = t1 - five;;
+
+        BOOST_CHECK_EQUAL(t2, I2n::clock::Time ((time_t)42 + five, 1337));
+        BOOST_CHECK_EQUAL(t3, I2n::clock::Time ((time_t)42 - five, 1337));
+        BOOST_CHECK_EQUAL(t1.difference (t3), t3.difference (t1));
+        BOOST_CHECK_EQUAL(t3.difference (t3), t3.difference (t3));
+    }
+
+    BOOST_AUTO_TEST_CASE(op_copyassign)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        BOOST_CHECK(t1.set ());
+
+        t2 = t1;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), t2.get_sec  ());
+        BOOST_CHECK_EQUAL(t1.get_nsec (), t2.get_nsec ());
+    }
+
+    BOOST_AUTO_TEST_CASE(op_equal)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        BOOST_CHECK(t1.set ());
+        t2 = t1;
+
+        BOOST_CHECK_EQUAL(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tsum;
+
+        t1.set (2187, 2187);
+        t2.set (1337, 1337);
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_Time_carry)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tsum;
+
+        t1.set (2187, 2187);
+# if LONG_BIT == 32
+        t2.set (1300,  2L * 1000 * 1000 * 1000 + 1337);
+# else
+        t2.set (1300, 37L * 1000 * 1000 * 1000 + 1337);
+# endif
+
+        tsum = t1 + t2;
+
+# if LONG_BIT == 32
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3489);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
+# else
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 3524);
+# endif
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+        I2n::clock::Time tsum;
+
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_add_time_t_external)
+    {
+        time_t           t1 = 1337;
+        I2n::clock::Time t2 (2187, 2187);
+        I2n::clock::Time tsum;
+
+        tsum = t1 + t2;
+
+        BOOST_CHECK_EQUAL(tsum.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(tsum.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_incr_Time)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        I2n::clock::Time t2 (1337, 1337);
+
+        t1 += t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 3524);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_incr_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+
+        t1 += t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 3524);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_Time)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+        I2n::clock::Time tdiff;
+
+        t1.set (2187, 2187);
+        t2.set (1337, 1337);
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 850);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+        I2n::clock::Time tdiff;
+
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_subtract_time_t_external)
+    {
+        time_t           t1 = 1337;
+        I2n::clock::Time t2 (2187, 2187);
+        I2n::clock::Time tdiff;
+
+        tdiff = t1 - t2;
+
+        BOOST_CHECK_EQUAL(tdiff.get_sec  (), -851);
+        BOOST_CHECK_EQUAL(tdiff.get_nsec (), 999997813);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_decr_Time)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        I2n::clock::Time t2 (1337, 1337);
+
+        t1 -= t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 850);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_decr_time_t)
+    {
+        I2n::clock::Time t1 (2187, 2187);
+        time_t           t2 = 1337;
+
+        t1 -= t2;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (), 850);
+        BOOST_CHECK_EQUAL(t1.get_nsec (), 2187);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_scale)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (1, 1);
+        t2 = t1 * 42;
+
+        BOOST_CHECK_EQUAL(t2.get_sec  (), 42);
+        BOOST_CHECK_EQUAL(t2.get_nsec (), 42);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_mutate)
+    {
+        I2n::clock::Time t1 (  42, 42);
+        I2n::clock::Time t2 (1337,  0);
+
+        t1 *=   2;
+        t2 *= -10;
+
+        BOOST_CHECK_EQUAL(t1.get_sec  (),     84);
+        BOOST_CHECK_EQUAL(t1.get_nsec (),     84);
+        BOOST_CHECK_EQUAL(t2.get_sec  (), -13370);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_mult_scale_carry)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (1, 500 * 1000 * 1000);
+        t2 = t1 * 3;
+
+        BOOST_CHECK_EQUAL(t2.get_sec  (),  4);
+        BOOST_CHECK_EQUAL(t2.get_nsec (),  500 * 1000 * 1000);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_equals)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (50, 50);
+        t2.set (50, 50);
+
+        BOOST_CHECK_EQUAL(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_equal)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 42);
+        t2.set (42, 42);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), 0);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_equal_type)
+    {
+        I2n::clock::Time t1 (42, 42, I2n::clock::type::real);
+        I2n::clock::Time t2 (42, 42, I2n::clock::type::cpu);
+        I2n::clock::Time t3 (42,  0, I2n::clock::type::real);
+        I2n::clock::Time t4 (42, 42, I2n::clock::type::real);
+
+        BOOST_CHECK_NE(t1, t2);
+        BOOST_CHECK_NE(t1, t3);
+        BOOST_CHECK_EQUAL(t1, t4);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_sec)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (  42, 42);
+        t2.set (1337, 42);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_nsec)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42,   42);
+        t2.set (42, 1337);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2), -1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1),  1);
+    }
+
+    BOOST_AUTO_TEST_CASE(compare_ne_both)
+    {
+        I2n::clock::Time t1;
+        I2n::clock::Time t2;
+
+        t1.set (42, 2187);
+        t2.set (23, 1337);
+
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t1, t2),  1);
+        BOOST_CHECK_EQUAL(I2n::clock::compare (t2, t1), -1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_sec)
+    {
+        I2n::clock::Time t1 (1337);
+        I2n::clock::Time t2 (2187);
+
+        BOOST_CHECK_LT(t1, t2);
+        BOOST_CHECK_GT(t2, t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_nsec)
+    {
+        I2n::clock::Time t1 (1337, 23);
+        I2n::clock::Time t2 (1337, 42);
+
+        BOOST_CHECK_LT(t1, t2);
+        BOOST_CHECK_GT(t2, t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_ineq_both)
+    {
+        I2n::clock::Time t1 (2187, 23);
+        I2n::clock::Time t2 (1337, 42);
+
+        BOOST_CHECK_LT(t2, t1);
+        BOOST_CHECK_GT(t1, t2);
+    }
+
+    BOOST_AUTO_TEST_CASE(op_eq_time_t)
+    {
+        boost::optional<I2n::clock::Time> t1  = I2n::clock::now ();
+        const time_t                      t2  = time (NULL); /* race here */
+
+        *t1 -= (time_t)42;
+
+        BOOST_CHECK_NE(*t1,  t2);
+        BOOST_CHECK_LT(*t1,  t2);
+        BOOST_CHECK_GT( t2, *t1);
+    }
+
+    BOOST_AUTO_TEST_CASE(Format_sec_msec)
+    {
+        I2n::clock::Time t1 (42, 42);
+        I2n::clock::Time t2 ( 4, 242424242);
+        I2n::clock::Time t3 ( 0, 133713371);
+        I2n::clock::Time t4 ( 0, 0);
+
+        std::string s1 = t1.format_sec_msec ();
+        std::string s2 = t2.format_sec_msec ();
+        std::string s3 = t3.format_sec_msec ();
+        std::string s4 = t4.format_sec_msec ();
+
+        BOOST_CHECK_EQUAL("42s 0ms"  , s1);
+        BOOST_CHECK_EQUAL( "4s 242ms", s2);
+        BOOST_CHECK_EQUAL( "0s 133ms", s3);
+        BOOST_CHECK_EQUAL( "0s 0ms"  , s4);
+    }
+
+    BOOST_AUTO_TEST_CASE(Format_min_sec_msec)
+    {
+        I2n::clock::Time t1 (42*60 + 42, 42);
+        I2n::clock::Time t2 ( 4*60 + 42, 242424242);
+        I2n::clock::Time t3 ( 0*60 + 42, 133713371);
+        I2n::clock::Time t4 (    0 +  0,  0);
+
+        std::string s1 = *t1.format_min_sec_msec ();
+        std::string s2 = *t2.format_min_sec_msec ();
+        std::string s3 = *t3.format_min_sec_msec ();
+        std::string s4 = *t4.format_min_sec_msec ();
+
+        BOOST_CHECK_EQUAL("42m42.000s", s1);
+        BOOST_CHECK_EQUAL( "4m42.242s", s2);
+        BOOST_CHECK_EQUAL( "0m42.133s", s3);
+        BOOST_CHECK_EQUAL(  "0m0.000s", s4);
+    }
+
+    BOOST_AUTO_TEST_CASE(FormatISO8601_T)
+    {
+        I2n::clock::Time t (42, 42);
+        boost::optional<std::string> s = t.format_iso8601 (true, false, true, false);
+
+        BOOST_CHECK_EQUAL("00:00:42", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(FormatISO8601_DT)
+    {
+        I2n::clock::Time t (1541934671, 0);
+        boost::optional<std::string> s = t.format_iso8601 (true, true, true, false);
+
+        BOOST_CHECK_EQUAL("2018-11-11T11:11:11", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(FormatISO8601_DTZ)
+    {
+        I2n::clock::Time t (1541934671, 0);
+        boost::optional<std::string> s = t.format_iso8601 (true, true, true, true);
+
+        BOOST_CHECK_EQUAL("2018-11-11T11:11:11Z+0000", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(Format_make_nice_time)
+    {
+        I2n::clock::Time t (111111, 0);
+        boost::optional<std::string> s = t.make_nice_time ();
+
+        BOOST_CHECK_EQUAL("1 day, 06:51:51", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(Format_format_full_time)
+    {
+        I2n::clock::Time t (1541934671, 0);
+        /*
+         * brr, the old formatters use localtime without a way to opt out of
+         * it!
+         */
+        this->set_utc ();
+        boost::optional<std::string> s = t.format_full_time ();
+
+        BOOST_CHECK_EQUAL("11.11.2018 11:11", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(Format_format_date)
+    {
+        I2n::clock::Time t (1541934671, 0);
+        boost::optional<std::string> s = t.format_date ();
+
+        BOOST_CHECK_EQUAL("11.11.2018", *s);
+    }
+
+    BOOST_AUTO_TEST_CASE(FromString_iso8601_full)
+    {
+        const std::string in1 ("0001-01-01T00:00:00Z+0000");
+        const std::string in2 ("2018-11-11T11:11:11Z+0000");
+
+        this->set_utc ();
+
+        boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1);
+        boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2);
+
+# if LONG_BIT == 32
+        BOOST_CHECK(!t1);
+# else
+        BOOST_CHECK(t1);
+        BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1);
+# endif
+
+        BOOST_CHECK(t2);
+        BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2);
+    }
+
+    BOOST_AUTO_TEST_CASE(FromString_iso8601_full_negyear)
+    {
+        const std::string in1 ("-0001-01-01T00:00:00Z+0000");
+        const std::string in2 ("-2018-11-11T11:11:11Z+0000");
+
+        this->set_utc ();
+
+        boost::optional<I2n::clock::Time> t1 = I2n::clock::time_of_iso8601 (in1);
+        boost::optional<I2n::clock::Time> t2 = I2n::clock::time_of_iso8601 (in2);
+
+# if LONG_BIT == 32
+        BOOST_CHECK(!t1);
+        BOOST_CHECK(!t2);
+# else
+        BOOST_CHECK(t1);
+        BOOST_CHECK(t2);
+        BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1);
+        BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2);
+# endif
+    }
+
+    BOOST_AUTO_TEST_CASE(FromString_iso8601_partial)
+    {
+        const std::string in1 ("2018-11-11T11:11:11");
+        const std::string in2 ("2018-11-11");
+
+        this->set_utc ();
+
+        boost::optional<I2n::clock::Time> t1 =
+            I2n::clock::time_of_iso8601 (in1, true, true, false);
+        boost::optional<I2n::clock::Time> t2 =
+            I2n::clock::time_of_iso8601 (in2, true, false, false);
+
+        BOOST_CHECK(t1);
+        BOOST_CHECK(t2);
+        /*
+         * We test for the difference here which is zero if the number is
+         * correct but causes the difference from the expected value to be
+         * printed in case the test fails.
+         */
+        BOOST_CHECK_EQUAL(*t1->format_iso8601 (true,  true,  true, false), in1);
+        BOOST_CHECK_EQUAL(*t2->format_iso8601 (true,  true, false, false), in2);
+    }
+
+    BOOST_AUTO_TEST_CASE(FromString_iso8601_32bit_time_t_err)
+    {
+        const std::string timeless ("11:11:11");
+        boost::optional<I2n::clock::Time> untimely = boost::none;
+
+        this->set_utc ();
+
+        untimely = I2n::clock::time_of_iso8601 (timeless, false, true, false);
+
+# if LONG_BIT == 32
+        BOOST_CHECK(!untimely);
+# else
+        BOOST_CHECK(untimely);
+        BOOST_CHECK_EQUAL(*untimely->format_iso8601 (true, false,  true, false),
+                          timeless);
+# endif
+    }
+
+    BOOST_AUTO_TEST_CASE(Ctor_32bit_time_t_err)
+    {
+        boost::optional<std::string> threw = boost::none;
+
+        struct tm tm;
+        memset (&tm, 0, sizeof (tm));
+
+        tm.tm_sec    = 11;
+        tm.tm_min    = 11;
+        tm.tm_hour   = 11;
+        tm.tm_mday   = 11;
+        tm.tm_mon    = 10;
+        tm.tm_year   = -789;
+        tm.tm_gmtoff = 0;
+
+        try {
+            I2n::clock::Time untimely (tm);
+        } catch (I2n::clock::conversion_error &exn) {
+            threw = std::string (exn);
+        }
+
+
+# if LONG_BIT == 32
+        BOOST_CHECK_EQUAL(*threw,
+                          "errno=0 [mktime: from struct tm {Sun Nov 11 11:11:11 1111}]");
+# else
+        BOOST_CHECK(!threw);
+# endif
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::zero ());
+        ts.push_back (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_vec)
+    {
+        std::vector<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::zero ());
+        ts.push_back (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        ts.insert (I2n::clock::zero ());
+        ts.insert (I2n::clock::Time (42, 2187));
+        ts.insert (I2n::clock::zero ());
+
+        BOOST_CHECK_EQUAL(ts.size (), 2);
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list_mean)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::Time (42, 42));
+        ts.push_back (I2n::clock::Time (1337, 1337));
+
+        BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
+                          I2n::clock::Time (689, 500000689));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list_mean_zero)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::Time (0, 0));
+        ts.push_back (I2n::clock::Time (0, 0));
+        ts.push_back (I2n::clock::Time (0, 0));
+        ts.push_back (I2n::clock::Time (0, 0));
+
+        BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
+                          I2n::clock::zero ());
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list_mean_empty)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        BOOST_CHECK_EQUAL(I2n::clock::mean (ts), I2n::clock::Time (0, 0));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set_mean)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        ts.insert (I2n::clock::Time (42));
+        ts.insert (I2n::clock::Time (1337));
+        ts.insert (I2n::clock::Time (2187));
+
+        BOOST_CHECK_EQUAL(I2n::clock::mean (ts),
+                          I2n::clock::Time (1188, 666666666));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set_median_empty)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0, 0));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set_median_one)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        ts.insert (I2n::clock::Time (42, 0));
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts),
+                          I2n::clock::Time (42, 0));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_set_median_multi)
+    {
+        std::set<I2n::clock::Time> ts;
+
+        ts.insert (I2n::clock::Time (42));
+        ts.insert (I2n::clock::Time (1337));
+        ts.insert (I2n::clock::Time (2187));
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_vec_median_multi)
+    {
+        std::vector<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::Time (42));
+        ts.push_back (I2n::clock::Time (1337));
+        ts.push_back (I2n::clock::Time (2187));
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (1337));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list_median_multi)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::Time (42));
+        ts.push_back (I2n::clock::Time (1337));
+        ts.push_back (I2n::clock::Time (2187));
+        ts.push_back (I2n::clock::Time (0xdead));
+        ts.push_back (I2n::clock::Time (0xbeef));
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts),
+                          I2n::clock::Time (2187));
+    }
+
+    BOOST_AUTO_TEST_CASE(containers_list_median_multi_evensize)
+    {
+        std::list<I2n::clock::Time> ts;
+
+        ts.push_back (I2n::clock::Time (42));
+        ts.push_back (I2n::clock::Time (1337));
+        ts.push_back (I2n::clock::Time (2187));
+        ts.push_back (I2n::clock::Time (0xf00d));
+        ts.push_back (I2n::clock::Time (0xfeed));
+        ts.push_back (I2n::clock::Time (0xdeadf0e));
+
+        BOOST_CHECK_EQUAL(I2n::clock::median (ts), I2n::clock::Time (0xf00d));
+    }
+
+BOOST_AUTO_TEST_SUITE_END() /* [Clock] */
 
 BOOST_AUTO_TEST_SUITE_END()