Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cpp/src/arrow/util/value_parsing.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,9 +826,16 @@ static inline bool ParseTimestampStrptime(const char* buf, size_t length,
if (!allow_trailing_chars && static_cast<size_t>(ret - clean_copy.c_str()) != length) {
return false;
}
// tm_year + 1900 can overflow int (e.g. with %s), and date::year only
// holds 16 bits
const int64_t year = static_cast<int64_t>(result.tm_year) + 1900;
if (year < static_cast<int>(arrow_vendored::date::year::min()) ||
year > static_cast<int>(arrow_vendored::date::year::max())) {
return false;
}
// ignore the time part
arrow_vendored::date::sys_seconds secs =
arrow_vendored::date::sys_days(arrow_vendored::date::year(result.tm_year + 1900) /
arrow_vendored::date::sys_days(arrow_vendored::date::year(static_cast<int>(year)) /
(result.tm_mon + 1) / std::max(result.tm_mday, 1));
if (!ignore_time_in_day) {
secs += (std::chrono::hours(result.tm_hour) + std::chrono::minutes(result.tm_min) +
Expand Down
19 changes: 19 additions & 0 deletions cpp/src/arrow/util/value_parsing_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,25 @@ TEST(TimestampParser, StrptimeParser) {
}
}

TEST(TimestampParser, StrptimeYearOutOfRange) {
auto parser = TimestampParser::MakeStrptime("%s");
int64_t converted = 0;
// A value past 2038 (2100-01-01), as a strptime that parses %s into a 32-bit
// time_t wraps larger values into ordinary dates
if (!(*parser)("4102444800", 10, TimeUnit::SECOND, &converted) ||
converted != 4102444800) {
GTEST_SKIP() << "strptime does not support 64-bit %s values on this platform";
}

// Years that do not fit in a date::year are rejected rather than wrapped,
// also where tm_year + 1900 would overflow int
for (const std::string value :
{"1000000000000000", "67768036000000000", "67768036191676799"}) {
SCOPED_TRACE(value);
ASSERT_FALSE((*parser)(value.c_str(), value.size(), TimeUnit::SECOND, &converted));
}
}

TEST(TimestampParser, StrptimeZoneOffset) {
if (!kStrptimeSupportsZone) {
GTEST_SKIP() << "strptime does not support %z on this platform";
Expand Down
Loading