use std::cmp::{Ord, Ordering};
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use chrono::{DateTime, TimeZone, Utc};
pub const BODHI_DATETIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
#[derive(Clone, Debug, Eq)]
pub struct BodhiDate {
date: DateTime<Utc>,
}
impl From<DateTime<Utc>> for BodhiDate {
fn from(date: DateTime<Utc>) -> Self {
BodhiDate { date }
}
}
impl TryFrom<&str> for BodhiDate {
type Error = chrono::ParseError;
fn try_from(string: &str) -> Result<Self, Self::Error> {
let string = if string.len() == 10 {
format!("{} 00:00:00", string)
} else {
string.to_owned()
};
Ok(BodhiDate {
date: Utc.datetime_from_str(&string, BODHI_DATETIME_FORMAT)?,
})
}
}
impl FromStr for BodhiDate {
type Err = chrono::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
TryFrom::try_from(s)
}
}
impl Display for BodhiDate {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{}", self.date.format(BODHI_DATETIME_FORMAT))
}
}
impl PartialEq for BodhiDate {
fn eq(&self, other: &Self) -> bool {
self.date.eq(&other.date)
}
}
impl PartialOrd for BodhiDate {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.date.partial_cmp(&other.date)
}
}
impl Ord for BodhiDate {
fn cmp(&self, other: &Self) -> Ordering {
self.date.cmp(&other.date)
}
}
#[allow(dead_code)]
pub(crate) mod bodhi_date_format {
use super::BodhiDate;
use chrono::{TimeZone, Utc};
use serde::{self, Deserialize, Deserializer, Serializer};
pub fn serialize<S>(date: &BodhiDate, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let string = date.date.format(super::BODHI_DATETIME_FORMAT).to_string();
serializer.serialize_str(&string)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<BodhiDate, D::Error>
where
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;
match Utc.datetime_from_str(&string, super::BODHI_DATETIME_FORMAT) {
Ok(result) => Ok(BodhiDate { date: result }),
Err(error) => Err(error).map_err(serde::de::Error::custom),
}
}
}
#[allow(dead_code)]
pub(crate) mod option_bodhi_date_format_ref {
use super::BodhiDate;
use serde::{self, Deserialize, Deserializer, Serializer};
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S>(date: &Option<&BodhiDate>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match date {
Some(dt) => super::bodhi_date_format::serialize(dt, serializer),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<BodhiDate>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper(#[serde(with = "super::bodhi_date_format")] BodhiDate);
let v: Option<Wrapper> = Deserialize::deserialize(deserializer)?;
Ok(v.map(|Wrapper(a)| a))
}
}
#[allow(dead_code)]
pub(crate) mod option_bodhi_date_format {
use super::BodhiDate;
use serde::{self, Deserialize, Deserializer, Serializer};
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S>(date: &Option<BodhiDate>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match date {
Some(ref dt) => super::bodhi_date_format::serialize(dt, serializer),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<BodhiDate>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper(#[serde(with = "super::bodhi_date_format")] BodhiDate);
let v: Option<Wrapper> = Deserialize::deserialize(deserializer)?;
Ok(v.map(|Wrapper(a)| a))
}
}