This is an automated email from the ASF dual-hosted git repository.

mneumann 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 ab9c062789 fix: fixed trait functions clash 
get_date_time_part_extract_fn (#8221) (#9424)
ab9c062789 is described below

commit ab9c0627892586e5e45832999253d2877a54c3d4
Author: Mateusz Matejuk <[email protected]>
AuthorDate: Thu Feb 19 10:49:00 2026 +0100

    fix: fixed trait functions clash get_date_time_part_extract_fn (#8221) 
(#9424)
    
    # Which issue does this PR close?
    
    fixes #8221
    
    # Rationale for this change
    
    It blocks users from building if the overall build state in Cargo.lock
    has `Chrono` in versions >= 0.4.40.
    Recently `Chrono` added `quarter()` function that clashes with
    `Datelike`'s, and requires disambiguation, or build will fail. That also
    makes users unable to use it in larger projects.
    
    # What changes are included in this PR?
    
    `arrow-rs/arrow-arith/src/temporal.rs:91`
    `get_date_time_part_extract_fn()`
    
    I forced `DatePart::Quarter` to return `Datelike::quarter()`.
    With versions < 0.4.40 of `Chrono` it worked since it did not export
    this function.
    
    # Are these changes tested?
    
    Full testing suite is not failing.
    I added a few tests confirming that quarter() does it job, but those are
    not regression tests. Those will only test if the quarter() actually
    works.
    
    Build-related tests are difficult to achieve and require extra setup,
    moreover are very fragile.
    Benchmarks were run, no deviation was found.
    
    # Are there any user-facing changes?
    
    No, users should not be affected.
    
    ---------
    
    Co-authored-by: Marco Neumann <[email protected]>
---
 arrow-arith/src/temporal.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

diff --git a/arrow-arith/src/temporal.rs b/arrow-arith/src/temporal.rs
index 771d0f97b7..12970f4498 100644
--- a/arrow-arith/src/temporal.rs
+++ b/arrow-arith/src/temporal.rs
@@ -93,8 +93,10 @@ where
     T: ChronoDateExt + Datelike + Timelike,
 {
     match part {
-        DatePart::Quarter => |d| d.quarter() as i32,
         DatePart::Year => |d| d.year(),
+        // Datelike and ChronoDataExt does export .quarter() function
+        // for this case we needs to be clarified which version are we using
+        DatePart::Quarter => |d| Datelike::quarter(&d) as i32,
         DatePart::YearISO => |d| d.iso_week().year(),
         DatePart::Month => |d| d.month() as i32,
         DatePart::Week | DatePart::WeekISO => |d| d.iso_week().week() as i32,
@@ -791,6 +793,76 @@ mod tests {
         assert_eq!(1, b.value(0));
     }
 
+    #[test]
+    fn test_all_quarters_date64() {
+        // verify all 4 quarters return 1-4 (not 0-indexed!)
+        // 1767225600000 -> 2026-01-01 (Q1)
+        // 1775001600000 -> 2026-04-01 (Q2, +90 days: jan31+feb28+mar31)
+        // 1782864000000 -> 2026-07-01 (Q3, +181 days)
+        // 1790812800000 -> 2026-10-01 (Q4, +273 days)
+        let a: PrimitiveArray<Date64Type> = vec![
+            Some(1767225600000),
+            Some(1775001600000),
+            Some(1782864000000),
+            Some(1790812800000),
+            None,
+        ]
+        .into();
+
+        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
+        assert_eq!(1, b.value(0)); // jan -> q1
+        assert_eq!(2, b.value(1)); // apr -> q2
+        assert_eq!(3, b.value(2)); // jul -> q3
+        assert_eq!(4, b.value(3)); // oct -> q4
+        assert!(!b.is_valid(4));
+    }
+
+    #[test]
+    fn test_all_quarters_date32() {
+        // verify all 4 quarters for Date32 (days since epoch)
+        // 20454 -> 2026-01-01 (Q1)
+        // 20544 -> 2026-04-01 (Q2, +90 days)
+        // 20635 -> 2026-07-01 (Q3, +181 days)
+        // 20727 -> 2026-10-01 (Q4, +273 days)
+        let a: PrimitiveArray<Date32Type> =
+            vec![Some(20454), Some(20544), Some(20635), Some(20727), 
None].into();
+
+        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
+        assert_eq!(1, b.value(0));
+        assert_eq!(2, b.value(1));
+        assert_eq!(3, b.value(2));
+        assert_eq!(4, b.value(3));
+        assert!(!b.is_valid(4));
+    }
+
+    #[test]
+    fn test_quarter_timestamp_microsecond() {
+        // timestamps are in microseconds (ms * 1000)
+        // 1767225600000000 -> 2026-01-01 (Q1)
+        // 1782864000000000 -> 2026-07-01 (Q3)
+        let a: TimestampMicrosecondArray =
+            vec![Some(1767225600000000), None, Some(1782864000000000)].into();
+
+        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
+        assert_eq!(1, b.value(0));
+        assert!(!b.is_valid(1));
+        assert_eq!(3, b.value(2));
+    }
+
+    #[test]
+    fn test_quarter_timestamp_nanosecond() {
+        // same as `test_quarter_timestamp_microsecond` but nanosecond 
precision (ms * 1_000_000)
+        // 1775001600000000000 -> 2026-04-01 (Q2)
+        // 1790812800000000000 -> 2026-10-01 (Q4)
+        let a: TimestampNanosecondArray =
+            vec![Some(1775001600000000000), None, 
Some(1790812800000000000)].into();
+
+        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
+        assert_eq!(2, b.value(0));
+        assert!(!b.is_valid(1));
+        assert_eq!(4, b.value(2));
+    }
+
     #[test]
     fn test_temporal_array_date64_month() {
         //1514764800000 -> 2018-01-01

Reply via email to