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 0b75e8fbb1 Fix timezoned timestamp arithmetic (#4546)
0b75e8fbb1 is described below
commit 0b75e8fbb1f20fb14c4aefae953f535e5be9bdbd
Author: Alexandre Crayssac <[email protected]>
AuthorDate: Wed Jul 26 17:37:29 2023 +0200
Fix timezoned timestamp arithmetic (#4546)
* Fix arithmetic for timezone-aware timestamp arrays
* Remove debug test from issue
* Update to pass timezone by value instead of reference because it's smaller
* Use as_datetime_with_timezone instead of manual conversion
* Add support for string tz, fix bug and refactor the whole thing
* Use checked arithmetic for months and days and use Self instead of type
name
* Refactor tests
* Add DST test case
* Add new tz parameter to docstring
* Add checked negations and refactor substraction
* Add tests for interval overflow
* Remove checked negation and use absolute unsigned instead
* Use Option instead of Result for overflow errors
* Move arithmetic functions to TimestampOp trait
* Revert "Move arithmetic functions to TimestampOp trait"
This reverts commit 8ec4be477e71531c6238ccf48a695a6b7e6a8798.
---
arrow-arith/Cargo.toml | 1 +
arrow-arith/src/numeric.rs | 250 ++++++++++++++++--
arrow-array/src/delta.rs | 72 +++++-
arrow-array/src/types.rs | 626 ++++++++++++++++-----------------------------
4 files changed, 508 insertions(+), 441 deletions(-)
diff --git a/arrow-arith/Cargo.toml b/arrow-arith/Cargo.toml
index b5ea2e3c43..6da472be66 100644
--- a/arrow-arith/Cargo.toml
+++ b/arrow-arith/Cargo.toml
@@ -46,3 +46,4 @@ num = { version = "0.4", default-features = false, features =
["std"] }
[features]
simd = ["arrow-array/simd"]
+chrono-tz = ["arrow-array/chrono-tz"]
diff --git a/arrow-arith/src/numeric.rs b/arrow-arith/src/numeric.rs
index b0bbb75c12..7862fe2f9b 100644
--- a/arrow-arith/src/numeric.rs
+++ b/arrow-arith/src/numeric.rs
@@ -22,6 +22,7 @@ use std::fmt::Formatter;
use std::sync::Arc;
use arrow_array::cast::AsArray;
+use arrow_array::timezone::Tz;
use arrow_array::types::*;
use arrow_array::*;
use arrow_buffer::ArrowNativeType;
@@ -345,13 +346,13 @@ fn float_op<T: ArrowPrimitiveType>(
trait TimestampOp: ArrowTimestampType {
type Duration: ArrowPrimitiveType<Native = i64>;
- fn add_year_month(timestamp: i64, delta: i32) -> Result<i64, ArrowError>;
- fn add_day_time(timestamp: i64, delta: i64) -> Result<i64, ArrowError>;
- fn add_month_day_nano(timestamp: i64, delta: i128) -> Result<i64,
ArrowError>;
+ fn add_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
+ fn add_day_time(timestamp: i64, delta: i64, tz: Tz) -> Option<i64>;
+ fn add_month_day_nano(timestamp: i64, delta: i128, tz: Tz) -> Option<i64>;
- fn sub_year_month(timestamp: i64, delta: i32) -> Result<i64, ArrowError>;
- fn sub_day_time(timestamp: i64, delta: i64) -> Result<i64, ArrowError>;
- fn sub_month_day_nano(timestamp: i64, delta: i128) -> Result<i64,
ArrowError>;
+ fn sub_year_month(timestamp: i64, delta: i32, tz: Tz) -> Option<i64>;
+ fn sub_day_time(timestamp: i64, delta: i64, tz: Tz) -> Option<i64>;
+ fn sub_month_day_nano(timestamp: i64, delta: i128, tz: Tz) -> Option<i64>;
}
macro_rules! timestamp {
@@ -359,28 +360,28 @@ macro_rules! timestamp {
impl TimestampOp for $t {
type Duration = $d;
- fn add_year_month(left: i64, right: i32) -> Result<i64,
ArrowError> {
- Self::add_year_months(left, right)
+ fn add_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
+ Self::add_year_months(left, right, tz)
}
- fn add_day_time(left: i64, right: i64) -> Result<i64, ArrowError> {
- Self::add_day_time(left, right)
+ fn add_day_time(left: i64, right: i64, tz: Tz) -> Option<i64> {
+ Self::add_day_time(left, right, tz)
}
- fn add_month_day_nano(left: i64, right: i128) -> Result<i64,
ArrowError> {
- Self::add_month_day_nano(left, right)
+ fn add_month_day_nano(left: i64, right: i128, tz: Tz) ->
Option<i64> {
+ Self::add_month_day_nano(left, right, tz)
}
- fn sub_year_month(left: i64, right: i32) -> Result<i64,
ArrowError> {
- Self::subtract_year_months(left, right)
+ fn sub_year_month(left: i64, right: i32, tz: Tz) -> Option<i64> {
+ Self::subtract_year_months(left, right, tz)
}
- fn sub_day_time(left: i64, right: i64) -> Result<i64, ArrowError> {
- Self::subtract_day_time(left, right)
+ fn sub_day_time(left: i64, right: i64, tz: Tz) -> Option<i64> {
+ Self::subtract_day_time(left, right, tz)
}
- fn sub_month_day_nano(left: i64, right: i128) -> Result<i64,
ArrowError> {
- Self::subtract_month_day_nano(left, right)
+ fn sub_month_day_nano(left: i64, right: i128, tz: Tz) ->
Option<i64> {
+ Self::subtract_month_day_nano(left, right, tz)
}
}
};
@@ -401,8 +402,9 @@ fn timestamp_op<T: TimestampOp>(
use DataType::*;
use IntervalUnit::*;
- // Note: interval arithmetic should account for timezones (#4457)
let l = l.as_primitive::<T>();
+ let l_tz: Tz = l.timezone().unwrap_or("+00:00").parse()?;
+
let array: PrimitiveArray<T> = match (op, r.data_type()) {
(Op::Sub | Op::SubWrapping, Timestamp(unit, _)) if unit == &T::UNIT =>
{
let r = r.as_primitive::<T>();
@@ -420,29 +422,77 @@ fn timestamp_op<T: TimestampOp>(
(Op::Add | Op::AddWrapping, Interval(YearMonth)) => {
let r = r.as_primitive::<IntervalYearMonthType>();
- try_op!(l, l_s, r, r_s, T::add_year_month(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::add_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
(Op::Sub | Op::SubWrapping, Interval(YearMonth)) => {
let r = r.as_primitive::<IntervalYearMonthType>();
- try_op!(l, l_s, r, r_s, T::sub_year_month(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::sub_year_month(l, r, l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
(Op::Add | Op::AddWrapping, Interval(DayTime)) => {
let r = r.as_primitive::<IntervalDayTimeType>();
- try_op!(l, l_s, r, r_s, T::add_day_time(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::add_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
(Op::Sub | Op::SubWrapping, Interval(DayTime)) => {
let r = r.as_primitive::<IntervalDayTimeType>();
- try_op!(l, l_s, r, r_s, T::sub_day_time(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::sub_day_time(l, r, l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
(Op::Add | Op::AddWrapping, Interval(MonthDayNano)) => {
let r = r.as_primitive::<IntervalMonthDayNanoType>();
- try_op!(l, l_s, r, r_s, T::add_month_day_nano(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::add_month_day_nano(l, r,
l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
(Op::Sub | Op::SubWrapping, Interval(MonthDayNano)) => {
let r = r.as_primitive::<IntervalMonthDayNanoType>();
- try_op!(l, l_s, r, r_s, T::sub_month_day_nano(l, r))
+ try_op!(
+ l,
+ l_s,
+ r,
+ r_s,
+ T::sub_month_day_nano(l, r,
l_tz).ok_or(ArrowError::ComputeError(
+ "Timestamp out of range".to_string()
+ ))
+ )
}
_ => {
return Err(ArrowError::InvalidArgumentError(format!(
@@ -803,9 +853,11 @@ fn decimal_op<T: DecimalType>(
#[cfg(test)]
mod tests {
use super::*;
- use arrow_array::temporal_conversions::{as_date, as_datetime};
+ use arrow_array::temporal_conversions::{
+ as_date, as_datetime, as_datetime_with_timezone,
+ };
use arrow_buffer::{i256, ScalarBuffer};
- use chrono::{DateTime, NaiveDate};
+ use chrono::{DateTime, NaiveDate, TimeZone};
fn test_neg_primitive<T: ArrowPrimitiveType>(
input: &[T::Native],
@@ -1472,4 +1524,148 @@ mod tests {
"Compute error: Overflow happened on: 9223372036854775807 - -1"
);
}
+
+ fn test_timestamp_with_timezone_impl<T: TimestampOp>(tz_str: &str) {
+ let tz: Tz = tz_str.parse().unwrap();
+
+ let transform_array = |x: &dyn Array| -> Vec<DateTime<_>> {
+ x.as_primitive::<T>()
+ .values()
+ .into_iter()
+ .map(|x| as_datetime_with_timezone::<T>(*x, tz).unwrap())
+ .collect()
+ };
+
+ let values = vec![
+ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0)
+ .unwrap()
+ .naive_utc(),
+ tz.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)
+ .unwrap()
+ .naive_utc(),
+ tz.with_ymd_and_hms(2010, 4, 1, 4, 0, 20)
+ .unwrap()
+ .naive_utc(),
+ tz.with_ymd_and_hms(1960, 1, 30, 4, 23, 20)
+ .unwrap()
+ .naive_utc(),
+ tz.with_ymd_and_hms(2023, 3, 25, 14, 0, 0)
+ .unwrap()
+ .naive_utc(),
+ ]
+ .into_iter()
+ .map(|x| T::make_value(x).unwrap())
+ .collect();
+
+ let a = PrimitiveArray::<T>::new(values, None).with_timezone(tz_str);
+
+ // IntervalYearMonth
+ let b = IntervalYearMonthArray::from(vec![
+ IntervalYearMonthType::make_value(0, 1),
+ IntervalYearMonthType::make_value(5, 34),
+ IntervalYearMonthType::make_value(-2, 4),
+ IntervalYearMonthType::make_value(7, -4),
+ IntervalYearMonthType::make_value(0, 1),
+ ]);
+ let r1 = add(&a, &b).unwrap();
+ assert_eq!(
+ &transform_array(r1.as_ref()),
+ &[
+ tz.with_ymd_and_hms(1970, 2, 28, 23, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(1977, 11, 1, 0, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(2008, 8, 1, 4, 0, 20).unwrap(),
+ tz.with_ymd_and_hms(1966, 9, 30, 4, 23, 20).unwrap(),
+ tz.with_ymd_and_hms(2023, 4, 25, 14, 0, 0).unwrap(),
+ ]
+ );
+
+ let r2 = sub(&r1, &b).unwrap();
+ assert_eq!(r2.as_ref(), &a);
+
+ // IntervalDayTime
+ let b = IntervalDayTimeArray::from(vec![
+ IntervalDayTimeType::make_value(0, 0),
+ IntervalDayTimeType::make_value(5, 454000),
+ IntervalDayTimeType::make_value(-34, 0),
+ IntervalDayTimeType::make_value(7, -4000),
+ IntervalDayTimeType::make_value(1, 0),
+ ]);
+ let r3 = add(&a, &b).unwrap();
+ assert_eq!(
+ &transform_array(r3.as_ref()),
+ &[
+ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(1970, 1, 6, 0, 7, 34).unwrap(),
+ tz.with_ymd_and_hms(2010, 2, 26, 4, 0, 20).unwrap(),
+ tz.with_ymd_and_hms(1960, 2, 6, 4, 23, 16).unwrap(),
+ tz.with_ymd_and_hms(2023, 3, 26, 14, 0, 0).unwrap(),
+ ]
+ );
+
+ let r4 = sub(&r3, &b).unwrap();
+ assert_eq!(r4.as_ref(), &a);
+
+ // IntervalMonthDayNano
+ let b = IntervalMonthDayNanoArray::from(vec![
+ IntervalMonthDayNanoType::make_value(1, 0, 0),
+ IntervalMonthDayNanoType::make_value(344, 34, -43_000_000_000),
+ IntervalMonthDayNanoType::make_value(-593, -33, 13_000_000_000),
+ IntervalMonthDayNanoType::make_value(5, 2, 493_000_000_000),
+ IntervalMonthDayNanoType::make_value(1, 0, 0),
+ ]);
+ let r5 = add(&a, &b).unwrap();
+ assert_eq!(
+ &transform_array(r5.as_ref()),
+ &[
+ tz.with_ymd_and_hms(1970, 2, 28, 23, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(1998, 10, 4, 23, 59, 17).unwrap(),
+ tz.with_ymd_and_hms(1960, 9, 29, 4, 0, 33).unwrap(),
+ tz.with_ymd_and_hms(1960, 7, 2, 4, 31, 33).unwrap(),
+ tz.with_ymd_and_hms(2023, 4, 25, 14, 0, 0).unwrap(),
+ ]
+ );
+
+ let r6 = sub(&r5, &b).unwrap();
+ assert_eq!(
+ &transform_array(r6.as_ref()),
+ &[
+ tz.with_ymd_and_hms(1970, 1, 28, 23, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(1970, 1, 2, 0, 0, 0).unwrap(),
+ tz.with_ymd_and_hms(2010, 4, 2, 4, 0, 20).unwrap(),
+ tz.with_ymd_and_hms(1960, 1, 31, 4, 23, 20).unwrap(),
+ tz.with_ymd_and_hms(2023, 3, 25, 14, 0, 0).unwrap(),
+ ]
+ );
+ }
+
+ #[cfg(not(feature = "chrono-tz"))]
+ #[test]
+ fn test_timestamp_with_timezone() {
+ let timezones = ["+00:00", "+01:00", "-01:00", "+03:30"];
+ for timezone in timezones {
+ test_timestamp_with_timezone_impl::<TimestampSecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampMillisecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampMicrosecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampNanosecondType>(timezone);
+ }
+ }
+
+ #[cfg(feature = "chrono-tz")]
+ #[test]
+ fn test_timestamp_with_timezone() {
+ let timezones = [
+ "Europe/Paris",
+ "Europe/London",
+ "Africa/Bamako",
+ "America/Dominica",
+ "Asia/Seoul",
+ "Asia/Shanghai",
+ ];
+ for timezone in timezones {
+ test_timestamp_with_timezone_impl::<TimestampSecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampMillisecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampMicrosecondType>(timezone);
+
test_timestamp_with_timezone_impl::<TimestampNanosecondType>(timezone);
+ }
+ }
}
diff --git a/arrow-array/src/delta.rs b/arrow-array/src/delta.rs
index 029168242b..bf9ee5ca68 100644
--- a/arrow-array/src/delta.rs
+++ b/arrow-array/src/delta.rs
@@ -23,22 +23,74 @@
// Copied from chronoutil crate
//! Contains utility functions for shifting Date objects.
-use chrono::{Datelike, Months};
+use chrono::{DateTime, Datelike, Days, Months, TimeZone};
use std::cmp::Ordering;
/// Shift a date by the given number of months.
-pub(crate) fn shift_months<
- D: Datelike
- + std::ops::Add<chrono::Months, Output = D>
- + std::ops::Sub<chrono::Months, Output = D>,
->(
- date: D,
- months: i32,
-) -> D {
+pub(crate) fn shift_months<D>(date: D, months: i32) -> D
+where
+ D: Datelike + std::ops::Add<Months, Output = D> + std::ops::Sub<Months,
Output = D>,
+{
match months.cmp(&0) {
Ordering::Equal => date,
Ordering::Greater => date + Months::new(months as u32),
- Ordering::Less => date - Months::new(-months as u32),
+ Ordering::Less => date - Months::new(months.unsigned_abs()),
+ }
+}
+
+/// Add the given number of months to the given datetime.
+///
+/// Returns `None` when it will result in overflow.
+pub(crate) fn add_months_datetime<Tz: TimeZone>(
+ dt: DateTime<Tz>,
+ months: i32,
+) -> Option<DateTime<Tz>> {
+ match months.cmp(&0) {
+ Ordering::Equal => Some(dt),
+ Ordering::Greater => dt.checked_add_months(Months::new(months as u32)),
+ Ordering::Less =>
dt.checked_sub_months(Months::new(months.unsigned_abs())),
+ }
+}
+
+/// Add the given number of days to the given datetime.
+///
+/// Returns `None` when it will result in overflow.
+pub(crate) fn add_days_datetime<Tz: TimeZone>(
+ dt: DateTime<Tz>,
+ days: i32,
+) -> Option<DateTime<Tz>> {
+ match days.cmp(&0) {
+ Ordering::Equal => Some(dt),
+ Ordering::Greater => dt.checked_add_days(Days::new(days as u64)),
+ Ordering::Less => dt.checked_sub_days(Days::new(days.unsigned_abs() as
u64)),
+ }
+}
+
+/// Substract the given number of months to the given datetime.
+///
+/// Returns `None` when it will result in overflow.
+pub(crate) fn sub_months_datetime<Tz: TimeZone>(
+ dt: DateTime<Tz>,
+ months: i32,
+) -> Option<DateTime<Tz>> {
+ match months.cmp(&0) {
+ Ordering::Equal => Some(dt),
+ Ordering::Greater => dt.checked_sub_months(Months::new(months as u32)),
+ Ordering::Less =>
dt.checked_add_months(Months::new(months.unsigned_abs())),
+ }
+}
+
+/// Substract the given number of days to the given datetime.
+///
+/// Returns `None` when it will result in overflow.
+pub(crate) fn sub_days_datetime<Tz: TimeZone>(
+ dt: DateTime<Tz>,
+ days: i32,
+) -> Option<DateTime<Tz>> {
+ match days.cmp(&0) {
+ Ordering::Equal => Some(dt),
+ Ordering::Greater => dt.checked_sub_days(Days::new(days as u64)),
+ Ordering::Less => dt.checked_add_days(Days::new(days.unsigned_abs() as
u64)),
}
}
diff --git a/arrow-array/src/types.rs b/arrow-array/src/types.rs
index 3d14cff384..769dbf974b 100644
--- a/arrow-array/src/types.rs
+++ b/arrow-array/src/types.rs
@@ -17,7 +17,12 @@
//! Zero-sized types used to parameterize generic array implementations
-use crate::delta::shift_months;
+use crate::delta::{
+ add_days_datetime, add_months_datetime, shift_months, sub_days_datetime,
+ sub_months_datetime,
+};
+use crate::temporal_conversions::as_datetime_with_timezone;
+use crate::timezone::Tz;
use crate::{ArrowNativeTypeOp, OffsetSizeTrait};
use arrow_buffer::{i256, Buffer, OffsetBuffer};
use arrow_data::decimal::{validate_decimal256_precision,
validate_decimal_precision};
@@ -350,158 +355,184 @@ impl ArrowTimestampType for TimestampNanosecondType {
}
}
+fn add_year_months<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let months = IntervalYearMonthType::to_months(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = add_months_datetime(res, months)?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
+fn add_day_time<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let (days, ms) = IntervalDayTimeType::to_parts(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = add_days_datetime(res, days)?;
+ let res = res.checked_add_signed(Duration::milliseconds(ms as i64))?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
+fn add_month_day_nano<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = add_months_datetime(res, months)?;
+ let res = add_days_datetime(res, days)?;
+ let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
+fn subtract_year_months<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let months = IntervalYearMonthType::to_months(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = sub_months_datetime(res, months)?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
+fn subtract_day_time<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let (days, ms) = IntervalDayTimeType::to_parts(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = sub_days_datetime(res, days)?;
+ let res = res.checked_sub_signed(Duration::milliseconds(ms as i64))?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
+fn subtract_month_day_nano<T: ArrowTimestampType>(
+ timestamp: <T as ArrowPrimitiveType>::Native,
+ delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
+ tz: Tz,
+) -> Option<<T as ArrowPrimitiveType>::Native> {
+ let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
+ let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
+ let res = sub_months_datetime(res, months)?;
+ let res = sub_days_datetime(res, days)?;
+ let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
+ let res = res.naive_utc();
+ T::make_value(res)
+}
+
impl TimestampSecondType {
- /// Adds the given IntervalYearMonthType to an arrow TimestampSecondType
+ /// Adds the given IntervalYearMonthType to an arrow TimestampSecondType.
+ ///
+ /// Returns `None` when it will result in overflow.
///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_year_months(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let prior = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
-
- let months = IntervalYearMonthType::to_months(delta);
- let posterior = shift_months(prior, months);
- TimestampSecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_year_months::<Self>(timestamp, delta, tz)
}
- /// Adds the given IntervalDayTimeType to an arrow TimestampSecondType
+ /// Adds the given IntervalDayTimeType to an arrow TimestampSecondType.
+ ///
+ /// Returns `None` when it will result in overflow.
///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_day_time(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampSecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_day_time::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalMonthDayNanoType to an arrow TimestampSecondType
///
+ /// Returns `None` when it will result in overflow.
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_month_day_nano(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, months);
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampSecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_month_day_nano::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalYearMonthType to an arrow
TimestampSecondType
///
+ /// Returns `None` when it will result in overflow.
+ ///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_year_months(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let prior = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let months = IntervalYearMonthType::to_months(-delta);
- let posterior = shift_months(prior, months);
- TimestampSecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_year_months::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalDayTimeType to an arrow TimestampSecondType
///
+ /// Returns `None` when it will result in overflow.
+ ///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_day_time(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampSecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_day_time::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalMonthDayNanoType to an arrow
TimestampSecondType
///
+ /// Returns `None` when it will result in overflow.
+ ///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_month_day_nano(
- timestamp: <TimestampSecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampSecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res = NaiveDateTime::from_timestamp_opt(timestamp,
0).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, -months);
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampSecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_month_day_nano::<Self>(timestamp, delta, tz)
}
}
@@ -512,18 +543,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_year_months(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let prior =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let months = IntervalYearMonthType::to_months(delta);
- let posterior = shift_months(prior, months);
- TimestampMicrosecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_year_months::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalDayTimeType to an arrow TimestampMicrosecondType
@@ -532,27 +558,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_day_time(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMicrosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_day_time::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalMonthDayNanoType to an arrow
TimestampMicrosecondType
@@ -561,28 +573,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_month_day_nano(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, months);
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMicrosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_month_day_nano::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalYearMonthType to an arrow
TimestampMicrosecondType
@@ -591,18 +588,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_year_months(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let prior =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let months = IntervalYearMonthType::to_months(-delta);
- let posterior = shift_months(prior, months);
- TimestampMicrosecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_year_months::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalDayTimeType to an arrow
TimestampMicrosecondType
@@ -611,27 +603,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_day_time(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMicrosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_day_time::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalMonthDayNanoType to an arrow
TimestampMicrosecondType
@@ -640,28 +618,13 @@ impl TimestampMicrosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_month_day_nano(
- timestamp: <TimestampMicrosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMicrosecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, -months);
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMicrosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_month_day_nano::<Self>(timestamp, delta, tz)
}
}
@@ -672,18 +635,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_year_months(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let prior =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let months = IntervalYearMonthType::to_months(delta);
- let posterior = shift_months(prior, months);
- TimestampMillisecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_year_months::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalDayTimeType to an arrow TimestampMillisecondType
@@ -692,27 +650,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_day_time(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMillisecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_day_time::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalMonthDayNanoType to an arrow
TimestampMillisecondType
@@ -721,28 +665,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_month_day_nano(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, months);
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMillisecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_month_day_nano::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalYearMonthType to an arrow
TimestampMillisecondType
@@ -751,18 +680,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_year_months(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let prior =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let months = IntervalYearMonthType::to_months(-delta);
- let posterior = shift_months(prior, months);
- TimestampMillisecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_year_months::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalDayTimeType to an arrow
TimestampMillisecondType
@@ -771,27 +695,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_day_time(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMillisecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_day_time::<Self>(timestamp, delta, tz)
}
/// Subtracts the given IntervalMonthDayNanoType to an arrow
TimestampMillisecondType
@@ -800,28 +710,13 @@ impl TimestampMillisecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_month_day_nano(
- timestamp: <TimestampMillisecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampMillisecondType as ArrowPrimitiveType>::Native,
ArrowError>
- {
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res =
NaiveDateTime::from_timestamp_millis(timestamp).ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = shift_months(res, -months);
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampMillisecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_month_day_nano::<Self>(timestamp, delta, tz)
}
}
@@ -832,19 +727,13 @@ impl TimestampNanosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_year_months(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let prior = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
- let months = IntervalYearMonthType::to_months(delta);
- let posterior = shift_months(prior, months);
- TimestampNanosecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_year_months::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalDayTimeType to an arrow TimestampNanosecondType
@@ -853,28 +742,13 @@ impl TimestampNanosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_day_time(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let res = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampNanosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_day_time::<Self>(timestamp, delta, tz)
}
/// Adds the given IntervalMonthDayNanoType to an arrow
TimestampNanosecondType
@@ -883,114 +757,58 @@ impl TimestampNanosecondType {
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn add_month_day_nano(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let res = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ add_month_day_nano::<Self>(timestamp, delta, tz)
+ }
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res = shift_months(res, months);
- let res = res
- .checked_add_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_add_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampNanosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
- }
-
- /// Subtracs the given IntervalYearMonthType to an arrow
TimestampNanosecondType
+ /// Subtracts the given IntervalYearMonthType to an arrow
TimestampNanosecondType
///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_year_months(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let prior = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
- let months = IntervalYearMonthType::to_months(-delta);
- let posterior = shift_months(prior, months);
- TimestampNanosecondType::make_value(posterior)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_year_months::<Self>(timestamp, delta, tz)
}
- /// Subtracs the given IntervalDayTimeType to an arrow
TimestampNanosecondType
+ /// Subtracts the given IntervalDayTimeType to an arrow
TimestampNanosecondType
///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_day_time(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let res = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_day_time::<Self>(timestamp, delta, tz)
+ }
- let (days, ms) = IntervalDayTimeType::to_parts(delta);
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::milliseconds(ms as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampNanosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
- }
-
- /// Subtracs the given IntervalMonthDayNanoType to an arrow
TimestampNanosecondType
+ /// Subtracts the given IntervalMonthDayNanoType to an arrow
TimestampNanosecondType
///
/// # Arguments
///
/// * `timestamp` - The date on which to perform the operation
/// * `delta` - The interval to add
+ /// * `tz` - The timezone in which to interpret `timestamp`
pub fn subtract_month_day_nano(
- timestamp: <TimestampNanosecondType as ArrowPrimitiveType>::Native,
+ timestamp: <Self as ArrowPrimitiveType>::Native,
delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
- ) -> Result<<TimestampNanosecondType as ArrowPrimitiveType>::Native,
ArrowError> {
- let seconds = timestamp / 1_000_000_000;
- let nanos = timestamp % 1_000_000_000;
- let res = NaiveDateTime::from_timestamp_opt(seconds, nanos as
u32).ok_or_else(
- || ArrowError::ComputeError("Timestamp out of range".to_string()),
- )?;
-
- let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
- let res = shift_months(res, -months);
- let res = res
- .checked_sub_signed(Duration::days(days as i64))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- let res = res
- .checked_sub_signed(Duration::nanoseconds(nanos))
- .ok_or_else(|| {
- ArrowError::ComputeError("Timestamp out of range".to_string())
- })?;
- TimestampNanosecondType::make_value(res)
- .ok_or_else(|| ArrowError::ComputeError("Timestamp out of
range".to_string()))
+ tz: Tz,
+ ) -> Option<<Self as ArrowPrimitiveType>::Native> {
+ subtract_month_day_nano::<Self>(timestamp, delta, tz)
}
}