From 02f2acc0f1aee192cb6efc72b4d0f319a9b4306b Mon Sep 17 00:00:00 2001 From: Fokko Date: Sun, 23 Mar 2025 21:05:32 +0100 Subject: [PATCH 1/2] Add negative example --- bindings/python/tests/test_transform.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bindings/python/tests/test_transform.py b/bindings/python/tests/test_transform.py index 4a90df08a..6156f0d68 100644 --- a/bindings/python/tests/test_transform.py +++ b/bindings/python/tests/test_transform.py @@ -90,9 +90,15 @@ def test_day_transform(): def test_hour_transform(): - arr = pa.array([datetime(1970, 1, 1, 19, 1, 23), datetime(2000, 3, 1, 12, 1, 23)]) + arr = pa.array( + [ + datetime(1970, 1, 1, 19, 1, 23), + datetime(2000, 3, 1, 12, 1, 23), + datetime(22, 5, 1, 22, 1, 1), # Negative + ] + ) result = transform.hour(arr) - expected = pa.array([19, 264420], type=pa.int32()) + expected = pa.array([19, 264420, -17072906], type=pa.int32()) assert result == expected From e8eafe088917c6515dfe3f576b2cab70ef268cd4 Mon Sep 17 00:00:00 2001 From: Fokko Date: Sun, 23 Mar 2025 21:38:36 +0100 Subject: [PATCH 2/2] Hour Transform: Divide by i64 --- bindings/python/tests/test_transform.py | 2 +- crates/iceberg/src/transform/temporal.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bindings/python/tests/test_transform.py b/bindings/python/tests/test_transform.py index 6156f0d68..223977541 100644 --- a/bindings/python/tests/test_transform.py +++ b/bindings/python/tests/test_transform.py @@ -98,7 +98,7 @@ def test_hour_transform(): ] ) result = transform.hour(arr) - expected = pa.array([19, 264420, -17072906], type=pa.int32()) + expected = pa.array([19, 264420, -17072905], type=pa.int32()) assert result == expected diff --git a/crates/iceberg/src/transform/temporal.rs b/crates/iceberg/src/transform/temporal.rs index 5dd4ab063..c88e54384 100644 --- a/crates/iceberg/src/transform/temporal.rs +++ b/crates/iceberg/src/transform/temporal.rs @@ -30,8 +30,10 @@ use super::TransformFunction; use crate::spec::{Datum, PrimitiveLiteral, PrimitiveType}; use crate::{Error, ErrorKind, Result}; -/// Hour in one second. -const HOUR_PER_SECOND: f64 = 1.0_f64 / 3600.0_f64; +/// Microseconds in one hour. +const MICROSECONDS_PER_HOUR: i64 = 3_600_000_000; +/// Nanoseconds in one hour. +const NANOSECONDS_PER_HOUR: i64 = 3_600_000_000_000; /// Year of unix epoch. const UNIX_EPOCH_YEAR: i32 = 1970; /// One second in micros. @@ -335,12 +337,12 @@ pub struct Hour; impl Hour { #[inline] fn hour_timestamp_micro(v: i64) -> i32 { - (v as f64 / 1000.0 / 1000.0 * HOUR_PER_SECOND) as i32 + (v / MICROSECONDS_PER_HOUR) as i32 } #[inline] fn hour_timestamp_nano(v: i64) -> i32 { - (v as f64 / 1_000_000.0 / 1000.0 * HOUR_PER_SECOND) as i32 + (v / NANOSECONDS_PER_HOUR) as i32 } } @@ -2761,9 +2763,11 @@ mod test { // Test TimestampMicrosecond test_timestamp_and_tz_transform("2017-12-01 18:00:00.00", &hour, Datum::int(420042)); test_timestamp_and_tz_transform("1969-12-31 23:00:00.00", &hour, Datum::int(-1)); + test_timestamp_and_tz_transform("0022-05-01 22:01:01.00", &hour, Datum::int(-17072905)); // Test TimestampNanosecond test_timestamp_ns_and_tz_transform("2017-12-01 18:00:00.00", &hour, Datum::int(420042)); test_timestamp_ns_and_tz_transform("1969-12-31 23:00:00.00", &hour, Datum::int(-1)); + test_timestamp_ns_and_tz_transform("1900-05-01 22:01:01.00", &hour, Datum::int(-610705)); } }