summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Evans <jacob.evans@10gen.com>2020-04-01 22:06:09 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-01-29 13:38:48 +0000
commitf952f10948d21b0fc588837d8937b0d04330c353 (patch)
treec0eb42b5aa6f05b19ef34e04e8d9d3c71b4e59e2
parent56d986cef0d74231f6e1e8a05a6aaf6510716bab (diff)
downloadmongo-f952f10948d21b0fc588837d8937b0d04330c353.tar.gz
SERVER-47030 Fix date_time_support to not throw exceptions
(cherry picked from commit d169769bba283cd0a1906c81580ff8e7cf7bcd93)
-rw-r--r--src/mongo/db/exec/document_value/document_value_test.cpp7
-rw-r--r--src/mongo/db/exec/document_value/value.cpp15
-rw-r--r--src/mongo/db/pipeline/expression.cpp10
-rw-r--r--src/mongo/db/query/datetime/date_time_support.cpp8
-rw-r--r--src/mongo/db/query/datetime/date_time_support.h75
-rw-r--r--src/mongo/db/query/datetime/date_time_support_test.cpp216
6 files changed, 207 insertions, 124 deletions
diff --git a/src/mongo/db/exec/document_value/document_value_test.cpp b/src/mongo/db/exec/document_value/document_value_test.cpp
index 74c42cefe14..4ed34854dac 100644
--- a/src/mongo/db/exec/document_value/document_value_test.cpp
+++ b/src/mongo/db/exec/document_value/document_value_test.cpp
@@ -30,6 +30,7 @@
#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
#include <math.h>
+#include <sstream>
#include "mongo/platform/basic.h"
@@ -2402,4 +2403,10 @@ public:
OldStyleSuiteInitializer<All> myall;
+TEST(ValueOutput, StreamOutputForIllegalDateProducesErrorToken) {
+ auto sout = std::ostringstream{};
+ sout << mongo::Value{Date_t::min()};
+ ASSERT_EQ("illegal date", sout.str());
+}
+
} // namespace DocumentTests
diff --git a/src/mongo/db/exec/document_value/value.cpp b/src/mongo/db/exec/document_value/value.cpp
index f0d9f684222..7afef48204d 100644
--- a/src/mongo/db/exec/document_value/value.cpp
+++ b/src/mongo/db/exec/document_value/value.cpp
@@ -57,6 +57,7 @@ using std::ostream;
using std::string;
using std::stringstream;
using std::vector;
+using namespace std::string_literals;
constexpr StringData Value::kISOFormatString;
@@ -634,7 +635,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:
@@ -1170,8 +1173,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 << [&] {
+ if (auto string = TimeZoneDatabase::utcZone().formatDate(Value::kISOFormatString,
+ val.coerceToDate());
+ 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/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 9534eebc108..4cee9ba5a3d 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -1876,10 +1876,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 {
@@ -5610,8 +5612,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][BSONType::Bool] =
diff --git a/src/mongo/db/query/datetime/date_time_support.cpp b/src/mongo/db/query/datetime/date_time_support.cpp
index 5fedc644686..5bd16d798c9 100644
--- a/src/mongo/db/query/datetime/date_time_support.cpp
+++ b/src/mongo/db/query/datetime/date_time_support.cpp
@@ -560,9 +560,11 @@ 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();
+ if (auto status = outputDateWithFormat(formatted, format, date); 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 be93ae1c9c4..c9f72f5ec58 100644
--- a/src/mongo/db/query/datetime/date_time_support.h
+++ b/src/mongo/db/query/datetime/date_time_support.h
@@ -31,7 +31,9 @@
#include <memory>
#include <string>
+#include <utility>
+#include "mongo/base/status.h"
#include "mongo/db/service_context.h"
#include "mongo/util/string_map.h"
#include "mongo/util/time_support.h"
@@ -43,6 +45,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
@@ -192,15 +196,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 != '%') {
@@ -217,51 +221,71 @@ public:
break;
case 'Y': // Year
{
- insertPadded(os, parts.year, 4);
+ if (auto status = insertPadded(os, parts.year, 4); status != Status::OK())
+ return status;
break;
}
case 'm': // Month
- insertPadded(os, parts.month, 2);
+ if (auto status = insertPadded(os, parts.month, 2); status != Status::OK())
+ return status;
break;
case 'd': // Day of month
- insertPadded(os, parts.dayOfMonth, 2);
+ if (auto status = insertPadded(os, parts.dayOfMonth, 2); status != Status::OK())
+ return status;
break;
case 'H': // Hour
- insertPadded(os, parts.hour, 2);
+ if (auto status = insertPadded(os, parts.hour, 2); status != Status::OK())
+ return status;
break;
case 'M': // Minute
- insertPadded(os, parts.minute, 2);
+ if (auto status = insertPadded(os, parts.minute, 2); status != Status::OK())
+ return status;
break;
case 'S': // Second
- insertPadded(os, parts.second, 2);
+ if (auto status = insertPadded(os, parts.second, 2); status != Status::OK())
+ return status;
break;
case 'L': // Millisecond
- insertPadded(os, parts.millisecond, 3);
+ if (auto status = insertPadded(os, parts.millisecond, 3);
+ status != Status::OK())
+ return status;
break;
case 'j': // Day of year
- insertPadded(os, dayOfYear(date), 3);
+ if (auto status = insertPadded(os, dayOfYear(date), 3); status != Status::OK())
+ return status;
break;
case 'w': // Day of week
- insertPadded(os, dayOfWeek(date), 1);
+ if (auto status = insertPadded(os, dayOfWeek(date), 1); status != Status::OK())
+ return status;
break;
case 'U': // Week
- insertPadded(os, week(date), 2);
+ if (auto status = insertPadded(os, week(date), 2); status != Status::OK())
+ return status;
break;
case 'G': // Iso year of week
- insertPadded(os, isoYear(date), 4);
+ if (auto status = insertPadded(os, isoYear(date), 4); status != Status::OK())
+ return status;
break;
case 'V': // Iso week
- insertPadded(os, isoWeek(date), 2);
+ if (auto status = insertPadded(os, isoWeek(date), 2); status != Status::OK())
+ return status;
break;
case 'u': // Iso day of week
- insertPadded(os, isoDayOfWeek(date), 1);
+ if (auto status = insertPadded(os, isoDayOfWeek(date), 1);
+ 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
+ if (auto status = insertPadded(os, std::abs(durationCount<Hours>(offset)), 2);
+ status != Status::OK()) // hh
+ return status;
+ if (auto status =
+ insertPadded(os, std::abs(durationCount<Minutes>(offset)) % 60, 2);
+ status != Status::OK()) // mm
+ return status;
break;
}
case 'Z': // UTC offset in minutes.
@@ -272,6 +296,7 @@ public:
MONGO_UNREACHABLE;
}
}
+ return Status::OK();
}
/**
@@ -289,14 +314,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},
+ "Could not convert date to string: date component was outside "
+ "the supported range of 0-9999: "s +
+ std::to_string(number)};
int digits = 1;
@@ -312,6 +338,7 @@ private:
os.write("0000", width - digits);
}
os << number;
+ return Status::OK();
}
struct TimelibTZInfoDeleter {
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 f11973aa145..fba52b3e029 100644
--- a/src/mongo/db/query/datetime/date_time_support_test.cpp
+++ b/src/mongo/db/query/datetime/date_time_support_test.cpp
@@ -387,12 +387,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) {
@@ -400,23 +404,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: %");
@@ -428,11 +437,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: %");
@@ -567,12 +576,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) {
@@ -580,22 +593,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: %");
@@ -605,11 +623,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: %");
@@ -879,47 +897,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: %");
@@ -930,11 +961,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: %");
@@ -965,37 +996,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) {