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