arrow-arith/src/temporal.rs (1,762 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. //! Defines temporal kernels for time and date related functions. use std::sync::Arc; use arrow_array::cast::AsArray; use cast::as_primitive_array; use chrono::{Datelike, TimeZone, Timelike, Utc}; use arrow_array::temporal_conversions::{ date32_to_datetime, date64_to_datetime, timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_s_to_datetime, timestamp_us_to_datetime, MICROSECONDS, MICROSECONDS_IN_DAY, MILLISECONDS, MILLISECONDS_IN_DAY, NANOSECONDS, NANOSECONDS_IN_DAY, SECONDS_IN_DAY, }; use arrow_array::timezone::Tz; use arrow_array::types::*; use arrow_array::*; use arrow_buffer::ArrowNativeType; use arrow_schema::{ArrowError, DataType, IntervalUnit, TimeUnit}; /// Valid parts to extract from date/time/timestamp arrays. /// /// See [`date_part`]. /// /// Marked as non-exhaustive as may expand to support more types of /// date parts in the future. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub enum DatePart { /// Quarter of the year, in range `1..=4` Quarter, /// Calendar year Year, /// ISO year, computed as per ISO 8601 YearISO, /// Month in the year, in range `1..=12` Month, /// week of the year, in range `1..=53`, computed as per ISO 8601 Week, /// ISO week of the year, in range `1..=53` WeekISO, /// Day of the month, in range `1..=31` Day, /// Day of the week, in range `0..=6`, where Sunday is `0` DayOfWeekSunday0, /// Day of the week, in range `0..=6`, where Monday is `0` DayOfWeekMonday0, /// Day of year, in range `1..=366` DayOfYear, /// Hour of the day, in range `0..=23` Hour, /// Minute of the hour, in range `0..=59` Minute, /// Second of the minute, in range `0..=59` Second, /// Millisecond of the second Millisecond, /// Microsecond of the second Microsecond, /// Nanosecond of the second Nanosecond, } impl std::fmt::Display for DatePart { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } /// Returns function to extract relevant [`DatePart`] from types like a /// [`NaiveDateTime`] or [`DateTime`]. /// /// [`NaiveDateTime`]: chrono::NaiveDateTime /// [`DateTime`]: chrono::DateTime fn get_date_time_part_extract_fn<T>(part: DatePart) -> fn(T) -> i32 where T: ChronoDateExt + Datelike + Timelike, { match part { DatePart::Quarter => |d| d.quarter() as i32, DatePart::Year => |d| d.year(), DatePart::YearISO => |d| d.iso_week().year(), DatePart::Month => |d| d.month() as i32, DatePart::Week | DatePart::WeekISO => |d| d.iso_week().week() as i32, DatePart::Day => |d| d.day() as i32, DatePart::DayOfWeekSunday0 => |d| d.num_days_from_sunday(), DatePart::DayOfWeekMonday0 => |d| d.num_days_from_monday(), DatePart::DayOfYear => |d| d.ordinal() as i32, DatePart::Hour => |d| d.hour() as i32, DatePart::Minute => |d| d.minute() as i32, DatePart::Second => |d| d.second() as i32, DatePart::Millisecond => |d| (d.nanosecond() / 1_000_000) as i32, DatePart::Microsecond => |d| (d.nanosecond() / 1_000) as i32, DatePart::Nanosecond => |d| d.nanosecond() as i32, } } /// Given an array, return a new array with the extracted [`DatePart`] as signed 32-bit /// integer values. /// /// Currently only supports temporal types: /// - Date32/Date64 /// - Time32/Time64 /// - Timestamp /// - Interval /// - Duration /// /// Returns an [`Int32Array`] unless input was a dictionary type, in which case returns /// the dictionary but with this function applied onto its values. /// /// If array passed in is not of the above listed types (or is a dictionary array where the /// values array isn't of the above listed types), then this function will return an error. /// /// # Examples /// /// ``` /// # use arrow_array::{Int32Array, TimestampMicrosecondArray}; /// # use arrow_arith::temporal::{DatePart, date_part}; /// let input: TimestampMicrosecondArray = /// vec![Some(1612025847000000), None, Some(1722015847000000)].into(); /// /// let week = date_part(&input, DatePart::Week).unwrap(); /// let week_iso = date_part(&input, DatePart::WeekISO).unwrap(); /// let expected: Int32Array = vec![Some(4), None, Some(30)].into(); /// assert_eq!(week.as_ref(), &expected); /// assert_eq!(week_iso.as_ref(), &expected); /// let year_iso = date_part(&input, DatePart::YearISO).unwrap(); /// let expected: Int32Array = vec![Some(2021), None, Some(2024)].into(); /// assert_eq!(year_iso.as_ref(), &expected); /// ``` pub fn date_part(array: &dyn Array, part: DatePart) -> Result<ArrayRef, ArrowError> { downcast_temporal_array!( array => { let array = array.date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Interval(IntervalUnit::YearMonth) => { let array = as_primitive_array::<IntervalYearMonthType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Interval(IntervalUnit::DayTime) => { let array = as_primitive_array::<IntervalDayTimeType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Interval(IntervalUnit::MonthDayNano) => { let array = as_primitive_array::<IntervalMonthDayNanoType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Duration(TimeUnit::Second) => { let array = as_primitive_array::<DurationSecondType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Duration(TimeUnit::Millisecond) => { let array = as_primitive_array::<DurationMillisecondType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Duration(TimeUnit::Microsecond) => { let array = as_primitive_array::<DurationMicrosecondType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Duration(TimeUnit::Nanosecond) => { let array = as_primitive_array::<DurationNanosecondType>(array).date_part(part)?; let array = Arc::new(array) as ArrayRef; Ok(array) } DataType::Dictionary(_, _) => { let array = array.as_any_dictionary(); let values = date_part(array.values(), part)?; let values = Arc::new(values) as ArrayRef; let new_array = array.with_values(values); Ok(new_array) } t => return_compute_error_with!(format!("{part} does not support"), t), ) } /// Used to integrate new [`date_part()`] method with deprecated shims such as /// [`hour()`] and [`week()`]. fn date_part_primitive<T: ArrowTemporalType>( array: &PrimitiveArray<T>, part: DatePart, ) -> Result<Int32Array, ArrowError> { let array = date_part(array, part)?; Ok(array.as_primitive::<Int32Type>().to_owned()) } /// Extract optional [`Tz`] from timestamp data types, returning error /// if called with a non-timestamp type. fn get_tz(dt: &DataType) -> Result<Option<Tz>, ArrowError> { match dt { DataType::Timestamp(_, Some(tz)) => Ok(Some(tz.parse::<Tz>()?)), DataType::Timestamp(_, None) => Ok(None), _ => Err(ArrowError::CastError(format!("Not a timestamp type: {dt}"))), } } /// Implement the specialized functions for extracting date part from temporal arrays. trait ExtractDatePartExt { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError>; } impl ExtractDatePartExt for PrimitiveArray<Time32SecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { #[inline] fn range_check(s: i32) -> bool { (0..SECONDS_IN_DAY as i32).contains(&s) } match part { DatePart::Hour => Ok(self.unary_opt(|s| range_check(s).then_some(s / 3_600))), DatePart::Minute => Ok(self.unary_opt(|s| range_check(s).then_some((s / 60) % 60))), DatePart::Second => Ok(self.unary_opt(|s| range_check(s).then_some(s % 60))), // Time32Second only encodes number of seconds, so these will always be 0 (if in valid range) DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond => { Ok(self.unary_opt(|s| range_check(s).then_some(0))) } _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()), } } } impl ExtractDatePartExt for PrimitiveArray<Time32MillisecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { #[inline] fn range_check(ms: i32) -> bool { (0..MILLISECONDS_IN_DAY as i32).contains(&ms) } let milliseconds = MILLISECONDS as i32; match part { DatePart::Hour => { Ok(self.unary_opt(|ms| range_check(ms).then_some(ms / 3_600 / milliseconds))) } DatePart::Minute => { Ok(self.unary_opt(|ms| range_check(ms).then_some((ms / 60 / milliseconds) % 60))) } DatePart::Second => { Ok(self.unary_opt(|ms| range_check(ms).then_some((ms / milliseconds) % 60))) } DatePart::Millisecond => { Ok(self.unary_opt(|ms| range_check(ms).then_some(ms % milliseconds))) } DatePart::Microsecond => { Ok(self.unary_opt(|ms| range_check(ms).then_some((ms % milliseconds) * 1_000))) } DatePart::Nanosecond => { Ok(self.unary_opt(|ms| range_check(ms).then_some((ms % milliseconds) * 1_000_000))) } _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()), } } } impl ExtractDatePartExt for PrimitiveArray<Time64MicrosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { #[inline] fn range_check(us: i64) -> bool { (0..MICROSECONDS_IN_DAY).contains(&us) } match part { DatePart::Hour => { Ok(self .unary_opt(|us| range_check(us).then_some((us / 3_600 / MICROSECONDS) as i32))) } DatePart::Minute => Ok(self .unary_opt(|us| range_check(us).then_some(((us / 60 / MICROSECONDS) % 60) as i32))), DatePart::Second => { Ok(self .unary_opt(|us| range_check(us).then_some(((us / MICROSECONDS) % 60) as i32))) } DatePart::Millisecond => Ok(self .unary_opt(|us| range_check(us).then_some(((us % MICROSECONDS) / 1_000) as i32))), DatePart::Microsecond => { Ok(self.unary_opt(|us| range_check(us).then_some((us % MICROSECONDS) as i32))) } DatePart::Nanosecond => Ok(self .unary_opt(|us| range_check(us).then_some(((us % MICROSECONDS) * 1_000) as i32))), _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()), } } } impl ExtractDatePartExt for PrimitiveArray<Time64NanosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { #[inline] fn range_check(ns: i64) -> bool { (0..NANOSECONDS_IN_DAY).contains(&ns) } match part { DatePart::Hour => { Ok(self .unary_opt(|ns| range_check(ns).then_some((ns / 3_600 / NANOSECONDS) as i32))) } DatePart::Minute => Ok(self .unary_opt(|ns| range_check(ns).then_some(((ns / 60 / NANOSECONDS) % 60) as i32))), DatePart::Second => Ok( self.unary_opt(|ns| range_check(ns).then_some(((ns / NANOSECONDS) % 60) as i32)) ), DatePart::Millisecond => Ok(self.unary_opt(|ns| { range_check(ns).then_some(((ns % NANOSECONDS) / 1_000_000) as i32) })), DatePart::Microsecond => { Ok(self .unary_opt(|ns| range_check(ns).then_some(((ns % NANOSECONDS) / 1_000) as i32))) } DatePart::Nanosecond => { Ok(self.unary_opt(|ns| range_check(ns).then_some((ns % NANOSECONDS) as i32))) } _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()), } } } impl ExtractDatePartExt for PrimitiveArray<Date32Type> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { // Date32 only encodes number of days, so these will always be 0 if let DatePart::Hour | DatePart::Minute | DatePart::Second | DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond = part { Ok(Int32Array::new( vec![0; self.len()].into(), self.nulls().cloned(), )) } else { let map_func = get_date_time_part_extract_fn(part); Ok(self.unary_opt(|d| date32_to_datetime(d).map(map_func))) } } } impl ExtractDatePartExt for PrimitiveArray<Date64Type> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { let map_func = get_date_time_part_extract_fn(part); Ok(self.unary_opt(|d| date64_to_datetime(d).map(map_func))) } } impl ExtractDatePartExt for PrimitiveArray<TimestampSecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { // TimestampSecond only encodes number of seconds, so these will always be 0 let array = if let DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond = part { Int32Array::new(vec![0; self.len()].into(), self.nulls().cloned()) } else if let Some(tz) = get_tz(self.data_type())? { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| { timestamp_s_to_datetime(d) .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz)) .map(map_func) }) } else { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| timestamp_s_to_datetime(d).map(map_func)) }; Ok(array) } } impl ExtractDatePartExt for PrimitiveArray<TimestampMillisecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { let array = if let Some(tz) = get_tz(self.data_type())? { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| { timestamp_ms_to_datetime(d) .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz)) .map(map_func) }) } else { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| timestamp_ms_to_datetime(d).map(map_func)) }; Ok(array) } } impl ExtractDatePartExt for PrimitiveArray<TimestampMicrosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { let array = if let Some(tz) = get_tz(self.data_type())? { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| { timestamp_us_to_datetime(d) .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz)) .map(map_func) }) } else { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| timestamp_us_to_datetime(d).map(map_func)) }; Ok(array) } } impl ExtractDatePartExt for PrimitiveArray<TimestampNanosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { let array = if let Some(tz) = get_tz(self.data_type())? { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| { timestamp_ns_to_datetime(d) .map(|c| Utc.from_utc_datetime(&c).with_timezone(&tz)) .map(map_func) }) } else { let map_func = get_date_time_part_extract_fn(part); self.unary_opt(|d| timestamp_ns_to_datetime(d).map(map_func)) }; Ok(array) } } impl ExtractDatePartExt for PrimitiveArray<IntervalYearMonthType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Year => Ok(self.unary_opt(|d| Some(d / 12))), DatePart::Month => Ok(self.unary_opt(|d| Some(d % 12))), DatePart::Quarter | DatePart::Week | DatePart::WeekISO | DatePart::YearISO | DatePart::Day | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear | DatePart::Hour | DatePart::Minute | DatePart::Second | DatePart::Millisecond | DatePart::Microsecond | DatePart::Nanosecond => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<IntervalDayTimeType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Week => Ok(self.unary_opt(|d| Some(d.days / 7))), DatePart::Day => Ok(self.unary_opt(|d| Some(d.days))), DatePart::Hour => Ok(self.unary_opt(|d| Some(d.milliseconds / (60 * 60 * 1_000)))), DatePart::Minute => Ok(self.unary_opt(|d| Some(d.milliseconds / (60 * 1_000) % 60))), DatePart::Second => Ok(self.unary_opt(|d| Some(d.milliseconds / 1_000 % 60))), DatePart::Millisecond => Ok(self.unary_opt(|d| Some(d.milliseconds % (60 * 1_000)))), DatePart::Microsecond => { Ok(self.unary_opt(|d| (d.milliseconds % (60 * 1_000)).checked_mul(1_000))) } DatePart::Nanosecond => { Ok(self.unary_opt(|d| (d.milliseconds % (60 * 1_000)).checked_mul(1_000_000))) } DatePart::Quarter | DatePart::Year | DatePart::YearISO | DatePart::WeekISO | DatePart::Month | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<IntervalMonthDayNanoType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Year => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.months / 12))), DatePart::Month => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.months % 12))), DatePart::Week => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.days / 7))), DatePart::Day => Ok(self.unary_opt(|d: IntervalMonthDayNano| Some(d.days))), DatePart::Hour => { Ok(self.unary_opt(|d| (d.nanoseconds / (60 * 60 * 1_000_000_000)).try_into().ok())) } DatePart::Minute => { Ok(self.unary_opt(|d| (d.nanoseconds / (60 * 1_000_000_000) % 60).try_into().ok())) } DatePart::Second => { Ok(self.unary_opt(|d| ((d.nanoseconds / 1_000_000_000) % 60).try_into().ok())) } DatePart::Millisecond => Ok(self.unary_opt(|d| { (d.nanoseconds % (60 * 1_000_000_000) / 1_000_000) .try_into() .ok() })), DatePart::Microsecond => Ok(self.unary_opt(|d| { (d.nanoseconds % (60 * 1_000_000_000) / 1_000) .try_into() .ok() })), DatePart::Nanosecond => { Ok(self.unary_opt(|d| (d.nanoseconds % (60 * 1_000_000_000)).try_into().ok())) } DatePart::Quarter | DatePart::WeekISO | DatePart::YearISO | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<DurationSecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Week => Ok(self.unary_opt(|d| (d / (60 * 60 * 24 * 7)).try_into().ok())), DatePart::Day => Ok(self.unary_opt(|d| (d / (60 * 60 * 24)).try_into().ok())), DatePart::Hour => Ok(self.unary_opt(|d| (d / (60 * 60)).try_into().ok())), DatePart::Minute => Ok(self.unary_opt(|d| (d / 60).try_into().ok())), DatePart::Second => Ok(self.unary_opt(|d| d.try_into().ok())), DatePart::Millisecond => { Ok(self.unary_opt(|d| d.checked_mul(1_000).and_then(|d| d.try_into().ok()))) } DatePart::Microsecond => { Ok(self.unary_opt(|d| d.checked_mul(1_000_000).and_then(|d| d.try_into().ok()))) } DatePart::Nanosecond => Ok( self.unary_opt(|d| d.checked_mul(1_000_000_000).and_then(|d| d.try_into().ok())) ), DatePart::Year | DatePart::YearISO | DatePart::WeekISO | DatePart::Quarter | DatePart::Month | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<DurationMillisecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Week => { Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24 * 7)).try_into().ok())) } DatePart::Day => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60 * 24)).try_into().ok())), DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000 * 60 * 60)).try_into().ok())), DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000 * 60)).try_into().ok())), DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())), DatePart::Millisecond => Ok(self.unary_opt(|d| d.try_into().ok())), DatePart::Microsecond => { Ok(self.unary_opt(|d| d.checked_mul(1_000).and_then(|d| d.try_into().ok()))) } DatePart::Nanosecond => { Ok(self.unary_opt(|d| d.checked_mul(1_000_000).and_then(|d| d.try_into().ok()))) } DatePart::Year | DatePart::YearISO | DatePart::WeekISO | DatePart::Quarter | DatePart::Month | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<DurationMicrosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Week => { Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24 * 7)).try_into().ok())) } DatePart::Day => { Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60 * 24)).try_into().ok())) } DatePart::Hour => Ok(self.unary_opt(|d| (d / (1_000_000 * 60 * 60)).try_into().ok())), DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000 * 60)).try_into().ok())), DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())), DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())), DatePart::Microsecond => Ok(self.unary_opt(|d| d.try_into().ok())), DatePart::Nanosecond => { Ok(self.unary_opt(|d| d.checked_mul(1_000).and_then(|d| d.try_into().ok()))) } DatePart::Year | DatePart::YearISO | DatePart::WeekISO | DatePart::Quarter | DatePart::Month | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } impl ExtractDatePartExt for PrimitiveArray<DurationNanosecondType> { fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> { match part { DatePart::Week => { Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24 * 7)).try_into().ok())) } DatePart::Day => { Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60 * 24)).try_into().ok())) } DatePart::Hour => { Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60 * 60)).try_into().ok())) } DatePart::Minute => Ok(self.unary_opt(|d| (d / (1_000_000_000 * 60)).try_into().ok())), DatePart::Second => Ok(self.unary_opt(|d| (d / 1_000_000_000).try_into().ok())), DatePart::Millisecond => Ok(self.unary_opt(|d| (d / 1_000_000).try_into().ok())), DatePart::Microsecond => Ok(self.unary_opt(|d| (d / 1_000).try_into().ok())), DatePart::Nanosecond => Ok(self.unary_opt(|d| d.try_into().ok())), DatePart::Year | DatePart::YearISO | DatePart::WeekISO | DatePart::Quarter | DatePart::Month | DatePart::DayOfWeekSunday0 | DatePart::DayOfWeekMonday0 | DatePart::DayOfYear => { return_compute_error_with!(format!("{part} does not support"), self.data_type()) } } } } macro_rules! return_compute_error_with { ($msg:expr, $param:expr) => { return { Err(ArrowError::ComputeError(format!("{}: {:?}", $msg, $param))) } }; } pub(crate) use return_compute_error_with; // Internal trait, which is used for mapping values from DateLike structures trait ChronoDateExt { /// Returns the day of week; Monday is encoded as `0`, Tuesday as `1`, etc. fn num_days_from_monday(&self) -> i32; /// Returns the day of week; Sunday is encoded as `0`, Monday as `1`, etc. fn num_days_from_sunday(&self) -> i32; } impl<T: Datelike> ChronoDateExt for T { fn num_days_from_monday(&self) -> i32 { self.weekday().num_days_from_monday() as i32 } fn num_days_from_sunday(&self) -> i32 { self.weekday().num_days_from_sunday() as i32 } } /// Extracts the hours of a given array as an array of integers within /// the range of [0, 23]. If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn hour_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Hour) } /// Extracts the hours of a given temporal primitive array as an array of integers within /// the range of [0, 23]. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn hour<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Hour) } /// Extracts the years of a given temporal array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn year_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Year) } /// Extracts the years of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn year<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Year) } /// Extracts the quarter of a given temporal array as an array of integersa within /// the range of [1, 4]. If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn quarter_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Quarter) } /// Extracts the quarter of a given temporal primitive array as an array of integers within /// the range of [1, 4]. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn quarter<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Quarter) } /// Extracts the month of a given temporal array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn month_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Month) } /// Extracts the month of a given temporal primitive array as an array of integers within /// the range of [1, 12]. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn month<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Month) } /// Extracts the day of week of a given temporal array as an array of /// integers. /// /// Monday is encoded as `0`, Tuesday as `1`, etc. /// /// See also [`num_days_from_sunday`] which starts at Sunday. /// /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn num_days_from_monday_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::DayOfWeekMonday0) } /// Extracts the day of week of a given temporal primitive array as an array of /// integers. /// /// Monday is encoded as `0`, Tuesday as `1`, etc. /// /// See also [`num_days_from_sunday`] which starts at Sunday. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn num_days_from_monday<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::DayOfWeekMonday0) } /// Extracts the day of week of a given temporal array as an array of /// integers, starting at Sunday. /// /// Sunday is encoded as `0`, Monday as `1`, etc. /// /// See also [`num_days_from_monday`] which starts at Monday. /// /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn num_days_from_sunday_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::DayOfWeekSunday0) } /// Extracts the day of week of a given temporal primitive array as an array of /// integers, starting at Sunday. /// /// Sunday is encoded as `0`, Monday as `1`, etc. /// /// See also [`num_days_from_monday`] which starts at Monday. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn num_days_from_sunday<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::DayOfWeekSunday0) } /// Extracts the day of a given temporal array as an array of integers. /// /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn day_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Day) } /// Extracts the day of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn day<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Day) } /// Extracts the day of year of a given temporal array as an array of integers. /// /// The day of year that ranges from 1 to 366. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn doy_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::DayOfYear) } /// Extracts the day of year of a given temporal primitive array as an array of integers. /// /// The day of year that ranges from 1 to 366 #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn doy<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, T::Native: ArrowNativeType, i64: From<T::Native>, { date_part_primitive(array, DatePart::DayOfYear) } /// Extracts the minutes of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn minute<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Minute) } /// Extracts the week of a given temporal array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn week_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Week) } /// Extracts the week of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn week<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Week) } /// Extracts the seconds of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn second<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Second) } /// Extracts the nanoseconds of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn nanosecond<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Nanosecond) } /// Extracts the nanoseconds of a given temporal primitive array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn nanosecond_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Nanosecond) } /// Extracts the microseconds of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn microsecond<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Microsecond) } /// Extracts the microseconds of a given temporal primitive array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn microsecond_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Microsecond) } /// Extracts the milliseconds of a given temporal primitive array as an array of integers #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn millisecond<T>(array: &PrimitiveArray<T>) -> Result<Int32Array, ArrowError> where T: ArrowTemporalType + ArrowNumericType, i64: From<T::Native>, { date_part_primitive(array, DatePart::Millisecond) } /// Extracts the milliseconds of a given temporal primitive array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn millisecond_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Millisecond) } /// Extracts the minutes of a given temporal array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn minute_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Minute) } /// Extracts the seconds of a given temporal array as an array of integers. /// If the given array isn't temporal primitive or dictionary array, /// an `Err` will be returned. #[deprecated(since = "51.0.0", note = "Use `date_part` instead")] pub fn second_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowError> { date_part(array, DatePart::Second) } #[cfg(test)] #[allow(deprecated)] mod tests { use super::*; #[test] fn test_temporal_array_date64_hour() { let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = hour(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(4, b.value(2)); } #[test] fn test_temporal_array_date32_hour() { let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15148)].into(); let b = hour(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(0, b.value(2)); } #[test] fn test_temporal_array_time32_second_hour() { let a: PrimitiveArray<Time32SecondType> = vec![37800, 86339].into(); let b = hour(&a).unwrap(); assert_eq!(10, b.value(0)); assert_eq!(23, b.value(1)); } #[test] fn test_temporal_array_time64_micro_hour() { let a: PrimitiveArray<Time64MicrosecondType> = vec![37800000000, 86339000000].into(); let b = hour(&a).unwrap(); assert_eq!(10, b.value(0)); assert_eq!(23, b.value(1)); } #[test] fn test_temporal_array_timestamp_micro_hour() { let a: TimestampMicrosecondArray = vec![37800000000, 86339000000].into(); let b = hour(&a).unwrap(); assert_eq!(10, b.value(0)); assert_eq!(23, b.value(1)); } #[test] fn test_temporal_array_date64_year() { let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = year(&a).unwrap(); assert_eq!(2018, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2019, b.value(2)); } #[test] fn test_temporal_array_date32_year() { let a: PrimitiveArray<Date32Type> = vec![Some(15147), None, Some(15448)].into(); let b = year(&a).unwrap(); assert_eq!(2011, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2012, b.value(2)); } #[test] fn test_temporal_array_date64_quarter() { //1514764800000 -> 2018-01-01 //1566275025000 -> 2019-08-20 let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1566275025000)].into(); let b = quarter(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(3, b.value(2)); } #[test] fn test_temporal_array_date32_quarter() { let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(300)].into(); let b = quarter(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(4, b.value(2)); } #[test] fn test_temporal_array_timestamp_quarter_with_timezone() { // 24 * 60 * 60 = 86400 let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("+00:00".to_string()); let b = quarter(&a).unwrap(); assert_eq!(2, b.value(0)); let a = TimestampSecondArray::from(vec![86400 * 90]).with_timezone("-10:00".to_string()); let b = quarter(&a).unwrap(); assert_eq!(1, b.value(0)); } #[test] fn test_temporal_array_date64_month() { //1514764800000 -> 2018-01-01 //1550636625000 -> 2019-02-20 let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = month(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2, b.value(2)); } #[test] fn test_temporal_array_date32_month() { let a: PrimitiveArray<Date32Type> = vec![Some(1), None, Some(31)].into(); let b = month(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2, b.value(2)); } #[test] fn test_temporal_array_timestamp_month_with_timezone() { // 24 * 60 * 60 = 86400 let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("+00:00".to_string()); let b = month(&a).unwrap(); assert_eq!(2, b.value(0)); let a = TimestampSecondArray::from(vec![86400 * 31]).with_timezone("-10:00".to_string()); let b = month(&a).unwrap(); assert_eq!(1, b.value(0)); } #[test] fn test_temporal_array_timestamp_day_with_timezone() { // 24 * 60 * 60 = 86400 let a = TimestampSecondArray::from(vec![86400]).with_timezone("+00:00".to_string()); let b = day(&a).unwrap(); assert_eq!(2, b.value(0)); let a = TimestampSecondArray::from(vec![86400]).with_timezone("-10:00".to_string()); let b = day(&a).unwrap(); assert_eq!(1, b.value(0)); } #[test] fn test_temporal_array_date64_weekday() { //1514764800000 -> 2018-01-01 (Monday) //1550636625000 -> 2019-02-20 (Wednesday) let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = num_days_from_monday(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2, b.value(2)); } #[test] fn test_temporal_array_date64_weekday0() { //1483228800000 -> 2017-01-01 (Sunday) //1514764800000 -> 2018-01-01 (Monday) //1550636625000 -> 2019-02-20 (Wednesday) let a: PrimitiveArray<Date64Type> = vec![ Some(1483228800000), None, Some(1514764800000), Some(1550636625000), ] .into(); let b = num_days_from_sunday(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(1, b.value(2)); assert_eq!(3, b.value(3)); } #[test] fn test_temporal_array_date64_day() { //1514764800000 -> 2018-01-01 //1550636625000 -> 2019-02-20 let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = day(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(20, b.value(2)); } #[test] fn test_temporal_array_date32_day() { let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(31)].into(); let b = day(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(1, b.value(2)); } #[test] fn test_temporal_array_date64_doy() { //1483228800000 -> 2017-01-01 (Sunday) //1514764800000 -> 2018-01-01 //1550636625000 -> 2019-02-20 let a: PrimitiveArray<Date64Type> = vec![ Some(1483228800000), Some(1514764800000), None, Some(1550636625000), ] .into(); let b = doy(&a).unwrap(); assert_eq!(1, b.value(0)); assert_eq!(1, b.value(1)); assert!(!b.is_valid(2)); assert_eq!(51, b.value(3)); } #[test] fn test_temporal_array_timestamp_micro_year() { let a: TimestampMicrosecondArray = vec![Some(1612025847000000), None, Some(1722015847000000)].into(); let b = year(&a).unwrap(); assert_eq!(2021, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2024, b.value(2)); } #[test] fn test_temporal_array_date64_minute() { let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = minute(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(23, b.value(2)); } #[test] fn test_temporal_array_timestamp_micro_minute() { let a: TimestampMicrosecondArray = vec![Some(1612025847000000), None, Some(1722015847000000)].into(); let b = minute(&a).unwrap(); assert_eq!(57, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(44, b.value(2)); } #[test] fn test_temporal_array_date32_week() { let a: PrimitiveArray<Date32Type> = vec![Some(0), None, Some(7)].into(); let b = week(&a).unwrap(); assert_eq!(1, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(2, b.value(2)); } #[test] fn test_temporal_array_date64_week() { // 1646116175000 -> 2022.03.01 , 1641171600000 -> 2022.01.03 // 1640998800000 -> 2022.01.01 let a: PrimitiveArray<Date64Type> = vec![ Some(1646116175000), None, Some(1641171600000), Some(1640998800000), ] .into(); let b = week(&a).unwrap(); assert_eq!(9, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(1, b.value(2)); assert_eq!(52, b.value(3)); } #[test] fn test_temporal_array_timestamp_micro_week() { //1612025847000000 -> 2021.1.30 //1722015847000000 -> 2024.7.27 let a: TimestampMicrosecondArray = vec![Some(1612025847000000), None, Some(1722015847000000)].into(); let b = week(&a).unwrap(); assert_eq!(4, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(30, b.value(2)); } #[test] fn test_temporal_array_date64_second() { let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), None, Some(1550636625000)].into(); let b = second(&a).unwrap(); assert_eq!(0, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(45, b.value(2)); } #[test] fn test_temporal_array_timestamp_micro_second() { let a: TimestampMicrosecondArray = vec![Some(1612025847000000), None, Some(1722015847000000)].into(); let b = second(&a).unwrap(); assert_eq!(27, b.value(0)); assert!(!b.is_valid(1)); assert_eq!(7, b.value(2)); } #[test] fn test_temporal_array_timestamp_second_with_timezone() { let a = TimestampSecondArray::from(vec![10, 20]).with_timezone("+00:00".to_string()); let b = second(&a).unwrap(); assert_eq!(10, b.value(0)); assert_eq!(20, b.value(1)); } #[test] fn test_temporal_array_timestamp_minute_with_timezone() { let a = TimestampSecondArray::from(vec![0, 60]).with_timezone("+00:50".to_string()); let b = minute(&a).unwrap(); assert_eq!(50, b.value(0)); assert_eq!(51, b.value(1)); } #[test] fn test_temporal_array_timestamp_minute_with_negative_timezone() { let a = TimestampSecondArray::from(vec![60 * 55]).with_timezone("-00:50".to_string()); let b = minute(&a).unwrap(); assert_eq!(5, b.value(0)); } #[test] fn test_temporal_array_timestamp_hour_with_timezone() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01:00".to_string()); let b = hour(&a).unwrap(); assert_eq!(11, b.value(0)); } #[test] fn test_temporal_array_timestamp_hour_with_timezone_without_colon() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+0100".to_string()); let b = hour(&a).unwrap(); assert_eq!(11, b.value(0)); } #[test] fn test_temporal_array_timestamp_hour_with_timezone_without_minutes() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("+01".to_string()); let b = hour(&a).unwrap(); assert_eq!(11, b.value(0)); } #[test] fn test_temporal_array_timestamp_hour_with_timezone_without_initial_sign() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("0100".to_string()); let err = hour(&a).unwrap_err().to_string(); assert!(err.contains("Invalid timezone"), "{}", err); } #[test] fn test_temporal_array_timestamp_hour_with_timezone_with_only_colon() { let a = TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("01:00".to_string()); let err = hour(&a).unwrap_err().to_string(); assert!(err.contains("Invalid timezone"), "{}", err); } #[test] fn test_temporal_array_timestamp_week_without_timezone() { // 1970-01-01T00:00:00 -> 1970-01-01T00:00:00 Thursday (week 1) // 1970-01-01T00:00:00 + 4 days -> 1970-01-05T00:00:00 Monday (week 2) // 1970-01-01T00:00:00 + 4 days - 1 second -> 1970-01-04T23:59:59 Sunday (week 1) let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1]); let b = week(&a).unwrap(); assert_eq!(1, b.value(0)); assert_eq!(2, b.value(1)); assert_eq!(1, b.value(2)); } #[test] fn test_temporal_array_timestamp_week_with_timezone() { // 1970-01-01T01:00:00+01:00 -> 1970-01-01T01:00:00+01:00 Thursday (week 1) // 1970-01-01T01:00:00+01:00 + 4 days -> 1970-01-05T01:00:00+01:00 Monday (week 2) // 1970-01-01T01:00:00+01:00 + 4 days - 1 second -> 1970-01-05T00:59:59+01:00 Monday (week 2) let a = TimestampSecondArray::from(vec![0, 86400 * 4, 86400 * 4 - 1]) .with_timezone("+01:00".to_string()); let b = week(&a).unwrap(); assert_eq!(1, b.value(0)); assert_eq!(2, b.value(1)); assert_eq!(2, b.value(2)); } #[test] fn test_hour_minute_second_dictionary_array() { let a = TimestampSecondArray::from(vec![ 60 * 60 * 10 + 61, 60 * 60 * 20 + 122, 60 * 60 * 30 + 183, ]) .with_timezone("+01:00".to_string()); let keys = Int8Array::from_iter_values([0_i8, 0, 1, 2, 1]); let dict = DictionaryArray::try_new(keys.clone(), Arc::new(a)).unwrap(); let b = hour_dyn(&dict).unwrap(); let expected_dict = DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![11, 21, 7]))); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); let b = date_part(&dict, DatePart::Minute).unwrap(); let b_old = minute_dyn(&dict).unwrap(); let expected_dict = DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3]))); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); assert_eq!(&expected, &b_old); let b = date_part(&dict, DatePart::Second).unwrap(); let b_old = second_dyn(&dict).unwrap(); let expected_dict = DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 2, 3]))); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); assert_eq!(&expected, &b_old); let b = date_part(&dict, DatePart::Nanosecond).unwrap(); let expected_dict = DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![0, 0, 0, 0, 0]))); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); } #[test] fn test_year_dictionary_array() { let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into(); let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = year_dyn(&dict).unwrap(); let expected_dict = DictionaryArray::new( keys, Arc::new(Int32Array::from(vec![2018, 2019, 2019, 2018])), ); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); } #[test] fn test_quarter_month_dictionary_array() { //1514764800000 -> 2018-01-01 //1566275025000 -> 2019-08-20 let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1566275025000)].into(); let keys = Int8Array::from_iter_values([0_i8, 1, 1, 0]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = quarter_dyn(&dict).unwrap(); let expected = DictionaryArray::new(keys.clone(), Arc::new(Int32Array::from(vec![1, 3, 3, 1]))); assert_eq!(b.as_ref(), &expected); let b = month_dyn(&dict).unwrap(); let expected = DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![1, 8, 8, 1]))); assert_eq!(b.as_ref(), &expected); } #[test] fn test_num_days_from_monday_sunday_day_doy_week_dictionary_array() { //1514764800000 -> 2018-01-01 (Monday) //1550636625000 -> 2019-02-20 (Wednesday) let a: PrimitiveArray<Date64Type> = vec![Some(1514764800000), Some(1550636625000)].into(); let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1), Some(0), None]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = num_days_from_monday_dyn(&dict).unwrap(); let a = Int32Array::from(vec![Some(0), Some(2), Some(2), Some(0), None]); let expected = DictionaryArray::new(keys.clone(), Arc::new(a)); assert_eq!(b.as_ref(), &expected); let b = num_days_from_sunday_dyn(&dict).unwrap(); let a = Int32Array::from(vec![Some(1), Some(3), Some(3), Some(1), None]); let expected = DictionaryArray::new(keys.clone(), Arc::new(a)); assert_eq!(b.as_ref(), &expected); let b = day_dyn(&dict).unwrap(); let a = Int32Array::from(vec![Some(1), Some(20), Some(20), Some(1), None]); let expected = DictionaryArray::new(keys.clone(), Arc::new(a)); assert_eq!(b.as_ref(), &expected); let b = doy_dyn(&dict).unwrap(); let a = Int32Array::from(vec![Some(1), Some(51), Some(51), Some(1), None]); let expected = DictionaryArray::new(keys.clone(), Arc::new(a)); assert_eq!(b.as_ref(), &expected); let b = week_dyn(&dict).unwrap(); let a = Int32Array::from(vec![Some(1), Some(8), Some(8), Some(1), None]); let expected = DictionaryArray::new(keys, Arc::new(a)); assert_eq!(b.as_ref(), &expected); } #[test] fn test_temporal_array_date64_nanosecond() { // new Date(1667328721453) // Tue Nov 01 2022 11:52:01 GMT-0700 (Pacific Daylight Time) // // new Date(1667328721453).getMilliseconds() // 453 let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into(); let b = nanosecond(&a).unwrap(); assert!(!b.is_valid(0)); assert_eq!(453_000_000, b.value(1)); let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = nanosecond_dyn(&dict).unwrap(); let a = Int32Array::from(vec![None, Some(453_000_000)]); let expected_dict = DictionaryArray::new(keys, Arc::new(a)); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); } #[test] fn test_temporal_array_date64_microsecond() { let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into(); let b = microsecond(&a).unwrap(); assert!(!b.is_valid(0)); assert_eq!(453_000, b.value(1)); let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = microsecond_dyn(&dict).unwrap(); let a = Int32Array::from(vec![None, Some(453_000)]); let expected_dict = DictionaryArray::new(keys, Arc::new(a)); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); } #[test] fn test_temporal_array_date64_millisecond() { let a: PrimitiveArray<Date64Type> = vec![None, Some(1667328721453)].into(); let b = millisecond(&a).unwrap(); assert!(!b.is_valid(0)); assert_eq!(453, b.value(1)); let keys = Int8Array::from(vec![Some(0_i8), Some(1), Some(1)]); let dict = DictionaryArray::new(keys.clone(), Arc::new(a)); let b = millisecond_dyn(&dict).unwrap(); let a = Int32Array::from(vec![None, Some(453)]); let expected_dict = DictionaryArray::new(keys, Arc::new(a)); let expected = Arc::new(expected_dict) as ArrayRef; assert_eq!(&expected, &b); } #[test] fn test_temporal_array_time64_nanoseconds() { // 23:32:50.123456789 let input: Time64NanosecondArray = vec![Some(84_770_123_456_789)].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(23, actual.value(0)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(32, actual.value(0)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(50, actual.value(0)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123, actual.value(0)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_456, actual.value(0)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_456_789, actual.value(0)); // invalid values should turn into null let input: Time64NanosecondArray = vec![ Some(-1), Some(86_400_000_000_000), Some(86_401_000_000_000), None, ] .into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); let expected: Int32Array = vec![None, None, None, None].into(); assert_eq!(&expected, actual); } #[test] fn test_temporal_array_time64_microseconds() { // 23:32:50.123456 let input: Time64MicrosecondArray = vec![Some(84_770_123_456)].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(23, actual.value(0)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(32, actual.value(0)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(50, actual.value(0)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123, actual.value(0)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_456, actual.value(0)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_456_000, actual.value(0)); // invalid values should turn into null let input: Time64MicrosecondArray = vec![Some(-1), Some(86_400_000_000), Some(86_401_000_000), None].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); let expected: Int32Array = vec![None, None, None, None].into(); assert_eq!(&expected, actual); } #[test] fn test_temporal_array_time32_milliseconds() { // 23:32:50.123 let input: Time32MillisecondArray = vec![Some(84_770_123)].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(23, actual.value(0)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(32, actual.value(0)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(50, actual.value(0)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123, actual.value(0)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_000, actual.value(0)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(123_000_000, actual.value(0)); // invalid values should turn into null let input: Time32MillisecondArray = vec![Some(-1), Some(86_400_000), Some(86_401_000), None].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); let expected: Int32Array = vec![None, None, None, None].into(); assert_eq!(&expected, actual); } #[test] fn test_temporal_array_time32_seconds() { // 23:32:50 let input: Time32SecondArray = vec![84_770].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(23, actual.value(0)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(32, actual.value(0)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(50, actual.value(0)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); // invalid values should turn into null let input: Time32SecondArray = vec![Some(-1), Some(86_400), Some(86_401), None].into(); let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); let expected: Int32Array = vec![None, None, None, None].into(); assert_eq!(&expected, actual); } #[test] fn test_temporal_array_time_invalid_parts() { fn ensure_returns_error(array: &dyn Array) { let invalid_parts = [ DatePart::Quarter, DatePart::Year, DatePart::Month, DatePart::Week, DatePart::Day, DatePart::DayOfWeekSunday0, DatePart::DayOfWeekMonday0, DatePart::DayOfYear, ]; for part in invalid_parts { let err = date_part(array, part).unwrap_err(); let expected = format!( "Compute error: {part} does not support: {}", array.data_type() ); assert_eq!(expected, err.to_string()); } } ensure_returns_error(&Time32SecondArray::from(vec![0])); ensure_returns_error(&Time32MillisecondArray::from(vec![0])); ensure_returns_error(&Time64MicrosecondArray::from(vec![0])); ensure_returns_error(&Time64NanosecondArray::from(vec![0])); } #[test] fn test_interval_year_month_array() { let input: IntervalYearMonthArray = vec![0, 5, 24].into(); let actual = date_part(&input, DatePart::Year).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(2, actual.value(2)); let actual = date_part(&input, DatePart::Month).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(5, actual.value(1)); assert_eq!(0, actual.value(2)); assert!(date_part(&input, DatePart::Day).is_err()); assert!(date_part(&input, DatePart::Week).is_err()); } // IntervalDayTimeType week, day, hour, minute, second, milli, u, nano; // invalid month, year; ignores the other part #[test] fn test_interval_day_time_array() { let input: IntervalDayTimeArray = vec![ IntervalDayTime::ZERO, IntervalDayTime::new(10, 42), // 10d, 42ms IntervalDayTime::new(10, 1042), // 10d, 1s, 42ms IntervalDayTime::new(10, MILLISECONDS_IN_DAY as i32 + 1), // 10d, 24h, 1ms IntervalDayTime::new( 6, (MILLISECONDS * 60 * 60 * 4 + MILLISECONDS * 60 * 22 + MILLISECONDS * 11 + 3) as i32, ), // 6d, 4h, 22m, 11s, 3ms ] .into(); // Time doesn't affect days. let actual = date_part(&input, DatePart::Day).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(10, actual.value(1)); assert_eq!(10, actual.value(2)); assert_eq!(10, actual.value(3)); assert_eq!(6, actual.value(4)); let actual = date_part(&input, DatePart::Week).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(1, actual.value(1)); assert_eq!(1, actual.value(2)); assert_eq!(1, actual.value(3)); assert_eq!(0, actual.value(4)); // Days doesn't affect time. let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(24, actual.value(3)); assert_eq!(4, actual.value(4)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(0, actual.value(3)); assert_eq!(22, actual.value(4)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(1, actual.value(2)); assert_eq!(0, actual.value(3)); assert_eq!(11, actual.value(4)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(1042, actual.value(2)); assert_eq!(1, actual.value(3)); assert_eq!(11003, actual.value(4)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000, actual.value(1)); assert_eq!(1_042_000, actual.value(2)); assert_eq!(1_000, actual.value(3)); assert_eq!(11_003_000, actual.value(4)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000_000, actual.value(1)); assert_eq!(1_042_000_000, actual.value(2)); assert_eq!(1_000_000, actual.value(3)); // Overflow returns zero. assert_eq!(0, actual.value(4)); // Month and year are not valid (since days in month varies). assert!(date_part(&input, DatePart::Month).is_err()); assert!(date_part(&input, DatePart::Year).is_err()); } // IntervalMonthDayNanoType year -> nano; // days don't affect months, time doesn't affect days, time doesn't affect months (and vice versa) #[test] fn test_interval_month_day_nano_array() { let input: IntervalMonthDayNanoArray = vec![ IntervalMonthDayNano::ZERO, IntervalMonthDayNano::new(5, 10, 42), // 5m, 1w, 3d, 42ns IntervalMonthDayNano::new(16, 35, NANOSECONDS_IN_DAY + 1), // 1y, 4m, 5w, 24h, 1ns IntervalMonthDayNano::new( 0, 0, NANOSECONDS * 60 * 60 * 4 + NANOSECONDS * 60 * 22 + NANOSECONDS * 11 + 1_000_000 * 33 + 1_000 * 44 + 5, ), // 4hr, 22m, 11s, 33ms, 44us, 5ns ] .into(); // Year and month follow from month, but are not affected by days or nanos. let actual = date_part(&input, DatePart::Year).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(1, actual.value(2)); assert_eq!(0, actual.value(3)); let actual = date_part(&input, DatePart::Month).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(5, actual.value(1)); assert_eq!(4, actual.value(2)); assert_eq!(0, actual.value(3)); // Week and day follow from day, but are not affected by months or nanos. let actual = date_part(&input, DatePart::Week).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(1, actual.value(1)); assert_eq!(5, actual.value(2)); assert_eq!(0, actual.value(3)); let actual = date_part(&input, DatePart::Day).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(10, actual.value(1)); assert_eq!(35, actual.value(2)); assert_eq!(0, actual.value(3)); // Times follow from nanos, but are not affected by months or days. let actual = date_part(&input, DatePart::Hour).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(24, actual.value(2)); assert_eq!(4, actual.value(3)); let actual = date_part(&input, DatePart::Minute).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(22, actual.value(3)); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(11, actual.value(3)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(11_033, actual.value(3)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); assert_eq!(11_033_044, actual.value(3)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(1, actual.value(2)); // Overflow returns zero. assert_eq!(0, actual.value(3)); } #[test] fn test_interval_array_invalid_parts() { fn ensure_returns_error(array: &dyn Array) { let invalid_parts = [ DatePart::Quarter, DatePart::DayOfWeekSunday0, DatePart::DayOfWeekMonday0, DatePart::DayOfYear, ]; for part in invalid_parts { let err = date_part(array, part).unwrap_err(); let expected = format!( "Compute error: {part} does not support: {}", array.data_type() ); assert_eq!(expected, err.to_string()); } } ensure_returns_error(&IntervalYearMonthArray::from(vec![0])); ensure_returns_error(&IntervalDayTimeArray::from(vec![IntervalDayTime::ZERO])); ensure_returns_error(&IntervalMonthDayNanoArray::from(vec![ IntervalMonthDayNano::ZERO, ])); } #[test] fn test_duration_second() { let input: DurationSecondArray = vec![0, 42, 60 * 60 * 24 + 1].into(); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(60 * 60 * 24 + 1, actual.value(2)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000_000, actual.value(1)); assert_eq!(0, actual.value(2)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); } #[test] fn test_duration_millisecond() { let input: DurationMillisecondArray = vec![0, 42, 60 * 60 * 24 + 1].into(); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(60 * 60 * 24 + 1, actual.value(2)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000_000, actual.value(1)); assert_eq!(0, actual.value(2)); } #[test] fn test_duration_microsecond() { let input: DurationMicrosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into(); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(60 * 60 * 24 + 1, actual.value(2)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42_000, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) * 1_000, actual.value(2)); } #[test] fn test_duration_nanosecond() { let input: DurationNanosecondArray = vec![0, 42, 60 * 60 * 24 + 1].into(); let actual = date_part(&input, DatePart::Second).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); let actual = date_part(&input, DatePart::Millisecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!(0, actual.value(2)); let actual = date_part(&input, DatePart::Microsecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(0, actual.value(1)); assert_eq!((60 * 60 * 24 + 1) / 1_000, actual.value(2)); let actual = date_part(&input, DatePart::Nanosecond).unwrap(); let actual = actual.as_primitive::<Int32Type>(); assert_eq!(0, actual.value(0)); assert_eq!(42, actual.value(1)); assert_eq!(60 * 60 * 24 + 1, actual.value(2)); } #[test] fn test_duration_invalid_parts() { fn ensure_returns_error(array: &dyn Array) { let invalid_parts = [ DatePart::Year, DatePart::Quarter, DatePart::Month, DatePart::DayOfWeekSunday0, DatePart::DayOfWeekMonday0, DatePart::DayOfYear, ]; for part in invalid_parts { let err = date_part(array, part).unwrap_err(); let expected = format!( "Compute error: {part} does not support: {}", array.data_type() ); assert_eq!(expected, err.to_string()); } } ensure_returns_error(&DurationSecondArray::from(vec![0])); ensure_returns_error(&DurationMillisecondArray::from(vec![0])); ensure_returns_error(&DurationMicrosecondArray::from(vec![0])); ensure_returns_error(&DurationNanosecondArray::from(vec![0])); } const TIMESTAMP_SECOND_1970_01_01: i64 = 0; const TIMESTAMP_SECOND_2018_01_01: i64 = 1_514_764_800; const TIMESTAMP_SECOND_2019_02_20: i64 = 1_550_636_625; const SECONDS_IN_DAY: i64 = 24 * 60 * 60; // In 2018 the ISO year and calendar year start on the same date— 2018-01-01 or 2018-W01-1 #[test] fn test_temporal_array_date64_week_iso() { let a: PrimitiveArray<Date64Type> = vec![ Some(TIMESTAMP_SECOND_2018_01_01 * 1000), Some(TIMESTAMP_SECOND_2019_02_20 * 1000), ] .into(); let b = date_part(&a, DatePart::WeekISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(1, actual.value(0)); assert_eq!(8, actual.value(1)); } #[test] fn test_temporal_array_date64_year_iso() { let a: PrimitiveArray<Date64Type> = vec![ Some(TIMESTAMP_SECOND_2018_01_01 * 1000), Some(TIMESTAMP_SECOND_2019_02_20 * 1000), ] .into(); let b = date_part(&a, DatePart::YearISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(2018, actual.value(0)); assert_eq!(2019, actual.value(1)); } #[test] fn test_temporal_array_timestamp_week_iso() { let a = TimestampSecondArray::from(vec![ TIMESTAMP_SECOND_1970_01_01, // 0 and is Thursday SECONDS_IN_DAY * 4, // Monday of week 2 SECONDS_IN_DAY * 4 - 1, // Sunday of week 1 ]); let b = date_part(&a, DatePart::WeekISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(1, actual.value(0)); assert_eq!(2, actual.value(1)); assert_eq!(1, actual.value(2)); } #[test] fn test_temporal_array_timestamp_year_iso() { let a = TimestampSecondArray::from(vec![ TIMESTAMP_SECOND_1970_01_01, SECONDS_IN_DAY * 4, SECONDS_IN_DAY * 4 - 1, ]); let b = date_part(&a, DatePart::YearISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(1970, actual.value(0)); assert_eq!(1970, actual.value(1)); assert_eq!(1970, actual.value(2)); } const TIMESTAMP_SECOND_2015_12_28: i64 = 1_451_260_800; const TIMESTAMP_SECOND_2016_01_03: i64 = 1_451_779_200; // January 1st 2016 is a Friday, so 2015 week 53 runs from // 2015-12-28 to 2016-01-03 inclusive, and // 2016 week 1 runs from 2016-01-04 to 2016-01-10 inclusive. #[test] fn test_temporal_array_date64_week_iso_edge_cases() { let a: PrimitiveArray<Date64Type> = vec![ Some(TIMESTAMP_SECOND_2015_12_28 * 1000), Some(TIMESTAMP_SECOND_2016_01_03 * 1000), Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000), ] .into(); let b = date_part(&a, DatePart::WeekISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(53, actual.value(0)); assert_eq!(53, actual.value(1)); assert_eq!(1, actual.value(2)); } #[test] fn test_temporal_array_date64_year_iso_edge_cases() { let a: PrimitiveArray<Date64Type> = vec![ Some(TIMESTAMP_SECOND_2015_12_28 * 1000), Some(TIMESTAMP_SECOND_2016_01_03 * 1000), Some((TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY) * 1000), ] .into(); let b = date_part(&a, DatePart::YearISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(2015, actual.value(0)); assert_eq!(2015, actual.value(1)); assert_eq!(2016, actual.value(2)); } #[test] fn test_temporal_array_timestamp_week_iso_edge_cases() { let a = TimestampSecondArray::from(vec![ TIMESTAMP_SECOND_2015_12_28, TIMESTAMP_SECOND_2016_01_03, TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY, ]); let b = date_part(&a, DatePart::WeekISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(53, actual.value(0)); assert_eq!(53, actual.value(1)); assert_eq!(1, actual.value(2)); } #[test] fn test_temporal_array_timestamp_year_iso_edge_cases() { let a = TimestampSecondArray::from(vec![ TIMESTAMP_SECOND_2015_12_28, TIMESTAMP_SECOND_2016_01_03, TIMESTAMP_SECOND_2016_01_03 + SECONDS_IN_DAY, ]); let b = date_part(&a, DatePart::YearISO).unwrap(); let actual = b.as_primitive::<Int32Type>(); assert_eq!(2015, actual.value(0)); assert_eq!(2015, actual.value(1)); assert_eq!(2016, actual.value(2)); } }