This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 2d89500980 feat: support casting `Time32` to `Int64` (#8971)
2d89500980 is described below
commit 2d8950098071f647d250ab34ebc3c51d6dbdf7bd
Author: Trent Hauck <[email protected]>
AuthorDate: Thu Dec 11 11:33:49 2025 -0800
feat: support casting `Time32` to `Int64` (#8971)
# Which issue does this PR close?
- Closes https://github.com/apache/datafusion/issues/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
---
arrow-cast/src/cast/mod.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 90 insertions(+), 1 deletion(-)
diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs
index 00927340e5..f61c335938 100644
--- a/arrow-cast/src/cast/mod.rs
+++ b/arrow-cast/src/cast/mod.rs
@@ -312,7 +312,7 @@ pub fn can_cast_types(from_type: &DataType, to_type:
&DataType) -> bool {
// temporal casts
(Int32, Date32 | Date64 | Time32(_)) => true,
(Date32, Int32 | Int64) => true,
- (Time32(_), Int32) => true,
+ (Time32(_), Int32 | Int64) => true,
(Int64, Date64 | Date32 | Time64(_)) => true,
(Date64, Int64 | Int32) => true,
(Time64(_), Int64) => true,
@@ -1698,6 +1698,16 @@ pub fn cast_with_options(
(Time32(TimeUnit::Millisecond), Int32) => {
cast_reinterpret_arrays::<Time32MillisecondType, Int32Type>(array)
}
+ (Time32(TimeUnit::Second), Int64) => cast_with_options(
+ &cast_with_options(array, &Int32, cast_options)?,
+ &Int64,
+ cast_options,
+ ),
+ (Time32(TimeUnit::Millisecond), Int64) => cast_with_options(
+ &cast_with_options(array, &Int32, cast_options)?,
+ &Int64,
+ cast_options,
+ ),
(Int64, Date64) => cast_reinterpret_arrays::<Int64Type,
Date64Type>(array),
(Int64, Date32) => cast_with_options(
&cast_with_options(array, &Int32, cast_options)?,
@@ -12079,4 +12089,83 @@ mod tests {
// Verify the run-ends were cast correctly (run ends at 3, 6, 9)
assert_eq!(run_array.run_ends().values(), &[3i64, 6i64, 9i64]);
}
+
+ #[test]
+ fn test_cast_time32_second_to_int64() {
+ let array = Time32SecondArray::from(vec![1000, 2000, 3000]);
+ let array = Arc::new(array) as Arc<dyn Array>;
+ let to_type = DataType::Int64;
+ let cast_options = CastOptions::default();
+
+ assert!(can_cast_types(array.data_type(), &to_type));
+
+ let result = cast_with_options(&array, &to_type, &cast_options);
+ assert!(
+ result.is_ok(),
+ "Failed to cast Time32(Second) to Int64: {:?}",
+ result.err()
+ );
+
+ let cast_array = result.unwrap();
+ let cast_array =
cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
+
+ assert_eq!(cast_array.value(0), 1000);
+ assert_eq!(cast_array.value(1), 2000);
+ assert_eq!(cast_array.value(2), 3000);
+ }
+
+ #[test]
+ fn test_cast_time32_millisecond_to_int64() {
+ let array = Time32MillisecondArray::from(vec![1000, 2000, 3000]);
+ let array = Arc::new(array) as Arc<dyn Array>;
+ let to_type = DataType::Int64;
+ let cast_options = CastOptions::default();
+
+ assert!(can_cast_types(array.data_type(), &to_type));
+
+ let result = cast_with_options(&array, &to_type, &cast_options);
+ assert!(
+ result.is_ok(),
+ "Failed to cast Time32(Millisecond) to Int64: {:?}",
+ result.err()
+ );
+
+ let cast_array = result.unwrap();
+ let cast_array =
cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
+
+ assert_eq!(cast_array.value(0), 1000);
+ assert_eq!(cast_array.value(1), 2000);
+ assert_eq!(cast_array.value(2), 3000);
+ }
+
+ #[test]
+ fn test_cast_string_to_time32_second_to_int64() {
+ // Mimic: select arrow_cast('03:12:44'::time,
'Time32(Second)')::bigint;
+ // raised in https://github.com/apache/datafusion/issues/19036
+ let array = StringArray::from(vec!["03:12:44"]);
+ let array = Arc::new(array) as Arc<dyn Array>;
+ let cast_options = CastOptions::default();
+
+ // 1. Cast String to Time32(Second)
+ let time32_type = DataType::Time32(TimeUnit::Second);
+ let time32_array = cast_with_options(&array, &time32_type,
&cast_options).unwrap();
+
+ // 2. Cast Time32(Second) to Int64
+ let int64_type = DataType::Int64;
+ assert!(can_cast_types(time32_array.data_type(), &int64_type));
+
+ let result = cast_with_options(&time32_array, &int64_type,
&cast_options);
+
+ assert!(
+ result.is_ok(),
+ "Failed to cast Time32(Second) to Int64: {:?}",
+ result.err()
+ );
+
+ let cast_array = result.unwrap();
+ let cast_array =
cast_array.as_any().downcast_ref::<Int64Array>().unwrap();
+
+ // 03:12:44 = 3*3600 + 12*60 + 44 = 10800 + 720 + 44 = 11564
+ assert_eq!(cast_array.value(0), 11564);
+ }
}