use std::hash::Hash;
use std::str::FromStr;
use chrono::Duration;
use tea_error::{tbail, tensure, TError, TResult};
use crate::convert::*;
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub struct TimeDelta {
pub months: i32,
pub inner: Duration,
}
impl FromStr for TimeDelta {
type Err = TError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
TimeDelta::parse(s)
}
}
impl From<&str> for TimeDelta {
#[inline]
fn from(s: &str) -> Self {
TimeDelta::parse(s).unwrap_or_else(|e| panic!("{}", e))
}
}
impl TimeDelta {
pub fn parse(duration: &str) -> TResult<Self> {
let mut nsecs = 0;
let mut secs = 0;
let mut months = 0;
let mut iter = duration.char_indices();
let mut start = 0;
let mut unit = String::with_capacity(2);
while let Some((i, mut ch)) = iter.next() {
if !ch.is_ascii_digit() && i != 0 {
let n = duration[start..i].parse::<i64>().unwrap();
loop {
if ch.is_ascii_alphabetic() {
unit.push(ch)
} else {
break;
}
match iter.next() {
Some((i, ch_)) => {
ch = ch_;
start = i
},
None => {
break;
},
}
}
tensure!(!unit.is_empty(), ParseError:"expected a unit in the duration string");
match unit.as_str() {
"ns" => nsecs += n,
"us" => nsecs += n * NANOS_PER_MICRO,
"ms" => nsecs += n * NANOS_PER_MILLI,
"s" => secs += n,
"m" => secs += n * SECS_PER_MINUTE,
"h" => secs += n * SECS_PER_HOUR,
"d" => secs += n * SECS_PER_DAY,
"w" => secs += n * SECS_PER_WEEK,
"mo" => months += n as i32,
"y" => months += n as i32 * 12,
unit => tbail!(ParseError:"unit: '{}' not supported", unit),
}
unit.clear();
}
}
let duration = Duration::seconds(secs) + Duration::nanoseconds(nsecs);
Ok(TimeDelta {
months,
inner: duration,
})
}
#[inline(always)]
pub fn nat() -> Self {
Self {
months: i32::MIN,
inner: Duration::seconds(0),
}
}
#[allow(dead_code)]
#[inline(always)]
pub fn is_nat(&self) -> bool {
self.months == i32::MIN
}
#[inline(always)]
pub fn is_not_nat(&self) -> bool {
self.months != i32::MIN
}
}