diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h
index 1b54f1634..cadc6c715 100644
--- a/Release/include/cpprest/asyncrt_utils.h
+++ b/Release/include/cpprest/asyncrt_utils.h
@@ -603,14 +603,21 @@ public:
}
}
- datetime() : m_interval(0) {}
+ datetime() : m_interval(0) { }
///
- /// Creates datetime from a string representing time in UTC in RFC 1123 format.
+ /// Creates datetime from a string representing time in UTC in RFC 1123 or ISO 8601 format.
///
/// Returns a datetime of zero if not successful.
static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
+ ///
+ /// Creates datetime from a string representing time in UTC in RFC 1123 or ISO 8601 format.
+ ///
+ /// Returns datetime::maximum() if not successful.
+ static _ASYNCRTIMP datetime __cdecl from_string_maximum_error(const utility::string_t& timestring,
+ date_format format = RFC_1123);
+
///
/// Returns a string representation of the datetime.
///
@@ -628,13 +635,13 @@ public:
bool operator==(datetime dt) const { return m_interval == dt.m_interval; }
bool operator!=(const datetime& dt) const { return !(*this == dt); }
-
+
bool operator>(const datetime& dt) const { return this->m_interval > dt.m_interval; }
-
+
bool operator<(const datetime& dt) const { return this->m_interval < dt.m_interval; }
-
+
bool operator>=(const datetime& dt) const { return this->m_interval >= dt.m_interval; }
-
+
bool operator<=(const datetime& dt) const { return this->m_interval <= dt.m_interval; }
static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; }
@@ -649,6 +656,8 @@ public:
bool is_initialized() const { return m_interval != 0; }
+ static datetime maximum() { return datetime(static_cast(-1)); }
+
private:
friend int operator-(datetime t1, datetime t2);
@@ -659,7 +668,7 @@ private:
static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks;
// Private constructor. Use static methods to create an instance.
- datetime(interval_type interval) : m_interval(interval) {}
+ datetime(interval_type interval) : m_interval(interval) { }
// Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.
interval_type m_interval;
diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp
index 7548bc5ea..e392fc15f 100644
--- a/Release/src/utilities/asyncrt_utils.cpp
+++ b/Release/src/utilities/asyncrt_utils.cpp
@@ -995,10 +995,20 @@ zone = "UT" / "GMT" ; Universal Time
; hours+min. (HHMM)
*/
-
datetime __cdecl datetime::from_string(const utility::string_t& dateString, date_format format)
{
- datetime result;
+ auto result = from_string_maximum_error(dateString, format);
+ if (result == datetime::maximum())
+ {
+ return datetime();
+ }
+
+ return result;
+}
+
+datetime __cdecl datetime::from_string_maximum_error(const utility::string_t& dateString, date_format format)
+{
+ datetime result = datetime::maximum();
int64_t secondsSince1900;
uint64_t fracSec = 0;
auto str = dateString.c_str();
diff --git a/Release/tests/functional/utils/datetime.cpp b/Release/tests/functional/utils/datetime.cpp
index 3949b000b..ab349beee 100644
--- a/Release/tests/functional/utils/datetime.cpp
+++ b/Release/tests/functional/utils/datetime.cpp
@@ -10,6 +10,7 @@
****/
#include "stdafx.h"
+
#include
#include
@@ -81,6 +82,10 @@ SUITE(datetime)
auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601);
utility::string_t str2 = dt.to_string(utility::datetime::ISO_8601);
VERIFY_ARE_EQUAL(str2, strExpected);
+
+ auto dt_me = utility::datetime::from_string_maximum_error(str, utility::datetime::ISO_8601);
+ utility::string_t str3 = dt_me.to_string(utility::datetime::ISO_8601);
+ VERIFY_ARE_EQUAL(str3, strExpected);
}
void TestDateTimeRoundtrip(utility::string_t str) { TestDateTimeRoundtrip(str, str); }
@@ -123,32 +128,18 @@ SUITE(datetime)
TestDateTimeRoundtrip(_XPLATSTR("2013-11-19T14:30:59.5Z"));
}
- TEST(parsing_time_roundtrip_year_1900)
- {
- TestDateTimeRoundtrip(_XPLATSTR("1900-01-01T00:00:00Z"));
- }
+ TEST(parsing_time_roundtrip_year_1900) { TestDateTimeRoundtrip(_XPLATSTR("1900-01-01T00:00:00Z")); }
- TEST(parsing_time_roundtrip_year_9999)
- {
- TestDateTimeRoundtrip(_XPLATSTR("9999-12-31T23:59:59Z"));
- }
+ TEST(parsing_time_roundtrip_year_9999) { TestDateTimeRoundtrip(_XPLATSTR("9999-12-31T23:59:59Z")); }
- TEST(parsing_time_roundtrip_year_2016)
- {
- TestDateTimeRoundtrip(_XPLATSTR("2016-12-31T20:59:59Z"));
- }
+ TEST(parsing_time_roundtrip_year_2016) { TestDateTimeRoundtrip(_XPLATSTR("2016-12-31T20:59:59Z")); }
- TEST(parsing_time_roundtrip_year_2020)
- {
- TestDateTimeRoundtrip(_XPLATSTR("2020-12-31T20:59:59Z"));
- }
+ TEST(parsing_time_roundtrip_year_2020) { TestDateTimeRoundtrip(_XPLATSTR("2020-12-31T20:59:59Z")); }
- TEST(parsing_time_roundtrip_year_2021)
- {
- TestDateTimeRoundtrip(_XPLATSTR("2021-01-01T20:59:59Z"));
- }
+ TEST(parsing_time_roundtrip_year_2021) { TestDateTimeRoundtrip(_XPLATSTR("2021-01-01T20:59:59Z")); }
- TEST(emitting_time_correct_day) {
+ TEST(emitting_time_correct_day)
+ {
const auto test = utility::datetime() + UINT64_C(132004507640000000); // 2019-04-22T23:52:44 is a Monday
const auto actual = test.to_string(utility::datetime::RFC_1123);
const utility::string_t expected(_XPLATSTR("Mon"));
@@ -296,13 +287,13 @@ SUITE(datetime)
_XPLATSTR("Thu, 01 Jan 1970 00:00:00 G"),
_XPLATSTR("Thu, 01 Jan 1970 00:00:00 GM"),
_XPLATSTR("Fri, 01 Jan 1970 00:00:00 GMT"), // wrong day
- _XPLATSTR("01 Jan 1899 00:00:00 GMT"), // year too small
- _XPLATSTR("01 Xxx 1971 00:00:00 GMT"), // month bad
- _XPLATSTR("00 Jan 1971 00:00:00 GMT"), // day too small
- _XPLATSTR("32 Jan 1971 00:00:00 GMT"), // day too big
- _XPLATSTR("30 Feb 1971 00:00:00 GMT"), // day too big for feb
- _XPLATSTR("30 Feb 1971 00:00:00 GMT"), // day too big for feb (non-leap year)
- _XPLATSTR("32 Mar 1971 00:00:00 GMT"), // other months
+ _XPLATSTR("01 Jan 1899 00:00:00 GMT"), // year too small
+ _XPLATSTR("01 Xxx 1971 00:00:00 GMT"), // month bad
+ _XPLATSTR("00 Jan 1971 00:00:00 GMT"), // day too small
+ _XPLATSTR("32 Jan 1971 00:00:00 GMT"), // day too big
+ _XPLATSTR("30 Feb 1971 00:00:00 GMT"), // day too big for feb
+ _XPLATSTR("30 Feb 1971 00:00:00 GMT"), // day too big for feb (non-leap year)
+ _XPLATSTR("32 Mar 1971 00:00:00 GMT"), // other months
_XPLATSTR("31 Apr 1971 00:00:00 GMT"),
_XPLATSTR("32 May 1971 00:00:00 GMT"),
_XPLATSTR("31 Jun 1971 00:00:00 GMT"),
@@ -317,8 +308,8 @@ SUITE(datetime)
_XPLATSTR("01 Jan 1971 00:60:00 GMT"), // minute too big
_XPLATSTR("01 Jan 1971 00:00:70 GMT"), // second too big
_XPLATSTR("01 Jan 1971 00:00:61 GMT"),
- _XPLATSTR("01 Jan 1899 00:00:00 GMT"), // underflow
- _XPLATSTR("01 Jan 1969 00:00:00 CEST"), // bad tz
+ _XPLATSTR("01 Jan 1899 00:00:00 GMT"), // underflow
+ _XPLATSTR("01 Jan 1969 00:00:00 CEST"), // bad tz
_XPLATSTR("14 Jan 2019 23:16:21 G0100"), // bad tzoffsets
_XPLATSTR("01 Jan 1970 00:00:00 +2400"),
_XPLATSTR("01 Jan 1970 00:00:00 -3000"),
@@ -332,6 +323,8 @@ SUITE(datetime)
{
auto dt = utility::datetime::from_string(str, utility::datetime::RFC_1123);
VERIFY_ARE_EQUAL(0, dt.to_interval());
+ auto dt_me = utility::datetime::from_string_maximum_error(str, utility::datetime::RFC_1123);
+ VERIFY_ARE_EQUAL(utility::datetime::maximum(), dt_me);
}
}
@@ -484,7 +477,7 @@ SUITE(datetime)
_XPLATSTR("1971-01-01T00:60:00Z"), // minute too big
_XPLATSTR("1971-01-01T00:00:70Z"), // second too big
_XPLATSTR("1971-01-01T00:00:61Z"),
- _XPLATSTR("1899-01-01T00:00:00Z"), // underflow
+ _XPLATSTR("1899-01-01T00:00:00Z"), // underflow
_XPLATSTR("1900-01-01T00:00:00+00:01"), // time zone underflow
// _XPLATSTR("1970-01-01T00:00:00.Z"), // accepted as invalid timezone above
_XPLATSTR("1970-01-01T00:00:00+24:00"), // bad tzoffsets
@@ -499,23 +492,22 @@ SUITE(datetime)
{
auto dt = utility::datetime::from_string(str, utility::datetime::ISO_8601);
VERIFY_ARE_EQUAL(dt.to_interval(), 0);
+ auto dt_me = utility::datetime::from_string_maximum_error(str, utility::datetime::ISO_8601);
+ VERIFY_ARE_EQUAL(dt_me, utility::datetime::maximum());
}
}
- TEST(can_emit_nt_epoch_zero)
+ TEST(can_emit_nt_epoch_zero_rfc_1123)
{
- // ISO 8601
- {
- auto result = utility::datetime{}.to_string(utility::datetime::RFC_1123);
- VERIFY_ARE_EQUAL(_XPLATSTR("Mon, 01 Jan 1601 00:00:00 GMT"), result);
- }
- // ISO 8601
- {
- auto result = utility::datetime{}.to_string(utility::datetime::ISO_8601);
- VERIFY_ARE_EQUAL(_XPLATSTR("1601-01-01T00:00:00Z"), result);
- }
+ auto result = utility::datetime {}.to_string(utility::datetime::RFC_1123);
+ VERIFY_ARE_EQUAL(_XPLATSTR("Mon, 01 Jan 1601 00:00:00 GMT"), result);
}
+ TEST(can_emit_nt_epoch_zero_iso_8601)
+ {
+ auto result = utility::datetime {}.to_string(utility::datetime::ISO_8601);
+ VERIFY_ARE_EQUAL(_XPLATSTR("1601-01-01T00:00:00Z"), result);
+ }
} // SUITE(datetime)
} // namespace utils_tests