use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Clone, Default)]
pub struct DateTime {
pub date: Date,
pub time: Time,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
pub struct PartialDateTime {
pub date: Option<PartialDate>,
pub time: Option<PartialTime>,
}
pub trait OffsetFormat: Sized {
type Err;
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
fn parse(s: &str) -> Result<Self, Self::Err>;
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Date {
YMD { year: i32, month: u32, day: u32 },
Week { year: i32, week: u32, day: u32 },
Ordinal { year: i32, day: u32 },
}
impl Default for Date {
fn default() -> Date {
Date::YMD {
year: 0,
month: 0,
day: 0,
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum PartialDate {
Year { year: Option<i32> },
YMD {
year: Option<i32>,
month: Option<u32>,
day: Option<u32>,
},
YWD {
year: Option<i32>,
week: Option<u32>,
day: Option<u32>,
},
YDDD { year: Option<i32>, day: Option<u32> },
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Clone, Default)]
pub struct Time {
pub hour: u32,
pub minute: u32,
pub second: u32,
pub millisecond: u32,
pub offset: Option<Offset>,
pub time_zone: Option<TimeZone>,
pub calendar: Option<Calendar>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct PartialTime {
pub hour: Option<u32>,
pub minute: Option<u32>,
pub second: Option<u32>,
pub millisecond: Option<u32>,
pub offset: Option<Offset>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub struct Interval {
pub repetitions: Option<Option<u32>>,
pub range: IntervalRange,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum IntervalRange {
Closed {
start: PartialDateTime,
end: PartialDateTime,
},
ClosedStart {
start: PartialDateTime,
duration: Duration,
},
ClosedEnd {
duration: Duration,
end: PartialDateTime,
},
Open {
duration: Duration,
},
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Offset {
LocalUnknown {
critical: bool,
},
Fixed {
hours: i32,
minutes: i32,
critical: bool,
},
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Debug, Default, Copy, Clone)]
pub struct Duration {
pub years: u32,
pub months: u32,
pub weeks: u32,
pub days: u32,
pub hours: u32,
pub minutes: u32,
pub seconds: u32,
pub milliseconds: Option<f32>,
}
impl PartialEq for Duration {
fn eq(&self, other: &Self) -> bool {
self.years == other.years
&& self.months == other.months
&& self.weeks == other.weeks
&& self.days == other.days
&& self.hours == other.hours
&& self.minutes == other.minutes
&& self.seconds == other.seconds
&& self.milliseconds.map(|v| v.to_bits()) == other.milliseconds.map(|v| v.to_bits())
}
}
impl Eq for Duration {}
impl Duration {
pub fn is_zero(&self) -> bool {
let Duration {
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
} = self;
[*years, *months, *weeks, *days, *hours, *minutes, *seconds]
.iter()
.all(|&x| x == 0)
&& milliseconds.unwrap_or(0.0) == 0.0
}
pub fn has_time(&self) -> bool {
let Duration {
days,
hours,
minutes,
seconds,
milliseconds,
..
} = self;
[*days, *hours, *minutes, *seconds].iter().all(|&x| x > 0)
|| milliseconds.unwrap_or(0.0) > 0.0
}
}
impl From<Duration> for ::core::time::Duration {
fn from(duration: Duration) -> Self {
let Duration {
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
} = duration;
let secs = years * 365 * 86_400
+ months * 30 * 86_400
+ weeks * 7 * 86_400
+ days * 86_400
+ hours * 3600
+ minutes * 60
+ seconds;
let nanos = (milliseconds.unwrap_or(0.0) * 1_000_000_000.0).floor();
Self::new(secs as u64, nanos as u32)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Copy, Clone)]
pub struct DurationPart {
pub whole: u32,
pub frac: Option<f32>,
}
impl PartialEq for DurationPart {
fn eq(&self, other: &Self) -> bool {
self.whole == other.whole
&& self.frac.map(|f| f.to_bits()) == other.frac.map(|f| f.to_bits())
}
}
impl Eq for DurationPart {}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Debug, Default, Copy, Clone)]
pub struct FractionalDuration {
pub years: (u32, Option<f32>),
pub months: (u32, Option<f32>),
pub weeks: (u32, Option<f32>),
pub days: (u32, Option<f32>),
pub hours: (u32, Option<f32>),
pub minutes: (u32, Option<f32>),
pub seconds: (u32, Option<f32>),
}
impl PartialEq for FractionalDuration {
fn eq(&self, other: &Self) -> bool {
[
self.years,
self.months,
self.weeks,
self.days,
self.hours,
self.minutes,
self.seconds,
]
.iter()
.zip([
other.years,
other.months,
other.weeks,
other.days,
other.hours,
other.minutes,
other.seconds,
])
.all(|(part, other_part)| {
part.0 == other_part.0
&& part.1.map(|v| v.to_bits()) == other_part.1.map(|v| v.to_bits())
})
}
}
impl Eq for FractionalDuration {}
impl FractionalDuration {
pub fn is_zero(&self) -> bool {
let FractionalDuration {
years,
months,
weeks,
days,
hours,
minutes,
seconds,
} = self;
[*years, *months, *weeks, *days, *hours, *minutes, *seconds]
.iter()
.all(|&x| x.0 == 0 && x.1.unwrap_or(0.0) == 0.0)
}
pub fn has_time(&self) -> bool {
let FractionalDuration {
days,
hours,
minutes,
seconds,
..
} = self;
[*days, *hours, *minutes, *seconds]
.iter()
.all(|&x| x.0 > 0 || x.1.unwrap_or(0.0) > 0.0)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Clone)]
pub enum TimeZone {
Named { zone: NamedTimeZone },
Fixed { offset: Offset },
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Clone, Default)]
pub struct NamedTimeZone {
pub identifier: String,
pub critical: bool,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Eq, PartialEq, Debug, Clone, Default)]
pub struct Calendar {
pub identifier: String,
pub critical: bool,
}