use crate::common::*;
use crate::error::DateTimeError;
use crate::parse::{decode_interval, decode_iso8601_interval, parse_date_time};
use crate::token::*;
use crate::{DateTime, DateUnit, FieldType, IntervalStyle, Time};
use std::cmp::Ordering;
use std::mem::MaybeUninit;
use std::ops::Add;
pub const INTERVAL_MASK_Y: i32 = TokenType::YEAR.mask();
pub const INTERVAL_MASK_M: i32 = TokenType::MONTH.mask();
pub const INTERVAL_MASK_YM: i32 = TokenType::YEAR.mask() | TokenType::MONTH.mask();
pub const INTERVAL_MASK_D: i32 = TokenType::DAY.mask();
pub const INTERVAL_MASK_H: i32 = TokenType::HOUR.mask();
pub const INTERVAL_MASK_DH: i32 = TokenType::DAY.mask() | TokenType::HOUR.mask();
pub const INTERVAL_MASK_MIN: i32 = TokenType::MINUTE.mask();
pub const INTERVAL_MASK_HM: i32 = TokenType::HOUR.mask() | TokenType::MINUTE.mask();
pub const INTERVAL_MASK_DHM: i32 =
TokenType::DAY.mask() | TokenType::HOUR.mask() | TokenType::MINUTE.mask();
pub const INTERVAL_MASK_S: i32 = TokenType::SECOND.mask();
pub const INTERVAL_MASK_MS: i32 = TokenType::MINUTE.mask() | TokenType::SECOND.mask();
pub const INTERVAL_MASK_HMS: i32 =
TokenType::HOUR.mask() | TokenType::MINUTE.mask() | TokenType::SECOND.mask();
pub const INTERVAL_MASK_DHMS: i32 = TokenType::DAY.mask()
| TokenType::HOUR.mask()
| TokenType::MINUTE.mask()
| TokenType::SECOND.mask();
pub const INTERVAL_FULL_RANGE: i32 = 0x7FFF;
pub const INTERVAL_RANGE_MASK: i32 = 0x7FFF;
pub const INTERVAL_FULL_PRECISION: i32 = 0xFFFF;
pub const INTERVAL_PRECISION_MASK: i32 = 0xFFFF;
const INTERVAL_SCALES: [i64; MAX_INTERVAL_PRECISION + 1] =
[1_000_000, 100_000, 10_000, 1000, 100, 10, 1];
const INTERVAL_OFFSETS: [i64; MAX_INTERVAL_PRECISION + 1] = [500_000, 50_000, 5_000, 500, 50, 5, 0];
#[inline]
const fn interval_range(t: i32) -> i32 {
(t >> 16) & INTERVAL_RANGE_MASK
}
#[allow(dead_code)]
#[inline]
const fn interval_type_mod(p: i32, r: i32) -> i32 {
((r & INTERVAL_RANGE_MASK) << 16) | (p & INTERVAL_PRECISION_MASK)
}
#[inline]
const fn interval_precision(t: i32) -> i32 {
t & INTERVAL_PRECISION_MASK
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Interval {
time: i64,
day: i32,
month: i32,
}
impl Interval {
#[inline]
pub const fn new() -> Self {
Self {
time: 0,
day: 0,
month: 0,
}
}
#[inline]
pub(crate) const fn from_mdt(month: i32, day: i32, time: i64) -> Self {
Self { time, day, month }
}
#[inline]
pub(crate) const fn time(&self) -> i64 {
self.time
}
#[inline]
pub(crate) const fn month(&self) -> i32 {
self.month
}
#[inline]
pub(crate) const fn day(&self) -> i32 {
self.day
}
#[inline]
pub fn try_from_ymwd_hms(
years: i32,
months: i32,
weeks: i32,
days: i32,
hours: i32,
minutes: i32,
seconds: f64,
) -> Result<Interval, DateTimeError> {
if seconds.is_infinite() || seconds.is_nan() {
return Err(DateTimeError::overflow());
}
let months = years.wrapping_mul(MONTHS_PER_YEAR).wrapping_add(months);
let days = weeks.wrapping_mul(7).wrapping_add(days);
let secs = unsafe { (seconds * USECS_PER_SEC as f64).to_int_unchecked() };
let time = (hours as i64)
.wrapping_mul(SECS_PER_HOUR as i64 * USECS_PER_SEC)
.wrapping_add((minutes as i64).wrapping_mul(SECS_PER_MINUTE as i64 * USECS_PER_SEC))
.wrapping_add(secs);
Ok(Interval::from_mdt(months, days, time))
}
#[inline]
pub fn add_interval(self, span: Self) -> Result<Self, DateTimeError> {
let month = self.month.checked_add(span.month);
let m = match month {
Some(m) => m,
None => return Err(DateTimeError::overflow()),
};
let day = self.day.checked_add(span.day);
let d = match day {
Some(d) => d,
None => return Err(DateTimeError::overflow()),
};
let time = self.time.checked_add(span.time);
let t = match time {
Some(t) => t,
None => return Err(DateTimeError::overflow()),
};
Ok(Interval::from_mdt(m, d, t))
}
#[inline]
pub fn negate(self) -> Result<Self, DateTimeError> {
let t_ret = self.time().checked_neg();
let time = match t_ret {
Some(t) => t,
None => return Err(DateTimeError::overflow()),
};
let d_ret = self.day().checked_neg();
let day = match d_ret {
Some(d) => d,
None => return Err(DateTimeError::overflow()),
};
let m_ret = self.month().checked_neg();
let month = match m_ret {
Some(m) => m,
None => return Err(DateTimeError::overflow()),
};
Ok(Self::from_mdt(month, day, time))
}
#[inline]
pub fn sub_interval(self, span: Self) -> Result<Self, DateTimeError> {
let month = self.month.checked_sub(span.month);
let m = match month {
Some(m) => m,
None => return Err(DateTimeError::overflow()),
};
let day = self.day.checked_sub(span.day);
let d = match day {
Some(d) => d,
None => return Err(DateTimeError::overflow()),
};
let time = self.time.checked_sub(span.time);
let t = match time {
Some(t) => t,
None => return Err(DateTimeError::overflow()),
};
Ok(Interval::from_mdt(m, d, t))
}
#[inline]
pub fn justify_hours(self) -> Self {
let mut result = self;
let (time, whole_day) = time_modulo(result.time, USECS_PER_DAY);
result.time = time;
result.day = result.day.wrapping_add(whole_day as i32);
if result.day > 0 && result.time < 0 {
result.time += USECS_PER_DAY;
result.day -= 1;
} else if result.day < 0 && result.time > 0 {
result.time -= USECS_PER_DAY;
result.day += 1;
}
result
}
#[inline]
pub fn justify_days(self) -> Self {
let mut result = self;
let whole_month = result.day / DAYS_PER_MONTH;
result.day -= whole_month * DAYS_PER_MONTH;
result.month = result.month.wrapping_add(whole_month);
if result.month > 0 && result.day < 0 {
result.day += DAYS_PER_MONTH;
result.month -= 1;
} else if result.month < 0 && result.day > 0 {
result.day -= DAYS_PER_MONTH;
result.month += 1;
}
result
}
#[inline]
pub fn justify_interval(self) -> Self {
let mut result = self;
let (time, whole_day) = time_modulo(result.time, USECS_PER_DAY);
result.time = time;
result.day = result.day.wrapping_add(whole_day as i32);
let whole_month = result.day / DAYS_PER_MONTH;
result.day = result.day.wrapping_sub(whole_month * DAYS_PER_MONTH);
result.month = result.month.wrapping_add(whole_month);
if result.month > 0 && (result.day < 0 || (result.day == 0 && result.time < 0)) {
result.day += DAYS_PER_MONTH;
result.month -= 1;
} else if result.month < 0 && (result.day > 0 || (result.day == 0 && result.time > 0)) {
result.day -= DAYS_PER_MONTH;
result.month += 1;
}
if result.day > 0 && result.time < 0 {
result.time += USECS_PER_DAY;
result.day -= 1;
} else if result.day < 0 && result.time > 0 {
result.time -= USECS_PER_DAY;
result.day += 1;
}
result
}
#[inline]
pub fn mul_f64(self, factor: f64) -> Result<Self, DateTimeError> {
let orig_month = self.month;
let orig_day = self.day;
let result_month = self.month as f64 * factor;
if result_month.is_nan()
|| result_month > std::i32::MAX as f64
|| result_month < std::i32::MIN as f64
{
return Err(DateTimeError::overflow());
}
let result_day = self.day as f64 * factor;
if result_day.is_nan()
|| result_day > std::i32::MAX as f64
|| result_day < std::i32::MIN as f64
{
return Err(DateTimeError::overflow());
}
let mut result = Interval::from_mdt(result_month as i32, result_day as i32, 0);
let month_remainder = orig_month as f64 * factor - result.month as f64;
let month_remainder_days = month_remainder * DAYS_PER_MONTH as f64;
let month_remainder_days = timestamp_round(month_remainder_days);
let sec_remainder = (orig_day as f64 * factor - result.day as f64 + month_remainder_days
- month_remainder_days as i32 as f64)
* SECS_PER_DAY as f64;
let mut sec_remainder = timestamp_round(sec_remainder);
if sec_remainder.abs() >= SECS_PER_DAY as f64 {
result.day += (sec_remainder / SECS_PER_DAY as f64) as i32;
sec_remainder -= (((sec_remainder / SECS_PER_DAY as f64) as i32) * SECS_PER_DAY) as f64;
}
result.day += month_remainder_days as i32;
let result_time =
(self.time as f64 * factor + sec_remainder * USECS_PER_SEC as f64).round();
if result_time > std::i64::MAX as f64 || result_time < std::i64::MIN as f64 {
return Err(DateTimeError::overflow());
}
result.time = result_time as i64;
Ok(result)
}
#[inline]
pub fn div_f64(self, factor: f64) -> Result<Self, DateTimeError> {
let orig_month = self.month;
let orig_day = self.day;
if factor == 0.0 {
return Err(DateTimeError::invalid(format!(
"interval: {:?} divide zero",
self
)));
}
let month = (self.month as f64 / factor) as i32;
let day = (self.day as f64 / factor) as i32;
let mut result = Interval::from_mdt(month, day, 0);
let mut month_remainder_days =
(orig_month as f64 / factor - result.month as f64) * DAYS_PER_MONTH as f64;
month_remainder_days = timestamp_round(month_remainder_days);
let mut sec_remainder = (orig_day as f64 / factor - result.day as f64
+ month_remainder_days
- month_remainder_days as i32 as f64)
* SECS_PER_DAY as f64;
sec_remainder = timestamp_round(sec_remainder);
if sec_remainder.abs() >= SECS_PER_DAY as f64 {
result.day += (sec_remainder / SECS_PER_DAY as f64) as i32;
sec_remainder -= (((sec_remainder / SECS_PER_DAY as f64) as i32) * SECS_PER_DAY) as f64;
}
result.day += month_remainder_days as i32;
result.time =
(self.time as f64 / factor + sec_remainder * USECS_PER_SEC as f64).round() as i64;
Ok(result)
}
#[inline]
pub(crate) fn from_pgtime(tm: &PgTime, fsec: i64) -> Result<Self, DateTimeError> {
let total_months = tm.year as f64 * MONTHS_PER_YEAR as f64 + tm.mon as f64;
if total_months > std::i32::MAX as f64 || total_months < std::i32::MIN as f64 {
return Err(DateTimeError::overflow());
}
let month = total_months as i32;
let day = tm.mday;
let time =
(((((tm.hour * 60) + tm.min) as i64 * 60) + tm.sec as i64) * USECS_PER_SEC) + fsec;
Ok(Self::from_mdt(month, day, time))
}
#[inline]
pub(crate) fn to_pgtime(&self, tm: &mut PgTime, fsec: &mut i64) -> Result<(), DateTimeError> {
tm.year = self.month / MONTHS_PER_YEAR;
tm.mon = self.month % MONTHS_PER_YEAR;
tm.mday = self.day;
let mut time = self.time;
let mut tfrac = time / USECS_PER_HOUR;
time -= tfrac * USECS_PER_HOUR;
if tfrac < std::i32::MIN as i64 || tfrac > std::i32::MAX as i64 {
return Err(DateTimeError::overflow());
}
tm.hour = tfrac as i32;
tfrac = time / USECS_PER_MINUTE;
time -= tfrac * USECS_PER_MINUTE;
tm.min = tfrac as i32;
tfrac = time / USECS_PER_SEC;
*fsec = time - (tfrac * USECS_PER_SEC);
tm.sec = tfrac as i32;
Ok(())
}
pub(crate) fn adjust_by_typmod(&mut self, typmod: i32) -> Result<(), DateTimeError> {
if typmod >= 0 {
let range = interval_range(typmod);
let precision = interval_precision(typmod);
if range == INTERVAL_FULL_RANGE {
} else if range == TokenType::YEAR.mask() {
self.month = (self.month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
self.day = 0;
self.time = 0;
}
else if range == TokenType::MONTH.mask()
|| range == (TokenType::YEAR.mask() | TokenType::MONTH.mask())
{
self.day = 0;
self.time = 0;
} else if range == TokenType::DAY.mask() {
self.time = 0;
} else if range == TokenType::HOUR.mask() {
self.time = (self.time / USECS_PER_HOUR) * USECS_PER_HOUR;
} else if range == TokenType::MINUTE.mask() {
self.time = (self.time / USECS_PER_MINUTE) * USECS_PER_MINUTE;
} else if range == TokenType::SECOND.mask() {
}
else if range == (TokenType::DAY.mask() | TokenType::HOUR.mask()) {
self.time = (self.time / USECS_PER_HOUR) * USECS_PER_HOUR;
}
else if range
== (TokenType::DAY.mask() | TokenType::HOUR.mask() | TokenType::MINUTE.mask())
{
self.time = (self.time / USECS_PER_MINUTE) * USECS_PER_MINUTE;
}
else if range
== (TokenType::DAY.mask()
| TokenType::HOUR.mask()
| TokenType::MINUTE.mask()
| TokenType::SECOND.mask())
{
}
else if range == (TokenType::HOUR.mask() | TokenType::MINUTE.mask()) {
self.time = (self.time / USECS_PER_MINUTE) * USECS_PER_MINUTE;
}
else if range
== (TokenType::HOUR.mask() | TokenType::MINUTE.mask() | TokenType::SECOND.mask())
|| range == (TokenType::MINUTE.mask() | TokenType::SECOND.mask())
{
} else {
return Err(DateTimeError::invalid(format!(
"range: {:?} is valid",
range
)));
}
if precision != INTERVAL_FULL_PRECISION {
if precision < 0 || precision > MAX_INTERVAL_PRECISION as i32 {
return Err(DateTimeError::overflow());
}
if self.time >= 0 {
self.time = ((self.time + INTERVAL_OFFSETS[precision as usize])
/ INTERVAL_SCALES[precision as usize])
* INTERVAL_SCALES[precision as usize];
} else {
self.time = -(((-self.time + INTERVAL_OFFSETS[precision as usize])
/ INTERVAL_SCALES[precision as usize])
* INTERVAL_SCALES[precision as usize]);
}
}
}
Ok(())
}
#[allow(clippy::uninit_assumed_init)]
pub fn try_from_str(
s: &str,
type_mod: i32,
format_type: IntervalStyle,
) -> Result<Self, DateTimeError> {
let s = s.as_bytes();
let mut fields: [&[u8]; MAX_DATE_FIELDS] = unsafe { MaybeUninit::uninit().assume_init() };
let mut work_buf: [u8; MAX_DATE_LEN] = unsafe { MaybeUninit::uninit().assume_init() };
let mut f_types: [TokenField; MAX_DATE_FIELDS] =
unsafe { MaybeUninit::uninit().assume_init() };
let mut d_type = TokenField::Number;
let mut fsec = 0;
let mut tm = PgTime::new();
let range = if type_mod >= 0 {
interval_range(type_mod)
} else {
INTERVAL_FULL_RANGE
};
let nf = parse_date_time(s, &mut work_buf, &mut fields, &mut f_types, MAX_DATE_FIELDS)?;
let err = decode_interval(
&fields[0..nf],
&f_types[0..nf],
range,
&mut d_type,
&mut tm,
&mut fsec,
format_type,
);
if let Err(e) = err {
if e.is_invalid() {
decode_iso8601_interval(s, &mut d_type, &mut tm, &mut fsec)?;
} else {
return Err(e);
}
}
let mut result = match d_type {
TokenField::Delta => Interval::from_pgtime(&tm, fsec)?,
_ => {
return Err(DateTimeError::invalid(format!(
"date: {:?} is invalid",
d_type
)))
}
};
result.adjust_by_typmod(type_mod)?;
Ok(result)
}
#[inline]
pub fn format(self, interval_format: IntervalStyle) -> Result<String, DateTimeError> {
let mut buf = Vec::with_capacity(128);
unsafe { buf.set_len(128) };
let mut tm: PgTime = PgTime::new();
let mut fsec = 0;
self.to_pgtime(&mut tm, &mut fsec)?;
let len = format_interval(buf.as_mut_slice(), &tm, fsec, interval_format)?;
unsafe {
buf.set_len(len);
Ok(String::from_utf8_unchecked(buf))
}
}
}
#[allow(clippy::cognitive_complexity)]
fn format_interval(
s: &mut [u8],
tm: &PgTime,
mut fsec: i64,
style: IntervalStyle,
) -> Result<usize, DateTimeError> {
let mut year = tm.year;
let mut mon = tm.mon;
let mut mday = tm.mday;
let mut hour = tm.hour;
let mut min = tm.min;
let mut sec = tm.sec;
let mut is_before = false;
let mut is_zero = true;
let mut offset = 0;
match style {
IntervalStyle::SQLStandard => {
let has_negative =
year < 0 || mon < 0 || mday < 0 || hour < 0 || min < 0 || sec < 0 || fsec < 0;
let has_positive =
year > 0 || mon > 0 || mday > 0 || hour > 0 || min > 0 || sec > 0 || fsec > 0;
let has_year_month = year != 0 || mon != 0;
let has_day_time = mday != 0 || hour != 0 || min != 0 || sec != 0 || fsec != 0;
let has_day = mday != 0;
let sql_standard_value =
!(has_negative && has_positive || has_year_month && has_day_time);
if has_negative && sql_standard_value {
offset = set_one_byte(s, offset, b'-');
year = -year;
mon = -mon;
mday = -mday;
hour = -hour;
min = -min;
sec = -sec;
fsec = -fsec;
}
if !has_negative && !has_positive {
offset = set_one_byte(s, offset, b'0');
Ok(offset)
} else if !sql_standard_value {
let year_sign = if year < 0 || mon < 0 { b'-' } else { b'+' };
let day_sign = if mday < 0 { b'-' } else { b'+' };
let sec_sign = if hour < 0 || min < 0 || sec < 0 || fsec < 0 {
b'-'
} else {
b'+'
};
offset = set_one_byte(s, offset, year_sign);
offset += pg_ltostr(&mut s[offset..], year.abs());
offset = set_one_byte(s, offset, b'-');
offset += pg_ltostr(&mut s[offset..], mon.abs());
offset = set_one_byte(s, offset, b' ');
offset = set_one_byte(s, offset, day_sign);
offset += pg_ltostr(&mut s[offset..], mday.abs());
offset = set_one_byte(s, offset, b' ');
offset = set_one_byte(s, offset, sec_sign);
offset += pg_ltostr(&mut s[offset..], hour.abs());
offset = set_one_byte(s, offset, b':');
offset += pg_ltostr_zeropad(&mut s[offset..], min.abs(), 2);
offset = set_one_byte(s, offset, b':');
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
true,
);
Ok(offset)
} else if has_year_month {
offset += pg_ltostr(&mut s[offset..], year);
offset = set_one_byte(s, offset, b'-');
offset += pg_ltostr(&mut s[offset..], mon);
Ok(offset)
} else if has_day {
offset += pg_ltostr(&mut s[offset..], mday);
offset = set_one_byte(s, offset, b' ');
offset += pg_ltostr(&mut s[offset..], hour);
offset = set_one_byte(s, offset, b':');
offset += pg_ltostr_zeropad(&mut s[offset..], min, 2);
offset = set_one_byte(s, offset, b':');
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
true,
);
Ok(offset)
} else {
offset += pg_ltostr(&mut s[offset..], hour);
offset = set_one_byte(s, offset, b':');
offset += pg_ltostr_zeropad(&mut s[offset..], min, 2);
offset = set_one_byte(s, offset, b':');
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
true,
);
Ok(offset)
}
}
IntervalStyle::ISO8601 => {
if year == 0 && mon == 0 && mday == 0 && hour == 0 && min == 0 && sec == 0 && fsec == 0
{
offset = copy_slice(s, offset, b"PT0S");
return Ok(offset);
}
offset = set_one_byte(s, offset, b'P');
offset += add_iso8601_int_part(&mut s[offset..], year, b'Y')?;
offset += add_iso8601_int_part(&mut s[offset..], mon, b'M')?;
offset += add_iso8601_int_part(&mut s[offset..], mday, b'D')?;
if hour != 0 || min != 0 || sec != 0 || fsec != 0 {
offset = set_one_byte(s, offset, b'T');
}
offset += add_iso8601_int_part(&mut s[offset..], hour, b'H')?;
offset += add_iso8601_int_part(&mut s[offset..], min, b'M')?;
if sec != 0 || fsec != 0 {
if sec < 0 || fsec < 0 {
offset = set_one_byte(s, offset, b'-');
}
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
false,
);
offset = set_one_byte(s, offset, b'S');
Ok(offset)
} else {
Ok(offset)
}
}
IntervalStyle::Postgres => {
offset += add_postgres_int_part(
&mut s[offset..],
year,
b"year",
&mut is_zero,
&mut is_before,
)?;
offset +=
add_postgres_int_part(&mut s[offset..], mon, b"mon", &mut is_zero, &mut is_before)?;
offset += add_postgres_int_part(
&mut s[offset..],
mday,
b"day",
&mut is_zero,
&mut is_before,
)?;
if is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0 {
let minus = hour < 0 || min < 0 || sec < 0 || fsec < 0;
if !is_zero {
offset = set_one_byte(s, offset, b' ');
}
if minus {
offset = set_one_byte(s, offset, b'-');
} else if is_before {
offset = set_one_byte(s, offset, b'+');
}
offset += pg_ltostr_zeropad(&mut s[offset..], hour.abs(), 2);
offset = set_one_byte(s, offset, b':');
offset += pg_ltostr_zeropad(&mut s[offset..], min.abs(), 2);
offset = set_one_byte(s, offset, b':');
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
true,
);
Ok(offset)
} else {
Ok(offset)
}
}
_ => {
offset = set_one_byte(s, offset, b'@');
offset += add_verbose_int_part(
&mut s[offset..],
year,
b"year",
&mut is_zero,
&mut is_before,
)?;
offset +=
add_verbose_int_part(&mut s[offset..], mon, b"mon", &mut is_zero, &mut is_before)?;
offset +=
add_verbose_int_part(&mut s[offset..], mday, b"day", &mut is_zero, &mut is_before)?;
offset += add_verbose_int_part(
&mut s[offset..],
hour,
b"hour",
&mut is_zero,
&mut is_before,
)?;
offset +=
add_verbose_int_part(&mut s[offset..], min, b"min", &mut is_zero, &mut is_before)?;
if sec != 0 || fsec != 0 {
offset = set_one_byte(s, offset, b' ');
if sec < 0 || (sec == 0 && fsec < 0) {
if is_zero {
is_before = true;
} else if !is_before {
offset = set_one_byte(s, offset, b'-');
}
} else if is_before {
offset = set_one_byte(s, offset, b'-');
}
offset += append_seconds(
&mut s[offset..],
sec,
fsec,
MAX_INTERVAL_PRECISION as i32,
false,
);
offset = copy_slice(s, offset, b" sec");
if sec.abs() != 1 || fsec != 0 {
offset = set_one_byte(s, offset, b's');
}
is_zero = false;
}
if is_zero {
offset = copy_slice(s, offset, b" 0");
}
if is_before {
offset = copy_slice(s, offset, b" ago");
}
Ok(offset)
}
}
}
#[inline]
fn add_iso8601_int_part(s: &mut [u8], value: i32, units: u8) -> Result<usize, DateTimeError> {
if value == 0 {
return Ok(0);
}
let mut offset = 0;
offset += pg_ltostr(&mut s[offset..], value);
offset = set_one_byte(s, offset, units);
Ok(offset)
}
#[inline]
fn add_postgres_int_part(
s: &mut [u8],
value: i32,
units: &[u8],
is_zero: &mut bool,
is_before: &mut bool,
) -> Result<usize, DateTimeError> {
let mut offset = 0;
if value == 0 {
return Ok(offset);
}
if !*is_zero {
offset = set_one_byte(s, offset, b' ');
}
if *is_before && value > 0 {
offset = set_one_byte(s, offset, b'+');
}
offset += pg_ltostr(&mut s[offset..], value);
offset = set_one_byte(s, offset, b' ');
offset = copy_slice(s, offset, units);
if value != 1 {
offset = set_one_byte(s, offset, b's');
}
*is_before = value < 0;
*is_zero = false;
Ok(offset)
}
#[inline]
fn add_verbose_int_part(
s: &mut [u8],
value: i32,
units: &[u8],
is_zero: &mut bool,
is_before: &mut bool,
) -> Result<usize, DateTimeError> {
if value == 0 {
return Ok(0);
}
let mut offset = 0;
offset = set_one_byte(s, offset, b' ');
if *is_zero {
*is_before = value < 0;
offset += pg_ltostr(&mut s[offset..], value.abs());
} else if *is_before {
offset += pg_ltostr(&mut s[offset..], -value);
} else {
offset += pg_ltostr(&mut s[offset..], value);
};
offset = set_one_byte(s, offset, b' ');
offset = copy_slice(s, offset, units);
if value != 1 {
offset = set_one_byte(s, offset, b's');
}
*is_zero = false;
Ok(offset as usize)
}
impl From<Time> for Interval {
#[inline]
fn from(value: Time) -> Self {
Interval::from_mdt(0, 0, value.value())
}
}
impl From<Interval> for i128 {
#[inline]
fn from(span: Interval) -> Self {
let mut v = span.time() as i128;
v += span.day() as i128 * USECS_PER_DAY as i128;
v += span.month() as i128 * DAYS_PER_MONTH as i128 * USECS_PER_DAY as i128;
v
}
}
impl Add<Interval> for Interval {
type Output = Interval;
#[inline]
fn add(self, rhs: Interval) -> Self::Output {
self.add_interval(rhs).unwrap()
}
}
impl PartialOrd for Interval {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let left: i128 = From::from(*self);
let right: i128 = From::from(*other);
left.partial_cmp(&right)
}
}
impl Ord for Interval {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
let left: i128 = From::from(*self);
let right: i128 = From::from(*other);
left.cmp(&right)
}
}
impl DateTime for Interval {
#[inline]
fn date_part(&self, ty: FieldType, unit: DateUnit) -> Result<Option<f64>, DateTimeError> {
match ty {
FieldType::Unit => {
let mut tm: PgTime = PgTime::new();
let mut fsec = 0;
self.to_pgtime(&mut tm, &mut fsec)?;
match unit {
DateUnit::MicroSec => Ok(Some(tm.sec as f64 * 1_000_000.0 + fsec as f64)),
DateUnit::MilliSec => Ok(Some(tm.sec as f64 * 1000.0 + fsec as f64 / 1000.0)),
DateUnit::Second => Ok(Some(tm.sec as f64 + fsec as f64 / 1_000_000.0)),
DateUnit::Minute => Ok(Some(tm.min as f64)),
DateUnit::Hour => Ok(Some(tm.hour as f64)),
DateUnit::Day => Ok(Some(tm.mday as f64)),
DateUnit::Month => Ok(Some(tm.mon as f64)),
DateUnit::Quarter => Ok(Some(((tm.mon / 3) + 1) as f64)),
DateUnit::Year => Ok(Some(tm.year as f64)),
DateUnit::Decade => Ok(Some((tm.year / 10) as f64)),
DateUnit::Century => Ok(Some((tm.year / 100) as f64)),
DateUnit::Millennium => Ok(Some((tm.year / 1000) as f64)),
_ => Err(DateTimeError::invalid(format!(
"unit: {:?} is invalid",
unit
))),
}
}
FieldType::Epoch => {
if unit == DateUnit::Epoch {
let mut result = self.time as f64 / 1_000_000.0;
result += (DAYS_PER_YEAR as f64 * SECS_PER_DAY as f64)
* (self.month / MONTHS_PER_YEAR) as f64;
result += (DAYS_PER_MONTH as f64 * SECS_PER_DAY as f64)
* (self.month % MONTHS_PER_YEAR) as f64;
result += SECS_PER_DAY as f64 * self.day as f64;
Ok(Some(result))
} else {
Err(DateTimeError::invalid(format!(
"token ty: {:?} is invalid",
ty
)))
}
}
}
}
#[inline]
fn is_finite(&self) -> bool {
true
}
#[inline]
fn truncate(&self, ty: FieldType, unit: DateUnit) -> Result<Self, DateTimeError> {
match ty {
FieldType::Unit => {
let mut tm = PgTime::new();
let mut fsec = 0;
self.to_pgtime(&mut tm, &mut fsec)?;
match unit {
DateUnit::Millennium => tm.truncate_interval_millennium(&mut fsec),
DateUnit::Century => tm.truncate_interval_century(&mut fsec),
DateUnit::Decade => tm.truncate_interval_decade(&mut fsec),
DateUnit::Year => tm.truncate_interval_year(&mut fsec),
DateUnit::Quarter => tm.truncate_interval_quarter(&mut fsec),
DateUnit::Month => tm.truncate_interval_month(&mut fsec),
DateUnit::Day => tm.truncate_day(&mut fsec),
DateUnit::Hour => tm.truncate_hour(&mut fsec),
DateUnit::Minute => (&mut tm).truncate_minute(&mut fsec),
DateUnit::Second => (&mut tm).truncate_sec(&mut fsec),
DateUnit::MilliSec => (&mut tm).truncate_milli_sec(&mut fsec),
DateUnit::MicroSec => (&mut tm).truncate_micro_sec(&mut fsec),
_ => {
return Err(DateTimeError::invalid(format!(
"date unit: {:?} is invalid",
unit
)))
}
}
Interval::from_pgtime(&tm, fsec)
}
_ => Err(DateTimeError::invalid(format!("type: {:?} is invalid", ty))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::DateTimeError;
use crate::{
Date, DateOrder, DateStyle, DateTime, DateUnit, FieldType, Interval, IntervalStyle,
Timestamp,
};
#[test]
fn test_interval_from_str() -> Result<(), DateTimeError> {
let interval = Interval::try_from_str("P1987-07-08-T", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P-1987-07-08T-06:40:50.02", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str(
"P198999999997-07-08T06:40:50.02",
-1,
IntervalStyle::ISO8601,
);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987/07/08T06:40:50.02r", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987-07/08T06:40:50.02r", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987-07-08Y06:40:50.02", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("P19870708T06:40:50.02r", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("P1987Y", -1, IntervalStyle::ISO8601)?;
assert_eq!(interval.format(IntervalStyle::SQLStandard)?, "1987-0");
let interval = Interval::try_from_str("P19870708T06:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 7 mons 8 days 06:40:50.02");
let interval = Interval::try_from_str("@ -8 month 1 millennium 9 century 8 decade 7 year 7 day 6 hour 40 minute 50 second 20 millisecond",
-1, IntervalStyle::SQLStandard)?;
let s = interval.format(IntervalStyle::SQLStandard)?;
assert_eq!(s, "-1987-8 -7 -6:40:50.02");
let interval = Interval::try_from_str("@ -1 millennium 9 century 8 decade 7 year 8 month 7 day 6 hour 40 minute 50 second 20 millisecond",
-1, IntervalStyle::SQLStandard)?;
let s = interval.format(IntervalStyle::SQLStandard)?;
assert_eq!(s, "-13-8 -7 -6:40:50.02");
let interval =
Interval::try_from_str("@ -7 year 8 month", -1, IntervalStyle::SQLStandard)?;
assert_eq!(interval.format(IntervalStyle::SQLStandard)?, "-7-8");
let interval = Interval::try_from_str("@ 7 year 8 month", -1, IntervalStyle::ISO8601)?;
assert_eq!(interval.format(IntervalStyle::SQLStandard)?, "7-8");
let interval = Interval::try_from_str("@ 7 day", -1, IntervalStyle::ISO8601)?;
assert_eq!(interval.format(IntervalStyle::SQLStandard)?, "7 0:00:00");
let interval = Interval::try_from_str(
"@ 6 hour 40 minute 50 second 20 millisecond",
-1,
IntervalStyle::ISO8601,
)?;
let s = interval.format(IntervalStyle::SQLStandard)?;
assert_eq!(s, "6:40:50.02");
let interval = Interval::try_from_str("@ 78.789.45 years", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ 78.789_45 years", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ J20045", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ @", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("invalid", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("6:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 6 hours 40 mins 50.02 secs");
let interval =
Interval::try_from_str("+1987-8 +7 +6:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons 7 days 6 hours 40 mins 50.02 secs");
let interval =
Interval::try_from_str("-1987-8 -7 -6:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(
s,
"@ 1987 years 8 mons 7 days 6 hours 40 mins 50.02 secs ago"
);
let interval =
Interval::try_from_str("@ 1 millennium 9 century", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1900 years");
let interval =
Interval::try_from_str("@ 1 millennium 9 century ago", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1900 years ago");
let interval = Interval::try_from_str("@ 1.1 millennium 9.1 century 8.1 decade 7 year 8 month 1 week 7 day 6 hour 40 minute 50 second 20 millisecond",
-1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 2098 years 8 mons 14 days 6 hours 40 mins 50.02 secs");
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8 month 7 day 6 hour 40 minute 50 second 20 millisecond",
-1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons 7 days 6 hours 40 mins 50.02 secs");
let s = interval.format(IntervalStyle::SQLStandard)?;
assert_eq!(s, "+1987-8 +7 +6:40:50.02");
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 06:40:50.02");
let s = interval.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P1987Y8M7DT6H40M50.02S");
let interval = Interval::try_from_str("@ -1 millennium -9 century 8 decade 7 year 8 month 7 day 6 hour 40 minute 50 second 20 millisecond",
-1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(
s,
"@ 1812 years 4 mons -7 days -6 hours -40 mins -50.02 secs ago"
);
let s = interval.format(IntervalStyle::SQLStandard)?;
assert_eq!(s, "-1812-4 +7 +6:40:50.02");
let interval = Interval::try_from_str(
"@ 1 millennium 9 century 9 century ago",
-1,
IntervalStyle::ISO8601,
);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ 1 yue", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("infinity", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987Y8M1W7DT6H40M50.02S", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 14 days 06:40:50.02");
let interval = Interval::try_from_str("P1987-8-7T06:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 06:40:50.02");
let interval = Interval::try_from_str("P1987T06:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 06:40:50.02");
let interval = Interval::try_from_str("P1987-8T06:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 06:40:50.02");
let interval = Interval::try_from_str("P1987-8-7", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days");
let interval = Interval::try_from_str("P1987", -1, IntervalStyle::ISO8601)?;
assert_eq!(interval.format(IntervalStyle::Postgres)?, "1987 years");
let interval = Interval::try_from_str("P1987-8", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons");
let interval = Interval::try_from_str("P1987-8-7T06:40:50.02", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 06:40:50.02");
let interval =
Interval::try_from_str("P1987-8-7T064020.34567", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 06:40:20.34567");
let interval = Interval::try_from_str("P1987-8-7T23.3", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 23:18:00");
let interval =
Interval::try_from_str("P1987-8-7T064020.34567", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 06:40:20.34567");
let interval = Interval::try_from_str("P19870807.23456", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "1987 years 8 mons 7 days 05:37:45.984142");
let interval = Interval::try_from_str("P807.23456", -1, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::Postgres)?;
assert_eq!(s, "807 years 2 mons");
let interval = Interval::try_from_str("P", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("P1987-n8-7T06:40:50.02", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987Y8M1W7DT6H40M50.02Y", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987Y8M1N7DT6H40M50.02S", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987Y8M17D4567.8T6H40M50.02S", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval =
Interval::try_from_str("P1987Y8M17DT6H40M50.02S5678.9", -1, IntervalStyle::ISO8601);
assert!(interval.is_err());
Ok(())
}
#[test]
fn test_interval_convert() -> Result<(), DateTimeError> {
let time = Time::try_from_hms(12, 34, 23.456788)?;
let interval1: Interval = From::from(time);
let interval2: Interval = Interval::try_from_ymwd_hms(0, 0, 0, 0, 12, 34, 23.456788)?;
assert_eq!(interval1, interval2);
let interval: Interval = Interval::try_from_ymwd_hms(2020, 12, 23, 12, 36, 34, 23.456788)?;
let time1: Time = From::from(interval);
let time2 = time;
assert_eq!(time1, time2);
let interval: Interval = Interval::try_from_ymwd_hms(2020, 12, 23, 12, -2, 34, 23.456788)?;
let time1: Time = From::from(interval);
assert_eq!(time1.format(DateStyle::SQL)?, "22:34:23.456788");
Ok(())
}
#[test]
fn test_mask() -> Result<(), DateTimeError> {
let type_mod = interval_type_mod(6, TokenType::YEAR.mask() | TokenType::HOUR.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day 6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601);
assert!(interval.is_err());
let type_mod = interval_type_mod(6, TokenType::MINUTE.mask() | TokenType::HOUR.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day 6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons 10 days 6 hours 40 mins");
let type_mod = interval_type_mod(6, TokenType::MINUTE.mask() | TokenType::HOUR.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day -6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons 10 days -5 hours -19 mins");
let type_mod = interval_type_mod(6, TokenType::DAY.mask() | TokenType::HOUR.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day 6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons 10 days 6 hours");
let type_mod = interval_type_mod(6, TokenType::MONTH.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day 6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 8 mons");
let type_mod = interval_type_mod(6, TokenType::YEAR.mask());
let interval = Interval::try_from_str("@ 1 millennium 9 century 8 decade 7 year 8.1 month 7 day 6 hour 40 minute 50 second 20 millisecond 567 microsecond",
type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years");
let type_mod = interval_type_mod(6, INTERVAL_MASK_Y);
let interval = Interval::try_from_str("@ 1987.34", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years");
let type_mod = interval_type_mod(6, INTERVAL_MASK_YM);
let interval = Interval::try_from_str("@ 1987-7", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 1987 years 7 mons");
let type_mod = interval_type_mod(6, INTERVAL_MASK_D);
let interval = Interval::try_from_str("@ 19", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 19 days");
let type_mod = interval_type_mod(6, INTERVAL_MASK_DH);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 hours");
let type_mod = interval_type_mod(6, INTERVAL_MASK_H);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 hours");
let type_mod = interval_type_mod(6, INTERVAL_MASK_MIN);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 mins");
let type_mod = interval_type_mod(6, INTERVAL_MASK_S);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 secs");
let type_mod = interval_type_mod(6, INTERVAL_MASK_MS);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 secs");
let type_mod = interval_type_mod(6, INTERVAL_FULL_RANGE);
let interval = Interval::try_from_str("@ 10", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10 secs");
let type_mod = interval_type_mod(6, INTERVAL_MASK_HMS);
let interval = Interval::try_from_str("@ 10.2345", type_mod, IntervalStyle::ISO8601)?;
let s = interval.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 10.2345 secs");
let type_mod = interval_type_mod(6, INTERVAL_MASK_YM);
let interval = Interval::try_from_str("@ 10-h", type_mod, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ 10-13", type_mod, IntervalStyle::ISO8601);
assert!(interval.is_err());
let interval = Interval::try_from_str("@ 10-13", type_mod, IntervalStyle::ISO8601);
assert!(interval.is_err());
let s = "@ 102222222222222222222-12";
let interval = Interval::try_from_str(s, type_mod, IntervalStyle::ISO8601);
assert!(interval.is_err());
Ok(())
}
#[test]
fn test_interval_range() -> Result<(), DateTimeError> {
let time = Interval::try_from_str("-178000000 year", -1, IntervalStyle::ISO8601)?;
let s = time.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 178000000 years ago");
let time = Interval::try_from_str("178000000 year", -1, IntervalStyle::ISO8601)?;
let s = time.format(IntervalStyle::PostgresVerbose)?;
assert_eq!(s, "@ 178000000 years");
let time = Interval::try_from_str("-179000000 year", -1, IntervalStyle::ISO8601);
assert!(time.is_err());
let time = Interval::try_from_str("-179000000 year", -1, IntervalStyle::ISO8601);
assert!(time.is_err());
Ok(())
}
#[test]
fn test_try_from_ymwd_hms() -> Result<(), DateTimeError> {
let span = Interval::try_from_ymwd_hms(1, 13, 3, 29, 34, 56, std::f64::INFINITY);
assert!(span.is_err());
let span = Interval::try_from_ymwd_hms(1, 13, 3, 29, 34, 56, std::f64::NAN);
assert!(span.is_err());
let span = Interval::try_from_ymwd_hms(1, 13, 3, 29, 34, 56, 67.8)?;
let s = span.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2Y1M50DT34H57M7.8S");
let span = Interval::try_from_ymwd_hms(
std::i32::MAX,
std::i32::MAX,
std::i32::MAX,
std::i32::MAX,
std::i32::MAX,
std::i32::MAX,
std::f64::MAX,
)?;
let s = span.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P178956969Y7M-8DT-378772746H-53M-54.775808S");
Ok(())
}
#[test]
fn test_interval_date_part() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(2001, 2, 0, 16, 20, 38, 40.4567890)?;
let ret = interval.date_part(FieldType::Epoch, DateUnit::Century);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(2001, 2, 0, 16, 20, 38, 40.4567890)?;
let ret = interval.date_part(FieldType::Unit, DateUnit::Century)?;
assert_eq!(ret, Some(20.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Millennium)?;
assert_eq!(ret, Some(2.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Decade)?;
assert_eq!(ret, Some(200.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Day)?;
assert_eq!(ret, Some(16.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Dow);
assert!(ret.is_err());
let ret = interval.date_part(FieldType::Unit, DateUnit::Doy);
assert!(ret.is_err());
let ret = interval.date_part(FieldType::Unit, DateUnit::IsoDow);
assert!(ret.is_err());
let ret = interval.date_part(FieldType::Unit, DateUnit::IsoYear);
assert!(ret.is_err());
let ret = interval.date_part(FieldType::Epoch, DateUnit::Epoch)?;
assert_eq!(ret, Some(63153398320.45679));
let ret = interval.date_part(FieldType::Unit, DateUnit::Hour)?;
assert_eq!(ret, Some(20.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Minute)?;
assert_eq!(ret, Some(38.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Second)?;
assert_eq!(ret, Some(40.456789));
let ret = interval.date_part(FieldType::Unit, DateUnit::MilliSec)?;
assert_eq!(ret, Some(40456.789));
let ret = interval.date_part(FieldType::Unit, DateUnit::MicroSec)?;
assert_eq!(ret, Some(40456789.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Month)?;
assert_eq!(ret, Some(2.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Quarter)?;
assert_eq!(ret, Some(1.0));
let ret = interval.date_part(FieldType::Unit, DateUnit::Week);
assert!(ret.is_err());
let ret = interval.date_part(FieldType::Unit, DateUnit::Year)?;
assert_eq!(ret, Some(2001.0));
Ok(())
}
#[test]
fn test_interval_tuncate() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 16, 20, 38, 40.4567890)?;
let ret = interval.truncate(FieldType::Epoch, DateUnit::MicroSec);
assert!(ret.is_err());
let ret = interval.truncate(FieldType::Unit, DateUnit::Epoch);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 16, 20, 38, 40.4567890)?;
let ret = interval.truncate(FieldType::Unit, DateUnit::Millennium)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2000Y");
let ret = interval.truncate(FieldType::Unit, DateUnit::Century)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2100Y");
let ret = interval.truncate(FieldType::Unit, DateUnit::Decade)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2110Y");
let ret = interval.truncate(FieldType::Unit, DateUnit::Year)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y");
let ret = interval.truncate(FieldType::Unit, DateUnit::Quarter)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y");
let ret = interval.truncate(FieldType::Unit, DateUnit::Month)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y2M");
let ret = interval.truncate(FieldType::Unit, DateUnit::Week);
assert!(ret.is_err());
let ret = interval.truncate(FieldType::Unit, DateUnit::Day)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y2M16D");
let ret = interval.truncate(FieldType::Unit, DateUnit::Hour)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y2M16DT20H");
let ret = interval.truncate(FieldType::Unit, DateUnit::Minute)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P2116Y2M16DT20H38M");
let ret = interval.truncate(FieldType::Unit, DateUnit::Second)?;
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y2M16DT20H38M40S");
let ret = interval.truncate(FieldType::Unit, DateUnit::MilliSec)?;
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y2M16DT20H38M40.456S");
let ret = interval.truncate(FieldType::Unit, DateUnit::MicroSec)?;
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y2M16DT20H38M40.456789S");
Ok(())
}
#[test]
fn test_justify() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 80, 80, 38, 40.4567890)?;
let ret = interval.justify_days();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y4M20DT80H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, 2, 0, -2, 20, 38, 40.4567890)?;
let ret = interval.justify_days();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P1M28DT20H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, -2, 0, 4, 12, 38, 40.4567890)?;
let ret = interval.justify_days();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P-1M-26DT12H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 80, 80, 38, 40.4567890)?;
let ret = interval.justify_hours();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y2M83DT8H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, 2, 0, 80, -2, 38, 40.4567890)?;
let ret = interval.justify_hours();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2M79DT22H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, 2, 0, -80, 48, 38, 40.4567890)?;
let ret = interval.justify_hours();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2M-77DT-23H-21M-19.543211S");
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 80, 80, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116Y4M23DT8H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, 2, 0, -2, 12, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P1M28DT12H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, 2, 0, 0, -8, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P1M29DT16H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(0, -1, 0, 23, 8, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P-6DT-15H-21M-19.543211S");
let interval = Interval::try_from_ymwd_hms(0, -1, 0, 0, 8, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P-29DT-15H-21M-19.543211S");
let interval = Interval::try_from_ymwd_hms(2116, 0, 0, 1, -8, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116YT16H38M40.456789S");
let interval = Interval::try_from_ymwd_hms(2116, 0, 0, -1, 28, 38, 40.4567890)?;
let ret = interval.justify_interval();
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2116YT4H38M40.456789S");
Ok(())
}
#[test]
fn test_finite() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(2116, 2, 0, 80, 80, 38, 40.4567890)?;
assert!(!interval.is_infinite());
assert!(interval.is_finite());
Ok(())
}
#[test]
fn test_add_operator() -> Result<(), DateTimeError> {
let timestamp = Timestamp::new(-211813488000000000);
let time = Time::from(-23);
let timestamp = timestamp.add_time(time);
assert!(timestamp.is_err());
let timestamp = Timestamp::try_from_ymd_hms(2011, 12, 09, 1, 15, 5.456)?;
let time = Time::try_from_hms(1, 20, 30.23)?;
let timestamp = timestamp.add_time(time)?;
let s = timestamp.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "2011-12-09 02:35:35.686");
let date = Date::try_from_ymd(2020, 1, 20)?;
let date2 = Date::try_from_ymd(2020, 1, 31)?;
let date1 = date.add_days(11)?;
assert_eq!(date1, date2);
let date2 = Date::try_from_ymd(2020, 1, 31)?;
let date1 = date.add_days(11)?;
assert_eq!(date1, date2);
let date_infinite = Date::new(std::i32::MIN);
let date1 = date_infinite.add_days(11)?;
let date2 = Date::new(std::i32::MIN);
assert_eq!(date1, date2);
let date_infinite = Date::new(std::i32::MAX);
let date1 = date_infinite.add_days(11)?;
let date2 = Date::new(std::i32::MAX);
assert_eq!(date1, date2);
let date = Date::try_from_ymd(5874897, 12, 31)?;
let ret = date.add_days(1);
assert!(ret.is_err());
let date = Date::try_from_ymd(2010, 10, 29)?;
let interval = Interval::try_from_ymwd_hms(1, 1, 1, 2, 25, 15, 5.456)?;
let timestamp2 = Timestamp::try_from_ymd_hms(2011, 12, 09, 1, 15, 5.456)?;
let timestamp1 = date.add_interval(interval)?;
assert_eq!(timestamp1, timestamp2);
let s = timestamp1.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "2011-12-09 01:15:05.456");
let date = Date::new(std::i32::MIN);
let ret = date.add_interval(interval)?;
let s = ret.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "-infinity");
let date = Date::try_from_ymd(5874897, 10, 29)?;
let interval = Interval::try_from_ymwd_hms(1, 1, 1, 2, 25, 15, 5.456)?;
let ret = date.add_interval(interval);
assert!(ret.is_err());
let date = Date::try_from_ymd(2010, 10, 29)?;
let time = Time::try_from_hms(1, 25, 34.56)?;
let timestamp2 = Timestamp::try_from_ymd_hms(2010, 10, 29, 1, 25, 34.56)?;
let timestamp1 = date.add_time(time)?;
assert_eq!(timestamp1, timestamp2);
let s = timestamp1.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "2010-10-29 01:25:34.56");
let date = Date::new(std::i32::MIN);
let time = Time::try_from_hms(1, 25, 34.56)?;
let timestamp1 = date.add_time(time)?;
let s = timestamp1.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "-infinity");
let date = Date::new(std::i32::MAX);
let time = Time::try_from_hms(1, 25, 34.56)?;
let timestamp1 = date.add_time(time)?;
let s = timestamp1.format(DateStyle::ISO, DateOrder::YMD)?;
assert_eq!(s, "infinity");
let interval = Interval::try_from_ymwd_hms(1, 1, 1, 2, 25, 15, 5.456)?;
let span = Interval::try_from_ymwd_hms(2, 40, 6, 31, 25, 15, 5.456)?;
let result = interval.add_interval(span)?;
assert_eq!(
result.format(IntervalStyle::ISO8601)?,
"P6Y5M82DT50H30M10.912S"
);
let span = Interval::try_from_ymwd_hms(0, std::i32::MAX, 6, 31, 25, 15, 5.456)?;
let result = interval.add_interval(span);
assert!(result.is_err());
let span = Interval::try_from_ymwd_hms(0, 10, 0, std::i32::MAX, 25, 15, 5.456)?;
let result = interval.add_interval(span);
assert!(result.is_err());
let span = Interval::try_from_ymwd_hms(
0,
10,
0,
0,
0,
0,
std::i64::MAX as f64 / USECS_PER_SEC as f64 - 1.0,
)?;
let result = interval.add_interval(span);
assert!(result.is_err());
let timestamp = Timestamp::try_from_ymd_hms(2011, 12, 09, 1, 15, 5.456)?;
let result = timestamp.add_interval(interval)?;
assert_eq!(
result.format(DateStyle::ISO, DateOrder::YMD)?,
"2013-01-19 02:30:10.912"
);
let time = Time::try_from_hms(1, 25, 34.56)?;
let result = time.add_interval(interval);
assert_eq!(result.format(DateStyle::ISO)?, "02:40:40.016");
let time = Time::from(-30000000);
let interval = Interval::try_from_str("@ 1 day", -1, IntervalStyle::Postgres)?;
let result = time.add_interval(interval);
assert_eq!(result.format(DateStyle::ISO)?, "23:59:30");
Ok(())
}
#[test]
fn test_negative() -> Result<(), DateTimeError> {
let span = Interval::try_from_ymwd_hms(12, 23, 6, 31, 25, 15, 5.456)?;
let result = span.negate()?;
assert_eq!(
result.format(IntervalStyle::ISO8601)?,
"P-13Y-11M-73DT-25H-15M-5.456S"
);
let span = Interval::from_mdt(12, 34, std::i64::MIN);
let ret = span.negate();
assert!(ret.is_err());
let span = Interval::from_mdt(12, 34, std::i64::MIN);
let ret = span.negate();
assert!(ret.is_err());
let span = Interval::from_mdt(12, std::i32::MIN, 23);
let ret = span.negate();
assert!(ret.is_err());
let span = Interval::from_mdt(std::i32::MIN, 23, 23);
let ret = span.negate();
assert!(ret.is_err());
Ok(())
}
#[test]
fn test_sub_operator() -> Result<(), DateTimeError> {
let date1 = Date::try_from_ymd(2020, 10, 1)?;
let date2 = Date::try_from_ymd(2000, 2, 28)?;
let ret = date1.sub_date(date2)?;
assert_eq!(ret, 7521);
let ret = date2.sub_date(date1)?;
assert_eq!(ret, -7521);
let date1 = Date::new(std::i32::MIN);
let date2 = Date::try_from_ymd(2000, 2, 28)?;
let ret = date1.sub_date(date2);
assert!(ret.is_err());
let ret = date2.sub_date(date1);
assert!(ret.is_err());
let date1 = Date::try_from_ymd(2020, 10, 1)?;
let ret = date1.sub_days(2)?;
assert_eq!(ret.format(DateStyle::ISO, DateOrder::YMD)?, "2020-09-29");
let date1 = Date::new(std::i32::MIN);
let ret = date1.sub_days(2)?;
assert_eq!(ret.format(DateStyle::ISO, DateOrder::YMD)?, "-infinity");
let date1 = Date::new(std::i32::MIN + 1);
let ret = date1.sub_days(2);
assert!(ret.is_err());
let date1 = Date::try_from_ymd(2020, 10, 1)?;
let ret = date1.sub_days(2451545 + 2020 * 365);
assert!(ret.is_err());
let date = Date::try_from_ymd(2020, 10, 1)?;
let interval = Interval::try_from_ymwd_hms(1, 2, 0, 34, 10, 20, 34.678)?;
let timestamp = date.sub_interval(interval)?;
assert_eq!(
timestamp.format(DateStyle::ISO, DateOrder::YMD)?,
"2019-06-27 13:39:25.322"
);
let time1 = Time::try_from_hms(10, 20, 45.567)?;
let time2 = Time::try_from_hms(4, 50, 54.56)?;
let ret = time1.sub_time(time2);
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "PT5H29M51.007S");
let time = Time::try_from_hms(10, 20, 45.567)?;
let interval = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let ret = time.sub_interval(interval);
assert_eq!(ret.format(DateStyle::ISO)?, "03:12:37.787");
let timestamp = Timestamp::try_from_ymd_hms(2010, 7, 14, 23, 14, 34.678)?;
let interval = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let ret = timestamp.sub_interval(interval)?;
assert_eq!(
ret.format(DateStyle::ISO, DateOrder::YMD)?,
"1989-05-01 16:06:26.898"
);
let interval1 = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let interval2 = Interval::try_from_ymwd_hms(10, 26, 4, 23, 45, 34, 100.78)?;
let ret = interval1.sub_interval(interval2)?;
assert_eq!(
ret.format(IntervalStyle::ISO8601)?,
"P8Y11M-8DT-14H-27M-33S"
);
let interval1 = Interval::try_from_ymwd_hms(1, std::i32::MIN + 1, 1, 1, 1, 1, 67.78)?;
let ret = interval1.sub_interval(interval2);
assert!(ret.is_err());
let interval1 = Interval::try_from_ymwd_hms(1, 1, 1, std::i32::MIN + 10, 1, 1, 67.78)?;
let ret = interval1.sub_interval(interval2);
assert!(ret.is_err());
let interval1 = Interval::try_from_ymwd_hms(
1,
1,
1,
std::i32::MIN + 10,
0,
0,
std::i64::MIN as f64 / USECS_PER_SEC as f64,
)?;
let ret = interval1.sub_interval(interval2);
assert!(ret.is_err());
let timestamp1 = Timestamp::try_from_ymd_hms(2010, 7, 14, 23, 14, 34.678)?;
let timestamp2 = Timestamp::try_from_ymd_hms(2008, 3, 31, 2, 14, 16.678)?;
let ret = timestamp1.sub_timestamp(timestamp2)?;
assert_eq!(ret.format(IntervalStyle::ISO8601)?, "P835DT21H18S");
let timestamp1 = Timestamp::new(std::i64::MIN);
let ret = timestamp1.sub_timestamp(timestamp2);
assert!(ret.is_err());
let timestamp1 = Timestamp::new(std::i64::MAX);
let ret = timestamp1.sub_timestamp(timestamp2);
assert!(ret.is_err());
Ok(())
}
#[test]
fn test_mul_operation() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(8.0)?;
assert_eq!(
ret.format(IntervalStyle::ISO8601)?,
"P168Y8M344DT249H5M2.24S"
);
let interval = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(800.0)?;
assert_eq!(
ret.format(IntervalStyle::ISO8601)?,
"P16866Y8M34400DT24908H23M44S"
);
let interval = Interval::try_from_ymwd_hms(0, 13, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(0.88)?;
assert_eq!(
ret.format(IntervalStyle::ISO8601)?,
"P11M51DT28H21M33.2464S"
);
let interval = Interval::try_from_ymwd_hms(0, 0, 0, 0, 12, 67, 67.78)?;
let ret = interval.mul_f64(std::f64::MAX);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(0, std::i32::MAX, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(std::f64::INFINITY);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(0, std::i32::MAX, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(8.0);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(0, std::i32::MIN, 2, 29, 30, 67, 67.78)?;
let ret = interval.mul_f64(8.0);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(0, 0, 0, std::i32::MAX, 30, 67, 67.78)?;
let ret = interval.mul_f64(8.0);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(0, 0, 0, std::i32::MIN, 30, 67, 67.78)?;
let ret = interval.mul_f64(8.0);
assert!(ret.is_err());
Ok(())
}
#[test]
fn test_divide_operation() -> Result<(), DateTimeError> {
let interval = Interval::try_from_ymwd_hms(20, 13, 2, 29, 30, 67, 67.78)?;
let ret = interval.div_f64(8.0)?;
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2Y7M24DT6H53M30.9725S");
let ret = interval.div_f64(0.0);
assert!(ret.is_err());
let interval = Interval::try_from_ymwd_hms(20, 13, 0, std::i32::MAX, 30, 67, 67.78)?;
let ret = interval.div_f64(8.0)?;
let s = ret.format(IntervalStyle::ISO8601)?;
assert_eq!(s, "P2Y7M268435474DT18H53M30.9725S");
Ok(())
}
#[test]
fn test_cmp_operation() -> Result<(), DateTimeError> {
let time1 = Time::try_from_hms(23, 45, 56.78)?;
let time2 = Time::try_from_hms(12, 56, 56.78)?;
assert!(time1 > time2);
assert!(time1 >= time2);
assert!(time1 == time1);
assert!(time1 != time2);
assert!(time2 < time1);
assert!(time2 <= time1);
let time1 = Time::try_from_hms(24, 0, 0.0)?;
let time2 = Time::try_from_hms(0, 0, 0.0)?;
assert!(time1 > time2);
assert!(time1 >= time2);
assert!(time1 == time1);
assert!(time1 != time2);
assert!(time2 < time1);
assert!(time2 <= time1);
let time1 = Time::try_from_hms(24, 0, 0.0)?;
let time2 = Time::try_from_hms(12, 1, 34.0)?;
assert!(time1 > time2);
assert!(time1 >= time2);
assert!(time1 == time1);
assert!(time1 != time2);
assert!(time2 < time1);
assert!(time2 <= time1);
let date1 = Date::try_from_ymd(2019, 7, 2)?;
let date2 = Date::try_from_ymd(2018, 8, 31)?;
assert!(date1 > date2);
assert!(date1 >= date2);
assert!(date1 == date1);
assert!(date1 != date2);
assert!(date2 < date1);
assert!(date2 <= date1);
let timestamp1 = Timestamp::try_from_ymd_hms(2020, 1, 2, 1, 23, 34.78)?;
let timestamp2 = Timestamp::try_from_ymd_hms(2019, 10, 12, 11, 43, 54.78)?;
assert!(timestamp1 > timestamp2);
assert!(timestamp1 >= timestamp2);
assert!(timestamp1 == timestamp1);
assert!(timestamp1 != timestamp2);
assert!(timestamp2 < timestamp1);
assert!(timestamp2 <= timestamp1);
let interval1 = Interval::try_from_ymwd_hms(10, 1, 2, 1, 23, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(8, 10, 5, 12, 11, 43, 54.78)?;
assert!(interval1 > interval2);
assert!(interval1 >= interval2);
assert!(interval1 == interval1);
assert!(interval1 != interval2);
assert!(interval2 < interval1);
assert!(interval2 <= interval1);
let interval1 = Interval::try_from_ymwd_hms(0, 11, 1, 1, 23, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 10, 2, 12, 11, 43, 54.78)?;
assert!(interval1 > interval2);
assert!(interval1 >= interval2);
assert!(interval1 == interval1);
assert!(interval1 != interval2);
assert!(interval2 < interval1);
assert!(interval2 <= interval1);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 3, 1, 23, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 2, 6, 11, 43, 54.78)?;
assert!(interval1 > interval2);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 0, 7, 22, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 0, 6, 23, 43, 54.78)?;
assert!(interval1 > interval2);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 23, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 22, 59, 54.78)?;
assert!(interval1 > interval2);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 56, 34.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 47, 54.78)?;
assert!(interval1 > interval2);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 0, 56.78)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 0, 54.78)?;
assert!(interval1 > interval2);
let interval1 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 0, 56.781)?;
let interval2 = Interval::try_from_ymwd_hms(0, 0, 0, 0, 0, 0, 56.78)?;
assert!(interval1 > interval2);
let ret = interval1.partial_cmp(&interval2);
assert_eq!(ret, Some(Ordering::Greater));
let ret = interval1.cmp(&interval2);
assert_eq!(ret, Ordering::Greater);
Ok(())
}
}