Skip to content

Commit 5aac113

Browse files
GH-48866: [C++][Gandiva] Truncate subseconds beyond milliseconds in castTIMESTAMP_utf8 and castTIME_utf8
1 parent 7820f67 commit 5aac113

File tree

2 files changed

+49
-24
lines changed

2 files changed

+49
-24
lines changed

cpp/src/gandiva/precompiled/time.cc

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -747,11 +747,12 @@ gdv_timestamp castTIMESTAMP_utf8(int64_t context, const char* input, gdv_int32 l
747747

748748
// adjust the milliseconds
749749
if (sub_seconds_len > 0) {
750-
if (sub_seconds_len > 3) {
751-
const char* msg = "Invalid millis for timestamp value ";
752-
set_error_for_date(length, input, msg, context);
753-
return 0;
750+
// Truncate to 3 digits (milliseconds precision) if more digits are provided
751+
while (sub_seconds_len > 3) {
752+
ts_fields[TimeFields::kSubSeconds] /= 10;
753+
sub_seconds_len--;
754754
}
755+
// Pad with zeros if less than 3 digits
755756
while (sub_seconds_len < 3) {
756757
ts_fields[TimeFields::kSubSeconds] *= 10;
757758
sub_seconds_len++;
@@ -867,12 +868,12 @@ gdv_time32 castTIME_utf8(int64_t context, const char* input, int32_t length) {
867868

868869
// adjust the milliseconds
869870
if (sub_seconds_len > 0) {
870-
if (sub_seconds_len > 3) {
871-
const char* msg = "Invalid millis for time value ";
872-
set_error_for_date(length, input, msg, context);
873-
return 0;
871+
// Truncate to 3 digits (milliseconds precision) if more digits are provided
872+
while (sub_seconds_len > 3) {
873+
time_fields[TimeFields::kSubSeconds - TimeFields::kHours] /= 10;
874+
sub_seconds_len--;
874875
}
875-
876+
// Pad with zeros if less than 3 digits
876877
while (sub_seconds_len < 3) {
877878
time_fields[TimeFields::kSubSeconds - TimeFields::kHours] *= 10;
878879
sub_seconds_len++;

cpp/src/gandiva/precompiled/time_test.cc

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,26 @@ TEST(TestTime, TestCastTimestamp) {
122122
"Not a valid time for timestamp value 2000-01-01 00:00:100");
123123
context.Reset();
124124

125-
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.0001", 24), 0);
126-
EXPECT_EQ(context.get_error(),
127-
"Invalid millis for timestamp value 2000-01-01 00:00:00.0001");
128-
context.Reset();
129-
130-
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.1000", 24), 0);
131-
EXPECT_EQ(context.get_error(),
132-
"Invalid millis for timestamp value 2000-01-01 00:00:00.1000");
133-
context.Reset();
125+
// Test truncation of subseconds to 3 digits (milliseconds)
126+
// "2000-01-01 00:00:00.0001" should truncate to "2000-01-01 00:00:00.000"
127+
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.0001", 24),
128+
castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.000", 23));
129+
130+
// "2000-01-01 00:00:00.1000" should truncate to "2000-01-01 00:00:00.100"
131+
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.1000", 24),
132+
castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.100", 23));
133+
134+
// "2000-01-01 00:00:00.123456789" should truncate to "2000-01-01 00:00:00.123"
135+
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.123456789", 29),
136+
castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.123", 23));
137+
138+
// "2000-01-01 00:00:00.1999" should truncate to "2000-01-01 00:00:00.199"
139+
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.1999", 24),
140+
castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.199", 23));
141+
142+
// "2000-01-01 00:00:00.1994" should truncate to "2000-01-01 00:00:00.199"
143+
EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.1994", 24),
144+
castTIMESTAMP_utf8(context_ptr, "2000-01-01 00:00:00.199", 23));
134145
}
135146

136147
TEST(TestTime, TestCastTimeUtf8) {
@@ -166,13 +177,26 @@ TEST(TestTime, TestCastTimeUtf8) {
166177
EXPECT_EQ(context.get_error(), "Not a valid time value 00:00:100");
167178
context.Reset();
168179

169-
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.0001", 13), 0);
170-
EXPECT_EQ(context.get_error(), "Invalid millis for time value 00:00:00.0001");
171-
context.Reset();
180+
// Test truncation of subseconds to 3 digits (milliseconds)
181+
// "00:00:00.0001" should truncate to "00:00:00.000"
182+
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.0001", 13),
183+
castTIME_utf8(context_ptr, "00:00:00.000", 12));
172184

173-
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.1000", 13), 0);
174-
EXPECT_EQ(context.get_error(), "Invalid millis for time value 00:00:00.1000");
175-
context.Reset();
185+
// "00:00:00.1000" should truncate to "00:00:00.100"
186+
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.1000", 13),
187+
castTIME_utf8(context_ptr, "00:00:00.100", 12));
188+
189+
// "9:45:30.123456789" should truncate to "9:45:30.123"
190+
EXPECT_EQ(castTIME_utf8(context_ptr, "9:45:30.123456789", 17),
191+
castTIME_utf8(context_ptr, "9:45:30.123", 11));
192+
193+
// "00:00:00.1999" should truncate to "00:00:00.199"
194+
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.1999", 13),
195+
castTIME_utf8(context_ptr, "00:00:00.199", 12));
196+
197+
// "00:00:00.1994" should truncate to "00:00:00.199"
198+
EXPECT_EQ(castTIME_utf8(context_ptr, "00:00:00.1994", 13),
199+
castTIME_utf8(context_ptr, "00:00:00.199", 12));
176200
}
177201

178202
#ifndef _WIN32

0 commit comments

Comments
 (0)