util: add time::{to,from}IsoExtendedString()

Also, backport weeks/months/years duration types from C++20

Change-Id: I6d5c831b7aa2ffa3a894a8adaba0e3879d84ef61
diff --git a/docs/doxygen.conf.in b/docs/doxygen.conf.in
index d70ac1c..82513e4 100644
--- a/docs/doxygen.conf.in
+++ b/docs/doxygen.conf.in
@@ -437,7 +437,7 @@
 # included in the documentation.
 # The default value is: NO.
 
-EXTRACT_STATIC         = YES
+EXTRACT_STATIC         = NO
 
 # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
 # locally in source files will be included in the documentation. If set to NO,
@@ -1041,13 +1041,6 @@
 
 ALPHABETICAL_INDEX     = YES
 
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX    = 5
-
 # In case all classes in a project start with a common prefix, all classes will
 # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
 # can be used to specify a prefix (or a list of prefixes) that should be ignored
diff --git a/ndn-cxx/util/time.cpp b/ndn-cxx/util/time.cpp
index 3f4f9db..e233ca5 100644
--- a/ndn-cxx/util/time.cpp
+++ b/ndn-cxx/util/time.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2021 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -102,27 +102,27 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////////
 
-const system_clock::TimePoint&
+const system_clock::time_point&
 getUnixEpoch()
 {
-  static constexpr system_clock::TimePoint epoch(seconds::zero());
+  static constexpr system_clock::time_point epoch(seconds::zero());
   return epoch;
 }
 
 milliseconds
-toUnixTimestamp(const system_clock::TimePoint& point)
+toUnixTimestamp(const system_clock::time_point& point)
 {
   return duration_cast<milliseconds>(point - getUnixEpoch());
 }
 
-system_clock::TimePoint
+system_clock::time_point
 fromUnixTimestamp(milliseconds duration)
 {
   return getUnixEpoch() + duration;
 }
 
 static boost::posix_time::ptime
-convertToPosixTime(const system_clock::TimePoint& timePoint)
+convertToPosixTime(const system_clock::time_point& timePoint)
 {
   namespace bpt = boost::posix_time;
   static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
@@ -140,12 +140,18 @@
 }
 
 std::string
-toIsoString(const system_clock::TimePoint& timePoint)
+toIsoString(const system_clock::time_point& timePoint)
 {
   return boost::posix_time::to_iso_string(convertToPosixTime(timePoint));
 }
 
-static system_clock::TimePoint
+std::string
+toIsoExtendedString(const system_clock::time_point& timePoint)
+{
+  return boost::posix_time::to_iso_extended_string(convertToPosixTime(timePoint));
+}
+
+static system_clock::time_point
 convertToTimePoint(const boost::posix_time::ptime& ptime)
 {
   namespace bpt = boost::posix_time;
@@ -154,18 +160,24 @@
   // .total_seconds() has an issue with large dates until Boost 1.66, see #4478.
   // time_t overflows for large dates on 32-bit platforms (Y2038 problem).
   auto sinceEpoch = ptime - epoch;
-  auto point = system_clock::TimePoint(seconds(sinceEpoch.ticks() / bpt::time_duration::ticks_per_second()));
+  auto point = system_clock::time_point(seconds(sinceEpoch.ticks() / bpt::time_duration::ticks_per_second()));
   return point + microseconds(sinceEpoch.total_microseconds() % 1000000);
 }
 
-system_clock::TimePoint
+system_clock::time_point
 fromIsoString(const std::string& isoString)
 {
   return convertToTimePoint(boost::posix_time::from_iso_string(isoString));
 }
 
+system_clock::time_point
+fromIsoExtendedString(const std::string& isoString)
+{
+  return convertToTimePoint(boost::posix_time::from_iso_extended_string(isoString));
+}
+
 std::string
