diff --git a/chrono/datetime.cpp b/chrono/datetime.cpp index 41f5c85..b75820f 100644 --- a/chrono/datetime.cpp +++ b/chrono/datetime.cpp @@ -196,8 +196,53 @@ std::pair DateTime::fromIsoString(const char *str) */ void DateTime::toString(string &result, DateTimeOutputFormat format, bool noMilliseconds) const { + if (format == DateTimeOutputFormat::Iso) { + result = toIsoString(); + return; + } + stringstream s(stringstream::in | stringstream::out); s << setfill('0'); + + if (format == DateTimeOutputFormat::IsoOmittingDefaultComponents) { + constexpr auto dateDelimiter = '-', timeDelimiter = ':'; + const int components[] = { year(), month(), day(), hour(), minute(), second(), millisecond(), microsecond(), nanosecond() }; + const int *const firstTimeComponent = components + 3; + const int *const firstFractionalComponent = components + 6; + const int *const lastComponent = components + 8; + const int *componentsEnd = noMilliseconds ? firstFractionalComponent : lastComponent + 1; + for (const int *i = componentsEnd - 1; i > components; --i) { + if (i >= firstTimeComponent && *i == 0) { + componentsEnd = i; + } else if (i < firstTimeComponent && *i == 1) { + componentsEnd = i; + } + } + for (const int *i = components; i != componentsEnd; ++i) { + if (i == firstTimeComponent) { + s << 'T'; + } else if (i == firstFractionalComponent) { + s << '.'; + } + if (i == components) { + s << setw(4) << *i; + } else if (i < firstFractionalComponent) { + if (i < firstTimeComponent) { + s << dateDelimiter; + } else if (i > firstTimeComponent) { + s << timeDelimiter; + } + s << setw(2) << *i; + } else if (i < lastComponent) { + s << setw(3) << *i; + } else { + s << *i / TimeSpan::nanosecondsPerTick; + } + } + result = s.str(); + return; + } + if (format == DateTimeOutputFormat::DateTimeAndWeekday || format == DateTimeOutputFormat::DateTimeAndShortWeekday) s << printDayOfWeek(dayOfWeek(), format == DateTimeOutputFormat::DateTimeAndShortWeekday) << ' '; if (format == DateTimeOutputFormat::DateOnly || format == DateTimeOutputFormat::DateAndTime || format == DateTimeOutputFormat::DateTimeAndWeekday diff --git a/chrono/datetime.h b/chrono/datetime.h index 319f8e1..e3173f6 100644 --- a/chrono/datetime.h +++ b/chrono/datetime.h @@ -19,7 +19,9 @@ enum class DateTimeOutputFormat { DateOnly, /**< date only */ TimeOnly, /**< time only */ DateTimeAndWeekday, /**< date with weekday and time */ - DateTimeAndShortWeekday /**< date with abbreviated weekday and time */ + DateTimeAndShortWeekday, /**< date with abbreviated weekday and time */ + Iso, /**< ISO format like DateTime::toIsoString() */ + IsoOmittingDefaultComponents, /**< ISO format like DateTime::toIsoString() omitting default components, e.g. just "2017" instead of "2017-01-01T00:00:00" */ }; /*! diff --git a/tests/chronotests.cpp b/tests/chronotests.cpp index 65a9028..3b67616 100644 --- a/tests/chronotests.cpp +++ b/tests/chronotests.cpp @@ -187,6 +187,23 @@ void ChronoTests::testDateTime() CPPUNIT_ASSERT_THROW_MESSAGE("invalid .", DateTime::fromIsoString("2017-08.5-23T19:40:15.985077682+02:00"), ConversionException); CPPUNIT_ASSERT_THROW_MESSAGE("invalid :", DateTime::fromIsoString("2017:08-23T19:40:15.985077682+02:00"), ConversionException); CPPUNIT_ASSERT_THROW_MESSAGE("invalid :", DateTime::fromIsoString("2017-08-23T19:40:15:985077682+02:00"), ConversionException); + // ISO string via toString() format option + CPPUNIT_ASSERT_EQUAL("1234-05-06T07:08:09.0105005"s, DateTime::fromDateAndTime(1234, 5, 6, 7, 8, 9, 10.5005).toString(DateTimeOutputFormat::Iso)); + CPPUNIT_ASSERT_EQUAL("1234-05-06T07:08:09.0105005"s, + DateTime::fromDateAndTime(1234, 5, 6, 7, 8, 9, 10.5005).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("1234-05-06T07:08:09.010500"s, + DateTime::fromDateAndTime(1234, 5, 6, 7, 8, 9, 10.500).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL( + "1234-05-06T07:08:09.010"s, DateTime::fromDateAndTime(1234, 5, 6, 7, 8, 9, 10).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL( + "1234-05-06T07:08:09"s, DateTime::fromDateAndTime(1234, 5, 6, 7, 8, 9).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL( + "1234-05-06T07:08"s, DateTime::fromDateAndTime(1234, 5, 6, 7, 8).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("1234-05-06T07"s, DateTime::fromDateAndTime(1234, 5, 6, 7).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("1234-05-06"s, DateTime::fromDateAndTime(1234, 5, 6).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("1234-05"s, DateTime::fromDateAndTime(1234, 5).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("1234"s, DateTime::fromDateAndTime(1234).toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); + CPPUNIT_ASSERT_EQUAL("0001"s, DateTime().toString(DateTimeOutputFormat::IsoOmittingDefaultComponents)); // test now() and exactNow() (or at least whether both behave the same) #if defined(PLATFORM_UNIX)