Skip to main content

arrow_arith/
temporal.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Defines temporal kernels for time and date related functions.
19
20use std::str::FromStr;
21use std::sync::Arc;
22
23use arrow_array::cast::AsArray;
24use cast::as_primitive_array;
25use chrono::{Datelike, TimeZone, Timelike, Utc};
26
27use arrow_array::temporal_conversions::{
28    MICROSECONDS, MICROSECONDS_IN_DAY, MILLISECONDS, MILLISECONDS_IN_DAY, NANOSECONDS,
29    NANOSECONDS_IN_DAY, SECONDS_IN_DAY, date32_to_datetime, date64_to_datetime,
30    timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_s_to_datetime,
31    timestamp_us_to_datetime,
32};
33use arrow_array::timezone::Tz;
34use arrow_array::types::*;
35use arrow_array::*;
36use arrow_schema::{ArrowError, DataType, IntervalUnit, TimeUnit};
37
38/// Valid parts to extract from date/time/timestamp arrays.
39///
40/// See [`date_part`].
41///
42/// Marked as non-exhaustive as may expand to support more types of
43/// date parts in the future.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45#[non_exhaustive]
46pub enum DatePart {
47    /// Quarter of the year, in range `1..=4`
48    Quarter,
49    /// Calendar year
50    Year,
51    /// ISO year, computed as per ISO 8601
52    YearISO,
53    /// Month in the year, in range `1..=12`
54    Month,
55    /// week of the year, in range `1..=53`, computed as per ISO 8601
56    Week,
57    /// ISO week of the year, in range `1..=53`
58    WeekISO,
59    /// Day of the month, in range `1..=31`
60    Day,
61    /// Day of the week, in range `0..=6`, where Sunday is `0`
62    DayOfWeekSunday0,
63    /// Day of the week, in range `0..=6`, where Monday is `0`
64    DayOfWeekMonday0,
65    /// Day of the week, in range `1..=7`, where Sunday is `1`
66    DayOfWeekSunday1,
67    /// ISO day of the week, in range `1..=7`, where Monday is `1`
68    DayOfWeekMonday1,
69    /// Day of year, in range `1..=366`
70    DayOfYear,
71    /// Hour of the day, in range `0..=23`
72    Hour,
73    /// Minute of the hour, in range `0..=59`
74    Minute,
75    /// Second of the minute, in range `0..=59`
76    Second,
77    /// Millisecond of the second
78    Millisecond,
79    /// Microsecond of the second
80    Microsecond,
81    /// Nanosecond of the second
82    Nanosecond,
83}
84
85impl std::fmt::Display for DatePart {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        write!(f, "{self:?}")
88    }
89}
90
91/// Parses a string into a [`DatePart`].
92///
93/// Matching is case-insensitive. The accepted names follow PostgreSQL's
94/// `EXTRACT` / `date_part` conventions (see
95/// <https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT>)
96/// and are aligned with the alias set accepted by `arrow-cast`'s
97/// `IntervalUnit::from_str` (plurals, short forms like `y`, `mon`, `ms`,
98/// `us`) so the two parsers round-trip on the names they share.
99///
100/// Names that do not map one-to-one onto a [`DatePart`] variant are
101/// intentionally not recognized:
102/// - `epoch` — a derived computation, not a date part.
103/// - `century`, `decade`, `millennium` — no matching [`DatePart`] variant.
104/// - `timezone`, `timezone_hour`, `timezone_minute` — not modeled by
105///   [`DatePart`].
106impl FromStr for DatePart {
107    type Err = ArrowError;
108
109    fn from_str(s: &str) -> Result<Self, ArrowError> {
110        Ok(match s.to_lowercase().as_str() {
111            "y" | "yr" | "yrs" | "year" | "years" => Self::Year,
112            "isoyear" => Self::YearISO,
113            "qtr" | "quarter" | "quarters" => Self::Quarter,
114            "mon" | "mons" | "month" | "months" => Self::Month,
115            "w" | "week" | "weeks" => Self::Week,
116            "isoweek" => Self::WeekISO,
117            "d" | "day" | "days" => Self::Day,
118            "dow" | "dayofweek" => Self::DayOfWeekSunday0,
119            "dow1" | "dayofweek1" => Self::DayOfWeekSunday1,
120            "isodow0" => Self::DayOfWeekMonday0,
121            "isodow" => Self::DayOfWeekMonday1,
122            "doy" | "dayofyear" => Self::DayOfYear,
123            "h" | "hr" | "hrs" | "hour" | "hours" => Self::Hour,
124            "m" | "min" | "mins" | "minute" | "minutes" => Self::Minute,
125            "s" | "sec" | "secs" | "second" | "seconds" => Self::Second,
126            "ms" | "msec" | "msecs" | "msecond" | "mseconds" | "millisecond" | "milliseconds" => {
127                Self::Millisecond
128            }
129            "us" | "usec" | "usecs" | "usecond" | "useconds" | "microsecond" | "microseconds" => {
130                Self::Microsecond
131            }
132            "nanosecond" | "nanoseconds" => Self::Nanosecond,
133            _ => {
134                return Err(ArrowError::InvalidArgumentError(format!(
135                    "Unknown date part: {s}"
136                )));
137            }
138        })
139    }
140}
141
142/// Returns function to extract relevant [`DatePart`] from types like a
143/// [`NaiveDateTime`] or [`DateTime`].
144///
145/// [`NaiveDateTime`]: chrono::NaiveDateTime
146/// [`DateTime`]: chrono::DateTime
147fn get_date_time_part_extract_fn<T>(part: DatePart) -> fn(T) -> i32
148where
149    T: ChronoDateExt + Datelike + Timelike,
150{
151    match part {
152        DatePart::Year => |d| d.year(),
153        // Datelike and ChronoDataExt does export .quarter() function
154        // for this case we needs to be clarified which version are we using
155        DatePart::Quarter => |d| Datelike::quarter(&d) as i32,
156        DatePart::YearISO => |d| d.iso_week().year(),
157        DatePart::Month => |d| d.month() as i32,
158        DatePart::Week | DatePart::WeekISO => |d| d.iso_week().week() as i32,
159        DatePart::Day => |d| d.day() as i32,
160        DatePart::DayOfWeekSunday0 => |d| d.num_days_from_sunday(),
161        DatePart::DayOfWeekMonday0 => |d| d.num_days_from_monday(),
162        DatePart::DayOfWeekSunday1 => |d| d.num_days_from_sunday() + 1,
163        DatePart::DayOfWeekMonday1 => |d| d.num_days_from_monday() + 1,
164        DatePart::DayOfYear => |d| d.ordinal() as i32,
165        DatePart::Hour => |d| d.hour() as i32,
166        DatePart::Minute => |d| d.minute() as i32,
167        DatePart::Second => |d| d.second() as i32,
168        DatePart::Millisecond => |d| (d.nanosecond() / 1_000_000) as i32,
169        DatePart::Microsecond => |d| (d.nanosecond() / 1_000) as i32,
170        DatePart::Nanosecond => |d| d.nanosecond() as i32,
171    }
172}
173
174/// Given an array, return a new array with the extracted [`DatePart`] as signed 32-bit
175/// integer values.
176///
177/// Currently only supports temporal types:
178///   - Date32/Date64
179///   - Time32/Time64
180///   - Timestamp
181///   - Interval
182///   - Duration
183///
184/// Returns an [`Int32Array`] unless input was a dictionary type, in which case returns
185/// the dictionary but with this function applied onto its values.
186///
187/// Null inputs produce null outputs. A timestamp outside the supported calendar
188/// range also produces null, except that for timestamps without a timezone the
189/// time parts (`Hour` through `Nanosecond`) are defined for every value.
190///
191/// If array passed in is not of the above listed types (or is a dictionary array where the
192/// values array isn't of the above listed types), then this function will return an error.
193///
194/// # Examples
195///
196/// ```
197/// # use arrow_array::{Int32Array, TimestampMicrosecondArray};
198/// # use arrow_arith::temporal::{DatePart, date_part};
199/// let input: TimestampMicrosecondArray =
200///     vec![Some(1612025847000000), None, Some(1722015847000000)].into();
201///
202/// let week = date_part(&input, DatePart::Week).unwrap();
203/// let week_iso = date_part(&input, DatePart::WeekISO).unwrap();
204/// let expected: Int32Array = vec![Some(4), None, Some(30)].into();
205/// assert_eq!(week.as_ref(), &expected);
206/// assert_eq!(week_iso.as_ref(), &expected);
207/// let year_iso = date_part(&input, DatePart::YearISO).unwrap();
208/// let expected: Int32Array = vec![Some(2021), None, Some(2024)].into();
209/// assert_eq!(year_iso.as_ref(), &expected);
210/// ```
211pub fn date_part(array: &dyn Array, part: DatePart) -> Result<ArrayRef, ArrowError> {
212    downcast_temporal_array!(
213        array => {
214            let array = array.date_part(part)?;
215            let array = Arc::new(array) as ArrayRef;
216            Ok(array)
217        }
218        DataType::Interval(IntervalUnit::YearMonth) => {
219            let array = as_primitive_array::<IntervalYearMonthType>(array).date_part(part)?;
220            let array = Arc::new(array) as ArrayRef;
221            Ok(array)
222        }
223        DataType::Interval(IntervalUnit::DayTime) => {
224            let array = as_primitive_array::<IntervalDayTimeType>(array).date_part(part)?;
225            let array = Arc::new(array) as ArrayRef;
226            Ok(array)
227        }
228        DataType::Interval(IntervalUnit::MonthDayNano) => {
229            let array = as_primitive_array::<IntervalMonthDayNanoType>(array).date_part(part)?;
230            let array = Arc::new(array) as ArrayRef;
231            Ok(array)
232        }
233        DataType::Duration(TimeUnit::Second) => {
234            let array = as_primitive_array::<DurationSecondType>(array).date_part(part)?;
235            let array = Arc::new(array) as ArrayRef;
236            Ok(array)
237        }
238        DataType::Duration(TimeUnit::Millisecond) => {
239            let array = as_primitive_array::<DurationMillisecondType>(array).date_part(part)?;
240            let array = Arc::new(array) as ArrayRef;
241            Ok(array)
242        }
243        DataType::Duration(TimeUnit::Microsecond) => {
244            let array = as_primitive_array::<DurationMicrosecondType>(array).date_part(part)?;
245            let array = Arc::new(array) as ArrayRef;
246            Ok(array)
247        }
248        DataType::Duration(TimeUnit::Nanosecond) => {
249            let array = as_primitive_array::<DurationNanosecondType>(array).date_part(part)?;
250            let array = Arc::new(array) as ArrayRef;
251            Ok(array)
252        }
253        DataType::Dictionary(_, _) => {
254            let array = array.as_any_dictionary();
255            let values = date_part(array.values(), part)?;
256            let new_array = array.with_values(values);
257            Ok(new_array)
258        }
259        DataType::RunEndEncoded(_, _) => {
260            let array = array.as_any_ree();
261            let values = date_part(array.values(), part)?;
262            let new_array = array.with_values(values);
263            Ok(new_array)
264        }
265        t => return_compute_error_with!(format!("{part} does not support"), t),
266    )
267}
268
269/// Extract optional [`Tz`] from timestamp data types, returning error
270/// if called with a non-timestamp type.
271fn get_tz(dt: &DataType) -> Result<Option<Tz>, ArrowError> {
272    match dt {
273        DataType::Timestamp(_, Some(tz)) => Ok(Some(tz.parse::<Tz>()?)),
274        DataType::Timestamp(_, None) => Ok(None),
275        _ => Err(ArrowError::CastError(format!("Not a timestamp type: {dt}"))),
276    }
277}
278
279/// Implement the specialized functions for extracting date part from temporal arrays.
280trait ExtractDatePartExt {
281    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError>;
282}
283
284impl ExtractDatePartExt for PrimitiveArray<Time32SecondType> {
285    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
286        #[inline]
287        fn range_check(s: i32) -> bool {
288            (0..SECONDS_IN_DAY as i32).contains(&s)
289        }
290        match part {
291            DatePart::Hour => Ok(self.unary_opt(|s| range_check(s).then_some(s / 3_600))),
292            DatePart::Minute => Ok(self.unary_opt(|s| range_check(s).then_some((s / 60) % 60))),
293            DatePart::Second => Ok(self.unary_opt(|s| range_check(s).then_some(s % 60))),
294            // Time32Second only encodes number of seconds, so these will always be 0 (if in valid range)
295            DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond => {
296                Ok(self.unary_opt(|s| range_check(s).then_some(0)))
297            }
298            _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
299        }
300    }
301}
302
303impl ExtractDatePartExt for PrimitiveArray<Time32MillisecondType> {
304    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
305        #[inline]
306        fn range_check(ms: i32) -> bool {
307            (0..MILLISECONDS_IN_DAY as i32).contains(&ms)
308        }
309        let milliseconds = MILLISECONDS as i32;
310        match part {
311            DatePart::Hour => {
312                Ok(self.unary_opt(|ms| range_check(ms).then_some(ms / 3_600 / milliseconds)))
313            }
314            DatePart::Minute => {
315                Ok(self.unary_opt(|ms| range_check(ms).then_some((ms / 60 / milliseconds) % 60)))
316            }
317            DatePart::Second => {
318                Ok(self.unary_opt(|ms| range_check(ms).then_some((ms / milliseconds) % 60)))
319            }
320            DatePart::Millisecond => {
321                Ok(self.unary_opt(|ms| range_check(ms).then_some(ms % milliseconds)))
322            }
323            DatePart::Microsecond => {
324                Ok(self.unary_opt(|ms| range_check(ms).then_some((ms % milliseconds) * 1_000)))
325            }
326            DatePart::Nanosecond => {
327                Ok(self.unary_opt(|ms| range_check(ms).then_some((ms % milliseconds) * 1_000_000)))
328            }
329            _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
330        }
331    }
332}
333
334impl ExtractDatePartExt for PrimitiveArray<Time64MicrosecondType> {
335    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
336        #[inline]
337        fn range_check(us: i64) -> bool {
338            (0..MICROSECONDS_IN_DAY).contains(&us)
339        }
340        match part {
341            DatePart::Hour => {
342                Ok(self
343                    .unary_opt(|us| range_check(us).then_some((us / 3_600 / MICROSECONDS) as i32)))
344            }
345            DatePart::Minute => Ok(self
346                .unary_opt(|us| range_check(us).then_some(((us / 60 / MICROSECONDS) % 60) as i32))),
347            DatePart::Second => {
348                Ok(self
349                    .unary_opt(|us| range_check(us).then_some(((us / MICROSECONDS) % 60) as i32)))
350            }
351            DatePart::Millisecond => Ok(self
352                .unary_opt(|us| range_check(us).then_some(((us % MICROSECONDS) / 1_000) as i32))),
353            DatePart::Microsecond => {
354                Ok(self.unary_opt(|us| range_check(us).then_some((us % MICROSECONDS) as i32)))
355            }
356            DatePart::Nanosecond => Ok(self
357                .unary_opt(|us| range_check(us).then_some(((us % MICROSECONDS) * 1_000) as i32))),
358            _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
359        }
360    }
361}
362
363impl ExtractDatePartExt for PrimitiveArray<Time64NanosecondType> {
364    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
365        #[inline]
366        fn range_check(ns: i64) -> bool {
367            (0..NANOSECONDS_IN_DAY).contains(&ns)
368        }
369        match part {
370            DatePart::Hour => {
371                Ok(self
372                    .unary_opt(|ns| range_check(ns).then_some((ns / 3_600 / NANOSECONDS) as i32)))
373            }
374            DatePart::Minute => Ok(self
375                .unary_opt(|ns| range_check(ns).then_some(((ns / 60 / NANOSECONDS) % 60) as i32))),
376            DatePart::Second => Ok(
377                self.unary_opt(|ns| range_check(ns).then_some(((ns / NANOSECONDS) % 60) as i32))
378            ),
379            DatePart::Millisecond => Ok(self.unary_opt(|ns| {
380                range_check(ns).then_some(((ns % NANOSECONDS) / 1_000_000) as i32)
381            })),
382            DatePart::Microsecond => {
383                Ok(self
384                    .unary_opt(|ns| range_check(ns).then_some(((ns % NANOSECONDS) / 1_000) as i32)))
385            }
386            DatePart::Nanosecond => {
387                Ok(self.unary_opt(|ns| range_check(ns).then_some((ns % NANOSECONDS) as i32)))
388            }
389            _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
390        }
391    }
392}
393
394impl ExtractDatePartExt for PrimitiveArray<Date32Type> {
395    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
396        // Date32 only encodes number of days, so these will always be 0
397        if let DatePart::Hour
398        | DatePart::Minute
399        | DatePart::Second
400        | DatePart::Millisecond
401        | DatePart::Microsecond
402        | DatePart::Nanosecond = part
403        {
404            Ok(Int32Array::new(
405                vec![0; self.len()].into(),
406                self.nulls().cloned(),
407            ))
408        } else {
409            let map_func = get_date_time_part_extract_fn(part);
410            Ok(self.unary_opt(|d| date32_to_datetime(d).map(map_func)))
411        }
412    }
413}
414
415impl ExtractDatePartExt for PrimitiveArray<Date64Type> {
416    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
417        let map_func = get_date_time_part_extract_fn(part);
418        Ok(self.unary_opt(|d| date64_to_datetime(d).map(map_func)))
419    }
420}
421
422/// Number of ticks in one second for timestamps of type `T`.
423const fn units_per_second<T: ArrowTimestampType>() -> i64 {
424    match T::UNIT {
425        TimeUnit::Second => 1,
426        TimeUnit::Millisecond => MILLISECONDS,
427        TimeUnit::Microsecond => MICROSECONDS,
428        TimeUnit::Nanosecond => NANOSECONDS,
429    }
430}
431
432/// Extracts a time-of-day part from a timestamp array without a timezone using
433/// integer arithmetic. Returns `None` for parts that require a calendar
434/// conversion.
435///
436/// `div_euclid` rounds toward negative infinity and `rem_euclid` yields a
437/// nonnegative remainder, so pre-epoch values produce in-range components:
438/// -1 ms is 1969-12-31 23:59:59.999, whose second is 59 and millisecond is 999.
439fn timestamp_time_part<T: ArrowTimestampType>(
440    array: &PrimitiveArray<T>,
441    part: DatePart,
442) -> Option<Int32Array> {
443    Some(match part {
444        DatePart::Hour => {
445            array.unary(|v| v.div_euclid(units_per_second::<T>() * 3_600).rem_euclid(24) as i32)
446        }
447        DatePart::Minute => {
448            array.unary(|v| v.div_euclid(units_per_second::<T>() * 60).rem_euclid(60) as i32)
449        }
450        DatePart::Second => {
451            array.unary(|v| v.div_euclid(units_per_second::<T>()).rem_euclid(60) as i32)
452        }
453        DatePart::Millisecond => {
454            array.unary(|v| subsecond(v, units_per_second::<T>(), MILLISECONDS))
455        }
456        DatePart::Microsecond => {
457            array.unary(|v| subsecond(v, units_per_second::<T>(), MICROSECONDS))
458        }
459        DatePart::Nanosecond => array.unary(|v| subsecond(v, units_per_second::<T>(), NANOSECONDS)),
460        _ => return None,
461    })
462}
463
464/// Fractional second of `v`, counted in `units` per second, rescaled to `target`
465/// per second. Both scales divide one second evenly, so the conversion is exact
466/// when scaling up and truncating when scaling down.
467#[inline]
468fn subsecond(v: i64, units: i64, target: i64) -> i32 {
469    let fraction = v.rem_euclid(units);
470    let scaled = if target >= units {
471        fraction * (target / units)
472    } else {
473        fraction / (units / target)
474    };
475    scaled as i32
476}
477
478impl ExtractDatePartExt for PrimitiveArray<TimestampSecondType> {
479    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
480        // TimestampSecond only encodes number of seconds, so these will always be 0
481        let array =
482            if let DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond = part {
483                Int32Array::new(vec![0; self.len()].into(), self.nulls().cloned())
484            } else if let Some(tz) = get_tz(self.data_type())? {
485                let map_func = get_date_time_part_extract_fn(part);
486                self.unary_opt(|d| {
487                    timestamp_s_to_datetime(d)
488                        .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz))
489                        .map(map_func)
490                })
491            } else if let Some(array) = timestamp_time_part(self, part) {
492                array
493            } else {
494                let map_func = get_date_time_part_extract_fn(part);
495                self.unary_opt(|d| timestamp_s_to_datetime(d).map(map_func))
496            };
497        Ok(array)
498    }
499}
500
501impl ExtractDatePartExt for PrimitiveArray<TimestampMillisecondType> {
502    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
503        let array = if let Some(tz) = get_tz(self.data_type())? {
504            let map_func = get_date_time_part_extract_fn(part);
505            self.unary_opt(|d| {
506                timestamp_ms_to_datetime(d)
507                    .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz))
508                    .map(map_func)
509            })
510        } else if let Some(array) = timestamp_time_part(self, part) {
511            array
512        } else {
513            let map_func = get_date_time_part_extract_fn(part);
514            self.unary_opt(|d| timestamp_ms_to_datetime(d).map(map_func))
515        };
516        Ok(array)
517    }
518}
519
520impl ExtractDatePartExt for PrimitiveArray<TimestampMicrosecondType> {
521    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
522        let array = if let Some(tz) = get_tz(self.data_type())? {
523            let map_func = get_date_time_part_extract_fn(part);
524            self.unary_opt(|d| {
525                timestamp_us_to_datetime(d)
526                    .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz))
527                    .map(map_func)
528            })
529        } else if let Some(array) = timestamp_time_part(self, part) {
530            array
531        } else {
532            let map_func = get_date_time_part_extract_fn(part);
533            self.unary_opt(|d| timestamp_us_to_datetime(d).map(map_func))
534        };
535        Ok(array)
536    }
537}
538
539impl ExtractDatePartExt for PrimitiveArray<TimestampNanosecondType> {
540    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
541        let array = if let Some(tz) = get_tz(self.data_type())? {
542            let map_func = get_date_time_part_extract_fn(part);
543            self.unary_opt(|d| {
544                timestamp_ns_to_datetime(d)
545                    .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz))
546                    .map(map_func)
547            })
548        } else if let Some(array) = timestamp_time_part(self, part) {
549            array
550        } else {
551            let map_func = get_date_time_part_extract_fn(part);
552            self.unary_opt(|d| timestamp_ns_to_datetime(d).map(map_func))
553        };
554        Ok(array)
555    }
556}
557
558impl ExtractDatePartExt for PrimitiveArray<IntervalYearMonthType> {
559    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
560        match part {
561            DatePart::Year => Ok(self.unary_opt(|d| Some(d / 12))),
562            DatePart::Month => Ok(self.unary_opt(|d| Some(d % 12))),
563
564            DatePart::Quarter
565            | DatePart::Week
566            | DatePart::WeekISO
567            | DatePart::YearISO
568            | DatePart::Day
569            | DatePart::DayOfWeekSunday0
570            | DatePart::DayOfWeekMonday0
571            | DatePart::DayOfWeekSunday1
572            | DatePart::DayOfWeekMonday1
573            | DatePart::DayOfYear
574            | DatePart::Hour
575            | DatePart::Minute
576            | DatePart::Second
577            | DatePart::Millisecond
578            | DatePart::Microsecond
579            | DatePart::Nanosecond => {
580                return_compute_error_with!(format!("{part} does not support"), self.data_type())
581            }
582        }
583    }
584}
585
586impl ExtractDatePartExt for PrimitiveArray<IntervalDayTimeType> {
587    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
588        match part {
589            DatePart::Week => Ok(self.unary_opt(|d| Some(d.days / 7))),
590            DatePart::Day => Ok(self.unary_opt(|d| Some(d.days))),
591            DatePart::Hour => Ok(self.unary_opt(|d| Some(d.milliseconds / (60 * 60 * 1_000)))),
592            DatePart::Minute => Ok(self.unary_opt(|d| Some(d.milliseconds / (60 * 1_000) % 60))),
593            DatePart::Second => Ok(self.unary_opt(|d| Some(d.milliseconds / 1_000 % 60))),
594            DatePart::Millisecond => Ok(self.unary_opt(|d| Some(d.milliseconds % (60 * 1_000)))),
595            DatePart::Microsecond => {
596                Ok(self.unary_opt(|d| (d.milliseconds % (60 * 1_000)).checked_mul(1_000)))
597            }
598            DatePart::Nanosecond => {
599                Ok(self.unary_opt(|d| (d.milliseconds % (60 * 1_000)).checked_mul(1_000_000)))
600            }
601
602            DatePart::Quarter
603            | DatePart::Year
604            | DatePart::YearISO
605            | DatePart::WeekISO
606            | DatePart::Month
607            | DatePart::DayOfWeekSunday0
608            | DatePart::DayOfWeekMonday0
609            | DatePart::DayOfWeekSunday1
610            | DatePart::DayOfWeekMonday1
611            | DatePart::DayOfYear => {
612                return_compute_error_with!(format!("{part} does not support"), self.data_type())
613            }
614        }
615    }
616}
617
618impl ExtractDatePartExt for PrimitiveArray<IntervalMonthDayNanoType> {
619    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
620        match part {
621            DatePart::Year => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.months / 12))),
622            DatePart::Month => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.months % 12))),
623            DatePart::Week => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.days / 7))),
624            DatePart::Day => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.days))),
625            DatePart::Hour => {
626                Ok(self.unary_opt(|d| (d.nanoseconds / (60 * 60 * 1_000_000_000)).try_into().ok()))
627            }
628            DatePart::Minute => {
629                Ok(self.unary_opt(|d| (d.nanoseconds / (60 * 1_000_000_000) % 60).try_into().ok()))
630            }
631            DatePart::Second => {
632                Ok(self.unary_opt(|d| ((d.nanoseconds / 1_000_000_000) % 60).try_into().ok()))
633            }
634            DatePart::Millisecond => Ok(self.unary_opt(|d| {
635                (d.nanoseconds % (60 * 1_000_000_000) / 1_000_000)
636                    .try_into()
637                    .ok()
638            })),
639            DatePart::Microsecond => Ok(self.unary_opt(|d| {
640                (d.nanoseconds % (60 * 1_000_000_000) / 1_000)
641                    .try_into()
642                    .ok()
643            })),
644            DatePart::Nanosecond => {
645                Ok(self.unary_opt(|d| (d.nanoseconds % (60 * 1_000_000_000)).try_into().ok()))
646            }
647
648            DatePart::Quarter
649            | DatePart::WeekISO
650            | DatePart::YearISO
651            | DatePart::DayOfWeekSunday0
652            | DatePart::DayOfWeekMonday0
653            | DatePart::DayOfWeekSunday1
654            | DatePart::DayOfWeekMonday1
655            | DatePart::DayOfYear => {
656                return_compute_error_with!(format!("{part} does not support"), self.data_type())
657            }
658        }
659    }
660}
661
662impl ExtractDatePartExt for PrimitiveArray<DurationSecondType> {
663    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
664        match part {
665            DatePart::Week => Ok(self.unary_opt(|d| (d / (60 * 60 * 24 * 7)).try_into().ok())),
666            DatePart::Day => Ok(self.unary_opt(|d| (d / (60 * 60 * 24)).try_into().ok())),
667            DatePart::Hour => Ok(self.unary_opt(|d| (d / (60 * 60)).try_into().ok())),
668            DatePart::Minute => Ok(self.unary_opt(|d| (d / 60).try_into().ok())),
669            DatePart::Second => Ok(self.unary_opt(|d| d.try_into().ok())),
670            DatePart::Millisecond => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
671            DatePart::Microsecond => {
672                Ok(self.unary_opt(|d| d.checked_mul(1_000_000)?.try_into().ok()))
673            }
674            DatePart::Nanosecond => {
675                Ok(self.unary_opt(|d| d.checked_mul(1_000_000_000)?.try_into().ok()))
676            }
677
678            DatePart::Year
679            | DatePart::YearISO
680            | DatePart::WeekISO
681            | DatePart::Quarter
682            | DatePart::Month
683            | DatePart::DayOfWeekSunday0
684            | DatePart::DayOfWeekMonday0
685            | DatePart::DayOfWeekSunday1
686            | DatePart::DayOfWeekMonday1
687            | DatePart::DayOfYear => {
688                return_compute_error_with!(format!("{part} does not support"), self.data_type())
689            }
690        }
691    }
692}
693
694impl ExtractDatePartExt for PrimitiveArray<DurationMillisecondType> {
695    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
696        match part {
697            DatePart::Week => {
698                Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24 * 7)).try_into().ok()))
699            }
700            DatePart::Day => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24)).try_into().ok())),
701            DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60)).try_into().ok())),
702            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000 * 60)).try_into().ok())),
703            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
704            DatePart::Millisecond => Ok(self.unary_opt(|d| d.try_into().ok())),
705            DatePart::Microsecond => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
706            DatePart::Nanosecond => {
707                Ok(self.unary_opt(|d| d.checked_mul(1_000_000)?.try_into().ok()))
708            }
709
710            DatePart::Year
711            | DatePart::YearISO
712            | DatePart::WeekISO
713            | DatePart::Quarter
714            | DatePart::Month
715            | DatePart::DayOfWeekSunday0
716            | DatePart::DayOfWeekMonday0
717            | DatePart::DayOfWeekSunday1
718            | DatePart::DayOfWeekMonday1
719            | DatePart::DayOfYear => {
720                return_compute_error_with!(format!("{part} does not support"), self.data_type())
721            }
722        }
723    }
724}
725
726impl ExtractDatePartExt for PrimitiveArray<DurationMicrosecondType> {
727    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
728        match part {
729            DatePart::Week => {
730                Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24 * 7)).try_into().ok()))
731            }
732            DatePart::Day => {
733                Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24)).try_into().ok()))
734            }
735            DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60)).try_into().ok())),
736            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000 * 60)).try_into().ok())),
737            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())),
738            DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
739            DatePart::Microsecond => Ok(self.unary_opt(|d| d.try_into().ok())),
740            DatePart::Nanosecond => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
741
742            DatePart::Year
743            | DatePart::YearISO
744            | DatePart::WeekISO
745            | DatePart::Quarter
746            | DatePart::Month
747            | DatePart::DayOfWeekSunday0
748            | DatePart::DayOfWeekMonday0
749            | DatePart::DayOfWeekSunday1
750            | DatePart::DayOfWeekMonday1
751            | DatePart::DayOfYear => {
752                return_compute_error_with!(format!("{part} does not support"), self.data_type())
753            }
754        }
755    }
756}
757
758impl ExtractDatePartExt for PrimitiveArray<DurationNanosecondType> {
759    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
760        match part {
761            DatePart::Week => {
762                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24 * 7)).try_into().ok()))
763            }
764            DatePart::Day => {
765                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24)).try_into().ok()))
766            }
767            DatePart::Hour => {
768                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60)).try_into().ok()))
769            }
770            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60)).try_into().ok())),
771            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000_000).try_into().ok())),
772            DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())),
773            DatePart::Microsecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
774            DatePart::Nanosecond => Ok(self.unary_opt(|d| d.try_into().ok())),
775
776            DatePart::Year
777            | DatePart::YearISO
778            | DatePart::WeekISO
779            | DatePart::Quarter
780            | DatePart::Month
781            | DatePart::DayOfWeekSunday0
782            | DatePart::DayOfWeekMonday0
783            | DatePart::DayOfWeekSunday1
784            | DatePart::DayOfWeekMonday1
785            | DatePart::DayOfYear => {
786                return_compute_error_with!(format!("{part} does not support"), self.data_type())
787            }
788        }
789    }
790}
791
792macro_rules! return_compute_error_with {
793    ($msg:expr, $param:expr) => {
794        return { Err(ArrowError::ComputeError(format!("{}: {}", $msg, $param))) }
795    };
796}
797
798pub(crate) use return_compute_error_with;
799
800// Internal trait, which is used for mapping values from DateLike structures
801trait ChronoDateExt {
802    /// Returns the day of week; Monday is encoded as `0`, Tuesday as `1`, etc.
803    fn num_days_from_monday(&self) -> i32;
804
805    /// Returns the day of week; Sunday is encoded as `0`, Monday as `1`, etc.
806    fn num_days_from_sunday(&self) -> i32;
807}
808
809impl<T: Datelike> ChronoDateExt for T {
810    fn num_days_from_monday(&self) -> i32 {
811        self.weekday().num_days_from_monday() as i32
812    }
813
814    fn num_days_from_sunday(&self) -> i32 {
815        self.weekday().num_days_from_sunday() as i32
816    }
817}
818
819#[cfg(test)]
820mod tests {
821    use super::*;
822
823    use arrow_array::temporal_conversions::as_datetime;
824    use chrono::NaiveDate;
825
826    /// Used to integrate new [`date_part()`] method with deprecated shims such as
827    /// [`hour()`] and [`week()`].
828    fn date_part_primitive<T: ArrowTemporalType>(
829        array: &PrimitiveArray<T>,
830        part: DatePart,
831    ) -> Result<Int32Array, ArrowError> {
832        let array = date_part(array, part)?;
833        Ok(array.as_primitive::<Int32Type>().to_owned())
834    }
835
836    /// Time-of-day parts of a timestamp.
837    const TIME_PARTS: [DatePart; 6] = [
838        DatePart::Hour,
839        DatePart::Minute,
840        DatePart::Second,
841        DatePart::Millisecond,
842        DatePart::Microsecond,
843        DatePart::Nanosecond,
844    ];
845
846    /// Checks time part extraction against the calendar conversion for values within
847    /// its supported range. Covers component boundaries, negative timestamps, nulls
848    /// and slices, plus timezone dispatch and invalid timezone metadata.
849    fn check_timestamp_time_parts<T: ArrowTimestampType>(units_per_second: i64) {
850        let mut values = vec![i64::MIN, i64::MAX];
851        for boundary in [1_000, 1_000_000] {
852            for delta in [-1, 0, 1] {
853                values.extend([boundary + delta, -boundary + delta]);
854            }
855        }
856        for base in [0, 60, 3_600, 86_400] {
857            for delta in [-1, 0, 1] {
858                for seconds in [base + delta, -base + delta] {
859                    for fraction in [-1, 0, 1, units_per_second - 1] {
860                        let value = i128::from(seconds) * i128::from(units_per_second)
861                            + i128::from(fraction);
862                        if let Ok(value) = i64::try_from(value) {
863                            values.push(value);
864                        }
865                    }
866                }
867            }
868        }
869        // Sample both the full i64 domain and dates near the epoch: most full-range
870        // second and millisecond timestamps are outside the supported calendar range.
871        let mut seed = 42_u64;
872        for _ in 0..256 {
873            seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
874            values.push(seed as i64);
875            let seconds = (seed % 4_000_000_000) as i64 - 2_000_000_000;
876            values.push(seconds * units_per_second + (seed % units_per_second as u64) as i64);
877        }
878        // The calendar conversion provides expected values only within its range.
879        // Behavior at the i64 extremes is checked separately.
880        values.retain(|&v| as_datetime::<T>(v).is_some());
881        let no_nulls = PrimitiveArray::<T>::new(values.clone().into(), None);
882        let mixed = PrimitiveArray::<T>::from_iter(
883            values
884                .iter()
885                .enumerate()
886                .map(|(i, &v)| (i % 5 != 0).then_some(v)),
887        );
888        for array in [no_nulls, mixed.slice(1, mixed.len() - 2)] {
889            for part in TIME_PARTS {
890                let map_func = get_date_time_part_extract_fn(part);
891                let expected: Int32Array = array.unary_opt(|v| as_datetime::<T>(v).map(map_func));
892                let actual = date_part(&array, part).unwrap();
893                assert_eq!(
894                    actual.as_primitive::<Int32Type>(),
895                    &expected,
896                    "{} {part}",
897                    T::DATA_TYPE
898                );
899            }
900        }
901
902        // An offset that changes both hour and minute checks that timezone metadata
903        // still routes through the calendar conversion.
904        let zoned = PrimitiveArray::<T>::from_iter_values([0]).with_timezone("+05:45");
905        for (part, expected) in [(DatePart::Hour, 5), (DatePart::Minute, 45)] {
906            assert_eq!(
907                date_part_primitive(&zoned, part).unwrap(),
908                Int32Array::from(vec![expected])
909            );
910        }
911        let invalid = PrimitiveArray::<T>::from_iter_values([0]).with_timezone("invalid timezone");
912        assert!(date_part(&invalid, DatePart::Second).is_err());
913    }
914
915    #[test]
916    fn test_timestamp_time_parts_match_chrono() {
917        check_timestamp_time_parts::<TimestampSecondType>(1);
918        check_timestamp_time_parts::<TimestampMillisecondType>(MILLISECONDS);
919        check_timestamp_time_parts::<TimestampMicrosecondType>(MICROSECONDS);
920        check_timestamp_time_parts::<TimestampNanosecondType>(NANOSECONDS);
921    }
922
923    #[test]
924    fn test_timestamp_time_parts_extremes() {
925        /// `(hour, minute, second, nanosecond)` expected at `i64::MIN` and `i64::MAX`.
926        fn check<T: ArrowTimestampType>(min: (u32, u32, u32, u32), max: (u32, u32, u32, u32)) {
927            let time = |(h, m, s, ns)| NaiveDate::default().and_hms_nano_opt(h, m, s, ns).unwrap();
928            let expected = [Some(time(min)), None, Some(time(max))];
929            let array = PrimitiveArray::<T>::from_iter([Some(i64::MIN), None, Some(i64::MAX)]);
930            for part in TIME_PARTS {
931                let map_func = get_date_time_part_extract_fn(part);
932                assert_eq!(
933                    date_part_primitive(&array, part).unwrap(),
934                    Int32Array::from_iter(expected.iter().map(|t| t.map(map_func))),
935                    "{} {part}",
936                    T::DATA_TYPE
937                );
938            }
939        }
940
941        // These values lie outside the supported calendar range for these units, so
942        // the expectations cannot be derived from the calendar conversion. Nanosecond
943        // extremes are within range and are covered by the comparison against it.
944        check::<TimestampSecondType>((8, 29, 52, 0), (15, 30, 7, 0));
945        check::<TimestampMillisecondType>((16, 47, 4, 192_000_000), (7, 12, 55, 807_000_000));
946        check::<TimestampMicrosecondType>((19, 59, 5, 224_192_000), (4, 0, 54, 775_807_000));
947    }
948
949    #[test]
950    fn test_temporal_array_date64_hour() {
951        let a: PrimitiveArray<Date64Type> =
952            vec![Some(1514764800000), None, Some(1550636625000)].into();
953
954        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
955        assert_eq!(0, b.value(0));
956        assert!(!b.is_valid(1));
957        assert_eq!(4, b.value(2));
958    }
959
960    #[test]
961    fn test_temporal_array_date32_hour() {
962        let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15148)].into();
963
964        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
965        assert_eq!(0, b.value(0));
966        assert!(!b.is_valid(1));
967        assert_eq!(0, b.value(2));
968    }
969
970    #[test]
971    fn test_temporal_array_time32_second_hour() {
972        let a: PrimitiveArray<Time32SecondType> = vec![37800, 86339].into();
973
974        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
975        assert_eq!(10, b.value(0));
976        assert_eq!(23, b.value(1));
977    }
978
979    #[test]
980    fn test_temporal_array_time64_micro_hour() {
981        let a: PrimitiveArray<Time64MicrosecondType> = vec![37800000000, 86339000000].into();
982
983        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
984        assert_eq!(10, b.value(0));
985        assert_eq!(23, b.value(1));
986    }
987
988    #[test]
989    fn test_temporal_array_timestamp_micro_hour() {
990        let a: TimestampMicrosecondArray = vec![37800000000, 86339000000].into();
991
992        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
993        assert_eq!(10, b.value(0));
994        assert_eq!(23, b.value(1));
995    }
996
997    #[test]
998    fn test_temporal_array_date64_year() {
999        let a: PrimitiveArray<Date64Type> =
1000            vec![Some(1514764800000), None, Some(1550636625000)].into();
1001
1002        let b = date_part_primitive(&a, DatePart::Year).unwrap();
1003        assert_eq!(2018, b.value(0));
1004        assert!(!b.is_valid(1));
1005        assert_eq!(2019, b.value(2));
1006    }
1007
1008    #[test]
1009    fn test_temporal_array_date32_year() {
1010        let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15448)].into();
1011
1012        let b = date_part_primitive(&a, DatePart::Year).unwrap();
1013        assert_eq!(2011, b.value(0));
1014        assert!(!b.is_valid(1));
1015        assert_eq!(2012, b.value(2));
1016    }
1017
1018    #[test]
1019    fn test_temporal_array_date64_quarter() {
1020        //1514764800000 -> 2018-01-01
1021        //1566275025000 -> 2019-08-20
1022        let a: PrimitiveArray<Date64Type> =
1023            vec![Some(1514764800000), None, Some(1566275025000)].into();
1024
1025        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1026        assert_eq!(1, b.value(0));
1027        assert!(!b.is_valid(1));
1028        assert_eq!(3, b.value(2));
1029    }
1030
1031    #[test]
1032    fn test_temporal_array_date32_quarter() {
1033        let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(300)].into();
1034
1035        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1036        assert_eq!(1, b.value(0));
1037        assert!(!b.is_valid(1));
1038        assert_eq!(4, b.value(2));
1039    }
1040
1041    #[test]
1042    fn test_temporal_array_timestamp_quarter_with_timezone() {
1043        // 24 * 60 * 60 = 86400
1044        let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("+00:00".to_string());
1045        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1046        assert_eq!(2, b.value(0));
1047        let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("-10:00".to_string());
1048        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1049        assert_eq!(1, b.value(0));
1050    }
1051
1052    #[test]
1053    fn test_all_quarters_date64() {
1054        // verify all 4 quarters return 1-4 (not 0-indexed!)
1055        // 1767225600000 -> 2026-01-01 (Q1)
1056        // 1775001600000 -> 2026-04-01 (Q2, +90 days: jan31+feb28+mar31)
1057        // 1782864000000 -> 2026-07-01 (Q3, +181 days)
1058        // 1790812800000 -> 2026-10-01 (Q4, +273 days)
1059        let a: PrimitiveArray<Date64Type> = vec![
1060            Some(1767225600000),
1061            Some(1775001600000),
1062            Some(1782864000000),
1063            Some(1790812800000),
1064            None,
1065        ]
1066        .into();
1067
1068        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1069        assert_eq!(1, b.value(0)); // jan -> q1
1070        assert_eq!(2, b.value(1)); // apr -> q2
1071        assert_eq!(3, b.value(2)); // jul -> q3
1072        assert_eq!(4, b.value(3)); // oct -> q4
1073        assert!(!b.is_valid(4));
1074    }
1075
1076    #[test]
1077    fn test_all_quarters_date32() {
1078        // verify all 4 quarters for Date32 (days since epoch)
1079        // 20454 -> 2026-01-01 (Q1)
1080        // 20544 -> 2026-04-01 (Q2, +90 days)
1081        // 20635 -> 2026-07-01 (Q3, +181 days)
1082        // 20727 -> 2026-10-01 (Q4, +273 days)
1083        let a: PrimitiveArray<Date32Type> =
1084            vec![Some(20454), Some(20544), Some(20635), Some(20727), None].into();
1085
1086        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1087        assert_eq!(1, b.value(0));
1088        assert_eq!(2, b.value(1));
1089        assert_eq!(3, b.value(2));
1090        assert_eq!(4, b.value(3));
1091        assert!(!b.is_valid(4));
1092    }
1093
1094    #[test]
1095    fn test_quarter_timestamp_microsecond() {
1096        // timestamps are in microseconds (ms * 1000)
1097        // 1767225600000000 -> 2026-01-01 (Q1)
1098        // 1782864000000000 -> 2026-07-01 (Q3)
1099        let a: TimestampMicrosecondArray =
1100            vec![Some(1767225600000000), None, Some(1782864000000000)].into();
1101
1102        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1103        assert_eq!(1, b.value(0));
1104        assert!(!b.is_valid(1));
1105        assert_eq!(3, b.value(2));
1106    }
1107
1108    #[test]
1109    fn test_quarter_timestamp_nanosecond() {
1110        // same as `test_quarter_timestamp_microsecond` but nanosecond precision (ms * 1_000_000)
1111        // 1775001600000000000 -> 2026-04-01 (Q2)
1112        // 1790812800000000000 -> 2026-10-01 (Q4)
1113        let a: TimestampNanosecondArray =
1114            vec![Some(1775001600000000000), None, Some(1790812800000000000)].into();
1115
1116        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
1117        assert_eq!(2, b.value(0));
1118        assert!(!b.is_valid(1));
1119        assert_eq!(4, b.value(2));
1120    }
1121
1122    #[test]
1123    fn test_temporal_array_date64_month() {
1124        //1514764800000 -> 2018-01-01
1125        //1550636625000 -> 2019-02-20
1126        let a: PrimitiveArray<Date64Type> =
1127            vec![Some(1514764800000), None, Some(1550636625000)].into();
1128
1129        let b = date_part_primitive(&a, DatePart::Month).unwrap();
1130        assert_eq!(1, b.value(0));
1131        assert!(!b.is_valid(1));
1132        assert_eq!(2, b.value(2));
1133    }
1134
1135    #[test]
1136    fn test_temporal_array_date32_month() {
1137        let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(31)].into();
1138
1139        let b = date_part_primitive(&a, DatePart::Month).unwrap();
1140        assert_eq!(1, b.value(0));
1141        assert!(!b.is_valid(1));
1142        assert_eq!(2, b.value(2));
1143    }
1144
1145    #[test]
1146    fn test_temporal_array_timestamp_month_with_timezone() {
1147        // 24 * 60 * 60 = 86400
1148        let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("+00:00".to_string());
1149        let b = date_part_primitive(&a, DatePart::Month).unwrap();
1150        assert_eq!(2, b.value(0));
1151        let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("-10:00".to_string());
1152        let b = date_part_primitive(&a, DatePart::Month).unwrap();
1153        assert_eq!(1, b.value(0));
1154    }
1155
1156    #[test]
1157    fn test_temporal_array_timestamp_day_with_timezone() {
1158        // 24 * 60 * 60 = 86400
1159        let a = TimestampSecondArray::from(vec![86400]).with_timezone("+00:00".to_string());
1160        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1161        assert_eq!(2, b.value(0));
1162        let a = TimestampSecondArray::from(vec![86400]).with_timezone("-10:00".to_string());
1163        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1164        assert_eq!(1, b.value(0));
1165    }
1166
1167    #[test]
1168    fn test_temporal_array_date64_weekday() {
1169        //1514764800000 -> 2018-01-01 (Monday)
1170        //1550636625000 -> 2019-02-20 (Wednesday)
1171        let a: PrimitiveArray<Date64Type> =
1172            vec![Some(1514764800000), None, Some(1550636625000)].into();
1173
1174        let b = date_part_primitive(&a, DatePart::DayOfWeekMonday0).unwrap();
1175        assert_eq!(0, b.value(0));
1176        assert!(!b.is_valid(1));
1177        assert_eq!(2, b.value(2));
1178    }
1179
1180    #[test]
1181    fn test_temporal_array_date64_dayofweek1() {
1182        //1514764800000 -> 2018-01-01 (Monday)
1183        //1550636625000 -> 2019-02-20 (Wednesday)
1184        //1483228800000 -> 2017-01-01 (Sunday)
1185        let a: PrimitiveArray<Date64Type> = vec![
1186            Some(1514764800000),
1187            None,
1188            Some(1550636625000),
1189            Some(1483228800000),
1190        ]
1191        .into();
1192
1193        let b = date_part_primitive(&a, DatePart::DayOfWeekSunday1).unwrap();
1194        assert_eq!(2, b.value(0));
1195        assert!(!b.is_valid(1));
1196        assert_eq!(4, b.value(2));
1197        assert_eq!(1, b.value(3));
1198    }
1199
1200    #[test]
1201    fn test_temporal_array_date64_isodow() {
1202        //1514764800000 -> 2018-01-01 (Monday)
1203        //1550636625000 -> 2019-02-20 (Wednesday)
1204        //1483228800000 -> 2017-01-01 (Sunday)
1205        let a: PrimitiveArray<Date64Type> = vec![
1206            Some(1514764800000),
1207            None,
1208            Some(1550636625000),
1209            Some(1483228800000),
1210        ]
1211        .into();
1212
1213        let b = date_part_primitive(&a, DatePart::DayOfWeekMonday1).unwrap();
1214        assert_eq!(1, b.value(0));
1215        assert!(!b.is_valid(1));
1216        assert_eq!(3, b.value(2));
1217        assert_eq!(7, b.value(3));
1218    }
1219
1220    #[test]
1221    fn test_temporal_array_date64_weekday0() {
1222        //1483228800000 -> 2017-01-01 (Sunday)
1223        //1514764800000 -> 2018-01-01 (Monday)
1224        //1550636625000 -> 2019-02-20 (Wednesday)
1225        let a: PrimitiveArray<Date64Type> = vec![
1226            Some(1483228800000),
1227            None,
1228            Some(1514764800000),
1229            Some(1550636625000),
1230        ]
1231        .into();
1232
1233        let b = date_part_primitive(&a, DatePart::DayOfWeekSunday0).unwrap();
1234        assert_eq!(0, b.value(0));
1235        assert!(!b.is_valid(1));
1236        assert_eq!(1, b.value(2));
1237        assert_eq!(3, b.value(3));
1238    }
1239
1240    #[test]
1241    fn test_temporal_array_date64_day() {
1242        //1514764800000 -> 2018-01-01
1243        //1550636625000 -> 2019-02-20
1244        let a: PrimitiveArray<Date64Type> =
1245            vec![Some(1514764800000), None, Some(1550636625000)].into();
1246
1247        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1248        assert_eq!(1, b.value(0));
1249        assert!(!b.is_valid(1));
1250        assert_eq!(20, b.value(2));
1251    }
1252
1253    #[test]
1254    fn test_temporal_array_date32_day() {
1255        let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(31)].into();
1256
1257        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1258        assert_eq!(1, b.value(0));
1259        assert!(!b.is_valid(1));
1260        assert_eq!(1, b.value(2));
1261    }
1262
1263    #[test]
1264    fn test_temporal_array_date64_doy() {
1265        //1483228800000 -> 2017-01-01 (Sunday)
1266        //1514764800000 -> 2018-01-01
1267        //1550636625000 -> 2019-02-20
1268        let a: PrimitiveArray<Date64Type> = vec![
1269            Some(1483228800000),
1270            Some(1514764800000),
1271            None,
1272            Some(1550636625000),
1273        ]
1274        .into();
1275
1276        let b = date_part_primitive(&a, DatePart::DayOfYear).unwrap();
1277        assert_eq!(1, b.value(0));
1278        assert_eq!(1, b.value(1));
1279        assert!(!b.is_valid(2));
1280        assert_eq!(51, b.value(3));
1281    }
1282
1283    #[test]
1284    fn test_temporal_array_timestamp_micro_year() {
1285        let a: TimestampMicrosecondArray =
1286            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1287
1288        let b = date_part_primitive(&a, DatePart::Year).unwrap();
1289        assert_eq!(2021, b.value(0));
1290        assert!(!b.is_valid(1));
1291        assert_eq!(2024, b.value(2));
1292    }
1293
1294    #[test]
1295    fn test_temporal_array_date64_minute() {
1296        let a: PrimitiveArray<Date64Type> =
1297            vec![Some(1514764800000), None, Some(1550636625000)].into();
1298
1299        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1300        assert_eq!(0, b.value(0));
1301        assert!(!b.is_valid(1));
1302        assert_eq!(23, b.value(2));
1303    }
1304
1305    #[test]
1306    fn test_temporal_array_timestamp_micro_minute() {
1307        let a: TimestampMicrosecondArray =
1308            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1309
1310        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1311        assert_eq!(57, b.value(0));
1312        assert!(!b.is_valid(1));
1313        assert_eq!(44, b.value(2));
1314    }
1315
1316    #[test]
1317    fn test_temporal_array_date32_week() {
1318        let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(7)].into();
1319
1320        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1321        assert_eq!(1, b.value(0));
1322        assert!(!b.is_valid(1));
1323        assert_eq!(2, b.value(2));
1324    }
1325
1326    #[test]
1327    fn test_temporal_array_date64_week() {
1328        // 1646116175000 -> 2022.03.01 , 1641171600000 -> 2022.01.03
1329        // 1640998800000 -> 2022.01.01
1330        let a: PrimitiveArray<Date64Type> = vec![
1331            Some(1646116175000),
1332            None,
1333            Some(1641171600000),
1334            Some(1640998800000),
1335        ]
1336        .into();
1337
1338        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1339        assert_eq!(9, b.value(0));
1340        assert!(!b.is_valid(1));
1341        assert_eq!(1, b.value(2));
1342        assert_eq!(52, b.value(3));
1343    }
1344
1345    #[test]
1346    fn test_temporal_array_timestamp_micro_week() {
1347        //1612025847000000 -> 2021.1.30
1348        //1722015847000000 -> 2024.7.27
1349        let a: TimestampMicrosecondArray =
1350            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1351
1352        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1353        assert_eq!(4, b.value(0));
1354        assert!(!b.is_valid(1));
1355        assert_eq!(30, b.value(2));
1356    }
1357
1358    #[test]
1359    fn test_temporal_array_date64_second() {
1360        let a: PrimitiveArray<Date64Type> =
1361            vec![Some(1514764800000), None, Some(1550636625000)].into();
1362
1363        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1364        assert_eq!(0, b.value(0));
1365        assert!(!b.is_valid(1));
1366        assert_eq!(45, b.value(2));
1367    }
1368
1369    #[test]
1370    fn test_temporal_array_timestamp_micro_second() {
1371        let a: TimestampMicrosecondArray =
1372            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1373
1374        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1375        assert_eq!(27, b.value(0));
1376        assert!(!b.is_valid(1));
1377        assert_eq!(7, b.value(2));
1378    }
1379
1380    #[test]
1381    fn test_temporal_array_timestamp_second_with_timezone() {
1382        let a = TimestampSecondArray::from(vec![10, 20]).with_timezone("+00:00".to_string());
1383        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1384        assert_eq!(10, b.value(0));
1385        assert_eq!(20, b.value(1));
1386    }
1387
1388    #[test]
1389    fn test_temporal_array_timestamp_minute_with_timezone() {
1390        let a = TimestampSecondArray::from(vec![0, 60]).with_timezone("+00:50".to_string());
1391        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1392        assert_eq!(50, b.value(0));
1393        assert_eq!(51, b.value(1));
1394    }
1395
1396    #[test]
1397    fn test_temporal_array_timestamp_minute_with_negative_timezone() {
1398        let a = TimestampSecondArray::from(vec![60 * 55]).with_timezone("-00:50".to_string());
1399        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1400        assert_eq!(5, b.value(0));
1401    }
1402
1403    #[test]
1404    fn test_temporal_array_timestamp_hour_with_timezone() {
1405        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01:00".to_string());
1406        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1407        assert_eq!(11, b.value(0));
1408    }
1409
1410    #[test]
1411    fn test_temporal_array_timestamp_hour_with_timezone_without_colon() {
1412        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+0100".to_string());
1413        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1414        assert_eq!(11, b.value(0));
1415    }
1416
1417    #[test]
1418    fn test_temporal_array_timestamp_hour_with_timezone_without_minutes() {
1419        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01".to_string());
1420        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1421        assert_eq!(11, b.value(0));
1422    }
1423
1424    #[test]
1425    fn test_temporal_array_timestamp_hour_with_timezone_without_initial_sign() {
1426        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("0100".to_string());
1427        let err = date_part_primitive(&a, DatePart::Hour)
1428            .unwrap_err()
1429            .to_string();
1430        assert!(err.contains("Invalid timezone"), "{}", err);
1431    }
1432
1433    #[test]
1434    fn test_temporal_array_timestamp_hour_with_timezone_with_only_colon() {
1435        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("01:00".to_string());
1436        let err = date_part_primitive(&a, DatePart::Hour)
1437            .unwrap_err()
1438            .to_string();
1439        assert!(err.contains("Invalid timezone"), "{}", err);
1440    }
1441
1442    #[test]
1443    fn test_temporal_array_timestamp_week_without_timezone() {
1444        // 1970-01-01T00:00:00                     -> 1970-01-01T00:00:00 Thursday (week 1)
1445        // 1970-01-01T00:00:00 + 4 days            -> 1970-01-05T00:00:00 Monday   (week 2)
1446        // 1970-01-01T00:00:00 + 4 days - 1 second -> 1970-01-04T23:59:59 Sunday   (week 1)
1447        let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1]);
1448        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1449        assert_eq!(1, b.value(0));
1450        assert_eq!(2, b.value(1));
1451        assert_eq!(1, b.value(2));
1452    }
1453
1454    #[test]
1455    fn test_temporal_array_timestamp_week_with_timezone() {
1456        // 1970-01-01T01:00:00+01:00                     -> 1970-01-01T01:00:00+01:00 Thursday (week 1)
1457        // 1970-01-01T01:00:00+01:00 + 4 days            -> 1970-01-05T01:00:00+01:00 Monday   (week 2)
1458        // 1970-01-01T01:00:00+01:00 + 4 days - 1 second -> 1970-01-05T00:59:59+01:00 Monday   (week 2)
1459        let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1])
1460            .with_timezone("+01:00".to_string());
1461        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1462        assert_eq!(1, b.value(0));
1463        assert_eq!(2, b.value(1));
1464        assert_eq!(2, b.value(2));
1465    }
1466
1467    #[test]
1468    fn test_hour_minute_second_dictionary_array() {
1469        let a = TimestampSecondArray::from(vec![
1470            60 * 60 * 10 + 61,
1471            60 * 60 * 20 + 122,
1472            60 * 60 * 30 + 183,
1473        ])
1474        .with_timezone("+01:00".to_string());
1475
1476        let keys = Int8Array::from_iter_values([0_i8, 0, 1, 2, 1]);
1477        let dict = DictionaryArray::try_new(keys.clone(), Arc::new(a)).unwrap();
1478
1479        let b = date_part(&dict, DatePart::Hour).unwrap();
1480
1481        let expected_dict =
1482            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![11, 21, 7])));
1483        let expected = Arc::new(expected_dict) as ArrayRef;
1484        assert_eq!(&expected, &b);
1485
1486        let b = date_part(&dict, DatePart::Minute).unwrap();
1487
1488        let b_old = date_part(&dict, DatePart::Minute).unwrap();
1489
1490        let expected_dict =
1491            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3])));
1492        let expected = Arc::new(expected_dict) as ArrayRef;
1493        assert_eq!(&expected, &b);
1494        assert_eq!(&expected, &b_old);
1495
1496        let b = date_part(&dict, DatePart::Second).unwrap();
1497
1498        let b_old = date_part(&dict, DatePart::Second).unwrap();
1499
1500        let expected_dict =
1501            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3])));
1502        let expected = Arc::new(expected_dict) as ArrayRef;
1503        assert_eq!(&expected, &b);
1504        assert_eq!(&expected, &b_old);
1505
1506        let b = date_part(&dict, DatePart::Nanosecond).unwrap();
1507
1508        let expected_dict =
1509            DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![0, 0, 0, 0, 0])));
1510        let expected = Arc::new(expected_dict) as ArrayRef;
1511        assert_eq!(&expected, &b);
1512    }
1513
1514    #[test]
1515    fn test_year_dictionary_array() {
1516        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into();
1517
1518        let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]);
1519        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1520
1521        let b = date_part(&dict, DatePart::Year).unwrap();
1522
1523        let expected_dict = DictionaryArray::new(
1524            keys,
1525            Arc::new(Int32Array::from(vec![2018, 2019, 2019, 2018])),
1526        );
1527        let expected = Arc::new(expected_dict) as ArrayRef;
1528        assert_eq!(&expected, &b);
1529    }
1530
1531    #[test]
1532    fn test_quarter_month_dictionary_array() {
1533        //1514764800000 -> 2018-01-01
1534        //1566275025000 -> 2019-08-20
1535        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1566275025000)].into();
1536
1537        let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]);
1538        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1539
1540        let b = date_part(&dict, DatePart::Quarter).unwrap();
1541
1542        let expected =
1543            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 3, 3, 1])));
1544        assert_eq!(b.as_ref(), &expected);
1545
1546        let b = date_part(&dict, DatePart::Month).unwrap();
1547
1548        let expected = DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![1, 8, 8, 1])));
1549        assert_eq!(b.as_ref(), &expected);
1550    }
1551
1552    #[test]
1553    fn test_num_days_from_monday_sunday_day_doy_week_dictionary_array() {
1554        //1514764800000 -> 2018-01-01 (Monday)
1555        //1550636625000 -> 2019-02-20 (Wednesday)
1556        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into();
1557
1558        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1), Some(0), None]);
1559        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1560
1561        let b = date_part(&dict, DatePart::DayOfWeekMonday0).unwrap();
1562
1563        let a = Int32Array::from(vec![Some(0), Some(2), Some(2), Some(0), None]);
1564        let expected = DictionaryArray::new(keys.clone(), Arc::new(a));
1565        assert_eq!(b.as_ref(), &expected);
1566
1567        let b = date_part(&dict, DatePart::DayOfWeekSunday0).unwrap();
1568
1569        let a = Int32Array::from(vec![Some(1), Some(3), Some(3), Some(1), None]);
1570        let expected = DictionaryArray::new(keys.clone(), Arc::new(a));
1571        assert_eq!(b.as_ref(), &expected);
1572
1573        let b = date_part(&dict, DatePart::Day).unwrap();
1574
1575        let a = Int32Array::from(vec![Some(1), Some(20), Some(20), Some(1), None]);
1576        let expected = DictionaryArray::new(keys.clone(), Arc::new(a));
1577        assert_eq!(b.as_ref(), &expected);
1578
1579        let b = date_part(&dict, DatePart::DayOfYear).unwrap();
1580
1581        let a = Int32Array::from(vec![Some(1), Some(51), Some(51), Some(1), None]);
1582        let expected = DictionaryArray::new(keys.clone(), Arc::new(a));
1583        assert_eq!(b.as_ref(), &expected);
1584
1585        let b = date_part(&dict, DatePart::Week).unwrap();
1586
1587        let a = Int32Array::from(vec![Some(1), Some(8), Some(8), Some(1), None]);
1588        let expected = DictionaryArray::new(keys, Arc::new(a));
1589        assert_eq!(b.as_ref(), &expected);
1590    }
1591
1592    #[test]
1593    fn test_temporal_array_date64_nanosecond() {
1594        // new Date(1667328721453)
1595        // Tue Nov 01 2022 11:52:01 GMT-0700 (Pacific Daylight Time)
1596        //
1597        // new Date(1667328721453).getMilliseconds()
1598        // 453
1599
1600        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1601
1602        let b = date_part_primitive(&a, DatePart::Nanosecond).unwrap();
1603        assert!(!b.is_valid(0));
1604        assert_eq!(453_000_000, b.value(1));
1605
1606        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1607        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1608        let b = date_part(&dict, DatePart::Nanosecond).unwrap();
1609
1610        let a = Int32Array::from(vec![None, Some(453_000_000)]);
1611        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1612        let expected = Arc::new(expected_dict) as ArrayRef;
1613        assert_eq!(&expected, &b);
1614    }
1615
1616    #[test]
1617    fn test_temporal_array_date64_microsecond() {
1618        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1619
1620        let b = date_part_primitive(&a, DatePart::Microsecond).unwrap();
1621        assert!(!b.is_valid(0));
1622        assert_eq!(453_000, b.value(1));
1623
1624        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1625        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1626        let b = date_part(&dict, DatePart::Microsecond).unwrap();
1627
1628        let a = Int32Array::from(vec![None, Some(453_000)]);
1629        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1630        let expected = Arc::new(expected_dict) as ArrayRef;
1631        assert_eq!(&expected, &b);
1632    }
1633
1634    #[test]
1635    fn test_temporal_array_date64_millisecond() {
1636        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1637
1638        let b = date_part_primitive(&a, DatePart::Millisecond).unwrap();
1639        assert!(!b.is_valid(0));
1640        assert_eq!(453, b.value(1));
1641
1642        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1643        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1644        let b = date_part(&dict, DatePart::Millisecond).unwrap();
1645
1646        let a = Int32Array::from(vec![None, Some(453)]);
1647        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1648        let expected = Arc::new(expected_dict) as ArrayRef;
1649        assert_eq!(&expected, &b);
1650    }
1651
1652    #[test]
1653    fn test_temporal_array_time64_nanoseconds() {
1654        // 23:32:50.123456789
1655        let input: Time64NanosecondArray = vec![Some(84_770_123_456_789)].into();
1656
1657        let actual = date_part(&input, DatePart::Hour).unwrap();
1658        let actual = actual.as_primitive::<Int32Type>();
1659        assert_eq!(23, actual.value(0));
1660
1661        let actual = date_part(&input, DatePart::Minute).unwrap();
1662        let actual = actual.as_primitive::<Int32Type>();
1663        assert_eq!(32, actual.value(0));
1664
1665        let actual = date_part(&input, DatePart::Second).unwrap();
1666        let actual = actual.as_primitive::<Int32Type>();
1667        assert_eq!(50, actual.value(0));
1668
1669        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1670        let actual = actual.as_primitive::<Int32Type>();
1671        assert_eq!(123, actual.value(0));
1672
1673        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1674        let actual = actual.as_primitive::<Int32Type>();
1675        assert_eq!(123_456, actual.value(0));
1676
1677        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1678        let actual = actual.as_primitive::<Int32Type>();
1679        assert_eq!(123_456_789, actual.value(0));
1680
1681        // invalid values should turn into null
1682        let input: Time64NanosecondArray = vec![
1683            Some(-1),
1684            Some(86_400_000_000_000),
1685            Some(86_401_000_000_000),
1686            None,
1687        ]
1688        .into();
1689        let actual = date_part(&input, DatePart::Hour).unwrap();
1690        let actual = actual.as_primitive::<Int32Type>();
1691        let expected: Int32Array = vec![None, None, None, None].into();
1692        assert_eq!(&expected, actual);
1693    }
1694
1695    #[test]
1696    fn test_temporal_array_time64_microseconds() {
1697        // 23:32:50.123456
1698        let input: Time64MicrosecondArray = vec![Some(84_770_123_456)].into();
1699
1700        let actual = date_part(&input, DatePart::Hour).unwrap();
1701        let actual = actual.as_primitive::<Int32Type>();
1702        assert_eq!(23, actual.value(0));
1703
1704        let actual = date_part(&input, DatePart::Minute).unwrap();
1705        let actual = actual.as_primitive::<Int32Type>();
1706        assert_eq!(32, actual.value(0));
1707
1708        let actual = date_part(&input, DatePart::Second).unwrap();
1709        let actual = actual.as_primitive::<Int32Type>();
1710        assert_eq!(50, actual.value(0));
1711
1712        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1713        let actual = actual.as_primitive::<Int32Type>();
1714        assert_eq!(123, actual.value(0));
1715
1716        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1717        let actual = actual.as_primitive::<Int32Type>();
1718        assert_eq!(123_456, actual.value(0));
1719
1720        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1721        let actual = actual.as_primitive::<Int32Type>();
1722        assert_eq!(123_456_000, actual.value(0));
1723
1724        // invalid values should turn into null
1725        let input: Time64MicrosecondArray =
1726            vec![Some(-1), Some(86_400_000_000), Some(86_401_000_000), None].into();
1727        let actual = date_part(&input, DatePart::Hour).unwrap();
1728        let actual = actual.as_primitive::<Int32Type>();
1729        let expected: Int32Array = vec![None, None, None, None].into();
1730        assert_eq!(&expected, actual);
1731    }
1732
1733    #[test]
1734    fn test_temporal_array_time32_milliseconds() {
1735        // 23:32:50.123
1736        let input: Time32MillisecondArray = vec![Some(84_770_123)].into();
1737
1738        let actual = date_part(&input, DatePart::Hour).unwrap();
1739        let actual = actual.as_primitive::<Int32Type>();
1740        assert_eq!(23, actual.value(0));
1741
1742        let actual = date_part(&input, DatePart::Minute).unwrap();
1743        let actual = actual.as_primitive::<Int32Type>();
1744        assert_eq!(32, actual.value(0));
1745
1746        let actual = date_part(&input, DatePart::Second).unwrap();
1747        let actual = actual.as_primitive::<Int32Type>();
1748        assert_eq!(50, actual.value(0));
1749
1750        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1751        let actual = actual.as_primitive::<Int32Type>();
1752        assert_eq!(123, actual.value(0));
1753
1754        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1755        let actual = actual.as_primitive::<Int32Type>();
1756        assert_eq!(123_000, actual.value(0));
1757
1758        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1759        let actual = actual.as_primitive::<Int32Type>();
1760        assert_eq!(123_000_000, actual.value(0));
1761
1762        // invalid values should turn into null
1763        let input: Time32MillisecondArray =
1764            vec![Some(-1), Some(86_400_000), Some(86_401_000), None].into();
1765        let actual = date_part(&input, DatePart::Hour).unwrap();
1766        let actual = actual.as_primitive::<Int32Type>();
1767        let expected: Int32Array = vec![None, None, None, None].into();
1768        assert_eq!(&expected, actual);
1769    }
1770
1771    #[test]
1772    fn test_temporal_array_time32_seconds() {
1773        // 23:32:50
1774        let input: Time32SecondArray = vec![84_770].into();
1775
1776        let actual = date_part(&input, DatePart::Hour).unwrap();
1777        let actual = actual.as_primitive::<Int32Type>();
1778        assert_eq!(23, actual.value(0));
1779
1780        let actual = date_part(&input, DatePart::Minute).unwrap();
1781        let actual = actual.as_primitive::<Int32Type>();
1782        assert_eq!(32, actual.value(0));
1783
1784        let actual = date_part(&input, DatePart::Second).unwrap();
1785        let actual = actual.as_primitive::<Int32Type>();
1786        assert_eq!(50, actual.value(0));
1787
1788        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1789        let actual = actual.as_primitive::<Int32Type>();
1790        assert_eq!(0, actual.value(0));
1791
1792        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1793        let actual = actual.as_primitive::<Int32Type>();
1794        assert_eq!(0, actual.value(0));
1795
1796        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1797        let actual = actual.as_primitive::<Int32Type>();
1798        assert_eq!(0, actual.value(0));
1799
1800        // invalid values should turn into null
1801        let input: Time32SecondArray = vec![Some(-1), Some(86_400), Some(86_401), None].into();
1802        let actual = date_part(&input, DatePart::Hour).unwrap();
1803        let actual = actual.as_primitive::<Int32Type>();
1804        let expected: Int32Array = vec![None, None, None, None].into();
1805        assert_eq!(&expected, actual);
1806    }
1807
1808    #[test]
1809    fn test_temporal_array_time_invalid_parts() {
1810        fn ensure_returns_error(array: &dyn Array) {
1811            let invalid_parts = [
1812                DatePart::Quarter,
1813                DatePart::Year,
1814                DatePart::YearISO,
1815                DatePart::Month,
1816                DatePart::Week,
1817                DatePart::WeekISO,
1818                DatePart::Day,
1819                DatePart::DayOfWeekSunday0,
1820                DatePart::DayOfWeekMonday0,
1821                DatePart::DayOfWeekSunday1,
1822                DatePart::DayOfWeekMonday1,
1823                DatePart::DayOfYear,
1824            ];
1825
1826            for part in invalid_parts {
1827                let err = date_part(array, part).unwrap_err();
1828                let expected = format!(
1829                    "Compute error: {part} does not support: {}",
1830                    array.data_type()
1831                );
1832                assert_eq!(expected, err.to_string());
1833            }
1834        }
1835
1836        ensure_returns_error(&Time32SecondArray::from(vec![0]));
1837        ensure_returns_error(&Time32MillisecondArray::from(vec![0]));
1838        ensure_returns_error(&Time64MicrosecondArray::from(vec![0]));
1839        ensure_returns_error(&Time64NanosecondArray::from(vec![0]));
1840    }
1841
1842    #[test]
1843    fn test_interval_year_month_array() {
1844        let input: IntervalYearMonthArray = vec![0, 5, 24].into();
1845
1846        let actual = date_part(&input, DatePart::Year).unwrap();
1847        let actual = actual.as_primitive::<Int32Type>();
1848        assert_eq!(0, actual.value(0));
1849        assert_eq!(0, actual.value(1));
1850        assert_eq!(2, actual.value(2));
1851
1852        let actual = date_part(&input, DatePart::Month).unwrap();
1853        let actual = actual.as_primitive::<Int32Type>();
1854        assert_eq!(0, actual.value(0));
1855        assert_eq!(5, actual.value(1));
1856        assert_eq!(0, actual.value(2));
1857
1858        assert!(date_part(&input, DatePart::Day).is_err());
1859        assert!(date_part(&input, DatePart::Week).is_err());
1860    }
1861
1862    // IntervalDayTimeType week, day, hour, minute, second, milli, u, nano;
1863    // invalid month, year; ignores the other part
1864    #[test]
1865    fn test_interval_day_time_array() {
1866        let input: IntervalDayTimeArray = vec![
1867            IntervalDayTime::ZERO,
1868            IntervalDayTime::new(10, 42),   // 10d, 42ms
1869            IntervalDayTime::new(10, 1042), // 10d, 1s, 42ms
1870            IntervalDayTime::new(10, MILLISECONDS_IN_DAY as i32 + 1), // 10d, 24h, 1ms
1871            IntervalDayTime::new(
1872                6,
1873                (MILLISECONDS * 60 * 60 * 4 + MILLISECONDS * 60 * 22 + MILLISECONDS * 11 + 3)
1874                    as i32,
1875            ), // 6d, 4h, 22m, 11s, 3ms
1876        ]
1877        .into();
1878
1879        // Time doesn't affect days.
1880        let actual = date_part(&input, DatePart::Day).unwrap();
1881        let actual = actual.as_primitive::<Int32Type>();
1882        assert_eq!(0, actual.value(0));
1883        assert_eq!(10, actual.value(1));
1884        assert_eq!(10, actual.value(2));
1885        assert_eq!(10, actual.value(3));
1886        assert_eq!(6, actual.value(4));
1887
1888        let actual = date_part(&input, DatePart::Week).unwrap();
1889        let actual = actual.as_primitive::<Int32Type>();
1890        assert_eq!(0, actual.value(0));
1891        assert_eq!(1, actual.value(1));
1892        assert_eq!(1, actual.value(2));
1893        assert_eq!(1, actual.value(3));
1894        assert_eq!(0, actual.value(4));
1895
1896        // Days doesn't affect time.
1897        let actual = date_part(&input, DatePart::Hour).unwrap();
1898        let actual = actual.as_primitive::<Int32Type>();
1899        assert_eq!(0, actual.value(0));
1900        assert_eq!(0, actual.value(1));
1901        assert_eq!(0, actual.value(2));
1902        assert_eq!(24, actual.value(3));
1903        assert_eq!(4, actual.value(4));
1904
1905        let actual = date_part(&input, DatePart::Minute).unwrap();
1906        let actual = actual.as_primitive::<Int32Type>();
1907        assert_eq!(0, actual.value(0));
1908        assert_eq!(0, actual.value(1));
1909        assert_eq!(0, actual.value(2));
1910        assert_eq!(0, actual.value(3));
1911        assert_eq!(22, actual.value(4));
1912
1913        let actual = date_part(&input, DatePart::Second).unwrap();
1914        let actual = actual.as_primitive::<Int32Type>();
1915        assert_eq!(0, actual.value(0));
1916        assert_eq!(0, actual.value(1));
1917        assert_eq!(1, actual.value(2));
1918        assert_eq!(0, actual.value(3));
1919        assert_eq!(11, actual.value(4));
1920
1921        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1922        let actual = actual.as_primitive::<Int32Type>();
1923        assert_eq!(0, actual.value(0));
1924        assert_eq!(42, actual.value(1));
1925        assert_eq!(1042, actual.value(2));
1926        assert_eq!(1, actual.value(3));
1927        assert_eq!(11003, actual.value(4));
1928
1929        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1930        let actual = actual.as_primitive::<Int32Type>();
1931        assert_eq!(0, actual.value(0));
1932        assert_eq!(42_000, actual.value(1));
1933        assert_eq!(1_042_000, actual.value(2));
1934        assert_eq!(1_000, actual.value(3));
1935        assert_eq!(11_003_000, actual.value(4));
1936
1937        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1938        let actual = actual.as_primitive::<Int32Type>();
1939        assert_eq!(0, actual.value(0));
1940        assert_eq!(42_000_000, actual.value(1));
1941        assert_eq!(1_042_000_000, actual.value(2));
1942        assert_eq!(1_000_000, actual.value(3));
1943        // Overflow returns zero.
1944        assert_eq!(0, actual.value(4));
1945
1946        // Month and year are not valid (since days in month varies).
1947        assert!(date_part(&input, DatePart::Month).is_err());
1948        assert!(date_part(&input, DatePart::Year).is_err());
1949    }
1950
1951    // IntervalMonthDayNanoType year -> nano;
1952    // days don't affect months, time doesn't affect days, time doesn't affect months (and vice versa)
1953    #[test]
1954    fn test_interval_month_day_nano_array() {
1955        let input: IntervalMonthDayNanoArray = vec![
1956            IntervalMonthDayNano::ZERO,
1957            IntervalMonthDayNano::new(5, 10, 42), // 5m, 1w, 3d, 42ns
1958            IntervalMonthDayNano::new(16, 35, NANOSECONDS_IN_DAY + 1), // 1y, 4m, 5w, 24h, 1ns
1959            IntervalMonthDayNano::new(
1960                0,
1961                0,
1962                NANOSECONDS * 60 * 60 * 4
1963                    + NANOSECONDS * 60 * 22
1964                    + NANOSECONDS * 11
1965                    + 1_000_000 * 33
1966                    + 1_000 * 44
1967                    + 5,
1968            ), // 4hr, 22m, 11s, 33ms, 44us, 5ns
1969        ]
1970        .into();
1971
1972        // Year and month follow from month, but are not affected by days or nanos.
1973        let actual = date_part(&input, DatePart::Year).unwrap();
1974        let actual = actual.as_primitive::<Int32Type>();
1975        assert_eq!(0, actual.value(0));
1976        assert_eq!(0, actual.value(1));
1977        assert_eq!(1, actual.value(2));
1978        assert_eq!(0, actual.value(3));
1979
1980        let actual = date_part(&input, DatePart::Month).unwrap();
1981        let actual = actual.as_primitive::<Int32Type>();
1982        assert_eq!(0, actual.value(0));
1983        assert_eq!(5, actual.value(1));
1984        assert_eq!(4, actual.value(2));
1985        assert_eq!(0, actual.value(3));
1986
1987        // Week and day follow from day, but are not affected by months or nanos.
1988        let actual = date_part(&input, DatePart::Week).unwrap();
1989        let actual = actual.as_primitive::<Int32Type>();
1990        assert_eq!(0, actual.value(0));
1991        assert_eq!(1, actual.value(1));
1992        assert_eq!(5, actual.value(2));
1993        assert_eq!(0, actual.value(3));
1994
1995        let actual = date_part(&input, DatePart::Day).unwrap();
1996        let actual = actual.as_primitive::<Int32Type>();
1997        assert_eq!(0, actual.value(0));
1998        assert_eq!(10, actual.value(1));
1999        assert_eq!(35, actual.value(2));
2000        assert_eq!(0, actual.value(3));
2001
2002        // Times follow from nanos, but are not affected by months or days.
2003        let actual = date_part(&input, DatePart::Hour).unwrap();
2004        let actual = actual.as_primitive::<Int32Type>();
2005        assert_eq!(0, actual.value(0));
2006        assert_eq!(0, actual.value(1));
2007        assert_eq!(24, actual.value(2));
2008        assert_eq!(4, actual.value(3));
2009
2010        let actual = date_part(&input, DatePart::Minute).unwrap();
2011        let actual = actual.as_primitive::<Int32Type>();
2012        assert_eq!(0, actual.value(0));
2013        assert_eq!(0, actual.value(1));
2014        assert_eq!(0, actual.value(2));
2015        assert_eq!(22, actual.value(3));
2016
2017        let actual = date_part(&input, DatePart::Second).unwrap();
2018        let actual = actual.as_primitive::<Int32Type>();
2019        assert_eq!(0, actual.value(0));
2020        assert_eq!(0, actual.value(1));
2021        assert_eq!(0, actual.value(2));
2022        assert_eq!(11, actual.value(3));
2023
2024        let actual = date_part(&input, DatePart::Millisecond).unwrap();
2025        let actual = actual.as_primitive::<Int32Type>();
2026        assert_eq!(0, actual.value(0));
2027        assert_eq!(0, actual.value(1));
2028        assert_eq!(0, actual.value(2));
2029        assert_eq!(11_033, actual.value(3));
2030
2031        let actual = date_part(&input, DatePart::Microsecond).unwrap();
2032        let actual = actual.as_primitive::<Int32Type>();
2033        assert_eq!(0, actual.value(0));
2034        assert_eq!(0, actual.value(1));
2035        assert_eq!(0, actual.value(2));
2036        assert_eq!(11_033_044, actual.value(3));
2037
2038        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2039        let actual = actual.as_primitive::<Int32Type>();
2040        assert_eq!(0, actual.value(0));
2041        assert_eq!(42, actual.value(1));
2042        assert_eq!(1, actual.value(2));
2043        // Overflow returns zero.
2044        assert_eq!(0, actual.value(3));
2045    }
2046
2047    #[test]
2048    fn test_interval_array_invalid_parts() {
2049        fn ensure_returns_error(array: &dyn Array) {
2050            let invalid_parts = [
2051                DatePart::Quarter,
2052                DatePart::YearISO,
2053                DatePart::WeekISO,
2054                DatePart::DayOfWeekSunday0,
2055                DatePart::DayOfWeekMonday0,
2056                DatePart::DayOfWeekSunday1,
2057                DatePart::DayOfWeekMonday1,
2058                DatePart::DayOfYear,
2059            ];
2060
2061            for part in invalid_parts {
2062                let err = date_part(array, part).unwrap_err();
2063                let expected = format!(
2064                    "Compute error: {part} does not support: {}",
2065                    array.data_type()
2066                );
2067                assert_eq!(expected, err.to_string());
2068            }
2069        }
2070
2071        ensure_returns_error(&IntervalYearMonthArray::from(vec![0]));
2072        ensure_returns_error(&IntervalDayTimeArray::from(vec![IntervalDayTime::ZERO]));
2073        ensure_returns_error(&IntervalMonthDayNanoArray::from(vec![
2074            IntervalMonthDayNano::ZERO,
2075        ]));
2076    }
2077
2078    #[test]
2079    fn test_duration_second() {
2080        let input: DurationSecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
2081
2082        let actual = date_part(&input, DatePart::Second).unwrap();
2083        let actual = actual.as_primitive::<Int32Type>();
2084        assert_eq!(0, actual.value(0));
2085        assert_eq!(42, actual.value(1));
2086        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
2087
2088        let actual = date_part(&input, DatePart::Millisecond).unwrap();
2089        let actual = actual.as_primitive::<Int32Type>();
2090        assert_eq!(0, actual.value(0));
2091        assert_eq!(42_000, actual.value(1));
2092        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
2093
2094        let actual = date_part(&input, DatePart::Microsecond).unwrap();
2095        let actual = actual.as_primitive::<Int32Type>();
2096        assert_eq!(0, actual.value(0));
2097        assert_eq!(42_000_000, actual.value(1));
2098        assert_eq!(0, actual.value(2));
2099
2100        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2101        let actual = actual.as_primitive::<Int32Type>();
2102        assert_eq!(0, actual.value(0));
2103        assert_eq!(0, actual.value(1));
2104        assert_eq!(0, actual.value(2));
2105    }
2106
2107    #[test]
2108    fn test_duration_millisecond() {
2109        let input: DurationMillisecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
2110
2111        let actual = date_part(&input, DatePart::Second).unwrap();
2112        let actual = actual.as_primitive::<Int32Type>();
2113        assert_eq!(0, actual.value(0));
2114        assert_eq!(0, actual.value(1));
2115        assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
2116
2117        let actual = date_part(&input, DatePart::Millisecond).unwrap();
2118        let actual = actual.as_primitive::<Int32Type>();
2119        assert_eq!(0, actual.value(0));
2120        assert_eq!(42, actual.value(1));
2121        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
2122
2123        let actual = date_part(&input, DatePart::Microsecond).unwrap();
2124        let actual = actual.as_primitive::<Int32Type>();
2125        assert_eq!(0, actual.value(0));
2126        assert_eq!(42_000, actual.value(1));
2127        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
2128
2129        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2130        let actual = actual.as_primitive::<Int32Type>();
2131        assert_eq!(0, actual.value(0));
2132        assert_eq!(42_000_000, actual.value(1));
2133        assert_eq!(0, actual.value(2));
2134    }
2135
2136    #[test]
2137    fn test_duration_microsecond() {
2138        let input: DurationMicrosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
2139
2140        let actual = date_part(&input, DatePart::Second).unwrap();
2141        let actual = actual.as_primitive::<Int32Type>();
2142        assert_eq!(0, actual.value(0));
2143        assert_eq!(0, actual.value(1));
2144        assert_eq!(0, actual.value(2));
2145
2146        let actual = date_part(&input, DatePart::Millisecond).unwrap();
2147        let actual = actual.as_primitive::<Int32Type>();
2148        assert_eq!(0, actual.value(0));
2149        assert_eq!(0, actual.value(1));
2150        assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
2151
2152        let actual = date_part(&input, DatePart::Microsecond).unwrap();
2153        let actual = actual.as_primitive::<Int32Type>();
2154        assert_eq!(0, actual.value(0));
2155        assert_eq!(42, actual.value(1));
2156        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
2157
2158        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2159        let actual = actual.as_primitive::<Int32Type>();
2160        assert_eq!(0, actual.value(0));
2161        assert_eq!(42_000, actual.value(1));
2162        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
2163    }
2164
2165    #[test]
2166    fn test_duration_nanosecond() {
2167        let input: DurationNanosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
2168
2169        let actual = date_part(&input, DatePart::Second).unwrap();
2170        let actual = actual.as_primitive::<Int32Type>();
2171        assert_eq!(0, actual.value(0));
2172        assert_eq!(0, actual.value(1));
2173        assert_eq!(0, actual.value(2));
2174
2175        let actual = date_part(&input, DatePart::Millisecond).unwrap();
2176        let actual = actual.as_primitive::<Int32Type>();
2177        assert_eq!(0, actual.value(0));
2178        assert_eq!(0, actual.value(1));
2179        assert_eq!(0, actual.value(2));
2180
2181        let actual = date_part(&input, DatePart::Microsecond).unwrap();
2182        let actual = actual.as_primitive::<Int32Type>();
2183        assert_eq!(0, actual.value(0));
2184        assert_eq!(0, actual.value(1));
2185        assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
2186
2187        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2188        let actual = actual.as_primitive::<Int32Type>();
2189        assert_eq!(0, actual.value(0));
2190        assert_eq!(42, actual.value(1));
2191        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
2192    }
2193
2194    #[test]
2195    fn test_duration_invalid_parts() {
2196        fn ensure_returns_error(array: &dyn Array) {
2197            let invalid_parts = [
2198                DatePart::Year,
2199                DatePart::YearISO,
2200                DatePart::Quarter,
2201                DatePart::Month,
2202                DatePart::WeekISO,
2203                DatePart::DayOfWeekSunday0,
2204                DatePart::DayOfWeekMonday0,
2205                DatePart::DayOfWeekSunday1,
2206                DatePart::DayOfWeekMonday1,
2207                DatePart::DayOfYear,
2208            ];
2209
2210            for part in invalid_parts {
2211                let err = date_part(array, part).unwrap_err();
2212                let expected = format!(
2213                    "Compute error: {part} does not support: {}",
2214                    array.data_type()
2215                );
2216                assert_eq!(expected, err.to_string());
2217            }
2218        }
2219
2220        ensure_returns_error(&DurationSecondArray::from(vec![0]));
2221        ensure_returns_error(&DurationMillisecondArray::from(vec![0]));
2222        ensure_returns_error(&DurationMicrosecondArray::from(vec![0]));
2223        ensure_returns_error(&DurationNanosecondArray::from(vec![0]));
2224    }
2225
2226    const TIMESTAMP_SECOND_1970_01_01: i64 = 0;
2227    const TIMESTAMP_SECOND_2018_01_01: i64 = 1_514_764_800;
2228    const TIMESTAMP_SECOND_2019_02_20: i64 = 1_550_636_625;
2229    const SECONDS_IN_DAY: i64 = 24 * 60 * 60;
2230    // In 2018 the ISO year and calendar year start on the same date— 2018-01-01 or 2018-W01-1
2231    #[test]
2232    fn test_temporal_array_date64_week_iso() {
2233        let a: PrimitiveArray<Date64Type> = vec![
2234            Some(TIMESTAMP_SECOND_2018_01_01 * 1000),
2235            Some(TIMESTAMP_SECOND_2019_02_20 * 1000),
2236        ]
2237        .into();
2238
2239        let b = date_part(&a, DatePart::WeekISO).unwrap();
2240        let actual = b.as_primitive::<Int32Type>();
2241        assert_eq!(1, actual.value(0));
2242        assert_eq!(8, actual.value(1));
2243    }
2244
2245    #[test]
2246    fn test_temporal_array_date64_year_iso() {
2247        let a: PrimitiveArray<Date64Type> = vec![
2248            Some(TIMESTAMP_SECOND_2018_01_01 * 1000),
2249            Some(TIMESTAMP_SECOND_2019_02_20 * 1000),
2250        ]
2251        .into();
2252
2253        let b = date_part(&a, DatePart::YearISO).unwrap();
2254        let actual = b.as_primitive::<Int32Type>();
2255        assert_eq!(2018, actual.value(0));
2256        assert_eq!(2019, actual.value(1));
2257    }
2258
2259    #[test]
2260    fn test_temporal_array_timestamp_week_iso() {
2261        let a = TimestampSecondArray::from(vec![
2262            TIMESTAMP_SECOND_1970_01_01, // 0 and is Thursday
2263            SECONDS_IN_DAY * 4,          //  Monday of week 2
2264            SECONDS_IN_DAY * 4 - 1,      // Sunday of week 1
2265        ]);
2266        let b = date_part(&a, DatePart::WeekISO).unwrap();
2267        let actual = b.as_primitive::<Int32Type>();
2268        assert_eq!(1, actual.value(0));
2269        assert_eq!(2, actual.value(1));
2270        assert_eq!(1, actual.value(2));
2271    }
2272
2273    #[test]
2274    fn test_temporal_array_timestamp_year_iso() {
2275        let a = TimestampSecondArray::from(vec![
2276            TIMESTAMP_SECOND_1970_01_01,
2277            SECONDS_IN_DAY * 4,
2278            SECONDS_IN_DAY * 4 - 1,
2279        ]);
2280        let b = date_part(&a, DatePart::YearISO).unwrap();
2281        let actual = b.as_primitive::<Int32Type>();
2282        assert_eq!(1970, actual.value(0));
2283        assert_eq!(1970, actual.value(1));
2284        assert_eq!(1970, actual.value(2));
2285    }
2286
2287    const TIMESTAMP_SECOND_2015_12_28: i64 = 1_451_260_800;
2288    const TIMESTAMP_SECOND_2016_01_03: i64 = 1_451_779_200;
2289    // January 1st 2016 is a Friday, so 2015 week 53 runs from
2290    // 2015-12-28 to 2016-01-03 inclusive, and
2291    // 2016 week 1 runs from 2016-01-04 to 2016-01-10 inclusive.
2292    #[test]
2293    fn test_temporal_array_date64_week_iso_edge_cases() {
2294        let a: PrimitiveArray<Date64Type> = vec![
2295            Some(TIMESTAMP_SECOND_2015_12_28 * 1000),
2296            Some(TIMESTAMP_SECOND_2016_01_03 * 1000),
2297            Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000),
2298        ]
2299        .into();
2300
2301        let b = date_part(&a, DatePart::WeekISO).unwrap();
2302        let actual = b.as_primitive::<Int32Type>();
2303        assert_eq!(53, actual.value(0));
2304        assert_eq!(53, actual.value(1));
2305        assert_eq!(1, actual.value(2));
2306    }
2307
2308    #[test]
2309    fn test_temporal_array_date64_year_iso_edge_cases() {
2310        let a: PrimitiveArray<Date64Type> = vec![
2311            Some(TIMESTAMP_SECOND_2015_12_28 * 1000),
2312            Some(TIMESTAMP_SECOND_2016_01_03 * 1000),
2313            Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000),
2314        ]
2315        .into();
2316
2317        let b = date_part(&a, DatePart::YearISO).unwrap();
2318        let actual = b.as_primitive::<Int32Type>();
2319        assert_eq!(2015, actual.value(0));
2320        assert_eq!(2015, actual.value(1));
2321        assert_eq!(2016, actual.value(2));
2322    }
2323
2324    #[test]
2325    fn test_temporal_array_timestamp_week_iso_edge_cases() {
2326        let a = TimestampSecondArray::from(vec![
2327            TIMESTAMP_SECOND_2015_12_28,
2328            TIMESTAMP_SECOND_2016_01_03,
2329            TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY,
2330        ]);
2331        let b = date_part(&a, DatePart::WeekISO).unwrap();
2332        let actual = b.as_primitive::<Int32Type>();
2333        assert_eq!(53, actual.value(0));
2334        assert_eq!(53, actual.value(1));
2335        assert_eq!(1, actual.value(2));
2336    }
2337
2338    #[test]
2339    fn test_temporal_array_timestamp_year_iso_edge_cases() {
2340        let a = TimestampSecondArray::from(vec![
2341            TIMESTAMP_SECOND_2015_12_28,
2342            TIMESTAMP_SECOND_2016_01_03,
2343            TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY,
2344        ]);
2345        let b = date_part(&a, DatePart::YearISO).unwrap();
2346        let actual = b.as_primitive::<Int32Type>();
2347        assert_eq!(2015, actual.value(0));
2348        assert_eq!(2015, actual.value(1));
2349        assert_eq!(2016, actual.value(2));
2350    }
2351
2352    #[test]
2353    fn test_ree_timestamp_year() {
2354        let vals: TimestampSecondArray =
2355            vec![Some(1514764800), Some(1550636625), Some(1550636625)].into();
2356        let run_ends = Int32Array::from(vec![1, 2, 3]);
2357        let ree = RunArray::try_new(&run_ends, &vals).unwrap();
2358
2359        let b = date_part(&ree, DatePart::Year).unwrap();
2360        let ree_result = b.as_run_opt::<Int32Type>().unwrap();
2361        let values = ree_result.values().as_primitive::<Int32Type>();
2362        assert_eq!(2018, values.value(0));
2363        assert_eq!(2019, values.value(1));
2364        assert_eq!(2019, values.value(2));
2365    }
2366
2367    #[test]
2368    fn test_ree_date64_month() {
2369        let vals: PrimitiveArray<Date64Type> =
2370            vec![Some(1514764800000), Some(1550636625000)].into();
2371        let run_ends = Int64Array::from(vec![2, 4]);
2372        let ree = RunArray::try_new(&run_ends, &vals).unwrap();
2373
2374        let b = date_part(&ree, DatePart::Month).unwrap();
2375        let ree_result = b.as_run_opt::<Int64Type>().unwrap();
2376        let values = ree_result.values().as_primitive::<Int32Type>();
2377        assert_eq!(1, values.value(0));
2378        assert_eq!(2, values.value(1));
2379    }
2380
2381    #[test]
2382    fn test_date_part_from_str() {
2383        let cases = [
2384            ("y", DatePart::Year),
2385            ("yr", DatePart::Year),
2386            ("year", DatePart::Year),
2387            ("years", DatePart::Year),
2388            ("YEAR", DatePart::Year),
2389            ("isoyear", DatePart::YearISO),
2390            ("qtr", DatePart::Quarter),
2391            ("quarter", DatePart::Quarter),
2392            ("quarters", DatePart::Quarter),
2393            ("mon", DatePart::Month),
2394            ("mons", DatePart::Month),
2395            ("month", DatePart::Month),
2396            ("MONTHS", DatePart::Month),
2397            ("w", DatePart::Week),
2398            ("week", DatePart::Week),
2399            ("isoweek", DatePart::WeekISO),
2400            ("d", DatePart::Day),
2401            ("day", DatePart::Day),
2402            ("dow", DatePart::DayOfWeekSunday0),
2403            ("DayOfWeek", DatePart::DayOfWeekSunday0),
2404            ("dow1", DatePart::DayOfWeekSunday1),
2405            ("dayofweek1", DatePart::DayOfWeekSunday1),
2406            ("DAYOFWEEK1", DatePart::DayOfWeekSunday1),
2407            ("isodow", DatePart::DayOfWeekMonday1),
2408            ("ISODOW", DatePart::DayOfWeekMonday1),
2409            ("doy", DatePart::DayOfYear),
2410            ("DayOfYear", DatePart::DayOfYear),
2411            ("h", DatePart::Hour),
2412            ("hr", DatePart::Hour),
2413            ("hour", DatePart::Hour),
2414            // Pin the famous `m`/`mon` ambiguity: `m` resolves to Minute,
2415            // matching `arrow-cast`'s `IntervalUnit::from_str`. Use `mon`
2416            // (or `month`) for Month.
2417            ("m", DatePart::Minute),
2418            ("min", DatePart::Minute),
2419            ("mins", DatePart::Minute),
2420            ("minute", DatePart::Minute),
2421            ("s", DatePart::Second),
2422            ("sec", DatePart::Second),
2423            ("second", DatePart::Second),
2424            ("ms", DatePart::Millisecond),
2425            ("msec", DatePart::Millisecond),
2426            ("mseconds", DatePart::Millisecond),
2427            ("millisecond", DatePart::Millisecond),
2428            ("us", DatePart::Microsecond),
2429            ("usec", DatePart::Microsecond),
2430            ("useconds", DatePart::Microsecond),
2431            ("microsecond", DatePart::Microsecond),
2432            ("nanosecond", DatePart::Nanosecond),
2433            ("nanoseconds", DatePart::Nanosecond),
2434        ];
2435        for (input, expected) in cases {
2436            assert_eq!(
2437                DatePart::from_str(input).unwrap(),
2438                expected,
2439                "parsing {input}"
2440            );
2441        }
2442    }
2443
2444    #[test]
2445    fn test_date_part_from_str_unknown() {
2446        // Names intentionally rejected — see the FromStr doc comment for why.
2447        let unknown = [
2448            "epoch",
2449            "century",
2450            "decade",
2451            "millennium",
2452            "timezone",
2453            "timezone_hour",
2454            "timezone_minute",
2455            // Whitespace is not trimmed — pin this so the behavior doesn't
2456            // change silently. Callers should trim before parsing.
2457            " year ",
2458            "year ",
2459            "",
2460            "nope",
2461        ];
2462        for s in unknown {
2463            let err = DatePart::from_str(s).unwrap_err();
2464            assert!(
2465                matches!(err, ArrowError::InvalidArgumentError(_)),
2466                "expected InvalidArgumentError for {s:?}, got: {err}"
2467            );
2468        }
2469    }
2470}