-toString(const system_clock::TimePoint& timePoint,
+toString(const system_clock::time_point& timePoint,
          const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
          const std::locale& locale/* = std::locale("C")*/)
 {
@@ -179,7 +191,7 @@
   return os.str();
 }
 
-system_clock::TimePoint
+system_clock::time_point
 fromString(const std::string& timePointStr,
            const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
            const std::locale& locale/* = std::locale("C")*/)
diff --git a/ndn-cxx/util/time.hpp b/ndn-cxx/util/time.hpp
index 1e7221f..0d55431 100644
--- a/ndn-cxx/util/time.hpp
+++ b/ndn-cxx/util/time.hpp
@@ -30,16 +30,24 @@
 namespace ndn {
 namespace time {
 
-using boost::chrono::duration;
+template<typename Rep, typename Period>
+using duration = boost::chrono::duration<Rep, Period>;
+
 using boost::chrono::duration_cast;
 
-using days = duration<int_fast32_t, boost::ratio<86400>>;
-using boost::chrono::hours;
-using boost::chrono::minutes;
-using boost::chrono::seconds;
-using boost::chrono::milliseconds;
-using boost::chrono::microseconds;
-using boost::chrono::nanoseconds;
+// C++20
+using days   = duration<int_fast32_t, boost::ratio<86400>>;
+using weeks  = duration<int_fast32_t, boost::ratio<604800>>;
+using months = duration<int_fast32_t, boost::ratio<2629746>>;
+using years  = duration<int_fast32_t, boost::ratio<31556952>>;
+
+// C++11
+using hours        = boost::chrono::hours;
+using minutes      = boost::chrono::minutes;
+using seconds      = boost::chrono::seconds;
+using milliseconds = boost::chrono::milliseconds;
+using microseconds = boost::chrono::microseconds;
+using nanoseconds  = boost::chrono::nanoseconds;
 
 /** \return the absolute value of the duration d
  *  \note The function does not participate in the overload resolution
@@ -172,15 +180,15 @@
  * To get the current time:
  *
  * <code>
- *     system_clock::TimePoint now = system_clock::now();
+ *     const auto now = system_clock::now();
  * </code>
  *
- * To convert a TimePoint to/from UNIX timestamp:
+ * To convert a time_point to/from UNIX timestamp:
  *
  * <code>
- *     system_clock::TimePoint time = ...;
+ *     system_clock::time_point time = ...;
  *     uint64_t timestampInMilliseconds = toUnixTimestamp(time).count();
- *     system_clock::TimePoint time2 = fromUnixTimestamp(milliseconds(timestampInMilliseconds));
+ *     system_clock::time_point time2 = fromUnixTimestamp(milliseconds(timestampInMilliseconds));
  * </code>
  */
 class system_clock
@@ -192,8 +200,8 @@
   using time_point = boost::chrono::time_point<system_clock>;
   static constexpr bool is_steady = boost::chrono::system_clock::is_steady;
 
-  typedef time_point TimePoint;
-  typedef duration Duration;
+  using TimePoint = time_point;
+  using Duration = duration;
 
   static time_point
   now() noexcept;
@@ -222,8 +230,8 @@
   using time_point = boost::chrono::time_point<steady_clock>;
   static constexpr bool is_steady = true;
 
-  typedef time_point TimePoint;
-  typedef duration Duration;
+  using TimePoint = time_point;
+  using Duration = duration;
 
   static time_point
   now() noexcept;
@@ -244,28 +252,28 @@
 };
 
 /**
- * \brief Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970)
+ * \brief Return a system_clock::time_point representing the UNIX time epoch,
+ *        i.e., 00:00:00 UTC on 1 January 1970.
  */
-const system_clock::TimePoint&
+const system_clock::time_point&
 getUnixEpoch();
 
 /**
- * \brief Convert system_clock::TimePoint to UNIX timestamp
+ * \brief Convert system_clock::time_point to UNIX timestamp
  */
 milliseconds
-toUnixTimestamp(const system_clock::TimePoint& point);
+toUnixTimestamp(const system_clock::time_point& point);
 
 /**
- * \brief Convert UNIX timestamp to system_clock::TimePoint
+ * \brief Convert UNIX timestamp to system_clock::time_point
  */
-system_clock::TimePoint
+system_clock::time_point
 fromUnixTimestamp(milliseconds duration);
 
 /**
- * \brief Convert to the ISO string representation of the time (YYYYMMDDTHHMMSS,fffffffff)
+ * \brief Convert to the ISO 8601 string representation, basic format (`YYYYMMDDTHHMMSS,fffffffff`).
  *
- * If \p timePoint contains doesn't contain fractional seconds,
- * the output format is YYYYMMDDTHHMMSS
+ * If \p timePoint does not contain any fractional seconds, the output format is `YYYYMMDDTHHMMSS`.
  *
  * Examples:
  *
@@ -275,25 +283,37 @@
  *   - without fractional seconds:   20020131T100001
  */
 std::string
-toIsoString(const system_clock::TimePoint& timePoint);
+toIsoString(const system_clock::time_point& timePoint);
 
 /**
- * \brief Convert from the ISO string (YYYYMMDDTHHMMSS,fffffffff) representation
- *        to the internal time format
+ * \brief Convert from the ISO 8601 basic string format (`YYYYMMDDTHHMMSS,fffffffff`)
+ *        to the internal time format.
  *
- * Examples of accepted ISO strings:
+ * Examples of accepted strings:
  *
  *   - with fractional nanoseconds:  20020131T100001,123456789
  *   - with fractional microseconds: 20020131T100001,123456
  *   - with fractional milliseconds: 20020131T100001,123
  *   - without fractional seconds:   20020131T100001
- *
  */
-system_clock::TimePoint
+system_clock::time_point
 fromIsoString(const std::string& isoString);
 
 /**
- * \brief Convert time point to string with specified format
+ * \brief Convert to the ISO 8601 string representation, extended format (`YYYY-MM-DDTHH:MM:SS,fffffffff`).
+ */
+std::string
+toIsoExtendedString(const system_clock::time_point& timePoint);
+
+/**
+ * \brief Convert from the ISO 8601 extended string format (`YYYY-MM-DDTHH:MM:SS,fffffffff`)
+ *        to the internal time format.
+ */
+system_clock::time_point
+fromIsoExtendedString(const std::string& isoString);
+
+/**
+ * \brief Convert time point to string with specified format.
  *
  * By default, `%Y-%m-%d %H:%M:%S` is used, producing dates like
  * `2014-04-10 22:51:00`
@@ -306,12 +326,12 @@
  *     describes possible formatting flags
  **/
 std::string
-toString(const system_clock::TimePoint& timePoint,
+toString(const system_clock::time_point& timePoint,
          const std::string& format = "%Y-%m-%d %H:%M:%S",
          const std::locale& locale = std::locale("C"));
 
 /**
- * \brief Convert from string of specified format into time point
+ * \brief Convert from string of specified format into time point.
  *
  * By default, `%Y-%m-%d %H:%M:%S` is used, accepting dates like
  * `2014-04-10 22:51:00`
@@ -323,7 +343,7 @@
  * \sa https://www.boost.org/doc/libs/1_65_1/doc/html/date_time/date_time_io.html#date_time.format_flags
  *     describes possible formatting flags
  */
-system_clock::TimePoint
+system_clock::time_point
 fromString(const std::string& timePointStr,
            const std::string& format = "%Y-%m-%d %H:%M:%S",
            const std::locale& locale = std::locale("C"));
@@ -334,14 +354,14 @@
 namespace boost {
 namespace chrono {
 
-template<class CharT>
+template<typename CharT>
 struct clock_string<ndn::time::system_clock, CharT>
 {
   static std::basic_string<CharT>
   since();
 };
 
-template<class CharT>
+template<typename CharT>
 struct clock_string<ndn::time::steady_clock, CharT>
 {
   static std::basic_string<CharT>
diff --git a/tests/unit/util/time.t.cpp b/tests/unit/util/time.t.cpp
index 92699a9..2232e12 100644
--- a/tests/unit/util/time.t.cpp
+++ b/tests/unit/util/time.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2021 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -33,14 +33,63 @@
 BOOST_AUTO_TEST_SUITE(Util)
 BOOST_AUTO_TEST_SUITE(TestTime)
 
+BOOST_AUTO_TEST_CASE(Duration)
+{
+  BOOST_TEST(years(1) == months(12));
+  BOOST_TEST(months(1) == minutes(43829) + seconds(6));
+  BOOST_TEST(weeks(1) == days(7));
+  BOOST_TEST(days(1) == hours(24));
+  BOOST_TEST(hours(1) == minutes(60));
+  BOOST_TEST(minutes(1) == seconds(60));
+  BOOST_TEST(seconds(1) == milliseconds(1000));
+  BOOST_TEST(milliseconds(1) == microseconds(1000));
+  BOOST_TEST(microseconds(1) == nanoseconds(1000));
+}
+
+BOOST_AUTO_TEST_CASE(Abs)
+{
+  BOOST_TEST(abs(nanoseconds(24422)) == nanoseconds(24422));
+  BOOST_TEST(abs(microseconds(0)) == microseconds(0));
+  BOOST_TEST(abs(milliseconds(-15583)) == milliseconds(15583));
+}
+
+BOOST_AUTO_TEST_CASE(Literals)
+{
+  BOOST_TEST(42_s == seconds(42));
+
+  BOOST_TEST(1_day == 24_h);
+  BOOST_TEST(2_days == 48_h);
+  BOOST_TEST(0.5_day == 12_h);
+  BOOST_TEST(.5_days == 12_h);
+
+  BOOST_TEST(1_h == 60_min);
+  BOOST_TEST(0.5_h == 30_min);
+
+  BOOST_TEST(1_min == 60_s);
+  BOOST_TEST(0.5_min == 30_s);
+
+  BOOST_TEST(1_s == 1000_ms);
+  BOOST_TEST(0.5_s == 500_ms);
+
+  BOOST_TEST(1_ms == 1000_us);
+  BOOST_TEST(0.5_ms == 500_us);
+
+  BOOST_TEST(1_us == 1000_ns);
+  BOOST_TEST(0.5_us == 500_ns);
+
+  BOOST_TEST(1_ns == nanoseconds(1));
+  BOOST_TEST(5.5_ns == 0.0055_us);
+}
+
 BOOST_AUTO_TEST_CASE(SystemClock)
 {
-  system_clock::TimePoint value = system_clock::now();
-  system_clock::TimePoint referenceTime = fromUnixTimestamp(1390966967032_ms);
+  system_clock::time_point value = system_clock::now();
+  system_clock::time_point referenceTime = fromUnixTimestamp(1390966967032_ms);
 
   BOOST_TEST(value > referenceTime);
 
   BOOST_CHECK_EQUAL(toIsoString(referenceTime), "20140129T034247.032000");
+  BOOST_CHECK_EQUAL(toIsoExtendedString(referenceTime), "2014-01-29T03:42:47.032000");
   BOOST_CHECK_EQUAL(toString(referenceTime), "2014-01-29 03:42:47");
 
   // Unfortunately, not all systems has lv_LV locale installed :(
@@ -53,6 +102,10 @@
   BOOST_TEST(fromIsoString("20140129T034247.032000Z") == referenceTime);
   BOOST_TEST(fromIsoString("20140129T034247") != referenceTime);
   BOOST_TEST(fromIsoString("20140129T034247") == fromUnixTimestamp(1390966967_s));
+  BOOST_TEST(fromIsoExtendedString("2014-01-29T03:42:47.032000") == referenceTime);
+  BOOST_TEST(fromIsoExtendedString("2014-01-29T03:42:47.032000Z") == referenceTime);
+  BOOST_TEST(fromIsoExtendedString("2014-01-29T03:42:47") != referenceTime);
+  BOOST_TEST(fromIsoExtendedString("2014-01-29T03:42:47") == fromUnixTimestamp(1390966967_s));
   BOOST_TEST(fromString("2014-01-29 03:42:47") != referenceTime);
   BOOST_TEST(fromString("2014-01-29 03:42:47") == fromUnixTimestamp(1390966967_s));
 
@@ -65,9 +118,9 @@
 
 BOOST_AUTO_TEST_CASE(SteadyClock)
 {
-  steady_clock::TimePoint oldValue = steady_clock::now();
+  steady_clock::time_point oldValue = steady_clock::now();
   std::this_thread::sleep_for(std::chrono::milliseconds(1));
-  steady_clock::TimePoint newValue = steady_clock::now();
+  steady_clock::time_point newValue = steady_clock::now();
   BOOST_CHECK_GT(newValue, oldValue);
 }
 
@@ -78,19 +131,15 @@
   tp += 1596592240_s;
 
   BOOST_TEST(toIsoString(tp) == "20200805T015040");
+  BOOST_TEST(toIsoExtendedString(tp) == "2020-08-05T01:50:40");
   BOOST_TEST(toString(tp) == "2020-08-05 01:50:40");
   BOOST_TEST(fromIsoString("20200805T015040") == tp);
   BOOST_TEST(fromIsoString("20200805T015040.123456") != tp);
+  BOOST_TEST(fromIsoExtendedString("2020-08-05T01:50:40") == tp);
+  BOOST_TEST(fromIsoExtendedString("2020-08-05T01:50:40.123456") != tp);
   BOOST_TEST(fromString("2020-08-05 01:50:40") == tp);
 }
 
-BOOST_AUTO_TEST_CASE(Abs)
-{
-  BOOST_CHECK_EQUAL(abs(nanoseconds(24422)), nanoseconds(24422));
-  BOOST_CHECK_EQUAL(abs(microseconds(0)), microseconds(0));
-  BOOST_CHECK_EQUAL(abs(milliseconds(-15583)), milliseconds(15583));
-}
-
 BOOST_AUTO_TEST_CASE(LargeDates)
 {
   auto value = fromUnixTimestamp(1390966967032_ms);
@@ -106,34 +155,6 @@
   BOOST_CHECK_EQUAL(fromString("2114-01-29 03:42:47.03200", "%Y-%m-%d %H:%M:%S%F"), value);
 }
 
-BOOST_AUTO_TEST_CASE(Literals)
-{
-  BOOST_CHECK_EQUAL(42_s, seconds(42));
-
-  BOOST_CHECK_EQUAL(1_day, 24_h);
-  BOOST_CHECK_EQUAL(2_days, 48_h);
-  BOOST_CHECK_EQUAL(0.5_day, 12_h);
-  BOOST_CHECK_EQUAL(.5_days, 12_h);
-
-  BOOST_CHECK_EQUAL(1_h, 60_min);
-  BOOST_CHECK_EQUAL(0.5_h, 30_min);
-
-  BOOST_CHECK_EQUAL(1_min, 60_s);
-  BOOST_CHECK_EQUAL(0.5_min, 30_s);
-
-  BOOST_CHECK_EQUAL(1_s, 1000_ms);
-  BOOST_CHECK_EQUAL(0.5_s, 500_ms);
-
-  BOOST_CHECK_EQUAL(1_ms, 1000_us);
-  BOOST_CHECK_EQUAL(0.5_ms, 500_us);
-
-  BOOST_CHECK_EQUAL(1_us, 1000_ns);
-  BOOST_CHECK_EQUAL(0.5_us, 500_ns);
-
-  BOOST_CHECK_EQUAL(1_ns, nanoseconds(1));
-  BOOST_CHECK_EQUAL(5.5_ns, 0.0055_us);
-}
-
 BOOST_AUTO_TEST_CASE(Year2038)
 {
   auto year2042 = fromIsoString("20420101T000001.042000");