You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by tu...@apache.org on 2024/01/24 19:57:37 UTC
(arrow-rs) branch master updated: Refactor temporal extract date part kernels (#5319)
This is an automated email from the ASF dual-hosted git repository.
tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/master by this push:
new 20e723e523 Refactor temporal extract date part kernels (#5319)
20e723e523 is described below
commit 20e723e52384b631d4585545e591c74d3ebee79e
Author: Jeffrey Vo <je...@gmail.com>
AuthorDate: Thu Jan 25 06:57:32 2024 +1100
Refactor temporal extract date part kernels (#5319)
* Refactor temporal extract date part kernels
* Use generics to simplify code
* Refactor how zeroed arrays are created
* Update docs and add deprecated labels
* Fix clippy
---
arrow-arith/src/temporal.rs | 531 ++++++++++++++++++++++++++++----------------
arrow/tests/arithmetic.rs | 8 +-
2 files changed, 344 insertions(+), 195 deletions(-)
diff --git a/arrow-arith/src/temporal.rs b/arrow-arith/src/temporal.rs
index a9c3de5401..a386559e30 100644
--- a/arrow-arith/src/temporal.rs
+++ b/arrow-arith/src/temporal.rs
@@ -19,105 +19,302 @@
use std::sync::Arc;
-use chrono::{DateTime, Datelike, NaiveDateTime, NaiveTime, Offset, Timelike};
-
-use arrow_array::builder::*;
-use arrow_array::iterator::ArrayIter;
-use arrow_array::temporal_conversions::{as_datetime, as_datetime_with_timezone, as_time};
+use arrow_array::cast::AsArray;
+use chrono::{Datelike, NaiveDateTime, Offset, TimeZone, Timelike, Utc};
+
+use arrow_array::temporal_conversions::{
+ date32_to_datetime, date64_to_datetime, time32ms_to_time, time32s_to_time, time64ns_to_time,
+ time64us_to_time, timestamp_ms_to_datetime, timestamp_ns_to_datetime, timestamp_s_to_datetime,
+ timestamp_us_to_datetime,
+};
use arrow_array::timezone::Tz;
use arrow_array::types::*;
use arrow_array::*;
use arrow_buffer::ArrowNativeType;
use arrow_schema::{ArrowError, DataType};
-/// This function takes an `ArrayIter` of input array and an extractor `op` which takes
-/// an input `NaiveTime` and returns time component (e.g. hour) as `i32` value.
-/// The extracted values are built by the given `builder` to be an `Int32Array`.
-fn as_time_with_op<A: ArrayAccessor<Item = T::Native>, T: ArrowTemporalType, F>(
- iter: ArrayIter<A>,
- mut builder: PrimitiveBuilder<Int32Type>,
- op: F,
-) -> Int32Array
+/// 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,
+ /// Month in the year, in range `1..=12`
+ Month,
+ /// ISO week of the year, in range `1..=53`
+ Week,
+ /// 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`].
+///
+/// [`DateTime`]: chrono::DateTime
+fn get_date_time_part_extract_fn<T>(part: DatePart) -> fn(T) -> i32
where
- F: Fn(NaiveTime) -> i32,
- i64: From<T::Native>,
+ T: ChronoDateExt + Datelike + Timelike,
{
- iter.into_iter().for_each(|value| {
- if let Some(value) = value {
- match as_time::<T>(i64::from(value)) {
- Some(dt) => builder.append_value(op(dt)),
- None => builder.append_null(),
- }
- } else {
- builder.append_null();
+ match part {
+ DatePart::Quarter => |d| d.quarter() as i32,
+ DatePart::Year => |d| d.year(),
+ DatePart::Month => |d| d.month() as i32,
+ DatePart::Week => |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 (Limited support)
+/// - Timestamp
+///
+/// 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 actual = date_part(&input, DatePart::Week).unwrap();
+/// let expected: Int32Array = vec![Some(4), None, Some(30)].into();
+/// assert_eq!(actual.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)
+ }
+ // TODO: support interval
+ // DataType::Interval(_) => {
+ // todo!();
+ // }
+ 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),
+ )
+}
- builder.finish()
+/// 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())
}
-/// This function takes an `ArrayIter` of input array and an extractor `op` which takes
-/// an input `NaiveDateTime` and returns data time component (e.g. hour) as `i32` value.
-/// The extracted values are built by the given `builder` to be an `Int32Array`.
-fn as_datetime_with_op<A: ArrayAccessor<Item = T::Native>, T: ArrowTemporalType, F>(
- iter: ArrayIter<A>,
- mut builder: PrimitiveBuilder<Int32Type>,
- op: F,
-) -> Int32Array
-where
- F: Fn(NaiveDateTime) -> i32,
- i64: From<T::Native>,
-{
- iter.into_iter().for_each(|value| {
- if let Some(value) = value {
- match as_datetime::<T>(i64::from(value)) {
- Some(dt) => builder.append_value(op(dt)),
- None => builder.append_null(),
- }
- } else {
- builder.append_null();
+/// 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> {
+ match part {
+ DatePart::Hour => Ok(self.unary_opt(|d| time32s_to_time(d).map(|c| c.hour() as i32))),
+ // TODO expand support for Time types, see: https://github.com/apache/arrow-rs/issues/5261
+ _ => 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> {
+ match part {
+ DatePart::Hour => Ok(self.unary_opt(|d| time32ms_to_time(d).map(|c| c.hour() as i32))),
+ // TODO expand support for Time types, see: https://github.com/apache/arrow-rs/issues/5261
+ _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
}
- });
+ }
+}
- builder.finish()
+impl ExtractDatePartExt for PrimitiveArray<Time64MicrosecondType> {
+ fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
+ match part {
+ DatePart::Hour => Ok(self.unary_opt(|d| time64us_to_time(d).map(|c| c.hour() as i32))),
+ // TODO expand support for Time types, see: https://github.com/apache/arrow-rs/issues/5261
+ _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
+ }
+ }
}
-/// This function extracts date time component (e.g. hour) from an array of datatime.
-/// `iter` is the `ArrayIter` of input datatime array. `builder` is used to build the
-/// returned `Int32Array` containing the extracted components. `tz` is timezone string
-/// which will be added to datetime values in the input array. `parsed` is a `Parsed`
-/// object used to parse timezone string. `op` is the extractor closure which takes
-/// data time object of `NaiveDateTime` type and returns `i32` value of extracted
-/// component.
-fn extract_component_from_datetime_array<
- A: ArrayAccessor<Item = T::Native>,
- T: ArrowTemporalType,
- F,
->(
- iter: ArrayIter<A>,
- mut builder: PrimitiveBuilder<Int32Type>,
- tz: &str,
- op: F,
-) -> Result<Int32Array, ArrowError>
-where
- F: Fn(DateTime<Tz>) -> i32,
- i64: From<T::Native>,
-{
- let tz: Tz = tz.parse()?;
- for value in iter {
- match value {
- Some(value) => match as_datetime_with_timezone::<T>(value.into(), tz) {
- Some(time) => builder.append_value(op(time)),
- _ => {
- return Err(ArrowError::ComputeError(
- "Unable to read value as datetime".to_string(),
- ))
- }
- },
- None => builder.append_null(),
+impl ExtractDatePartExt for PrimitiveArray<Time64NanosecondType> {
+ fn date_part(&self, part: DatePart) -> Result<Int32Array, ArrowError> {
+ match part {
+ DatePart::Hour => Ok(self.unary_opt(|d| time64ns_to_time(d).map(|c| c.hour() as i32))),
+ // TODO expand support for Time types, see: https://github.com/apache/arrow-rs/issues/5261
+ _ => return_compute_error_with!(format!("{part} does not support"), self.data_type()),
}
}
- Ok(builder.finish())
+}
+
+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)
+ }
}
macro_rules! return_compute_error_with {
@@ -170,7 +367,6 @@ pub fn using_chrono_tz_and_utc_naive_date_time(
tz: &str,
utc: NaiveDateTime,
) -> Option<chrono::offset::FixedOffset> {
- use chrono::TimeZone;
let tz: Tz = tz.parse().ok()?;
Some(tz.offset_from_utc_datetime(&utc).fix())
}
@@ -178,91 +374,76 @@ pub fn using_chrono_tz_and_utc_naive_date_time(
/// 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> {
- time_fraction_dyn(array, "hour", |t| t.hour() as i32)
+ 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>,
{
- let b = Int32Builder::with_capacity(array.len());
- match array.data_type() {
- DataType::Time32(_) | DataType::Time64(_) => {
- let iter = ArrayIter::new(array);
- Ok(as_time_with_op::<&PrimitiveArray<T>, T, _>(iter, b, |t| {
- t.hour() as i32
- }))
- }
- DataType::Date32 | DataType::Date64 | DataType::Timestamp(_, None) => {
- let iter = ArrayIter::new(array);
- Ok(as_datetime_with_op::<&PrimitiveArray<T>, T, _>(
- iter,
- b,
- |t| t.hour() as i32,
- ))
- }
- DataType::Timestamp(_, Some(tz)) => {
- let iter = ArrayIter::new(array);
- extract_component_from_datetime_array::<&PrimitiveArray<T>, T, _>(iter, b, tz, |t| {
- t.hour() as i32
- })
- }
- _ => return_compute_error_with!("hour does not support", array.data_type()),
- }
+ 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> {
- time_fraction_dyn(array, "year", |t| t.year())
+ 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>,
{
- time_fraction_internal(array, "year", |t| t.year())
+ 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> {
- time_fraction_dyn(array, "quarter", |t| t.quarter() as i32)
+ 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>,
{
- time_fraction_internal(array, "quarter", |t| t.quarter() as i32)
+ 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> {
- time_fraction_dyn(array, "month", |t| t.month() as i32)
+ 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>,
{
- time_fraction_internal(array, "month", |t| t.month() as i32)
+ date_part_primitive(array, DatePart::Month)
}
/// Extracts the day of week of a given temporal array as an array of
@@ -274,8 +455,9 @@ where
///
/// 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> {
- time_fraction_dyn(array, "num_days_from_monday", |t| t.num_days_from_monday())
+ date_part(array, DatePart::DayOfWeekMonday0)
}
/// Extracts the day of week of a given temporal primitive array as an array of
@@ -284,12 +466,13 @@ pub fn num_days_from_monday_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowErro
/// 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>,
{
- time_fraction_internal(array, "num_days_from_monday", |t| t.num_days_from_monday())
+ date_part_primitive(array, DatePart::DayOfWeekMonday0)
}
/// Extracts the day of week of a given temporal array as an array of
@@ -301,8 +484,9 @@ where
///
/// 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> {
- time_fraction_dyn(array, "num_days_from_sunday", |t| t.num_days_from_sunday())
+ date_part(array, DatePart::DayOfWeekSunday0)
}
/// Extracts the day of week of a given temporal primitive array as an array of
@@ -311,201 +495,164 @@ pub fn num_days_from_sunday_dyn(array: &dyn Array) -> Result<ArrayRef, ArrowErro
/// 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>,
{
- time_fraction_internal(array, "num_days_from_sunday", |t| t.num_days_from_sunday())
+ 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> {
- time_fraction_dyn(array, "day", |t| t.day() as i32)
+ 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>,
{
- time_fraction_internal(array, "day", |t| t.day() as i32)
+ 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> {
- time_fraction_dyn(array, "doy", |t| t.ordinal() as i32)
+ 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>,
{
- time_fraction_internal(array, "doy", |t| t.ordinal() as i32)
+ 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>,
{
- time_fraction_internal(array, "minute", |t| t.minute() as i32)
+ 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> {
- time_fraction_dyn(array, "week", |t| t.iso_week().week() as i32)
+ 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>,
{
- time_fraction_internal(array, "week", |t| t.iso_week().week() as i32)
+ 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>,
{
- time_fraction_internal(array, "second", |t| t.second() as i32)
+ 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>,
{
- time_fraction_internal(array, "nanosecond", |t| t.nanosecond() as i32)
+ 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> {
- time_fraction_dyn(array, "nanosecond", |t| t.nanosecond() as i32)
+ 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>,
{
- time_fraction_internal(array, "microsecond", |t| (t.nanosecond() / 1_000) as i32)
+ 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> {
- time_fraction_dyn(array, "microsecond", |t| (t.nanosecond() / 1_000) as i32)
+ 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>,
{
- time_fraction_internal(array, "millisecond", |t| {
- (t.nanosecond() / 1_000_000) as i32
- })
+ 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> {
- time_fraction_dyn(array, "millisecond", |t| {
- (t.nanosecond() / 1_000_000) as i32
- })
-}
-
-/// Extracts the time fraction of a given temporal array as an array of integers
-fn time_fraction_dyn<F>(array: &dyn Array, name: &str, op: F) -> Result<ArrayRef, ArrowError>
-where
- F: Fn(NaiveDateTime) -> i32,
-{
- match array.data_type().clone() {
- DataType::Dictionary(_, _) => {
- downcast_dictionary_array!(
- array => {
- let values = time_fraction_dyn(array.values(), name, op)?;
- Ok(Arc::new(array.with_values(values)))
- }
- dt => return_compute_error_with!(format!("{name} does not support"), dt),
- )
- }
- _ => {
- downcast_temporal_array!(
- array => {
- time_fraction_internal(array, name, op)
- .map(|a| Arc::new(a) as ArrayRef)
- }
- dt => return_compute_error_with!(format!("{name} does not support"), dt),
- )
- }
- }
-}
-
-/// Extracts the time fraction of a given temporal array as an array of integers
-fn time_fraction_internal<T, F>(
- array: &PrimitiveArray<T>,
- name: &str,
- op: F,
-) -> Result<Int32Array, ArrowError>
-where
- F: Fn(NaiveDateTime) -> i32,
- T: ArrowTemporalType + ArrowNumericType,
- i64: From<T::Native>,
-{
- let b = Int32Builder::with_capacity(array.len());
- match array.data_type() {
- DataType::Date32 | DataType::Date64 | DataType::Timestamp(_, None) => {
- let iter = ArrayIter::new(array);
- Ok(as_datetime_with_op::<_, T, _>(iter, b, op))
- }
- DataType::Timestamp(_, Some(tz)) => {
- let iter = ArrayIter::new(array);
- extract_component_from_datetime_array::<_, T, _>(iter, b, tz, |t| op(t.naive_local()))
- }
- _ => return_compute_error_with!(format!("{name} does not support"), array.data_type()),
- }
+ 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> {
- time_fraction_dyn(array, "minute", |t| t.minute() as i32)
+ 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> {
- time_fraction_dyn(array, "second", |t| t.second() as i32)
+ date_part(array, DatePart::Second)
}
#[cfg(test)]
+#[allow(deprecated)]
mod tests {
use super::*;
@@ -932,7 +1079,7 @@ mod tests {
let expected = Arc::new(expected_dict) as ArrayRef;
assert_eq!(&expected, &b);
- let b = time_fraction_dyn(&dict, "minute", |t| t.minute() as i32).unwrap();
+ let b = date_part(&dict, DatePart::Minute).unwrap();
let b_old = minute_dyn(&dict).unwrap();
@@ -942,7 +1089,7 @@ mod tests {
assert_eq!(&expected, &b);
assert_eq!(&expected, &b_old);
- let b = time_fraction_dyn(&dict, "second", |t| t.second() as i32).unwrap();
+ let b = date_part(&dict, DatePart::Second).unwrap();
let b_old = second_dyn(&dict).unwrap();
@@ -952,7 +1099,7 @@ mod tests {
assert_eq!(&expected, &b);
assert_eq!(&expected, &b_old);
- let b = time_fraction_dyn(&dict, "nanosecond", |t| t.nanosecond() as i32).unwrap();
+ let b = date_part(&dict, DatePart::Nanosecond).unwrap();
let expected_dict =
DictionaryArray::new(keys, Arc::new(Int32Array::from(vec![0, 0, 0, 0, 0])));
diff --git a/arrow/tests/arithmetic.rs b/arrow/tests/arithmetic.rs
index 81a19d4b5e..59a162ef6d 100644
--- a/arrow/tests/arithmetic.rs
+++ b/arrow/tests/arithmetic.rs
@@ -16,7 +16,7 @@
// under the License.
use arrow_arith::numeric::{add, sub};
-use arrow_arith::temporal::hour;
+use arrow_arith::temporal::{date_part, DatePart};
use arrow_array::cast::AsArray;
use arrow_array::temporal_conversions::as_datetime_with_timezone;
use arrow_array::timezone::Tz;
@@ -28,7 +28,8 @@ use chrono::{DateTime, TimeZone};
fn test_temporal_array_timestamp_hour_with_timezone_using_chrono_tz() {
let a =
TimestampSecondArray::from(vec![60 * 60 * 10]).with_timezone("Asia/Kolkata".to_string());
- let b = hour(&a).unwrap();
+ let b = date_part(&a, DatePart::Hour).unwrap();
+ let b = b.as_primitive::<Int32Type>();
assert_eq!(15, b.value(0));
}
@@ -41,7 +42,8 @@ fn test_temporal_array_timestamp_hour_with_dst_timezone_using_chrono_tz() {
let a = TimestampMillisecondArray::from(vec![Some(1635577147000)])
.with_timezone("Australia/Sydney".to_string());
- let b = hour(&a).unwrap();
+ let b = date_part(&a, DatePart::Hour).unwrap();
+ let b = b.as_primitive::<Int32Type>();
assert_eq!(17, b.value(0));
}