namanjain24-sudo commented on code in PR #25326:
URL: https://github.com/apache/datafusion/pull/25326#discussion_r4052937018


##########
datafusion/functions/src/datetime/date_trunc.rs:
##########
@@ -778,26 +817,42 @@ fn general_date_trunc_array_fine_granularity<T: 
ArrowTimestampType>(
 
     if let Some(unit) = unit {
         let unit = unit.get();
-        // Truncation can only underflow within one `unit` of `i64::MIN`.
-        // Track that possibility while computing the common case so the loop
-        // remains infallible and can be vectorized.
-        let underflow_bound = i64::MIN + unit;
+        // Truncate the value shifted by the (whole-unit) timezone offset and
+        // shift back: `truncate_tz(v) == truncate_naive(v + offset) - offset`.
+        // For fine granularities the offset is a multiple of `unit` and 
cancels
+        // out; for hour/day it shifts the result as required.
+        let offset_in_unit = offset_nanos / nanos_per_unit(tu);
+        let add_lower = i64::MIN.saturating_sub(offset_in_unit);
+        let add_upper = i64::MAX.saturating_sub(offset_in_unit);
+        // Truncation of the shifted value can only underflow within one `unit`
+        // of `i64::MIN`. Track that (plus a wrapping shift at either extreme)
+        // while computing the common case so the loop remains infallible and
+        // can be vectorized.
+        let underflow_bound = i64::MIN + unit - offset_in_unit.min(0);
         let mut maybe_underflow = false;
         let values: Vec<i64> = array
             .values()
             .iter()
             .map(|value| {
-                maybe_underflow |= *value < underflow_bound;
-                value.wrapping_sub(value.rem_euclid(unit))
+                maybe_underflow |=
+                    *value < add_lower || *value > add_upper || *value < 
underflow_bound;
+                let shifted = value.wrapping_add(offset_in_unit);
+                shifted.wrapping_sub(shifted.rem_euclid(unit)) - offset_in_unit

Review Comment:
   This `- offset_in_unit` isn't wrapping, and it runs for every value before 
`maybe_underflow` is checked, so it panics in debug builds near the ends of the 
range. On this branch, `date_trunc('hour', ...)` over a `Timestamp(Second, 
"+05:00")` column holding `i64::MIN` or `i64::MAX` panics here with `attempt to 
subtract with overflow`; on `main` the same input returns `Timestamp ... out of 
range`.
   
   Since those values already set `maybe_underflow` and go through the checked 
path, `.wrapping_sub(offset_in_unit)` should be enough. Could be worth adding 
them to the underflow tests too.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to