From 01709c7337be26af303983a0b270d52fe5b6b07c Mon Sep 17 00:00:00 2001 From: Benoit Boissinot Date: Fri, 19 Dec 2025 14:54:46 +0000 Subject: [PATCH] fix(arrow-cast): fix incorrect conversion MICROSECONDS / NANOSECONDS = 0, this should be NANOSECONDS / MILLISECONDS. Found with claude code audit. --- arrow-cast/src/cast/mod.rs | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs index 5f08dcbfc138..2d9923c9a299 100644 --- a/arrow-cast/src/cast/mod.rs +++ b/arrow-cast/src/cast/mod.rs @@ -1729,7 +1729,7 @@ pub fn cast_with_options( (Time32(TimeUnit::Millisecond), Time64(TimeUnit::Nanosecond)) => Ok(Arc::new( array .as_primitive::() - .unary::<_, Time64NanosecondType>(|x| x as i64 * (MICROSECONDS / NANOSECONDS)), + .unary::<_, Time64NanosecondType>(|x| x as i64 * (NANOSECONDS / MILLISECONDS)), )), (Time64(TimeUnit::Microsecond), Time32(TimeUnit::Second)) => Ok(Arc::new( @@ -13277,6 +13277,52 @@ mod tests { assert_eq!(cast_array.value(2), 3000); } + #[test] + fn test_cast_time32_millisecond_to_time64_nanosecond() { + let array = + Time32MillisecondArray::from(vec![Some(1_000), Some(2_000), None, Some(43_200_000)]); + let b = cast(&array, &DataType::Time64(TimeUnit::Nanosecond)).unwrap(); + let c = b.as_primitive::(); + assert_eq!(c.value(0), 1_000_000_000); + assert_eq!(c.value(1), 2_000_000_000); + assert!(c.is_null(2)); + assert_eq!(c.value(3), 43_200_000_000_000); + } + + #[test] + fn test_cast_time32_millisecond_to_time64_microsecond() { + let array = + Time32MillisecondArray::from(vec![Some(1_000), Some(2_000), None, Some(43_200_000)]); + let b = cast(&array, &DataType::Time64(TimeUnit::Microsecond)).unwrap(); + let c = b.as_primitive::(); + assert_eq!(c.value(0), 1_000_000); + assert_eq!(c.value(1), 2_000_000); + assert!(c.is_null(2)); + assert_eq!(c.value(3), 43_200_000_000); + } + + #[test] + fn test_cast_time32_second_to_time64_nanosecond() { + let array = Time32SecondArray::from(vec![Some(1), Some(60), None, Some(43_200)]); + let b = cast(&array, &DataType::Time64(TimeUnit::Nanosecond)).unwrap(); + let c = b.as_primitive::(); + assert_eq!(c.value(0), 1_000_000_000); + assert_eq!(c.value(1), 60_000_000_000); + assert!(c.is_null(2)); + assert_eq!(c.value(3), 43_200_000_000_000); + } + + #[test] + fn test_cast_time32_second_to_time64_microsecond() { + let array = Time32SecondArray::from(vec![Some(1), Some(60), None, Some(43_200)]); + let b = cast(&array, &DataType::Time64(TimeUnit::Microsecond)).unwrap(); + let c = b.as_primitive::(); + assert_eq!(c.value(0), 1_000_000); + assert_eq!(c.value(1), 60_000_000); + assert!(c.is_null(2)); + assert_eq!(c.value(3), 43_200_000_000); + } + #[test] fn test_cast_string_to_time32_second_to_int64() { // Mimic: select arrow_cast('03:12:44'::time, 'Time32(Second)')::bigint;