Adding datetime format decimal and no decimal (#936)

* revert change to xmlsoft link

* remove link

* Add DateFormat::Iso8601WithDecimals and DateFormat::Iso8601WithNoDecimals

* changelog

* add ToISO8601String with TimeFractionFormat

* update the name and add extra test
This commit is contained in:
Victor Vazquez 2020-11-09 17:50:05 -08:00 committed by GitHub
parent 038d02fd50
commit 4b4e8ba7ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 7 deletions

View File

@ -13,6 +13,7 @@
- Added `GetPort()` to `Url`.
- Added `TransportPolicyOptions`.
- Added `TelemetryPolicyOptions`.
- Added `DateFormat::ToIso8601String(TimeFractionFormat)`.
### Other changes and Improvements

View File

@ -25,6 +25,23 @@ namespace Azure { namespace Core {
static constexpr IntervalType WindowsToPosixOffsetSeconds = 11644473600LL;
public:
/**
* @brief Defines the format applied to the fraction part from any @DateFormat
*
*/
enum class TimeFractionFormat
{
/// Decimals are not included when there are no decimals in the source Datetime and any zeros
/// from the right are also removed.
DropTrailingZeros,
/// Decimals are included for any Datetime.
AllDigits,
/// Decimals are removed for any Datetime.
Truncate
};
/**
* @brief Defines the supported date and time string formats.
*/
@ -34,7 +51,7 @@ namespace Azure { namespace Core {
Rfc1123,
/// ISO 8601.
Iso8601
Iso8601,
};
/**
@ -76,6 +93,19 @@ namespace Azure { namespace Core {
std::string const& timeString,
DateFormat format = DateFormat::Rfc1123);
private:
/**
* @brief Get a string representation of the @DateTime.
*
* @param format The representation format to use.
* @param fractionFormat The format for the fraction part of the Datetime. Only supported by
* ISO8601
*
* @throw DateTimeException If year exceeds 9999, or if \p format is not recognized.
*/
std::string ToString(DateFormat format, TimeFractionFormat fractionFormat) const;
public:
/**
* @brief Get a string representation of the @DateTime.
*
@ -83,7 +113,22 @@ namespace Azure { namespace Core {
*
* @throw DateTimeException If year exceeds 9999, or if \p format is not recognized.
*/
std::string ToString(DateFormat format = DateFormat::Rfc1123) const;
std::string ToString(DateFormat format = DateFormat::Rfc1123) const
{
return ToString(format, TimeFractionFormat::DropTrailingZeros);
};
/**
* @brief Get a string representation of the @DateTime formated with ISO8601.
*
* @param fractionFormat The format that is applied to the fraction part from the ISO8601 date.
*
* @throw DateTimeException If year exceeds 9999, or if \p fractionFormat is not recognized.
*/
std::string ToIso8601String(TimeFractionFormat fractionFormat) const
{
return ToString(DateFormat::Iso8601, fractionFormat);
};
/// Get the integral time value.
IntervalType ToInterval() const { return m_interval; }

View File

@ -127,7 +127,7 @@ constexpr char const monthNames[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep
} // namespace
std::string DateTime::ToString(DateFormat format) const
std::string DateTime::ToString(DateFormat format, TimeFractionFormat fractionFormat) const
{
if (m_interval > 2650467743999999999LL)
{
@ -209,7 +209,8 @@ std::string DateTime::ToString(DateFormat format) const
leftover);
outCursor += 19;
if (fracSec != 0)
if ((fracSec != 0 && fractionFormat != TimeFractionFormat::Truncate)
|| fractionFormat == TimeFractionFormat::AllDigits)
{
// Append fractional second, which is a 7-digit value with no trailing zeros
// This way, '1200' becomes '00012'
@ -226,11 +227,13 @@ std::string DateTime::ToString(DateFormat format) const
".%07d",
fracSec);
while (outCursor[appended - 1] == '0')
if (fractionFormat != TimeFractionFormat::AllDigits)
{
--appended; // trim trailing zeros
while (outCursor[appended - 1] == '0')
{
--appended; // trim trailing zeros
}
}
outCursor += appended;
}

View File

@ -73,6 +73,59 @@ TEST(DateTime, ParseTimeRoundrip2)
TestDateTimeRoundtrip("2013-11-19T14:30:59.1234567999Z", "2013-11-19T14:30:59.1234567Z");
}
TEST(DateTime, decimals)
{
{
std::string strExpected("2020-10-13T21:06:15.3300000Z");
auto dt = DateTime::FromString("2020-10-13T21:06:15.33Z", DateTime::DateFormat::Iso8601);
auto const str2 = dt.ToIso8601String(DateTime::TimeFractionFormat::AllDigits);
EXPECT_EQ(str2, strExpected);
}
{
std::string strExpected("2020-10-13T21:06:15.0000000Z");
auto dt = DateTime::FromString("2020-10-13T21:06:15Z", DateTime::DateFormat::Iso8601);
auto const str2 = dt.ToIso8601String(DateTime::TimeFractionFormat::AllDigits);
EXPECT_EQ(str2, strExpected);
}
{
std::string strExpected("2020-10-13T21:06:15.1234500Z");
auto dt = DateTime::FromString("2020-10-13T21:06:15.12345Z", DateTime::DateFormat::Iso8601);
auto const str2 = dt.ToIso8601String(DateTime::TimeFractionFormat::AllDigits);
EXPECT_EQ(str2, strExpected);
}
}
TEST(DateTime, noDecimals)
{
{
std::string strExpected("2020-10-13T21:06:15Z");
auto dt = DateTime::FromString("2020-10-13T21:06:15Z", DateTime::DateFormat::Iso8601);
auto const str2 = dt.ToIso8601String(DateTime::TimeFractionFormat::Truncate);
EXPECT_EQ(str2, strExpected);
}
{
std::string strExpected("2020-10-13T21:06:15Z");
auto dt = DateTime::FromString("2020-10-13T21:06:15.99999Z", DateTime::DateFormat::Iso8601);
auto const str2 = dt.ToIso8601String(DateTime::TimeFractionFormat::Truncate);
EXPECT_EQ(str2, strExpected);
}
}
TEST(DateTime, sameResultFromDefaultISO)
{
{
auto dt = DateTime::FromString("2020-10-13T21:06:15.33000000Z", DateTime::DateFormat::Iso8601);
auto dt2
= DateTime::FromString("2020-10-13T21:06:15.330000000Z", DateTime::DateFormat::Iso8601);
auto const str1 = dt.ToIso8601String(DateTime::TimeFractionFormat::DropTrailingZeros);
auto const str2 = dt2.ToString(DateTime::DateFormat::Iso8601);
EXPECT_EQ(str1, str2);
}
}
TEST(DateTime, ParseTimeRoundrip3)
{
// leading 0-s after the comma, tricky to parse correctly