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