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 => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
603            DatePart::Microsecond => {
604                Ok(self.unary_opt(|d| d.checked_mul(1_000_000)?.try_into().ok()))
605            }
606            DatePart::Nanosecond => {
607                Ok(self.unary_opt(|d| d.checked_mul(1_000_000_000)?.try_into().ok()))
608            }
609
610            DatePart::Year
611            | DatePart::YearISO
612            | DatePart::WeekISO
613            | DatePart::Quarter
614            | DatePart::Month
615            | DatePart::DayOfWeekSunday0
616            | DatePart::DayOfWeekMonday0
617            | DatePart::DayOfWeekSunday1
618            | DatePart::DayOfWeekMonday1
619            | DatePart::DayOfYear => {
620                return_compute_error_with!(format!("{part} does not support"), self.data_type())
621            }
622        }
623    }
624}
625
626impl ExtractDatePartExt for PrimitiveArray<DurationMillisecondType> {
627    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
628        match part {
629            DatePart::Week => {
630                Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24 * 7)).try_into().ok()))
631            }
632            DatePart::Day => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24)).try_into().ok())),
633            DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60)).try_into().ok())),
634            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000 * 60)).try_into().ok())),
635            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
636            DatePart::Millisecond => Ok(self.unary_opt(|d| d.try_into().ok())),
637            DatePart::Microsecond => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
638            DatePart::Nanosecond => {
639                Ok(self.unary_opt(|d| d.checked_mul(1_000_000)?.try_into().ok()))
640            }
641
642            DatePart::Year
643            | DatePart::YearISO
644            | DatePart::WeekISO
645            | DatePart::Quarter
646            | DatePart::Month
647            | DatePart::DayOfWeekSunday0
648            | DatePart::DayOfWeekMonday0
649            | DatePart::DayOfWeekSunday1
650            | DatePart::DayOfWeekMonday1
651            | DatePart::DayOfYear => {
652                return_compute_error_with!(format!("{part} does not support"), self.data_type())
653            }
654        }
655    }
656}
657
658impl ExtractDatePartExt for PrimitiveArray<DurationMicrosecondType> {
659    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
660        match part {
661            DatePart::Week => {
662                Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24 * 7)).try_into().ok()))
663            }
664            DatePart::Day => {
665                Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24)).try_into().ok()))
666            }
667            DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60)).try_into().ok())),
668            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000 * 60)).try_into().ok())),
669            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())),
670            DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
671            DatePart::Microsecond => Ok(self.unary_opt(|d| d.try_into().ok())),
672            DatePart::Nanosecond => Ok(self.unary_opt(|d| d.checked_mul(1_000)?.try_into().ok())),
673
674            DatePart::Year
675            | DatePart::YearISO
676            | DatePart::WeekISO
677            | DatePart::Quarter
678            | DatePart::Month
679            | DatePart::DayOfWeekSunday0
680            | DatePart::DayOfWeekMonday0
681            | DatePart::DayOfWeekSunday1
682            | DatePart::DayOfWeekMonday1
683            | DatePart::DayOfYear => {
684                return_compute_error_with!(format!("{part} does not support"), self.data_type())
685            }
686        }
687    }
688}
689
690impl ExtractDatePartExt for PrimitiveArray<DurationNanosecondType> {
691    fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
692        match part {
693            DatePart::Week => {
694                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24 * 7)).try_into().ok()))
695            }
696            DatePart::Day => {
697                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24)).try_into().ok()))
698            }
699            DatePart::Hour => {
700                Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60)).try_into().ok()))
701            }
702            DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60)).try_into().ok())),
703            DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000_000).try_into().ok())),
704            DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())),
705            DatePart::Microsecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())),
706            DatePart::Nanosecond => Ok(self.unary_opt(|d| d.try_into().ok())),
707
708            DatePart::Year
709            | DatePart::YearISO
710            | DatePart::WeekISO
711            | DatePart::Quarter
712            | DatePart::Month
713            | DatePart::DayOfWeekSunday0
714            | DatePart::DayOfWeekMonday0
715            | DatePart::DayOfWeekSunday1
716            | DatePart::DayOfWeekMonday1
717            | DatePart::DayOfYear => {
718                return_compute_error_with!(format!("{part} does not support"), self.data_type())
719            }
720        }
721    }
722}
723
724macro_rules! return_compute_error_with {
725    ($msg:expr, $param:expr) => {
726        return { Err(ArrowError::ComputeError(format!("{}: {}", $msg, $param))) }
727    };
728}
729
730pub(crate) use return_compute_error_with;
731
732// Internal trait, which is used for mapping values from DateLike structures
733trait ChronoDateExt {
734    /// Returns the day of week; Monday is encoded as `0`, Tuesday as `1`, etc.
735    fn num_days_from_monday(&self) -> i32;
736
737    /// Returns the day of week; Sunday is encoded as `0`, Monday as `1`, etc.
738    fn num_days_from_sunday(&self) -> i32;
739}
740
741impl<T: Datelike> ChronoDateExt for T {
742    fn num_days_from_monday(&self) -> i32 {
743        self.weekday().num_days_from_monday() as i32
744    }
745
746    fn num_days_from_sunday(&self) -> i32 {
747        self.weekday().num_days_from_sunday() as i32
748    }
749}
750
751#[cfg(test)]
752mod tests {
753    use super::*;
754
755    /// Used to integrate new [`date_part()`] method with deprecated shims such as
756    /// [`hour()`] and [`week()`].
757    fn date_part_primitive<T: ArrowTemporalType>(
758        array: &PrimitiveArray<T>,
759        part: DatePart,
760    ) -> Result<Int32Array, ArrowError> {
761        let array = date_part(array, part)?;
762        Ok(array.as_primitive::<Int32Type>().to_owned())
763    }
764
765    #[test]
766    fn test_temporal_array_date64_hour() {
767        let a: PrimitiveArray<Date64Type> =
768            vec![Some(1514764800000), None, Some(1550636625000)].into();
769
770        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
771        assert_eq!(0, b.value(0));
772        assert!(!b.is_valid(1));
773        assert_eq!(4, b.value(2));
774    }
775
776    #[test]
777    fn test_temporal_array_date32_hour() {
778        let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15148)].into();
779
780        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
781        assert_eq!(0, b.value(0));
782        assert!(!b.is_valid(1));
783        assert_eq!(0, b.value(2));
784    }
785
786    #[test]
787    fn test_temporal_array_time32_second_hour() {
788        let a: PrimitiveArray<Time32SecondType> = vec![37800, 86339].into();
789
790        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
791        assert_eq!(10, b.value(0));
792        assert_eq!(23, b.value(1));
793    }
794
795    #[test]
796    fn test_temporal_array_time64_micro_hour() {
797        let a: PrimitiveArray<Time64MicrosecondType> = vec![37800000000, 86339000000].into();
798
799        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
800        assert_eq!(10, b.value(0));
801        assert_eq!(23, b.value(1));
802    }
803
804    #[test]
805    fn test_temporal_array_timestamp_micro_hour() {
806        let a: TimestampMicrosecondArray = vec![37800000000, 86339000000].into();
807
808        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
809        assert_eq!(10, b.value(0));
810        assert_eq!(23, b.value(1));
811    }
812
813    #[test]
814    fn test_temporal_array_date64_year() {
815        let a: PrimitiveArray<Date64Type> =
816            vec![Some(1514764800000), None, Some(1550636625000)].into();
817
818        let b = date_part_primitive(&a, DatePart::Year).unwrap();
819        assert_eq!(2018, b.value(0));
820        assert!(!b.is_valid(1));
821        assert_eq!(2019, b.value(2));
822    }
823
824    #[test]
825    fn test_temporal_array_date32_year() {
826        let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15448)].into();
827
828        let b = date_part_primitive(&a, DatePart::Year).unwrap();
829        assert_eq!(2011, b.value(0));
830        assert!(!b.is_valid(1));
831        assert_eq!(2012, b.value(2));
832    }
833
834    #[test]
835    fn test_temporal_array_date64_quarter() {
836        //1514764800000 -> 2018-01-01
837        //1566275025000 -> 2019-08-20
838        let a: PrimitiveArray<Date64Type> =
839            vec![Some(1514764800000), None, Some(1566275025000)].into();
840
841        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
842        assert_eq!(1, b.value(0));
843        assert!(!b.is_valid(1));
844        assert_eq!(3, b.value(2));
845    }
846
847    #[test]
848    fn test_temporal_array_date32_quarter() {
849        let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(300)].into();
850
851        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
852        assert_eq!(1, b.value(0));
853        assert!(!b.is_valid(1));
854        assert_eq!(4, b.value(2));
855    }
856
857    #[test]
858    fn test_temporal_array_timestamp_quarter_with_timezone() {
859        // 24 * 60 * 60 = 86400
860        let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("+00:00".to_string());
861        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
862        assert_eq!(2, b.value(0));
863        let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("-10:00".to_string());
864        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
865        assert_eq!(1, b.value(0));
866    }
867
868    #[test]
869    fn test_all_quarters_date64() {
870        // verify all 4 quarters return 1-4 (not 0-indexed!)
871        // 1767225600000 -> 2026-01-01 (Q1)
872        // 1775001600000 -> 2026-04-01 (Q2, +90 days: jan31+feb28+mar31)
873        // 1782864000000 -> 2026-07-01 (Q3, +181 days)
874        // 1790812800000 -> 2026-10-01 (Q4, +273 days)
875        let a: PrimitiveArray<Date64Type> = vec![
876            Some(1767225600000),
877            Some(1775001600000),
878            Some(1782864000000),
879            Some(1790812800000),
880            None,
881        ]
882        .into();
883
884        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
885        assert_eq!(1, b.value(0)); // jan -> q1
886        assert_eq!(2, b.value(1)); // apr -> q2
887        assert_eq!(3, b.value(2)); // jul -> q3
888        assert_eq!(4, b.value(3)); // oct -> q4
889        assert!(!b.is_valid(4));
890    }
891
892    #[test]
893    fn test_all_quarters_date32() {
894        // verify all 4 quarters for Date32 (days since epoch)
895        // 20454 -> 2026-01-01 (Q1)
896        // 20544 -> 2026-04-01 (Q2, +90 days)
897        // 20635 -> 2026-07-01 (Q3, +181 days)
898        // 20727 -> 2026-10-01 (Q4, +273 days)
899        let a: PrimitiveArray<Date32Type> =
900            vec![Some(20454), Some(20544), Some(20635), Some(20727), None].into();
901
902        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
903        assert_eq!(1, b.value(0));
904        assert_eq!(2, b.value(1));
905        assert_eq!(3, b.value(2));
906        assert_eq!(4, b.value(3));
907        assert!(!b.is_valid(4));
908    }
909
910    #[test]
911    fn test_quarter_timestamp_microsecond() {
912        // timestamps are in microseconds (ms * 1000)
913        // 1767225600000000 -> 2026-01-01 (Q1)
914        // 1782864000000000 -> 2026-07-01 (Q3)
915        let a: TimestampMicrosecondArray =
916            vec![Some(1767225600000000), None, Some(1782864000000000)].into();
917
918        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
919        assert_eq!(1, b.value(0));
920        assert!(!b.is_valid(1));
921        assert_eq!(3, b.value(2));
922    }
923
924    #[test]
925    fn test_quarter_timestamp_nanosecond() {
926        // same as `test_quarter_timestamp_microsecond` but nanosecond precision (ms * 1_000_000)
927        // 1775001600000000000 -> 2026-04-01 (Q2)
928        // 1790812800000000000 -> 2026-10-01 (Q4)
929        let a: TimestampNanosecondArray =
930            vec![Some(1775001600000000000), None, Some(1790812800000000000)].into();
931
932        let b = date_part_primitive(&a, DatePart::Quarter).unwrap();
933        assert_eq!(2, b.value(0));
934        assert!(!b.is_valid(1));
935        assert_eq!(4, b.value(2));
936    }
937
938    #[test]
939    fn test_temporal_array_date64_month() {
940        //1514764800000 -> 2018-01-01
941        //1550636625000 -> 2019-02-20
942        let a: PrimitiveArray<Date64Type> =
943            vec![Some(1514764800000), None, Some(1550636625000)].into();
944
945        let b = date_part_primitive(&a, DatePart::Month).unwrap();
946        assert_eq!(1, b.value(0));
947        assert!(!b.is_valid(1));
948        assert_eq!(2, b.value(2));
949    }
950
951    #[test]
952    fn test_temporal_array_date32_month() {
953        let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(31)].into();
954
955        let b = date_part_primitive(&a, DatePart::Month).unwrap();
956        assert_eq!(1, b.value(0));
957        assert!(!b.is_valid(1));
958        assert_eq!(2, b.value(2));
959    }
960
961    #[test]
962    fn test_temporal_array_timestamp_month_with_timezone() {
963        // 24 * 60 * 60 = 86400
964        let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("+00:00".to_string());
965        let b = date_part_primitive(&a, DatePart::Month).unwrap();
966        assert_eq!(2, b.value(0));
967        let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("-10:00".to_string());
968        let b = date_part_primitive(&a, DatePart::Month).unwrap();
969        assert_eq!(1, b.value(0));
970    }
971
972    #[test]
973    fn test_temporal_array_timestamp_day_with_timezone() {
974        // 24 * 60 * 60 = 86400
975        let a = TimestampSecondArray::from(vec![86400]).with_timezone("+00:00".to_string());
976        let b = date_part_primitive(&a, DatePart::Day).unwrap();
977        assert_eq!(2, b.value(0));
978        let a = TimestampSecondArray::from(vec![86400]).with_timezone("-10:00".to_string());
979        let b = date_part_primitive(&a, DatePart::Day).unwrap();
980        assert_eq!(1, b.value(0));
981    }
982
983    #[test]
984    fn test_temporal_array_date64_weekday() {
985        //1514764800000 -> 2018-01-01 (Monday)
986        //1550636625000 -> 2019-02-20 (Wednesday)
987        let a: PrimitiveArray<Date64Type> =
988            vec![Some(1514764800000), None, Some(1550636625000)].into();
989
990        let b = date_part_primitive(&a, DatePart::DayOfWeekMonday0).unwrap();
991        assert_eq!(0, b.value(0));
992        assert!(!b.is_valid(1));
993        assert_eq!(2, b.value(2));
994    }
995
996    #[test]
997    fn test_temporal_array_date64_dayofweek1() {
998        //1514764800000 -> 2018-01-01 (Monday)
999        //1550636625000 -> 2019-02-20 (Wednesday)
1000        //1483228800000 -> 2017-01-01 (Sunday)
1001        let a: PrimitiveArray<Date64Type> = vec![
1002            Some(1514764800000),
1003            None,
1004            Some(1550636625000),
1005            Some(1483228800000),
1006        ]
1007        .into();
1008
1009        let b = date_part_primitive(&a, DatePart::DayOfWeekSunday1).unwrap();
1010        assert_eq!(2, b.value(0));
1011        assert!(!b.is_valid(1));
1012        assert_eq!(4, b.value(2));
1013        assert_eq!(1, b.value(3));
1014    }
1015
1016    #[test]
1017    fn test_temporal_array_date64_isodow() {
1018        //1514764800000 -> 2018-01-01 (Monday)
1019        //1550636625000 -> 2019-02-20 (Wednesday)
1020        //1483228800000 -> 2017-01-01 (Sunday)
1021        let a: PrimitiveArray<Date64Type> = vec![
1022            Some(1514764800000),
1023            None,
1024            Some(1550636625000),
1025            Some(1483228800000),
1026        ]
1027        .into();
1028
1029        let b = date_part_primitive(&a, DatePart::DayOfWeekMonday1).unwrap();
1030        assert_eq!(1, b.value(0));
1031        assert!(!b.is_valid(1));
1032        assert_eq!(3, b.value(2));
1033        assert_eq!(7, b.value(3));
1034    }
1035
1036    #[test]
1037    fn test_temporal_array_date64_weekday0() {
1038        //1483228800000 -> 2017-01-01 (Sunday)
1039        //1514764800000 -> 2018-01-01 (Monday)
1040        //1550636625000 -> 2019-02-20 (Wednesday)
1041        let a: PrimitiveArray<Date64Type> = vec![
1042            Some(1483228800000),
1043            None,
1044            Some(1514764800000),
1045            Some(1550636625000),
1046        ]
1047        .into();
1048
1049        let b = date_part_primitive(&a, DatePart::DayOfWeekSunday0).unwrap();
1050        assert_eq!(0, b.value(0));
1051        assert!(!b.is_valid(1));
1052        assert_eq!(1, b.value(2));
1053        assert_eq!(3, b.value(3));
1054    }
1055
1056    #[test]
1057    fn test_temporal_array_date64_day() {
1058        //1514764800000 -> 2018-01-01
1059        //1550636625000 -> 2019-02-20
1060        let a: PrimitiveArray<Date64Type> =
1061            vec![Some(1514764800000), None, Some(1550636625000)].into();
1062
1063        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1064        assert_eq!(1, b.value(0));
1065        assert!(!b.is_valid(1));
1066        assert_eq!(20, b.value(2));
1067    }
1068
1069    #[test]
1070    fn test_temporal_array_date32_day() {
1071        let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(31)].into();
1072
1073        let b = date_part_primitive(&a, DatePart::Day).unwrap();
1074        assert_eq!(1, b.value(0));
1075        assert!(!b.is_valid(1));
1076        assert_eq!(1, b.value(2));
1077    }
1078
1079    #[test]
1080    fn test_temporal_array_date64_doy() {
1081        //1483228800000 -> 2017-01-01 (Sunday)
1082        //1514764800000 -> 2018-01-01
1083        //1550636625000 -> 2019-02-20
1084        let a: PrimitiveArray<Date64Type> = vec![
1085            Some(1483228800000),
1086            Some(1514764800000),
1087            None,
1088            Some(1550636625000),
1089        ]
1090        .into();
1091
1092        let b = date_part_primitive(&a, DatePart::DayOfYear).unwrap();
1093        assert_eq!(1, b.value(0));
1094        assert_eq!(1, b.value(1));
1095        assert!(!b.is_valid(2));
1096        assert_eq!(51, b.value(3));
1097    }
1098
1099    #[test]
1100    fn test_temporal_array_timestamp_micro_year() {
1101        let a: TimestampMicrosecondArray =
1102            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1103
1104        let b = date_part_primitive(&a, DatePart::Year).unwrap();
1105        assert_eq!(2021, b.value(0));
1106        assert!(!b.is_valid(1));
1107        assert_eq!(2024, b.value(2));
1108    }
1109
1110    #[test]
1111    fn test_temporal_array_date64_minute() {
1112        let a: PrimitiveArray<Date64Type> =
1113            vec![Some(1514764800000), None, Some(1550636625000)].into();
1114
1115        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1116        assert_eq!(0, b.value(0));
1117        assert!(!b.is_valid(1));
1118        assert_eq!(23, b.value(2));
1119    }
1120
1121    #[test]
1122    fn test_temporal_array_timestamp_micro_minute() {
1123        let a: TimestampMicrosecondArray =
1124            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1125
1126        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1127        assert_eq!(57, b.value(0));
1128        assert!(!b.is_valid(1));
1129        assert_eq!(44, b.value(2));
1130    }
1131
1132    #[test]
1133    fn test_temporal_array_date32_week() {
1134        let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(7)].into();
1135
1136        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1137        assert_eq!(1, b.value(0));
1138        assert!(!b.is_valid(1));
1139        assert_eq!(2, b.value(2));
1140    }
1141
1142    #[test]
1143    fn test_temporal_array_date64_week() {
1144        // 1646116175000 -> 2022.03.01 , 1641171600000 -> 2022.01.03
1145        // 1640998800000 -> 2022.01.01
1146        let a: PrimitiveArray<Date64Type> = vec![
1147            Some(1646116175000),
1148            None,
1149            Some(1641171600000),
1150            Some(1640998800000),
1151        ]
1152        .into();
1153
1154        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1155        assert_eq!(9, b.value(0));
1156        assert!(!b.is_valid(1));
1157        assert_eq!(1, b.value(2));
1158        assert_eq!(52, b.value(3));
1159    }
1160
1161    #[test]
1162    fn test_temporal_array_timestamp_micro_week() {
1163        //1612025847000000 -> 2021.1.30
1164        //1722015847000000 -> 2024.7.27
1165        let a: TimestampMicrosecondArray =
1166            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1167
1168        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1169        assert_eq!(4, b.value(0));
1170        assert!(!b.is_valid(1));
1171        assert_eq!(30, b.value(2));
1172    }
1173
1174    #[test]
1175    fn test_temporal_array_date64_second() {
1176        let a: PrimitiveArray<Date64Type> =
1177            vec![Some(1514764800000), None, Some(1550636625000)].into();
1178
1179        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1180        assert_eq!(0, b.value(0));
1181        assert!(!b.is_valid(1));
1182        assert_eq!(45, b.value(2));
1183    }
1184
1185    #[test]
1186    fn test_temporal_array_timestamp_micro_second() {
1187        let a: TimestampMicrosecondArray =
1188            vec![Some(1612025847000000), None, Some(1722015847000000)].into();
1189
1190        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1191        assert_eq!(27, b.value(0));
1192        assert!(!b.is_valid(1));
1193        assert_eq!(7, b.value(2));
1194    }
1195
1196    #[test]
1197    fn test_temporal_array_timestamp_second_with_timezone() {
1198        let a = TimestampSecondArray::from(vec![10, 20]).with_timezone("+00:00".to_string());
1199        let b = date_part_primitive(&a, DatePart::Second).unwrap();
1200        assert_eq!(10, b.value(0));
1201        assert_eq!(20, b.value(1));
1202    }
1203
1204    #[test]
1205    fn test_temporal_array_timestamp_minute_with_timezone() {
1206        let a = TimestampSecondArray::from(vec![0, 60]).with_timezone("+00:50".to_string());
1207        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1208        assert_eq!(50, b.value(0));
1209        assert_eq!(51, b.value(1));
1210    }
1211
1212    #[test]
1213    fn test_temporal_array_timestamp_minute_with_negative_timezone() {
1214        let a = TimestampSecondArray::from(vec![60 * 55]).with_timezone("-00:50".to_string());
1215        let b = date_part_primitive(&a, DatePart::Minute).unwrap();
1216        assert_eq!(5, b.value(0));
1217    }
1218
1219    #[test]
1220    fn test_temporal_array_timestamp_hour_with_timezone() {
1221        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01:00".to_string());
1222        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1223        assert_eq!(11, b.value(0));
1224    }
1225
1226    #[test]
1227    fn test_temporal_array_timestamp_hour_with_timezone_without_colon() {
1228        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+0100".to_string());
1229        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1230        assert_eq!(11, b.value(0));
1231    }
1232
1233    #[test]
1234    fn test_temporal_array_timestamp_hour_with_timezone_without_minutes() {
1235        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01".to_string());
1236        let b = date_part_primitive(&a, DatePart::Hour).unwrap();
1237        assert_eq!(11, b.value(0));
1238    }
1239
1240    #[test]
1241    fn test_temporal_array_timestamp_hour_with_timezone_without_initial_sign() {
1242        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("0100".to_string());
1243        let err = date_part_primitive(&a, DatePart::Hour)
1244            .unwrap_err()
1245            .to_string();
1246        assert!(err.contains("Invalid timezone"), "{}", err);
1247    }
1248
1249    #[test]
1250    fn test_temporal_array_timestamp_hour_with_timezone_with_only_colon() {
1251        let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("01:00".to_string());
1252        let err = date_part_primitive(&a, DatePart::Hour)
1253            .unwrap_err()
1254            .to_string();
1255        assert!(err.contains("Invalid timezone"), "{}", err);
1256    }
1257
1258    #[test]
1259    fn test_temporal_array_timestamp_week_without_timezone() {
1260        // 1970-01-01T00:00:00                     -> 1970-01-01T00:00:00 Thursday (week 1)
1261        // 1970-01-01T00:00:00 + 4 days            -> 1970-01-05T00:00:00 Monday   (week 2)
1262        // 1970-01-01T00:00:00 + 4 days - 1 second -> 1970-01-04T23:59:59 Sunday   (week 1)
1263        let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1]);
1264        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1265        assert_eq!(1, b.value(0));
1266        assert_eq!(2, b.value(1));
1267        assert_eq!(1, b.value(2));
1268    }
1269
1270    #[test]
1271    fn test_temporal_array_timestamp_week_with_timezone() {
1272        // 1970-01-01T01:00:00+01:00                     -> 1970-01-01T01:00:00+01:00 Thursday (week 1)
1273        // 1970-01-01T01:00:00+01:00 + 4 days            -> 1970-01-05T01:00:00+01:00 Monday   (week 2)
1274        // 1970-01-01T01:00:00+01:00 + 4 days - 1 second -> 1970-01-05T00:59:59+01:00 Monday   (week 2)
1275        let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1])
1276            .with_timezone("+01:00".to_string());
1277        let b = date_part_primitive(&a, DatePart::Week).unwrap();
1278        assert_eq!(1, b.value(0));
1279        assert_eq!(2, b.value(1));
1280        assert_eq!(2, b.value(2));
1281    }
1282
1283    #[test]
1284    fn test_hour_minute_second_dictionary_array() {
1285        let a = TimestampSecondArray::from(vec![
1286            60 * 60 * 10 + 61,
1287            60 * 60 * 20 + 122,
1288            60 * 60 * 30 + 183,
1289        ])
1290        .with_timezone("+01:00".to_string());
1291
1292        let keys = Int8Array::from_iter_values([0_i8, 0, 1, 2, 1]);
1293        let dict = DictionaryArray::try_new(keys.clone(), Arc::new(a)).unwrap();
1294
1295        let b = date_part(&dict, DatePart::Hour).unwrap();
1296
1297        let expected_dict =
1298            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![11, 21, 7])));
1299        let expected = Arc::new(expected_dict) as ArrayRef;
1300        assert_eq!(&expected, &b);
1301
1302        let b = date_part(&dict, DatePart::Minute).unwrap();
1303
1304        let b_old = date_part(&dict, DatePart::Minute).unwrap();
1305
1306        let expected_dict =
1307            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3])));
1308        let expected = Arc::new(expected_dict) as ArrayRef;
1309        assert_eq!(&expected, &b);
1310        assert_eq!(&expected, &b_old);
1311
1312        let b = date_part(&dict, DatePart::Second).unwrap();
1313
1314        let b_old = date_part(&dict, DatePart::Second).unwrap();
1315
1316        let expected_dict =
1317            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3])));
1318        let expected = Arc::new(expected_dict) as ArrayRef;
1319        assert_eq!(&expected, &b);
1320        assert_eq!(&expected, &b_old);
1321
1322        let b = date_part(&dict, DatePart::Nanosecond).unwrap();
1323
1324        let expected_dict =
1325            DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![0, 0, 0, 0, 0])));
1326        let expected = Arc::new(expected_dict) as ArrayRef;
1327        assert_eq!(&expected, &b);
1328    }
1329
1330    #[test]
1331    fn test_year_dictionary_array() {
1332        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into();
1333
1334        let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]);
1335        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1336
1337        let b = date_part(&dict, DatePart::Year).unwrap();
1338
1339        let expected_dict = DictionaryArray::new(
1340            keys,
1341            Arc::new(Int32Array::from(vec![2018, 2019, 2019, 2018])),
1342        );
1343        let expected = Arc::new(expected_dict) as ArrayRef;
1344        assert_eq!(&expected, &b);
1345    }
1346
1347    #[test]
1348    fn test_quarter_month_dictionary_array() {
1349        //1514764800000 -> 2018-01-01
1350        //1566275025000 -> 2019-08-20
1351        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1566275025000)].into();
1352
1353        let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]);
1354        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1355
1356        let b = date_part(&dict, DatePart::Quarter).unwrap();
1357
1358        let expected =
1359            DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 3, 3, 1])));
1360        assert_eq!(b.as_ref(), &expected);
1361
1362        let b = date_part(&dict, DatePart::Month).unwrap();
1363
1364        let expected = DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![1, 8, 8, 1])));
1365        assert_eq!(b.as_ref(), &expected);
1366    }
1367
1368    #[test]
1369    fn test_num_days_from_monday_sunday_day_doy_week_dictionary_array() {
1370        //1514764800000 -> 2018-01-01 (Monday)
1371        //1550636625000 -> 2019-02-20 (Wednesday)
1372        let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into();
1373
1374        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1), Some(0), None]);
1375        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1376
1377        let b = date_part(&dict, DatePart::DayOfWeekMonday0).unwrap();
1378
1379        let a = Int32Array::from(vec![Some(0), Some(2), Some(2), Some(0), None]);
1380        let expected = DictionaryArray::new(keys.clone(), Arc::new(a));
1381        assert_eq!(b.as_ref(), &expected);
1382
1383        let b = date_part(&dict, DatePart::DayOfWeekSunday0).unwrap();
1384
1385        let a = Int32Array::from(vec![Some(1), Some(3), Some(3), Some(1), 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::Day).unwrap();
1390
1391        let a = Int32Array::from(vec![Some(1), Some(20), Some(20), 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::DayOfYear).unwrap();
1396
1397        let a = Int32Array::from(vec![Some(1), Some(51), Some(51), 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::Week).unwrap();
1402
1403        let a = Int32Array::from(vec![Some(1), Some(8), Some(8), Some(1), None]);
1404        let expected = DictionaryArray::new(keys, Arc::new(a));
1405        assert_eq!(b.as_ref(), &expected);
1406    }
1407
1408    #[test]
1409    fn test_temporal_array_date64_nanosecond() {
1410        // new Date(1667328721453)
1411        // Tue Nov 01 2022 11:52:01 GMT-0700 (Pacific Daylight Time)
1412        //
1413        // new Date(1667328721453).getMilliseconds()
1414        // 453
1415
1416        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1417
1418        let b = date_part_primitive(&a, DatePart::Nanosecond).unwrap();
1419        assert!(!b.is_valid(0));
1420        assert_eq!(453_000_000, b.value(1));
1421
1422        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1423        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1424        let b = date_part(&dict, DatePart::Nanosecond).unwrap();
1425
1426        let a = Int32Array::from(vec![None, Some(453_000_000)]);
1427        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1428        let expected = Arc::new(expected_dict) as ArrayRef;
1429        assert_eq!(&expected, &b);
1430    }
1431
1432    #[test]
1433    fn test_temporal_array_date64_microsecond() {
1434        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1435
1436        let b = date_part_primitive(&a, DatePart::Microsecond).unwrap();
1437        assert!(!b.is_valid(0));
1438        assert_eq!(453_000, b.value(1));
1439
1440        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1441        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1442        let b = date_part(&dict, DatePart::Microsecond).unwrap();
1443
1444        let a = Int32Array::from(vec![None, Some(453_000)]);
1445        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1446        let expected = Arc::new(expected_dict) as ArrayRef;
1447        assert_eq!(&expected, &b);
1448    }
1449
1450    #[test]
1451    fn test_temporal_array_date64_millisecond() {
1452        let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into();
1453
1454        let b = date_part_primitive(&a, DatePart::Millisecond).unwrap();
1455        assert!(!b.is_valid(0));
1456        assert_eq!(453, b.value(1));
1457
1458        let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]);
1459        let dict = DictionaryArray::new(keys.clone(), Arc::new(a));
1460        let b = date_part(&dict, DatePart::Millisecond).unwrap();
1461
1462        let a = Int32Array::from(vec![None, Some(453)]);
1463        let expected_dict = DictionaryArray::new(keys, Arc::new(a));
1464        let expected = Arc::new(expected_dict) as ArrayRef;
1465        assert_eq!(&expected, &b);
1466    }
1467
1468    #[test]
1469    fn test_temporal_array_time64_nanoseconds() {
1470        // 23:32:50.123456789
1471        let input: Time64NanosecondArray = vec![Some(84_770_123_456_789)].into();
1472
1473        let actual = date_part(&input, DatePart::Hour).unwrap();
1474        let actual = actual.as_primitive::<Int32Type>();
1475        assert_eq!(23, actual.value(0));
1476
1477        let actual = date_part(&input, DatePart::Minute).unwrap();
1478        let actual = actual.as_primitive::<Int32Type>();
1479        assert_eq!(32, actual.value(0));
1480
1481        let actual = date_part(&input, DatePart::Second).unwrap();
1482        let actual = actual.as_primitive::<Int32Type>();
1483        assert_eq!(50, actual.value(0));
1484
1485        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1486        let actual = actual.as_primitive::<Int32Type>();
1487        assert_eq!(123, actual.value(0));
1488
1489        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1490        let actual = actual.as_primitive::<Int32Type>();
1491        assert_eq!(123_456, actual.value(0));
1492
1493        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1494        let actual = actual.as_primitive::<Int32Type>();
1495        assert_eq!(123_456_789, actual.value(0));
1496
1497        // invalid values should turn into null
1498        let input: Time64NanosecondArray = vec![
1499            Some(-1),
1500            Some(86_400_000_000_000),
1501            Some(86_401_000_000_000),
1502            None,
1503        ]
1504        .into();
1505        let actual = date_part(&input, DatePart::Hour).unwrap();
1506        let actual = actual.as_primitive::<Int32Type>();
1507        let expected: Int32Array = vec![None, None, None, None].into();
1508        assert_eq!(&expected, actual);
1509    }
1510
1511    #[test]
1512    fn test_temporal_array_time64_microseconds() {
1513        // 23:32:50.123456
1514        let input: Time64MicrosecondArray = vec![Some(84_770_123_456)].into();
1515
1516        let actual = date_part(&input, DatePart::Hour).unwrap();
1517        let actual = actual.as_primitive::<Int32Type>();
1518        assert_eq!(23, actual.value(0));
1519
1520        let actual = date_part(&input, DatePart::Minute).unwrap();
1521        let actual = actual.as_primitive::<Int32Type>();
1522        assert_eq!(32, actual.value(0));
1523
1524        let actual = date_part(&input, DatePart::Second).unwrap();
1525        let actual = actual.as_primitive::<Int32Type>();
1526        assert_eq!(50, actual.value(0));
1527
1528        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1529        let actual = actual.as_primitive::<Int32Type>();
1530        assert_eq!(123, actual.value(0));
1531
1532        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1533        let actual = actual.as_primitive::<Int32Type>();
1534        assert_eq!(123_456, actual.value(0));
1535
1536        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1537        let actual = actual.as_primitive::<Int32Type>();
1538        assert_eq!(123_456_000, actual.value(0));
1539
1540        // invalid values should turn into null
1541        let input: Time64MicrosecondArray =
1542            vec![Some(-1), Some(86_400_000_000), Some(86_401_000_000), None].into();
1543        let actual = date_part(&input, DatePart::Hour).unwrap();
1544        let actual = actual.as_primitive::<Int32Type>();
1545        let expected: Int32Array = vec![None, None, None, None].into();
1546        assert_eq!(&expected, actual);
1547    }
1548
1549    #[test]
1550    fn test_temporal_array_time32_milliseconds() {
1551        // 23:32:50.123
1552        let input: Time32MillisecondArray = vec![Some(84_770_123)].into();
1553
1554        let actual = date_part(&input, DatePart::Hour).unwrap();
1555        let actual = actual.as_primitive::<Int32Type>();
1556        assert_eq!(23, actual.value(0));
1557
1558        let actual = date_part(&input, DatePart::Minute).unwrap();
1559        let actual = actual.as_primitive::<Int32Type>();
1560        assert_eq!(32, actual.value(0));
1561
1562        let actual = date_part(&input, DatePart::Second).unwrap();
1563        let actual = actual.as_primitive::<Int32Type>();
1564        assert_eq!(50, actual.value(0));
1565
1566        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1567        let actual = actual.as_primitive::<Int32Type>();
1568        assert_eq!(123, actual.value(0));
1569
1570        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1571        let actual = actual.as_primitive::<Int32Type>();
1572        assert_eq!(123_000, actual.value(0));
1573
1574        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1575        let actual = actual.as_primitive::<Int32Type>();
1576        assert_eq!(123_000_000, actual.value(0));
1577
1578        // invalid values should turn into null
1579        let input: Time32MillisecondArray =
1580            vec![Some(-1), Some(86_400_000), Some(86_401_000), None].into();
1581        let actual = date_part(&input, DatePart::Hour).unwrap();
1582        let actual = actual.as_primitive::<Int32Type>();
1583        let expected: Int32Array = vec![None, None, None, None].into();
1584        assert_eq!(&expected, actual);
1585    }
1586
1587    #[test]
1588    fn test_temporal_array_time32_seconds() {
1589        // 23:32:50
1590        let input: Time32SecondArray = vec![84_770].into();
1591
1592        let actual = date_part(&input, DatePart::Hour).unwrap();
1593        let actual = actual.as_primitive::<Int32Type>();
1594        assert_eq!(23, actual.value(0));
1595
1596        let actual = date_part(&input, DatePart::Minute).unwrap();
1597        let actual = actual.as_primitive::<Int32Type>();
1598        assert_eq!(32, actual.value(0));
1599
1600        let actual = date_part(&input, DatePart::Second).unwrap();
1601        let actual = actual.as_primitive::<Int32Type>();
1602        assert_eq!(50, actual.value(0));
1603
1604        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1605        let actual = actual.as_primitive::<Int32Type>();
1606        assert_eq!(0, actual.value(0));
1607
1608        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1609        let actual = actual.as_primitive::<Int32Type>();
1610        assert_eq!(0, actual.value(0));
1611
1612        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1613        let actual = actual.as_primitive::<Int32Type>();
1614        assert_eq!(0, actual.value(0));
1615
1616        // invalid values should turn into null
1617        let input: Time32SecondArray = vec![Some(-1), Some(86_400), Some(86_401), None].into();
1618        let actual = date_part(&input, DatePart::Hour).unwrap();
1619        let actual = actual.as_primitive::<Int32Type>();
1620        let expected: Int32Array = vec![None, None, None, None].into();
1621        assert_eq!(&expected, actual);
1622    }
1623
1624    #[test]
1625    fn test_temporal_array_time_invalid_parts() {
1626        fn ensure_returns_error(array: &dyn Array) {
1627            let invalid_parts = [
1628                DatePart::Quarter,
1629                DatePart::Year,
1630                DatePart::YearISO,
1631                DatePart::Month,
1632                DatePart::Week,
1633                DatePart::WeekISO,
1634                DatePart::Day,
1635                DatePart::DayOfWeekSunday0,
1636                DatePart::DayOfWeekMonday0,
1637                DatePart::DayOfWeekSunday1,
1638                DatePart::DayOfWeekMonday1,
1639                DatePart::DayOfYear,
1640            ];
1641
1642            for part in invalid_parts {
1643                let err = date_part(array, part).unwrap_err();
1644                let expected = format!(
1645                    "Compute error: {part} does not support: {}",
1646                    array.data_type()
1647                );
1648                assert_eq!(expected, err.to_string());
1649            }
1650        }
1651
1652        ensure_returns_error(&Time32SecondArray::from(vec![0]));
1653        ensure_returns_error(&Time32MillisecondArray::from(vec![0]));
1654        ensure_returns_error(&Time64MicrosecondArray::from(vec![0]));
1655        ensure_returns_error(&Time64NanosecondArray::from(vec![0]));
1656    }
1657
1658    #[test]
1659    fn test_interval_year_month_array() {
1660        let input: IntervalYearMonthArray = vec![0, 5, 24].into();
1661
1662        let actual = date_part(&input, DatePart::Year).unwrap();
1663        let actual = actual.as_primitive::<Int32Type>();
1664        assert_eq!(0, actual.value(0));
1665        assert_eq!(0, actual.value(1));
1666        assert_eq!(2, actual.value(2));
1667
1668        let actual = date_part(&input, DatePart::Month).unwrap();
1669        let actual = actual.as_primitive::<Int32Type>();
1670        assert_eq!(0, actual.value(0));
1671        assert_eq!(5, actual.value(1));
1672        assert_eq!(0, actual.value(2));
1673
1674        assert!(date_part(&input, DatePart::Day).is_err());
1675        assert!(date_part(&input, DatePart::Week).is_err());
1676    }
1677
1678    // IntervalDayTimeType week, day, hour, minute, second, milli, u, nano;
1679    // invalid month, year; ignores the other part
1680    #[test]
1681    fn test_interval_day_time_array() {
1682        let input: IntervalDayTimeArray = vec![
1683            IntervalDayTime::ZERO,
1684            IntervalDayTime::new(10, 42),   // 10d, 42ms
1685            IntervalDayTime::new(10, 1042), // 10d, 1s, 42ms
1686            IntervalDayTime::new(10, MILLISECONDS_IN_DAY as i32 + 1), // 10d, 24h, 1ms
1687            IntervalDayTime::new(
1688                6,
1689                (MILLISECONDS * 60 * 60 * 4 + MILLISECONDS * 60 * 22 + MILLISECONDS * 11 + 3)
1690                    as i32,
1691            ), // 6d, 4h, 22m, 11s, 3ms
1692        ]
1693        .into();
1694
1695        // Time doesn't affect days.
1696        let actual = date_part(&input, DatePart::Day).unwrap();
1697        let actual = actual.as_primitive::<Int32Type>();
1698        assert_eq!(0, actual.value(0));
1699        assert_eq!(10, actual.value(1));
1700        assert_eq!(10, actual.value(2));
1701        assert_eq!(10, actual.value(3));
1702        assert_eq!(6, actual.value(4));
1703
1704        let actual = date_part(&input, DatePart::Week).unwrap();
1705        let actual = actual.as_primitive::<Int32Type>();
1706        assert_eq!(0, actual.value(0));
1707        assert_eq!(1, actual.value(1));
1708        assert_eq!(1, actual.value(2));
1709        assert_eq!(1, actual.value(3));
1710        assert_eq!(0, actual.value(4));
1711
1712        // Days doesn't affect time.
1713        let actual = date_part(&input, DatePart::Hour).unwrap();
1714        let actual = actual.as_primitive::<Int32Type>();
1715        assert_eq!(0, actual.value(0));
1716        assert_eq!(0, actual.value(1));
1717        assert_eq!(0, actual.value(2));
1718        assert_eq!(24, actual.value(3));
1719        assert_eq!(4, actual.value(4));
1720
1721        let actual = date_part(&input, DatePart::Minute).unwrap();
1722        let actual = actual.as_primitive::<Int32Type>();
1723        assert_eq!(0, actual.value(0));
1724        assert_eq!(0, actual.value(1));
1725        assert_eq!(0, actual.value(2));
1726        assert_eq!(0, actual.value(3));
1727        assert_eq!(22, actual.value(4));
1728
1729        let actual = date_part(&input, DatePart::Second).unwrap();
1730        let actual = actual.as_primitive::<Int32Type>();
1731        assert_eq!(0, actual.value(0));
1732        assert_eq!(0, actual.value(1));
1733        assert_eq!(1, actual.value(2));
1734        assert_eq!(0, actual.value(3));
1735        assert_eq!(11, actual.value(4));
1736
1737        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1738        let actual = actual.as_primitive::<Int32Type>();
1739        assert_eq!(0, actual.value(0));
1740        assert_eq!(42, actual.value(1));
1741        assert_eq!(1042, actual.value(2));
1742        assert_eq!(1, actual.value(3));
1743        assert_eq!(11003, actual.value(4));
1744
1745        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1746        let actual = actual.as_primitive::<Int32Type>();
1747        assert_eq!(0, actual.value(0));
1748        assert_eq!(42_000, actual.value(1));
1749        assert_eq!(1_042_000, actual.value(2));
1750        assert_eq!(1_000, actual.value(3));
1751        assert_eq!(11_003_000, actual.value(4));
1752
1753        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1754        let actual = actual.as_primitive::<Int32Type>();
1755        assert_eq!(0, actual.value(0));
1756        assert_eq!(42_000_000, actual.value(1));
1757        assert_eq!(1_042_000_000, actual.value(2));
1758        assert_eq!(1_000_000, actual.value(3));
1759        // Overflow returns zero.
1760        assert_eq!(0, actual.value(4));
1761
1762        // Month and year are not valid (since days in month varies).
1763        assert!(date_part(&input, DatePart::Month).is_err());
1764        assert!(date_part(&input, DatePart::Year).is_err());
1765    }
1766
1767    // IntervalMonthDayNanoType year -> nano;
1768    // days don't affect months, time doesn't affect days, time doesn't affect months (and vice versa)
1769    #[test]
1770    fn test_interval_month_day_nano_array() {
1771        let input: IntervalMonthDayNanoArray = vec![
1772            IntervalMonthDayNano::ZERO,
1773            IntervalMonthDayNano::new(5, 10, 42), // 5m, 1w, 3d, 42ns
1774            IntervalMonthDayNano::new(16, 35, NANOSECONDS_IN_DAY + 1), // 1y, 4m, 5w, 24h, 1ns
1775            IntervalMonthDayNano::new(
1776                0,
1777                0,
1778                NANOSECONDS * 60 * 60 * 4
1779                    + NANOSECONDS * 60 * 22
1780                    + NANOSECONDS * 11
1781                    + 1_000_000 * 33
1782                    + 1_000 * 44
1783                    + 5,
1784            ), // 4hr, 22m, 11s, 33ms, 44us, 5ns
1785        ]
1786        .into();
1787
1788        // Year and month follow from month, but are not affected by days or nanos.
1789        let actual = date_part(&input, DatePart::Year).unwrap();
1790        let actual = actual.as_primitive::<Int32Type>();
1791        assert_eq!(0, actual.value(0));
1792        assert_eq!(0, actual.value(1));
1793        assert_eq!(1, actual.value(2));
1794        assert_eq!(0, actual.value(3));
1795
1796        let actual = date_part(&input, DatePart::Month).unwrap();
1797        let actual = actual.as_primitive::<Int32Type>();
1798        assert_eq!(0, actual.value(0));
1799        assert_eq!(5, actual.value(1));
1800        assert_eq!(4, actual.value(2));
1801        assert_eq!(0, actual.value(3));
1802
1803        // Week and day follow from day, but are not affected by months or nanos.
1804        let actual = date_part(&input, DatePart::Week).unwrap();
1805        let actual = actual.as_primitive::<Int32Type>();
1806        assert_eq!(0, actual.value(0));
1807        assert_eq!(1, actual.value(1));
1808        assert_eq!(5, actual.value(2));
1809        assert_eq!(0, actual.value(3));
1810
1811        let actual = date_part(&input, DatePart::Day).unwrap();
1812        let actual = actual.as_primitive::<Int32Type>();
1813        assert_eq!(0, actual.value(0));
1814        assert_eq!(10, actual.value(1));
1815        assert_eq!(35, actual.value(2));
1816        assert_eq!(0, actual.value(3));
1817
1818        // Times follow from nanos, but are not affected by months or days.
1819        let actual = date_part(&input, DatePart::Hour).unwrap();
1820        let actual = actual.as_primitive::<Int32Type>();
1821        assert_eq!(0, actual.value(0));
1822        assert_eq!(0, actual.value(1));
1823        assert_eq!(24, actual.value(2));
1824        assert_eq!(4, actual.value(3));
1825
1826        let actual = date_part(&input, DatePart::Minute).unwrap();
1827        let actual = actual.as_primitive::<Int32Type>();
1828        assert_eq!(0, actual.value(0));
1829        assert_eq!(0, actual.value(1));
1830        assert_eq!(0, actual.value(2));
1831        assert_eq!(22, actual.value(3));
1832
1833        let actual = date_part(&input, DatePart::Second).unwrap();
1834        let actual = actual.as_primitive::<Int32Type>();
1835        assert_eq!(0, actual.value(0));
1836        assert_eq!(0, actual.value(1));
1837        assert_eq!(0, actual.value(2));
1838        assert_eq!(11, actual.value(3));
1839
1840        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1841        let actual = actual.as_primitive::<Int32Type>();
1842        assert_eq!(0, actual.value(0));
1843        assert_eq!(0, actual.value(1));
1844        assert_eq!(0, actual.value(2));
1845        assert_eq!(11_033, actual.value(3));
1846
1847        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1848        let actual = actual.as_primitive::<Int32Type>();
1849        assert_eq!(0, actual.value(0));
1850        assert_eq!(0, actual.value(1));
1851        assert_eq!(0, actual.value(2));
1852        assert_eq!(11_033_044, actual.value(3));
1853
1854        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1855        let actual = actual.as_primitive::<Int32Type>();
1856        assert_eq!(0, actual.value(0));
1857        assert_eq!(42, actual.value(1));
1858        assert_eq!(1, actual.value(2));
1859        // Overflow returns zero.
1860        assert_eq!(0, actual.value(3));
1861    }
1862
1863    #[test]
1864    fn test_interval_array_invalid_parts() {
1865        fn ensure_returns_error(array: &dyn Array) {
1866            let invalid_parts = [
1867                DatePart::Quarter,
1868                DatePart::YearISO,
1869                DatePart::WeekISO,
1870                DatePart::DayOfWeekSunday0,
1871                DatePart::DayOfWeekMonday0,
1872                DatePart::DayOfWeekSunday1,
1873                DatePart::DayOfWeekMonday1,
1874                DatePart::DayOfYear,
1875            ];
1876
1877            for part in invalid_parts {
1878                let err = date_part(array, part).unwrap_err();
1879                let expected = format!(
1880                    "Compute error: {part} does not support: {}",
1881                    array.data_type()
1882                );
1883                assert_eq!(expected, err.to_string());
1884            }
1885        }
1886
1887        ensure_returns_error(&IntervalYearMonthArray::from(vec![0]));
1888        ensure_returns_error(&IntervalDayTimeArray::from(vec![IntervalDayTime::ZERO]));
1889        ensure_returns_error(&IntervalMonthDayNanoArray::from(vec![
1890            IntervalMonthDayNano::ZERO,
1891        ]));
1892    }
1893
1894    #[test]
1895    fn test_duration_second() {
1896        let input: DurationSecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
1897
1898        let actual = date_part(&input, DatePart::Second).unwrap();
1899        let actual = actual.as_primitive::<Int32Type>();
1900        assert_eq!(0, actual.value(0));
1901        assert_eq!(42, actual.value(1));
1902        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
1903
1904        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1905        let actual = actual.as_primitive::<Int32Type>();
1906        assert_eq!(0, actual.value(0));
1907        assert_eq!(42_000, actual.value(1));
1908        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
1909
1910        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1911        let actual = actual.as_primitive::<Int32Type>();
1912        assert_eq!(0, actual.value(0));
1913        assert_eq!(42_000_000, actual.value(1));
1914        assert_eq!(0, actual.value(2));
1915
1916        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1917        let actual = actual.as_primitive::<Int32Type>();
1918        assert_eq!(0, actual.value(0));
1919        assert_eq!(0, actual.value(1));
1920        assert_eq!(0, actual.value(2));
1921    }
1922
1923    #[test]
1924    fn test_duration_millisecond() {
1925        let input: DurationMillisecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
1926
1927        let actual = date_part(&input, DatePart::Second).unwrap();
1928        let actual = actual.as_primitive::<Int32Type>();
1929        assert_eq!(0, actual.value(0));
1930        assert_eq!(0, actual.value(1));
1931        assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
1932
1933        let actual = date_part(&input, DatePart::Millisecond).unwrap();
1934        let actual = actual.as_primitive::<Int32Type>();
1935        assert_eq!(0, actual.value(0));
1936        assert_eq!(42, actual.value(1));
1937        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
1938
1939        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1940        let actual = actual.as_primitive::<Int32Type>();
1941        assert_eq!(0, actual.value(0));
1942        assert_eq!(42_000, actual.value(1));
1943        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
1944
1945        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1946        let actual = actual.as_primitive::<Int32Type>();
1947        assert_eq!(0, actual.value(0));
1948        assert_eq!(42_000_000, actual.value(1));
1949        assert_eq!(0, actual.value(2));
1950    }
1951
1952    #[test]
1953    fn test_duration_microsecond() {
1954        let input: DurationMicrosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
1955
1956        let actual = date_part(&input, DatePart::Second).unwrap();
1957        let actual = actual.as_primitive::<Int32Type>();
1958        assert_eq!(0, actual.value(0));
1959        assert_eq!(0, actual.value(1));
1960        assert_eq!(0, actual.value(2));
1961
1962        let actual = date_part(&input, DatePart::Millisecond).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!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
1967
1968        let actual = date_part(&input, DatePart::Microsecond).unwrap();
1969        let actual = actual.as_primitive::<Int32Type>();
1970        assert_eq!(0, actual.value(0));
1971        assert_eq!(42, actual.value(1));
1972        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
1973
1974        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
1975        let actual = actual.as_primitive::<Int32Type>();
1976        assert_eq!(0, actual.value(0));
1977        assert_eq!(42_000, actual.value(1));
1978        assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2));
1979    }
1980
1981    #[test]
1982    fn test_duration_nanosecond() {
1983        let input: DurationNanosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into();
1984
1985        let actual = date_part(&input, DatePart::Second).unwrap();
1986        let actual = actual.as_primitive::<Int32Type>();
1987        assert_eq!(0, actual.value(0));
1988        assert_eq!(0, actual.value(1));
1989        assert_eq!(0, actual.value(2));
1990
1991        let actual = date_part(&input, DatePart::Millisecond).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::Microsecond).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!((60 * 60 * 24 + 1) / 1_000, actual.value(2));
2002
2003        let actual = date_part(&input, DatePart::Nanosecond).unwrap();
2004        let actual = actual.as_primitive::<Int32Type>();
2005        assert_eq!(0, actual.value(0));
2006        assert_eq!(42, actual.value(1));
2007        assert_eq!(60 * 60 * 24 + 1, actual.value(2));
2008    }
2009
2010    #[test]
2011    fn test_duration_invalid_parts() {
2012        fn ensure_returns_error(array: &dyn Array) {
2013            let invalid_parts = [
2014                DatePart::Year,
2015                DatePart::YearISO,
2016                DatePart::Quarter,
2017                DatePart::Month,
2018                DatePart::WeekISO,
2019                DatePart::DayOfWeekSunday0,
2020                DatePart::DayOfWeekMonday0,
2021                DatePart::DayOfWeekSunday1,
2022                DatePart::DayOfWeekMonday1,
2023                DatePart::DayOfYear,
2024            ];
2025
2026            for part in invalid_parts {
2027                let err = date_part(array, part).unwrap_err();
2028                let expected = format!(
2029                    "Compute error: {part} does not support: {}",
2030                    array.data_type()
2031                );
2032                assert_eq!(expected, err.to_string());
2033            }
2034        }
2035
2036        ensure_returns_error(&DurationSecondArray::from(vec![0]));
2037        ensure_returns_error(&DurationMillisecondArray::from(vec![0]));
2038        ensure_returns_error(&DurationMicrosecondArray::from(vec![0]));
2039        ensure_returns_error(&DurationNanosecondArray::from(vec![0]));
2040    }
2041
2042    const TIMESTAMP_SECOND_1970_01_01: i64 = 0;
2043    const TIMESTAMP_SECOND_2018_01_01: i64 = 1_514_764_800;
2044    const TIMESTAMP_SECOND_2019_02_20: i64 = 1_550_636_625;
2045    const SECONDS_IN_DAY: i64 = 24 * 60 * 60;
2046    // In 2018 the ISO year and calendar year start on the same date— 2018-01-01 or 2018-W01-1
2047    #[test]
2048    fn test_temporal_array_date64_week_iso() {
2049        let a: PrimitiveArray<Date64Type> = vec![
2050            Some(TIMESTAMP_SECOND_2018_01_01 * 1000),
2051            Some(TIMESTAMP_SECOND_2019_02_20 * 1000),
2052        ]
2053        .into();
2054
2055        let b = date_part(&a, DatePart::WeekISO).unwrap();
2056        let actual = b.as_primitive::<Int32Type>();
2057        assert_eq!(1, actual.value(0));
2058        assert_eq!(8, actual.value(1));
2059    }
2060
2061    #[test]
2062    fn test_temporal_array_date64_year_iso() {
2063        let a: PrimitiveArray<Date64Type> = vec![
2064            Some(TIMESTAMP_SECOND_2018_01_01 * 1000),
2065            Some(TIMESTAMP_SECOND_2019_02_20 * 1000),
2066        ]
2067        .into();
2068
2069        let b = date_part(&a, DatePart::YearISO).unwrap();
2070        let actual = b.as_primitive::<Int32Type>();
2071        assert_eq!(2018, actual.value(0));
2072        assert_eq!(2019, actual.value(1));
2073    }
2074
2075    #[test]
2076    fn test_temporal_array_timestamp_week_iso() {
2077        let a = TimestampSecondArray::from(vec![
2078            TIMESTAMP_SECOND_1970_01_01, // 0 and is Thursday
2079            SECONDS_IN_DAY * 4,          //  Monday of week 2
2080            SECONDS_IN_DAY * 4 - 1,      // Sunday of week 1
2081        ]);
2082        let b = date_part(&a, DatePart::WeekISO).unwrap();
2083        let actual = b.as_primitive::<Int32Type>();
2084        assert_eq!(1, actual.value(0));
2085        assert_eq!(2, actual.value(1));
2086        assert_eq!(1, actual.value(2));
2087    }
2088
2089    #[test]
2090    fn test_temporal_array_timestamp_year_iso() {
2091        let a = TimestampSecondArray::from(vec![
2092            TIMESTAMP_SECOND_1970_01_01,
2093            SECONDS_IN_DAY * 4,
2094            SECONDS_IN_DAY * 4 - 1,
2095        ]);
2096        let b = date_part(&a, DatePart::YearISO).unwrap();
2097        let actual = b.as_primitive::<Int32Type>();
2098        assert_eq!(1970, actual.value(0));
2099        assert_eq!(1970, actual.value(1));
2100        assert_eq!(1970, actual.value(2));
2101    }
2102
2103    const TIMESTAMP_SECOND_2015_12_28: i64 = 1_451_260_800;
2104    const TIMESTAMP_SECOND_2016_01_03: i64 = 1_451_779_200;
2105    // January 1st 2016 is a Friday, so 2015 week 53 runs from
2106    // 2015-12-28 to 2016-01-03 inclusive, and
2107    // 2016 week 1 runs from 2016-01-04 to 2016-01-10 inclusive.
2108    #[test]
2109    fn test_temporal_array_date64_week_iso_edge_cases() {
2110        let a: PrimitiveArray<Date64Type> = vec![
2111            Some(TIMESTAMP_SECOND_2015_12_28 * 1000),
2112            Some(TIMESTAMP_SECOND_2016_01_03 * 1000),
2113            Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000),
2114        ]
2115        .into();
2116
2117        let b = date_part(&a, DatePart::WeekISO).unwrap();
2118        let actual = b.as_primitive::<Int32Type>();
2119        assert_eq!(53, actual.value(0));
2120        assert_eq!(53, actual.value(1));
2121        assert_eq!(1, actual.value(2));
2122    }
2123
2124    #[test]
2125    fn test_temporal_array_date64_year_iso_edge_cases() {
2126        let a: PrimitiveArray<Date64Type> = vec![
2127            Some(TIMESTAMP_SECOND_2015_12_28 * 1000),
2128            Some(TIMESTAMP_SECOND_2016_01_03 * 1000),
2129            Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000),
2130        ]
2131        .into();
2132
2133        let b = date_part(&a, DatePart::YearISO).unwrap();
2134        let actual = b.as_primitive::<Int32Type>();
2135        assert_eq!(2015, actual.value(0));
2136        assert_eq!(2015, actual.value(1));
2137        assert_eq!(2016, actual.value(2));
2138    }
2139
2140    #[test]
2141    fn test_temporal_array_timestamp_week_iso_edge_cases() {
2142        let a = TimestampSecondArray::from(vec![
2143            TIMESTAMP_SECOND_2015_12_28,
2144            TIMESTAMP_SECOND_2016_01_03,
2145            TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY,
2146        ]);
2147        let b = date_part(&a, DatePart::WeekISO).unwrap();
2148        let actual = b.as_primitive::<Int32Type>();
2149        assert_eq!(53, actual.value(0));
2150        assert_eq!(53, actual.value(1));
2151        assert_eq!(1, actual.value(2));
2152    }
2153
2154    #[test]
2155    fn test_temporal_array_timestamp_year_iso_edge_cases() {
2156        let a = TimestampSecondArray::from(vec![
2157            TIMESTAMP_SECOND_2015_12_28,
2158            TIMESTAMP_SECOND_2016_01_03,
2159            TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY,
2160        ]);
2161        let b = date_part(&a, DatePart::YearISO).unwrap();
2162        let actual = b.as_primitive::<Int32Type>();
2163        assert_eq!(2015, actual.value(0));
2164        assert_eq!(2015, actual.value(1));
2165        assert_eq!(2016, actual.value(2));
2166    }
2167
2168    #[test]
2169    fn test_ree_timestamp_year() {
2170        let vals: TimestampSecondArray =
2171            vec![Some(1514764800), Some(1550636625), Some(1550636625)].into();
2172        let run_ends = Int32Array::from(vec![1, 2, 3]);
2173        let ree = RunArray::try_new(&run_ends, &vals).unwrap();
2174
2175        let b = date_part(&ree, DatePart::Year).unwrap();
2176        let ree_result = b.as_run_opt::<Int32Type>().unwrap();
2177        let values = ree_result.values().as_primitive::<Int32Type>();
2178        assert_eq!(2018, values.value(0));
2179        assert_eq!(2019, values.value(1));
2180        assert_eq!(2019, values.value(2));
2181    }
2182
2183    #[test]
2184    fn test_ree_date64_month() {
2185        let vals: PrimitiveArray<Date64Type> =
2186            vec![Some(1514764800000), Some(1550636625000)].into();
2187        let run_ends = Int64Array::from(vec![2, 4]);
2188        let ree = RunArray::try_new(&run_ends, &vals).unwrap();
2189
2190        let b = date_part(&ree, DatePart::Month).unwrap();
2191        let ree_result = b.as_run_opt::<Int64Type>().unwrap();
2192        let values = ree_result.values().as_primitive::<Int32Type>();
2193        assert_eq!(1, values.value(0));
2194        assert_eq!(2, values.value(1));
2195    }
2196
2197    #[test]
2198    fn test_date_part_from_str() {
2199        let cases = [
2200            ("y", DatePart::Year),
2201            ("yr", DatePart::Year),
2202            ("year", DatePart::Year),
2203            ("years", DatePart::Year),
2204            ("YEAR", DatePart::Year),
2205            ("isoyear", DatePart::YearISO),
2206            ("qtr", DatePart::Quarter),
2207            ("quarter", DatePart::Quarter),
2208            ("quarters", DatePart::Quarter),
2209            ("mon", DatePart::Month),
2210            ("mons", DatePart::Month),
2211            ("month", DatePart::Month),
2212            ("MONTHS", DatePart::Month),
2213            ("w", DatePart::Week),
2214            ("week", DatePart::Week),
2215            ("isoweek", DatePart::WeekISO),
2216            ("d", DatePart::Day),
2217            ("day", DatePart::Day),
2218            ("dow", DatePart::DayOfWeekSunday0),
2219            ("DayOfWeek", DatePart::DayOfWeekSunday0),
2220            ("dow1", DatePart::DayOfWeekSunday1),
2221            ("dayofweek1", DatePart::DayOfWeekSunday1),
2222            ("DAYOFWEEK1", DatePart::DayOfWeekSunday1),
2223            ("isodow", DatePart::DayOfWeekMonday1),
2224            ("ISODOW", DatePart::DayOfWeekMonday1),
2225            ("doy", DatePart::DayOfYear),
2226            ("DayOfYear", DatePart::DayOfYear),
2227            ("h", DatePart::Hour),
2228            ("hr", DatePart::Hour),
2229            ("hour", DatePart::Hour),
2230            // Pin the famous `m`/`mon` ambiguity: `m` resolves to Minute,
2231            // matching `arrow-cast`'s `IntervalUnit::from_str`. Use `mon`
2232            // (or `month`) for Month.
2233            ("m", DatePart::Minute),
2234            ("min", DatePart::Minute),
2235            ("mins", DatePart::Minute),
2236            ("minute", DatePart::Minute),
2237            ("s", DatePart::Second),
2238            ("sec", DatePart::Second),
2239            ("second", DatePart::Second),
2240            ("ms", DatePart::Millisecond),
2241            ("msec", DatePart::Millisecond),
2242            ("mseconds", DatePart::Millisecond),
2243            ("millisecond", DatePart::Millisecond),
2244            ("us", DatePart::Microsecond),
2245            ("usec", DatePart::Microsecond),
2246            ("useconds", DatePart::Microsecond),
2247            ("microsecond", DatePart::Microsecond),
2248            ("nanosecond", DatePart::Nanosecond),
2249            ("nanoseconds", DatePart::Nanosecond),
2250        ];
2251        for (input, expected) in cases {
2252            assert_eq!(
2253                DatePart::from_str(input).unwrap(),
2254                expected,
2255                "parsing {input}"
2256            );
2257        }
2258    }
2259
2260    #[test]
2261    fn test_date_part_from_str_unknown() {
2262        // Names intentionally rejected — see the FromStr doc comment for why.
2263        let unknown = [
2264            "epoch",
2265            "century",
2266            "decade",
2267            "millennium",
2268            "timezone",
2269            "timezone_hour",
2270            "timezone_minute",
2271            // Whitespace is not trimmed — pin this so the behavior doesn't
2272            // change silently. Callers should trim before parsing.
2273            " year ",
2274            "year ",
2275            "",
2276            "nope",
2277        ];
2278        for s in unknown {
2279            let err = DatePart::from_str(s).unwrap_err();
2280            assert!(
2281                matches!(err, ArrowError::InvalidArgumentError(_)),
2282                "expected InvalidArgumentError for {s:?}, got: {err}"
2283            );
2284        }
2285    }
2286}