Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(timestamp): toMicros() should work for all timestamps fitting in bigint #11774

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
29 changes: 15 additions & 14 deletions velox/type/Timestamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,12 @@ struct Timestamp {
int64_t toMillis() const {
// We use int128_t to make sure the computation does not overflows since
// there are cases such that seconds*1000 does not fit in int64_t,
// but seconds*1000 + nanos does, an example is TimeStamp::minMillis().
// but seconds*1000 + nanos does, an example is Timestamp::minMillis().

// If the final result does not fit in int64_tw we throw.
// If the final result does not fit in int64_t we throw.
__int128_t result =
(__int128_t)seconds_ * 1'000 + (int64_t)(nanos_ / 1'000'000);
if (result < std::numeric_limits<int64_t>::min() ||
result > std::numeric_limits<int64_t>::max()) {
if (result < INT64_MIN || result > INT64_MAX) {
VELOX_USER_FAIL(
"Could not convert Timestamp({}, {}) to milliseconds",
seconds_,
Expand All @@ -183,19 +182,21 @@ struct Timestamp {

// Keep it in header for getting inlined.
int64_t toMicros() const {
// When an integer overflow occurs in the calculation,
// an exception will be thrown.
try {
return checkedPlus(
checkedMultiply(seconds_, (int64_t)1'000'000),
(int64_t)(nanos_ / 1'000));
} catch (const std::exception& e) {
// We use int128_t to make sure the computation does not overflows since
// there are cases such that a negative seconds*1000000 does not fit in
// int64_t, but seconds*1000000 + nanos does. An example is
// Timestamp(-9223372036855, 224'192'000).

// If the final result does not fit in int64_t we throw.
__int128_t result =
(__int128_t)seconds_ * 1'000'000 + (int64_t)(nanos_ / 1'000);
Copy link
Collaborator

@rui-mo rui-mo Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use static_cast to avoid C-style casts. See 28c319e.

if (result < INT64_MIN || result > INT64_MAX) {
VELOX_USER_FAIL(
"Could not convert Timestamp({}, {}) to microseconds, {}",
"Could not convert Timestamp({}, {}) to microseconds",
seconds_,
nanos_,
e.what());
nanos_);
}
return result;
}

Timestamp toPrecision(const TimestampPrecision& precision) const {
Expand Down
2 changes: 2 additions & 0 deletions velox/type/tests/TimestampTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ TEST(TimestampTest, arithmeticOverflow) {
0));
ASSERT_NO_THROW(Timestamp::minMillis().toMillis());
ASSERT_NO_THROW(Timestamp::maxMillis().toMillis());
ASSERT_NO_THROW(Timestamp(-9223372036855, 224'192'000).toMicros());
ASSERT_NO_THROW(Timestamp(9223372036854, 775'807'000).toMicros());
}

TEST(TimestampTest, toAppend) {
Expand Down
Loading