use std::ops::{Add, Div, Mul, Neg, Sub};
use chrono::{DateTime as CrDateTime, Months, Utc};
use crate::{DateTime, TimeDelta, TimeUnitTrait};
impl<U: TimeUnitTrait> Add<TimeDelta> for DateTime<U>
where
Self: From<CrDateTime<Utc>> + TryInto<CrDateTime<Utc>>,
{
type Output = DateTime<U>;
fn add(self, rhs: TimeDelta) -> Self::Output {
if self.is_not_nat() && rhs.is_not_nat() {
let dt = self.to_cr().unwrap();
let out = if rhs.months != 0 {
if rhs.months > 0 {
dt + Months::new(rhs.months as u32)
} else {
dt - Months::new((-rhs.months) as u32)
}
} else {
dt
};
(out + rhs.inner).into()
} else {
DateTime::nat()
}
}
}
impl<U: TimeUnitTrait> Sub<TimeDelta> for DateTime<U>
where
Self: From<CrDateTime<Utc>> + TryInto<CrDateTime<Utc>>,
{
type Output = DateTime<U>;
fn sub(self, rhs: TimeDelta) -> Self::Output {
if self.is_not_nat() && rhs.is_not_nat() {
let dt = self.to_cr().unwrap();
let out = if rhs.months != 0 {
if rhs.months > 0 {
dt - Months::new(rhs.months as u32)
} else {
dt + Months::new((-rhs.months) as u32)
}
} else {
dt
};
(out - rhs.inner).into()
} else {
DateTime::nat()
}
}
}
impl<U: TimeUnitTrait> Sub<DateTime<U>> for DateTime<U>
where
Self: From<CrDateTime<Utc>> + TryInto<CrDateTime<Utc>>,
{
type Output = TimeDelta;
fn sub(self, rhs: DateTime<U>) -> Self::Output {
if self.is_not_nat() && rhs.is_not_nat() {
let dt1 = self.to_cr().unwrap();
let dt2 = rhs.to_cr().unwrap();
let duration = dt1 - dt2;
TimeDelta {
months: 0,
inner: duration,
}
} else {
TimeDelta::nat()
}
}
}
impl Neg for TimeDelta {
type Output = TimeDelta;
#[inline]
fn neg(self) -> TimeDelta {
if self.is_not_nat() {
Self {
months: -self.months,
inner: -self.inner,
}
} else {
self
}
}
}
impl Add for TimeDelta {
type Output = TimeDelta;
#[inline]
fn add(self, rhs: TimeDelta) -> TimeDelta {
if self.is_not_nat() & rhs.is_not_nat() {
Self {
months: self.months + rhs.months,
inner: self.inner + rhs.inner,
}
} else {
TimeDelta::nat()
}
}
}
impl Sub for TimeDelta {
type Output = TimeDelta;
#[inline]
fn sub(self, rhs: TimeDelta) -> TimeDelta {
if self.is_not_nat() & rhs.is_not_nat() {
Self {
months: self.months - rhs.months,
inner: self.inner - rhs.inner,
}
} else {
TimeDelta::nat()
}
}
}
impl Mul<i32> for TimeDelta {
type Output = TimeDelta;
#[inline]
fn mul(self, rhs: i32) -> Self {
if self.is_not_nat() {
Self {
months: self.months * rhs,
inner: self.inner * rhs,
}
} else {
TimeDelta::nat()
}
}
}
impl Div<TimeDelta> for TimeDelta {
type Output = i32;
fn div(self, rhs: TimeDelta) -> Self::Output {
if self.is_not_nat() & rhs.is_not_nat() {
let inner_div =
self.inner.num_nanoseconds().unwrap() / rhs.inner.num_nanoseconds().unwrap();
if self.months == 0 || rhs.months == 0 {
return inner_div as i32;
}
let month_div = self.months / rhs.months;
if month_div == inner_div as i32 {
month_div
} else {
panic!("not support div TimeDelta when month div and time div is not equal")
}
} else {
panic!("not support div TimeDelta when one of them is nat")
}
}
}