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