Skip to content

Commit 2d89500

Browse files
authored
feat: support casting Time32 to Int64 (#8971)
# Which issue does this PR close? - Closes apache/datafusion#19036 While this issue was raised on the datafusion side, I think this is where the underlying issue exists, i.e., that arrow cannot do the cast directly. # Rationale for this change It should be possible to directly go from a time32 to an int64, but currently it is not. # What changes are included in this PR? 1. Add match arms for needed cases. 2. Add test that mimics cast issue described in datafusion issue. # Are these changes tested? Yes, adds test to mimic the case described in the datafusion issue. # Are there any user-facing changes? No
1 parent cf8582b commit 2d89500

File tree

1 file changed

+90
-1
lines changed

1 file changed

+90
-1
lines changed

arrow-cast/src/cast/mod.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
312312
// temporal casts
313313
(Int32, Date32 | Date64 | Time32(_)) => true,
314314
(Date32, Int32 | Int64) => true,
315-
(Time32(_), Int32) => true,
315+
(Time32(_), Int32 | Int64) => true,
316316
(Int64, Date64 | Date32 | Time64(_)) => true,
317317
(Date64, Int64 | Int32) => true,
318318
(Time64(_), Int64) => true,
@@ -1698,6 +1698,16 @@ pub fn cast_with_options(
16981698
(Time32(TimeUnit::Millisecond), Int32) => {
16991699
cast_reinterpret_arrays::<Time32MillisecondType, Int32Type>(array)
17001700
}
1701+
(Time32(TimeUnit::Second), Int64) => cast_with_options(
1702+
&cast_with_options(array, &Int32, cast_options)?,
1703+
&Int64,
1704+
cast_options,
1705+
),
1706+
(Time32(TimeUnit::Millisecond), Int64) => cast_with_options(
1707+
&cast_with_options(array, &Int32, cast_options)?,
1708+
&Int64,
1709+
cast_options,
1710+
),
17011711
(Int64, Date64) => cast_reinterpret_arrays::<Int64Type, Date64Type>(array),
17021712
(Int64, Date32) => cast_with_options(
17031713
&cast_with_options(array, &Int32, cast_options)?,
@@ -12079,4 +12089,83 @@ mod tests {
1207912089
// Verify the run-ends were cast correctly (run ends at 3, 6, 9)
1208012090
assert_eq!(run_array.run_ends().values(), &[3i64, 6i64, 9i64]);
1208112091
}
12092+
12093+
#[test]
12094+
fn test_cast_time32_second_to_int64() {
12095+
let array = Time32SecondArray::from(vec![1000, 2000, 3000]);
12096+
let array = Arc::new(array) as Arc<dyn Array>;
12097+
let to_type = DataType::Int64;
12098+
let cast_options = CastOptions::default();
12099+
12100+
assert!(can_cast_types(array.data_type(), &to_type));
12101+
12102+
let result = cast_with_options(&array, &to_type, &cast_options);
12103+
assert!(
12104+
result.is_ok(),
12105+
"Failed to cast Time32(Second) to Int64: {:?}",
12106+
result.err()
12107+
);
12108+
12109+
let cast_array = result.unwrap();
12110+
let cast_array = cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
12111+
12112+
assert_eq!(cast_array.value(0), 1000);
12113+
assert_eq!(cast_array.value(1), 2000);
12114+
assert_eq!(cast_array.value(2), 3000);
12115+
}
12116+
12117+
#[test]
12118+
fn test_cast_time32_millisecond_to_int64() {
12119+
let array = Time32MillisecondArray::from(vec![1000, 2000, 3000]);
12120+
let array = Arc::new(array) as Arc<dyn Array>;
12121+
let to_type = DataType::Int64;
12122+
let cast_options = CastOptions::default();
12123+
12124+
assert!(can_cast_types(array.data_type(), &to_type));
12125+
12126+
let result = cast_with_options(&array, &to_type, &cast_options);
12127+
assert!(
12128+
result.is_ok(),
12129+
"Failed to cast Time32(Millisecond) to Int64: {:?}",
12130+
result.err()
12131+
);
12132+
12133+
let cast_array = result.unwrap();
12134+
let cast_array = cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
12135+
12136+
assert_eq!(cast_array.value(0), 1000);
12137+
assert_eq!(cast_array.value(1), 2000);
12138+
assert_eq!(cast_array.value(2), 3000);
12139+
}
12140+
12141+
#[test]
12142+
fn test_cast_string_to_time32_second_to_int64() {
12143+
// Mimic: select arrow_cast('03:12:44'::time, 'Time32(Second)')::bigint;
12144+
// raised in https://github.com/apache/datafusion/issues/19036
12145+
let array = StringArray::from(vec!["03:12:44"]);
12146+
let array = Arc::new(array) as Arc<dyn Array>;
12147+
let cast_options = CastOptions::default();
12148+
12149+
// 1. Cast String to Time32(Second)
12150+
let time32_type = DataType::Time32(TimeUnit::Second);
12151+
let time32_array = cast_with_options(&array, &time32_type, &cast_options).unwrap();
12152+
12153+
// 2. Cast Time32(Second) to Int64
12154+
let int64_type = DataType::Int64;
12155+
assert!(can_cast_types(time32_array.data_type(), &int64_type));
12156+
12157+
let result = cast_with_options(&time32_array, &int64_type, &cast_options);
12158+
12159+
assert!(
12160+
result.is_ok(),
12161+
"Failed to cast Time32(Second) to Int64: {:?}",
12162+
result.err()
12163+
);
12164+
12165+
let cast_array = result.unwrap();
12166+
let cast_array = cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
12167+
12168+
// 03:12:44 = 3*3600 + 12*60 + 44 = 10800 + 720 + 44 = 11564
12169+
assert_eq!(cast_array.value(0), 11564);
12170+
}
1208212171
}

0 commit comments

Comments
 (0)