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);
+    }
 }

Reply via email to