*
*/
+#include <errno.h>
#include <string>
#include <sstream>
#include <iostream>
} // eo realtime_clock_gettime(long int&,long int&)
+static const char *const iso8601_fmt_d = "%F";
+static const char *const iso8601_fmt_t = "%T";
+static const char *const iso8601_fmt_tz = "%TZ%z";
+static const char *const iso8601_fmt_dt = "%FT%T";
+static const char *const iso8601_fmt_dtz = "%FT%TZ%z";
+
+/**
+ * @brief Format a time structure according to ISO-8601, e. g.
+ * “2018-01-09T10:40:00Z+0100”; see \c strftime(3) for
+ * the details.
+ *
+ * @param tm Time to format as broken-down \c struct tm.
+ * @param date Include the day part ([-]YYYY-MM-DD).
+ * @param time Include the time part (hh:mm:ss).
+ * @param tz Include the timezone ([±]ZZZZ); only heeded if
+ * \c time is requested as well.
+ *
+ * @return The formatted timestamp.
+ */
+std::string format_iso8601 (const struct tm &tm, const bool date,
+ const bool time, const bool tz)
+{
+# define ISO8601_BUFSIZE 27 /* max: -YYYY-MM-DDThh:mm:ssZ+zzzz ⇒ 26 */
+ char buf [ISO8601_BUFSIZE] = { 0 };
+ const char *format = NULL;
+
+ if (date) {
+ if (time) {
+ if (tz) {
+ format = iso8601_fmt_dtz;
+ } else {
+ format = iso8601_fmt_dt;
+ }
+ } else {
+ format = iso8601_fmt_d;
+ }
+ } else if (time && tz) {
+ format = iso8601_fmt_tz;
+ } else {
+ format = iso8601_fmt_t; /* default to %T */
+ }
+
+ const size_t n = strftime (buf, ISO8601_BUFSIZE, format, &tm);
+
+ buf [n] = '\0';
+
+ return std::string (buf);
+}
+
+
+typedef struct tm * (*time_breakdown_fn) (const time_t *, struct tm *);
+
+/**
+ * @brief Format a UNIX timestamp according to ISO-8601. Converts
+ * to broken down time first.
+ *
+ * @param t Time to format as broken-down \c struct tm.
+ * @param date Include the day part ([-]YYYY-MM-DD).
+ * @param time Include the time part (hh:mm:ss).
+ * @param tz Include the timezone ([±]ZZZZ); only heeded if
+ * \c time is requested as well.
+ *
+ * @return The formatted timestamp.
+ */
+std::string format_iso8601 (time_t t, const bool utc, const bool date,
+ const bool time, const bool tz)
+{
+ time_breakdown_fn breakdown = utc ? gmtime_r : localtime_r;
+ struct tm tm;
+
+ errno = 0;
+ if (breakdown (&t, &tm) == NULL) {
+ return std::string ("error analyzing timestamp: ") + strerror (errno);
+ }
+
+ return format_iso8601 (tm, date, time, tz);
+}
+
+
namespace I2n {
namespace clock {
} /* [namespace clock] */
} /* [namespace I2n] */
-
/** @file
* @brief time related functions.
*
- * @copyright Copyright © 2001-2008 by Intra2net AG
+ * @copyright Copyright © 2001-2018 by Intra2net AG
*/
#ifndef __TIMEFUNC_HXX
std::string make_nice_time(int seconds);
std::string format_full_time(time_t seconds);
std::string format_date(time_t seconds);
+std::string format_iso8601(const struct tm &tm, const bool date=true,
+ const bool time=true, const bool tz=true);
+std::string format_iso8601(time_t t, const bool utc=true,
+ const bool date=true, const bool time=true,
+ const bool tz=true);
+inline std::string format_iso8601(const struct timespec ts, const bool utc=true,
+ const bool date=true, const bool time=true,
+ const bool tz=true)
+{ return format_iso8601 (ts.tv_sec, utc, date, time, tz); }
+
void seconds_to_hour_minute(int seconds, int *hour, int *minute);
void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
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)