summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2021-02-25 15:19:51 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-02-25 15:45:03 +0000
commit37d125cd1aba897ab45da36f9054c35938ee9d59 (patch)
tree0b1911a3feb42d277e9f86696fcb413bb77179bf
parent59366112f105c361258a751955b576aa45f19ceb (diff)
downloadmongo-37d125cd1aba897ab45da36f9054c35938ee9d59.tar.gz
SERVER-47030 Fix date_time_support to not throw exceptions
-rw-r--r--src/mongo/db/pipeline/expression.cpp10
-rw-r--r--src/mongo/db/pipeline/value.cpp15
-rw-r--r--src/mongo/db/query/datetime/date_time_support.cpp9
-rw-r--r--src/mongo/db/query/datetime/date_time_support.h112
-rw-r--r--src/mongo/db/query/datetime/date_time_support_test.cpp216
5 files changed, 236 insertions, 126 deletions
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 51a284e6a52..33659fe89e2 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -1873,10 +1873,12 @@ Value ExpressionDateToString::evaluate(const Document& root, Variables* variable
return Value(BSONNULL);
}
- return Value(timeZone->formatDate(formatValue.getStringData(), date.coerceToDate()));
+ return Value(uassertStatusOK(
+ timeZone->formatDate(formatValue.getStringData(), date.coerceToDate())));
}
- return Value(timeZone->formatDate(Value::kISOFormatString, date.coerceToDate()));
+ return Value(
+ uassertStatusOK(timeZone->formatDate(Value::kISOFormatString, date.coerceToDate())));
}
void ExpressionDateToString::_doAddDependencies(DepsTracker* deps) const {
@@ -5178,8 +5180,8 @@ public:
};
table[BSONType::Date][BSONType::String] =
[](const boost::intrusive_ptr<ExpressionContext>& expCtx, Value inputValue) {
- auto dateString = TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString,
- inputValue.getDate());
+ auto dateString = uassertStatusOK(TimeZoneDatabase::utcZone().formatDate(
+ Value::kISOFormatString, inputValue.getDate()));
return Value(dateString);
};
table[BSONType::Date]
diff --git a/src/mongo/db/pipeline/value.cpp b/src/mongo/db/pipeline/value.cpp
index 065a7e12f67..ef3451191bc 100644
--- a/src/mongo/db/pipeline/value.cpp
+++ b/src/mongo/db/pipeline/value.cpp
@@ -58,6 +58,7 @@ using std::ostream;
using std::string;
using std::stringstream;
using std::vector;
+using namespace std::string_literals;
constexpr StringData Value::kISOFormatString;
@@ -628,7 +629,9 @@ string Value::coerceToString() const {
return getTimestamp().toStringPretty();
case Date:
- return TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString, getDate());
+ return uassertStatusOKWithContext(
+ TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString, getDate()),
+ "failed while coercing date to string");
case EOO:
case jstNULL:
@@ -1164,8 +1167,14 @@ ostream& operator<<(ostream& out, const Value& val) {
case Undefined:
return out << "undefined";
case Date:
- return out << TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString,
- val.coerceToDate());
+ return out << [&] {
+ auto string = TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString,
+ val.coerceToDate());
+ if (string.isOK())
+ return string.getValue();
+ else
+ return "illegal date"s;
+ }();
case bsonTimestamp:
return out << val.getTimestamp().toString();
case Object:
diff --git a/src/mongo/db/query/datetime/date_time_support.cpp b/src/mongo/db/query/datetime/date_time_support.cpp
index 478efe044be..76002d0d87d 100644
--- a/src/mongo/db/query/datetime/date_time_support.cpp
+++ b/src/mongo/db/query/datetime/date_time_support.cpp
@@ -558,9 +558,12 @@ void TimeZone::validateFromStringFormat(StringData format) {
return validateFormat(format, kDateFromStringFormatMap);
}
-std::string TimeZone::formatDate(StringData format, Date_t date) const {
+StatusWith<std::string> TimeZone::formatDate(StringData format, Date_t date) const {
StringBuilder formatted;
- outputDateWithFormat(formatted, format, date);
- return formatted.str();
+ auto status = outputDateWithFormat(formatted, format, date);
+ if (status != Status::OK())
+ return status;
+ else
+ return formatted.str();
}
} // namespace mongo
diff --git a/src/mongo/db/query/datetime/date_time_support.h b/src/mongo/db/query/datetime/date_time_support.h
index 18462f40cc3..56818020319 100644
--- a/src/mongo/db/query/datetime/date_time_support.h
+++ b/src/mongo/db/query/datetime/date_time_support.h
@@ -32,8 +32,10 @@
#include <memory>
#include <string>
+#include <utility>
#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
#include "mongo/db/service_context.h"
#include "mongo/util/string_map.h"
#include "mongo/util/time_support.h"
@@ -45,6 +47,8 @@ struct _timelib_tzinfo;
namespace mongo {
+using namespace std::string_literals;
+
/**
* A TimeZone object represents one way of formatting/reading dates to compute things like the day
* of the week or the hour of a given date. Different TimeZone objects may report different answers
@@ -194,15 +198,15 @@ public:
* Converts a date object to a string according to 'format'. 'format' can be any string literal,
* containing 0 or more format specifiers like %Y (year) or %d (day of month). Callers must pass
* a valid format string for 'format', i.e. one that has already been passed to
- * validateFormat().
+ * validateFormat(). May return a Status indicating that the date value is an unprintable range.
*/
- std::string formatDate(StringData format, Date_t) const;
+ StatusWith<std::string> formatDate(StringData format, Date_t) const;
/**
* Like formatDate, except outputs to an output stream like a std::ostream or a StringBuilder.
*/
template <typename OutputStream>
- void outputDateWithFormat(OutputStream& os, StringData format, Date_t date) const {
+ auto outputDateWithFormat(OutputStream& os, StringData format, Date_t date) const {
auto parts = dateParts(date);
for (auto&& it = format.begin(); it != format.end(); ++it) {
if (*it != '%') {
@@ -219,51 +223,105 @@ public:
break;
case 'Y': // Year
{
- insertPadded(os, parts.year, 4);
+ auto status = insertPadded(os, parts.year, 4);
+ if (status != Status::OK())
+ return status;
break;
}
case 'm': // Month
- insertPadded(os, parts.month, 2);
+ {
+ auto status = insertPadded(os, parts.month, 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'd': // Day of month
- insertPadded(os, parts.dayOfMonth, 2);
+ {
+ auto status = insertPadded(os, parts.dayOfMonth, 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'H': // Hour
- insertPadded(os, parts.hour, 2);
+ {
+ auto status = insertPadded(os, parts.hour, 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'M': // Minute
- insertPadded(os, parts.minute, 2);
+ {
+ auto status = insertPadded(os, parts.minute, 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'S': // Second
- insertPadded(os, parts.second, 2);
+ {
+ auto status = insertPadded(os, parts.second, 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'L': // Millisecond
- insertPadded(os, parts.millisecond, 3);
+ {
+ auto status = insertPadded(os, parts.millisecond, 3);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'j': // Day of year
- insertPadded(os, dayOfYear(date), 3);
+ {
+ auto status = insertPadded(os, dayOfYear(date), 3);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'w': // Day of week
- insertPadded(os, dayOfWeek(date), 1);
+ {
+ auto status = insertPadded(os, dayOfWeek(date), 1);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'U': // Week
- insertPadded(os, week(date), 2);
+ {
+ auto status = insertPadded(os, week(date), 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'G': // Iso year of week
- insertPadded(os, isoYear(date), 4);
+ {
+ auto status = insertPadded(os, isoYear(date), 4);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'V': // Iso week
- insertPadded(os, isoWeek(date), 2);
+ {
+ auto status = insertPadded(os, isoWeek(date), 2);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'u': // Iso day of week
- insertPadded(os, isoDayOfWeek(date), 1);
+ {
+ auto status = insertPadded(os, isoDayOfWeek(date), 1);
+ if (status != Status::OK())
+ return status;
break;
+ }
case 'z': // UTC offset as ±hhmm.
{
auto offset = utcOffset(date);
- os << ((offset.count() < 0) ? "-" : "+"); // sign
- insertPadded(os, std::abs(durationCount<Hours>(offset)), 2); // hh
- insertPadded(os, std::abs(durationCount<Minutes>(offset)) % 60, 2); // mm
+ os << ((offset.count() < 0) ? "-" : "+"); // sign
+ auto status = insertPadded(os, std::abs(durationCount<Hours>(offset)), 2);
+ if (status != Status::OK()) // hh
+ return status;
+ status = insertPadded(os, std::abs(durationCount<Minutes>(offset)) % 60, 2);
+ if (status != Status::OK()) // mm
+ return status;
break;
}
case 'Z': // UTC offset in minutes.
@@ -274,6 +332,7 @@ public:
MONGO_UNREACHABLE;
}
}
+ return Status::OK();
}
/**
@@ -291,15 +350,15 @@ private:
* count of number we simply insert the number without padding.
*/
template <typename OutputStream>
- void insertPadded(OutputStream& os, int number, int width) const {
+ static auto insertPadded(OutputStream& os, int number, int width) {
invariant(width >= 1);
invariant(width <= 4);
- uassert(18537,
- str::stream() << "Could not convert date to string: date component was outside "
- << "the supported range of 0-9999: "
- << number,
- (number >= 0) && (number <= 9999));
+ if ((number < 0) || (number > 9999))
+ return Status(ErrorCodes::Error(18537),
+ str::stream() << "Could not convert date to string: date component was "
+ "outside the supported range of 0-9999: "
+ << number);
int digits = 1;
@@ -315,6 +374,7 @@ private:
os.write("0000", width - digits);
}
os << number;
+ return Status::OK();
}
struct TimelibTZInfoDeleter {
@@ -326,7 +386,7 @@ private:
// represents the UTC offset in seconds if _tzInfo is null and it is not 0
Seconds _utcOffset{0};
-};
+}; // namespace mongo
/**
* A C++ interface wrapping the third-party timelib library. A single instance of this class can be
diff --git a/src/mongo/db/query/datetime/date_time_support_test.cpp b/src/mongo/db/query/datetime/date_time_support_test.cpp
index b8230180621..fd1e86eea97 100644
--- a/src/mongo/db/query/datetime/date_time_support_test.cpp
+++ b/src/mongo/db/query/datetime/date_time_support_test.cpp
@@ -388,12 +388,16 @@ TEST(NewYorkTimeBeforeEpoch, DoesComputeISOWeek) {
TEST(UTCTimeBeforeEpoch, DoesFormatDate) {
// Tuesday, Dec 30, 1969 13:42:23:211
auto date = Date_t::fromMillisSinceEpoch(-123456789LL);
- ASSERT_EQ(TimeZoneDatabase::utcZone().formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "1969/12/30 13:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
- "isoWeek: 01, isoDayOfWeek: 2, percent: %");
+ auto result = TimeZoneDatabase::utcZone().formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "1969/12/30 13:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
+ "isoWeek: 01, isoDayOfWeek: 2, percent: %",
+ result.getValue());
}
TEST(NewYorkTimeBeforeEpoch, DoesFormatDate) {
@@ -401,23 +405,28 @@ TEST(NewYorkTimeBeforeEpoch, DoesFormatDate) {
// Tuesday, Dec 30, 1969 13:42:23:211
auto date = Date_t::fromMillisSinceEpoch(-123456789LL);
- ASSERT_EQ(newYorkZone.formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "1969/12/30 08:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
- "isoWeek: 01, isoDayOfWeek: 2, percent: %");
+ auto result = newYorkZone.formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "1969/12/30 08:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
+ "isoWeek: 01, isoDayOfWeek: 2, percent: %",
+ result.getValue());
}
TEST(UTCTimeBeforeEpoch, DoesOutputFormatDate) {
// Tuesday, Dec 30, 1969 13:42:23:211
auto date = Date_t::fromMillisSinceEpoch(-123456789LL);
std::ostringstream os;
- TimeZoneDatabase::utcZone().outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(TimeZoneDatabase::utcZone().outputDateWithFormat(
+ os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"1969/12/30 13:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
"isoWeek: 01, isoDayOfWeek: 2, percent: %");
@@ -429,11 +438,11 @@ TEST(NewYorkTimeBeforeEpoch, DoesOutputFormatDate) {
// Tuesday, Dec 30, 1969 13:42:23:211
auto date = Date_t::fromMillisSinceEpoch(-123456789LL);
std::ostringstream os;
- newYorkZone.outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(newYorkZone.outputDateWithFormat(os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"1969/12/30 08:42:23:211, dayOfYear: 364, dayOfWeek: 3, week: 52, isoYear: 1970, "
"isoWeek: 01, isoDayOfWeek: 2, percent: %");
@@ -568,12 +577,16 @@ TEST(NewYorkTimeAtEpoch, DoesComputeISOWeek) {
TEST(UTCTimeAtEpoch, DoesFormatDate) {
// Thu, Jan 1, 1970 00:00:00:000
auto date = Date_t::fromMillisSinceEpoch(0);
- ASSERT_EQ(TimeZoneDatabase::utcZone().formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "1970/01/01 00:00:00:000, dayOfYear: 001, dayOfWeek: 5, week: 00, isoYear: 1970, "
- "isoWeek: 01, isoDayOfWeek: 4, percent: %");
+ auto result = TimeZoneDatabase::utcZone().formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "1970/01/01 00:00:00:000, dayOfYear: 001, dayOfWeek: 5, week: 00, isoYear: 1970, "
+ "isoWeek: 01, isoDayOfWeek: 4, percent: %",
+ result.getValue());
}
TEST(NewYorkTimeAtEpoch, DoesFormatDate) {
@@ -581,22 +594,27 @@ TEST(NewYorkTimeAtEpoch, DoesFormatDate) {
// Thu, Jan 1, 1970 00:00:00:000Z
auto date = Date_t::fromMillisSinceEpoch(0);
- ASSERT_EQ(newYorkZone.formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "1969/12/31 19:00:00:000, dayOfYear: 365, dayOfWeek: 4, week: 52, isoYear: 1970, "
- "isoWeek: 01, isoDayOfWeek: 3, percent: %");
+ auto result = newYorkZone.formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "1969/12/31 19:00:00:000, dayOfYear: 365, dayOfWeek: 4, week: 52, isoYear: 1970, "
+ "isoWeek: 01, isoDayOfWeek: 3, percent: %",
+ result.getValue());
}
TEST(UTCTimeAtEpoch, DoesOutputFormatDate) {
auto date = Date_t::fromMillisSinceEpoch(0);
std::ostringstream os;
- TimeZoneDatabase::utcZone().outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(TimeZoneDatabase::utcZone().outputDateWithFormat(
+ os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"1970/01/01 00:00:00:000, dayOfYear: 001, dayOfWeek: 5, week: 00, isoYear: 1970, "
"isoWeek: 01, isoDayOfWeek: 4, percent: %");
@@ -606,11 +624,11 @@ TEST(NewYorkTimeAtEpoch, DoesOutputFormatDate) {
auto newYorkZone = kDefaultTimeZoneDatabase.getTimeZone("America/New_York");
auto date = Date_t::fromMillisSinceEpoch(0);
std::ostringstream os;
- newYorkZone.outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(newYorkZone.outputDateWithFormat(os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"1969/12/31 19:00:00:000, dayOfYear: 365, dayOfWeek: 4, week: 52, isoYear: 1970, "
"isoWeek: 01, isoDayOfWeek: 3, percent: %");
@@ -880,47 +898,60 @@ TEST(NewYorkTimeAfterEpoch, DoesComputeISOWeek) {
TEST(UTCTimeAfterEpoch, DoesFormatDate) {
// Tue, Jun 6, 2017 19:38:43:234.
auto date = Date_t::fromMillisSinceEpoch(1496777923234LL);
- ASSERT_EQ(TimeZoneDatabase::utcZone().formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "2017/06/06 19:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
- "isoWeek: 23, isoDayOfWeek: 2, percent: %");
+ auto result = TimeZoneDatabase::utcZone().formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "2017/06/06 19:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
+ "isoWeek: 23, isoDayOfWeek: 2, percent: %",
+ result.getValue());
}
TEST(NewYorkTimeAfterEpoch, DoesFormatDate) {
// 2017-06-06T19:38:43:234Z (Tuesday).
auto date = Date_t::fromMillisSinceEpoch(1496777923234LL);
auto newYorkZone = kDefaultTimeZoneDatabase.getTimeZone("America/New_York");
- ASSERT_EQ(newYorkZone.formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "2017/06/06 15:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
- "isoWeek: 23, isoDayOfWeek: 2, percent: %");
+ auto result = newYorkZone.formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "2017/06/06 15:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
+ "isoWeek: 23, isoDayOfWeek: 2, percent: %",
+ result.getValue());
}
TEST(UTCOffsetAfterEpoch, DoesFormatDate) {
// 2017-06-06T19:38:43:234Z (Tuesday).
auto date = Date_t::fromMillisSinceEpoch(1496777923234LL);
auto offsetSpec = kDefaultTimeZoneDatabase.getTimeZone("+02:30");
- ASSERT_EQ(offsetSpec.formatDate("%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date),
- "2017/06/06 22:08:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
- "isoWeek: 23, isoDayOfWeek: 2, percent: %");
+ auto result = offsetSpec.formatDate(
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date);
+ ASSERT_OK(result);
+ ASSERT_EQ(
+ "2017/06/06 22:08:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
+ "isoWeek: 23, isoDayOfWeek: 2, percent: %",
+ result.getValue());
}
TEST(UTCTimeAfterEpoch, DoesOutputFormatDate) {
// Tue, Jun 6, 2017 19:38:43:234.
auto date = Date_t::fromMillisSinceEpoch(1496777923234LL);
std::ostringstream os;
- TimeZoneDatabase::utcZone().outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(TimeZoneDatabase::utcZone().outputDateWithFormat(
+ os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"2017/06/06 19:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
"isoWeek: 23, isoDayOfWeek: 2, percent: %");
@@ -931,11 +962,11 @@ TEST(NewYorkTimeAfterEpoch, DoesOutputFormatDate) {
auto date = Date_t::fromMillisSinceEpoch(1496777923234LL);
std::ostringstream os;
auto newYorkZone = kDefaultTimeZoneDatabase.getTimeZone("America/New_York");
- newYorkZone.outputDateWithFormat(os,
- "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
- "dayOfWeek: %w, week: %U, isoYear: %G, "
- "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
- date);
+ ASSERT_OK(newYorkZone.outputDateWithFormat(os,
+ "%Y/%m/%d %H:%M:%S:%L, dayOfYear: %j, "
+ "dayOfWeek: %w, week: %U, isoYear: %G, "
+ "isoWeek: %V, isoDayOfWeek: %u, percent: %%",
+ date));
ASSERT_EQ(os.str(),
"2017/06/06 15:38:43:234, dayOfYear: 157, dayOfWeek: 3, week: 23, isoYear: 2017, "
"isoWeek: 23, isoDayOfWeek: 2, percent: %");
@@ -966,37 +997,42 @@ TEST(DateFormat, ThrowsUserExceptionIfGivenUnmatchedPercent) {
18535);
}
-TEST(DateFormat, ThrowsUserExceptionIfGivenDateBeforeYear0) {
+TEST(DateFormat, ProducesNonOKStatusGivenDateBeforeYear0) {
const long long kMillisPerYear = 31556926000;
- ASSERT_THROWS_CODE(TimeZoneDatabase::utcZone().formatDate(
- "%Y", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1971))),
- AssertionException,
- 18537);
+ ASSERT_EQ(18537,
+ TimeZoneDatabase::utcZone()
+ .formatDate("%Y", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1971)))
+ .getStatus()
+ .code());
- ASSERT_THROWS_CODE(TimeZoneDatabase::utcZone().formatDate(
- "%G", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1971))),
- AssertionException,
- 18537);
+ ASSERT_EQ(18537,
+ TimeZoneDatabase::utcZone()
+ .formatDate("%G", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1971)))
+ .getStatus()
+ .code());
- ASSERT_EQ("0000",
- TimeZoneDatabase::utcZone().formatDate(
- "%Y", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1970))));
+ auto result = TimeZoneDatabase::utcZone().formatDate(
+ "%Y", Date_t::fromMillisSinceEpoch(-(kMillisPerYear * 1970)));
+ ASSERT_OK(result);
+ ASSERT_EQ("0000", result.getValue());
}
-TEST(DateFormat, ThrowsUserExceptionIfGivenDateAfterYear9999) {
- ASSERT_THROWS_CODE(
- TimeZoneDatabase::utcZone().formatDate("%Y", Date_t::max()), AssertionException, 18537);
+TEST(DateFormat, ProducesNonOKStatusIfGivenDateAfterYear9999) {
+ ASSERT_EQ(18537,
+ TimeZoneDatabase::utcZone().formatDate("%Y", Date_t::max()).getStatus().code());
- ASSERT_THROWS_CODE(
- TimeZoneDatabase::utcZone().formatDate("%G", Date_t::max()), AssertionException, 18537);
+ ASSERT_EQ(18537,
+ TimeZoneDatabase::utcZone().formatDate("%G", Date_t::max()).getStatus().code());
}
TEST(DateFromString, CorrectlyParsesStringThatMatchesFormat) {
auto input = "2017-07-04T10:56:02Z";
auto format = "%Y-%m-%dT%H:%M:%SZ"_sd;
auto date = kDefaultTimeZoneDatabase.fromString(input, kDefaultTimeZone, format);
- ASSERT_EQ(TimeZoneDatabase::utcZone().formatDate(format, date), input);
+ auto result = TimeZoneDatabase::utcZone().formatDate(format, date);
+ ASSERT_OK(result);
+ ASSERT_EQ(input, result.getValue());
}
TEST(DateFromString, RejectsStringWithInvalidYearFormat) {