Skip to main content

arrow_arith/
temporal.rs

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