mbutrovich commented on code in PR #11199:
URL: https://github.com/apache/arrow-rs/pull/11199#discussion_r4098305747


##########
arrow-cast/src/cast/mod.rs:
##########
@@ -645,11 +731,16 @@ fn timestamp_to_date32<T: ArrowTimestampType>(
                     .map(|d| Date32Type::from_naive_date(d.date_naive()))
             })?
         }
-        None => array.try_unary(|x| {
-            as_datetime::<T>(x)
-                .ok_or_else(|| err(x))
-                .map(|d| Date32Type::from_naive_date(d.date()))
-        })?,
+        None => {
+            // Date32 stores days since the epoch. Round down so that a 
timestamp
+            // just before the epoch belongs to the preceding day.
+            let days = |x: i64| x.div_euclid(SECONDS_IN_DAY * 
time_unit_multiple(&T::UNIT));
+            match T::UNIT {
+                // Every microsecond or nanosecond timestamp lies within the 
Date32 range.
+                TimeUnit::Microsecond | TimeUnit::Nanosecond => 
array.unary(|x| days(x) as i32),
+                _ => array.try_unary(|x| i32::try_from(days(x)).map_err(|_| 
err(x)))?,

Review Comment:
   With `safe: true`, should a day count that doesn't fit in `i32` produce 
`NULL` instead of an error? That's what `CastOptions::safe` documents, and the 
`Timestamp(Second)` to `Date64` cast right below this one handles overflow that 
way with `unary_opt`. The new doc line on 770 describes the current behavior 
accurately, but once it's documented it becomes harder to change later. The 
timezone branch of `timestamp_to_date32` ignores `safe` too, and that behavior 
predates this PR. If you'd rather keep this PR focused on performance, could 
you open an issue for honoring `safe` in both branches and link it here?



##########
arrow-cast/src/cast/mod.rs:
##########
@@ -674,6 +765,9 @@ fn timestamp_to_date32<T: ArrowTimestampType>(
 /// * `Date32` and `Date64`: precision lost when going to higher interval
 /// * `Time32` and `Time64`: precision lost when going to higher interval
 /// * `Timestamp` and `Date{32|64}`: precision lost when going to higher 
interval
+/// * `Timestamp` without a timezone to `Date32`, `Time32`, or `Time64`: 
supports
+///   timestamps outside Chrono's date range. A `Date32` day count that does 
not fit
+///   in `i32` returns an error, regardless of [`CastOptions::safe`].

Review Comment:
   This is the same question I raised on #11187, and I think it would be good 
to settle it once for both PRs. I'm not sure which behavior is better. After 
this PR, `i64::MAX` seconds casts to `Time64` without a timezone, but the same 
value with `+00:00` returns an error, as 
`test_cast_timestamp_date_time_timezone_validation` checks.
   
   If we'd like to keep the current semantics, the range check I suggested on 
#11187 would work here too: one branch-free pass over `values()` against 
Chrono's bounds, skipped for nanoseconds, with a fallback to the existing path. 
On `date_part` it cost about 0.7 us per 8192 values. I haven't measured it on 
the casts. If we keep the new behavior instead, the `api-change` label would 
make sure it shows up in the changelog. What do you and the other maintainers 
think?



-- 
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]

Reply via email to