use std::io;
use time::format_description::well_known::Rfc2822;
use time::{Date, OffsetDateTime, PrimitiveDateTime, UtcOffset};
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[serde(rename_all = "kebab-case", untagged)]
pub enum DateItem {
Date(Date),
DateTime(PrimitiveDateTime),
DateTimeTz(OffsetDateTime),
}
impl DateItem {
pub fn add_timezone(self, offset: UtcOffset) -> Option<Self> {
let datetime_tz = match self {
DateItem::Date(date) => date.midnight().assume_offset(offset),
DateItem::DateTime(datetime) => datetime.assume_offset(offset),
DateItem::DateTimeTz(_) => return None,
};
Some(DateItem::DateTimeTz(datetime_tz))
}
pub fn timestamp(self) -> i64 {
match self {
DateItem::Date(date) => date.midnight().assume_utc().unix_timestamp(),
DateItem::DateTime(datetime) => datetime.assume_utc().unix_timestamp(),
DateItem::DateTimeTz(datetime_tz) => datetime_tz.unix_timestamp(),
}
}
pub fn time_since(self) -> i64 {
self.timestamp() - now().timestamp()
}
pub fn to_datetime_tz(self) -> OffsetDateTime {
match self {
DateItem::Date(date) => date.midnight().assume_utc(),
DateItem::DateTime(datetime) => datetime.assume_utc(),
DateItem::DateTimeTz(datetime_tz) => datetime_tz,
}
}
pub fn format(self) -> io::Result<String> {
use time::error::Format;
let result = match self {
DateItem::Date(date) => date.format(&Rfc2822),
DateItem::DateTime(datetime) => datetime.format(&Rfc2822),
DateItem::DateTimeTz(datetime_tz) => datetime_tz.format(&Rfc2822),
};
result.map_err(|error| match error {
Format::StdIo(io_error) => io_error,
_ => io::Error::new(io::ErrorKind::Other, error),
})
}
}
impl From<Date> for DateItem {
#[inline]
fn from(date: Date) -> Self {
DateItem::Date(date)
}
}
impl From<PrimitiveDateTime> for DateItem {
#[inline]
fn from(datetime: PrimitiveDateTime) -> Self {
DateItem::DateTime(datetime)
}
}
impl From<OffsetDateTime> for DateItem {
#[inline]
fn from(datetime_tz: OffsetDateTime) -> Self {
DateItem::DateTimeTz(datetime_tz)
}
}
cfg_if! {
if #[cfg(test)] {
#[inline]
fn now() -> DateItem {
time::macros::datetime!(2010-01-01 08:10:00).into()
}
} else {
#[inline]
fn now() -> DateItem {
OffsetDateTime::now_utc().into()
}
}
}