, err (0)
{ }
+ /*
+ * Ctor from *struct tm*. On 32 bit systems the conversion to *time_t* will
+ * fail with years outside the range from epoch to 2038.
+ */
Time::Time (const struct tm &tm,
const enum type::id id,
- const enum type::variant var) NOEXCEPT
+ const enum type::variant var)
{
struct tm tmp_tm; /* dummy for mktime(3) */
Time tmp_time;
memcpy (&tmp_tm, &tm, sizeof (tmp_tm));
- tmp_time = Time (mktime (&tmp_tm), 0l, id, var);
+
+ errno = 0;
+ const time_t t = mktime (&tmp_tm);
+ if (t == - 1) { /* Glibc does not set errno on out-of-range here! */
+ const char *datestr = asctime (&tm);
+ throw conversion_error (errno,
+ std::string ("mktime: from struct tm {")
+ + std::string (datestr, 0, strlen(datestr)-1)
+ + "}");
+ }
+
+ tmp_time = Time (t, 0l, id, var);
this->swap (tmp_time);
}
return boost::none;
}
- return Time (*tm, id, var);
+ try {
+ return Time (*tm, id, var);
+ }
+ catch (conversion_error &_unused) { }
+
+ return boost::none;
}
} /* [namespace clock] */
namespace clock {
+ class conversion_error : public std::exception
+ {
+ public:
+ const int err;
+ const std::string context;
+
+ conversion_error (const int err, const std::string &context)
+ : err (err)
+ , context (context)
+ { }
+
+ virtual ~conversion_error (void) throw() { };
+
+ operator std::string (void)
+ {
+ return std::string ("errno=") + I2n::to_string (this->err)
+ + " [" + this->context + "]";
+ }
+ };
+
namespace {
/* helper for ctor initializer list; we still lack aggregate initializers */
, err (t.err)
{ }
- inline Time (const time_t sec,
- const long nsec = 0,
- const enum type::id id = type::mono,
- const enum type::variant var = type::dflt,
- const int err = 0) NOEXCEPT
+ inline
+ Time (const time_t sec,
+ const long nsec = 0,
+ const enum type::id id = type::mono,
+ const enum type::variant var = type::dflt,
+ const int err = 0) NOEXCEPT
: value (timespec_of_parts (sec, nsec))
, id (id)
, variant (var)
, err (err)
{ this->carry_nsec (); }
+ explicit
Time (const struct tm &tm,
const enum type::id id = type::mono,
- const enum type::variant var = type::dflt) NOEXCEPT;
+ const enum type::variant var = type::dflt);
/* value read access *************************************************/
public:
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)
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(t2);
-
BOOST_CHECK_EQUAL(*t1->format_iso8601 (), in1);
+# endif
+
+ BOOST_CHECK(t2);
BOOST_CHECK_EQUAL(*t2->format_iso8601 (), in2);
}
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");
- const std::string in3 ("11:11:11");
+
+ setenv ("TZ", "UTC", 1);
+ tzset();
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::optional<I2n::clock::Time> t3 =
- I2n::clock::time_of_iso8601 (in3, false, true, false);
BOOST_CHECK(t1);
BOOST_CHECK(t2);
- BOOST_CHECK(t3);
/*
* We test for the difference here which is zero if the number is
* correct but causes the difference from the expected value to be
*/
BOOST_CHECK_EQUAL(*t1->format_iso8601 (true, true, true, false), in1);
BOOST_CHECK_EQUAL(*t2->format_iso8601 (true, true, false, false), in2);
- BOOST_CHECK_EQUAL(*t3->format_iso8601 (true, false, true, false), in3);
+ }
+
+ 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;
+
+ 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)
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 (0xcafebabe));
- ts.push_back (I2n::clock::Time (0xdeadbeef));
+ 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_CHECK_EQUAL(I2n::clock::median (ts),
+ I2n::clock::Time (2187));
}
BOOST_AUTO_TEST_CASE(containers_list_median_multi_evensize)
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 (0xcafebabe));
- ts.push_back (I2n::clock::Time (0xdeadbeef));
+ 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));
}