Skip to content

Commit

Permalink
Fix negative nano
Browse files Browse the repository at this point in the history
  • Loading branch information
liujiayi771 authored and rui-mo committed Mar 27, 2024
1 parent e1f4228 commit 1df8bf1
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
15 changes: 4 additions & 11 deletions velox/dwio/parquet/reader/PageReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,24 +388,17 @@ void PageReader::prepareDictionary(const PageHeader& pageHeader) {
for (auto i = dictionary_.numValues - 1; i >= 0; --i) {
// Convert the timestamp into seconds and nanos since the Unix epoch,
// 00:00:00.000000 on 1 January 1970.
uint64_t nanos;
int64_t nanos;
memcpy(
&nanos,
parquetValues + i * sizeof(Int96Timestamp),
sizeof(uint64_t));
sizeof(int64_t));
int32_t days;
memcpy(
&days,
parquetValues + i * sizeof(Int96Timestamp) + sizeof(uint64_t),
parquetValues + i * sizeof(Int96Timestamp) + sizeof(int64_t),
sizeof(int32_t));
int64_t seconds = (days - Timestamp::kJulianToUnixEpochDays) *
Timestamp::kSecondsPerDay;
if (nanos > Timestamp::kMaxNanos) {
seconds += nanos / Timestamp::kNanosInSecond;
nanos -=
(nanos / Timestamp::kNanosInSecond) * Timestamp::kNanosInSecond;
}
values[i] = Timestamp(seconds, nanos);
values[i] = Timestamp::fromDaysAndNanos(days, nanos);
}
break;
}
Expand Down
13 changes: 12 additions & 1 deletion velox/type/Timestamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct Timestamp {
static constexpr int64_t kNanosInSecond =
kNanosecondsInMillisecond * kMillisecondsInSecond;
static constexpr int64_t kJulianToUnixEpochDays = 2440588LL;
static constexpr int64_t kSecondsPerDay = 86400LL;
static constexpr int64_t kSecondsInDay = 86400LL;

// Limit the range of seconds to avoid some problems. Seconds should be
// in the range [INT64_MIN/1000 - 1, INT64_MAX/1000].
Expand All @@ -110,6 +110,17 @@ struct Timestamp {
VELOX_USER_DCHECK_LE(nanos, kMaxNanos, "Timestamp nanos out of range");
}

static Timestamp fromDaysAndNanos(int32_t days, int64_t nanos) {
int64_t seconds = (days - kJulianToUnixEpochDays) * kSecondsInDay +
nanos / kNanosInSecond;
int64_t remainingNanos = nanos % kNanosInSecond;
if (remainingNanos < 0) {
remainingNanos += kNanosInSecond;
seconds--;
}
return Timestamp(seconds, remainingNanos);
}

// Returns the current unix timestamp (ms precision).
static Timestamp now();

Expand Down
24 changes: 24 additions & 0 deletions velox/type/tests/TimestampTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ std::string timestampToString(
return result;
}

TEST(TimestampTest, fromDaysAndNanos) {
EXPECT_EQ(
Timestamp(Timestamp::kSecondsInDay + 2, 1),
Timestamp::fromDaysAndNanos(
Timestamp::kJulianToUnixEpochDays + 1,
2 * Timestamp::kNanosInSecond + 1));
EXPECT_EQ(
Timestamp(Timestamp::kSecondsInDay + 2, 0),
Timestamp::fromDaysAndNanos(
Timestamp::kJulianToUnixEpochDays + 1,
2 * Timestamp::kNanosInSecond));
EXPECT_EQ(
Timestamp(
Timestamp::kSecondsInDay * 5 - 3, Timestamp::kNanosInSecond - 6),
Timestamp::fromDaysAndNanos(
Timestamp::kJulianToUnixEpochDays + 5,
-2 * Timestamp::kNanosInSecond - 6));
EXPECT_EQ(
Timestamp(Timestamp::kSecondsInDay * 5 - 2, 0),
Timestamp::fromDaysAndNanos(
Timestamp::kJulianToUnixEpochDays + 5,
-2 * Timestamp::kNanosInSecond));
}

TEST(TimestampTest, fromMillisAndMicros) {
int64_t positiveSecond = 10'000;
int64_t negativeSecond = -10'000;
Expand Down

0 comments on commit 1df8bf1

Please sign in to comment.