Support formatting ISO timestamps via DateTime::toString() with option to omit defaults
Omitting components are also allowed when parsing ISO timestamps so it makes sense to have something similar in the other direction as well. Note that the idea comes from ID3v2.4.0 which stores timestamps in a subset of ISO 8601 similarily to what this library supports and it allows to omit default components as well.
This commit is contained in:
parent
c834f8923d
commit
32780ed6a6
|
@ -196,8 +196,53 @@ std::pair<DateTime, TimeSpan> 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
|
||||
|
|
|
@ -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" */
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue