diff --git a/cpp/src/gandiva/precompiled/time.cc b/cpp/src/gandiva/precompiled/time.cc index e1e9ac44567c..8414d0ed37cf 100644 --- a/cpp/src/gandiva/precompiled/time.cc +++ b/cpp/src/gandiva/precompiled/time.cc @@ -923,13 +923,15 @@ gdv_time32 castTIME_int32(int32_t int_val) { const char* castVARCHAR_timestamp_int64(gdv_int64 context, gdv_timestamp in, gdv_int64 length, gdv_int32* out_len) { - gdv_int64 year = extractYear_timestamp(in); - gdv_int64 month = extractMonth_timestamp(in); - gdv_int64 day = extractDay_timestamp(in); - gdv_int64 hour = extractHour_timestamp(in); - gdv_int64 minute = extractMinute_timestamp(in); - gdv_int64 second = extractSecond_timestamp(in); - gdv_int64 millis = in % MILLIS_IN_SEC; + EpochTimePoint tp(in); + gdv_int64 year = 1900 + tp.TmYear(); + gdv_int64 month = 1 + tp.TmMon(); + gdv_int64 day = tp.TmMday(); + gdv_int64 hour = tp.TmHour(); + gdv_int64 minute = tp.TmMin(); + gdv_int64 second = tp.TmSec(); + // Use TimeOfDay().subseconds() to correctly handle negative timestamps + gdv_int64 millis = tp.TimeOfDay().subseconds().count(); static const int kTimeStampStringLen = 23; const int char_buffer_length = kTimeStampStringLen + 1; // snprintf adds \0 diff --git a/cpp/src/gandiva/precompiled/time_test.cc b/cpp/src/gandiva/precompiled/time_test.cc index 82b38d1b5777..6cfa6acf579d 100644 --- a/cpp/src/gandiva/precompiled/time_test.cc +++ b/cpp/src/gandiva/precompiled/time_test.cc @@ -904,6 +904,24 @@ TEST(TestTime, castVarcharTimestamp) { ts = StringToTimestamp("2-5-1 00:00:04"); out = castVARCHAR_timestamp_int64(context_ptr, ts, 24L, &out_len); EXPECT_EQ(std::string(out, out_len), "0002-05-01 00:00:04.000"); + + // StringToTimestamp doesn't parse milliseconds, so we add them manually + ts = StringToTimestamp("67-5-1 00:00:04") + 920; + out = castVARCHAR_timestamp_int64(context_ptr, ts, 24L, &out_len); + EXPECT_EQ(std::string(out, out_len), "0067-05-01 00:00:04.920"); + + ts = StringToTimestamp("107-10-17 12:20:03") + 900; + out = castVARCHAR_timestamp_int64(context_ptr, ts, 24L, &out_len); + EXPECT_EQ(std::string(out, out_len), "0107-10-17 12:20:03.900"); + + // Test pre-epoch timestamps with 4-digit years + ts = StringToTimestamp("1969-12-31 23:59:59") + 920; + out = castVARCHAR_timestamp_int64(context_ptr, ts, 24L, &out_len); + EXPECT_EQ(std::string(out, out_len), "1969-12-31 23:59:59.920"); + + ts = StringToTimestamp("1899-12-31 23:59:59") + 123; + out = castVARCHAR_timestamp_int64(context_ptr, ts, 24L, &out_len); + EXPECT_EQ(std::string(out, out_len), "1899-12-31 23:59:59.123"); } TEST(TestTime, TestCastTimestampToDate) {