billecta 1.14.0

Generated Billecta API
Documentation
use std::fmt;

use crate::DateTime;

const BILLECTA_DATE_FORMAT: &[time::format_description::FormatItem] =
    time::macros::format_description!("[year]-[month]-[day]");

const BILLECTA_ALTERNATIVE_DATE_FORMAT: &[time::format_description::FormatItem] =
    time::macros::format_description!("[year][month][day]");

#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Date(pub time::Date);

impl Date {
    pub fn ymd(year: i32, month: u8, day: u8) -> Self {
        time::Date::from_calendar_date(year, month.try_into().expect("invalid month"), day)
            .expect("invalid date")
            .into()
    }

    pub fn with_hms_stockholm(self, hour: u8, minute: u8, second: u8) -> DateTime {
        DateTime::from(self.0.with_hms(hour, minute, second).expect("invalid time"))
    }

    pub fn next_day(self) -> Self {
        Self(self.0.next_day().expect("Date max range exceeded"))
    }

    pub fn previous_day(self) -> Self {
        Self(self.0.previous_day().expect("Date min range exceeded"))
    }

    pub fn year(&self) -> i32 {
        self.0.year()
    }

    pub fn month(&self) -> u8 {
        self.0.month() as u8
    }

    pub fn day(&self) -> u8 {
        self.0.day()
    }
}

impl From<time::Date> for Date {
    fn from(d: time::Date) -> Self {
        Self(d)
    }
}

impl From<Date> for time::Date {
    fn from(d: Date) -> Self {
        d.0
    }
}

struct Visitor;

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{:04}-{:02}-{:02}",
            self.year(),
            self.month(),
            self.day()
        )
    }
}

impl std::str::FromStr for Date {
    type Err = time::error::Parse;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        time::Date::parse(s, &BILLECTA_DATE_FORMAT)
            .or_else(|_| time::Date::parse(s, BILLECTA_ALTERNATIVE_DATE_FORMAT))
            .map(Date)
    }
}

impl serde::de::Visitor<'_> for Visitor {
    type Value = Date;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(r#"a date string on the form: "2013-12-30""#)
    }

    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        s.parse::<Date>().map_err(E::custom)
    }
}

impl<'de> serde::Deserialize<'de> for Date {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_str(Visitor)
    }
}

impl serde::Serialize for Date {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let s = self.0.to_string();

        serializer.serialize_str(&s)
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn display() {
        assert_eq!("2024-04-10", Date::ymd(2024, 4, 10).to_string());
        assert_eq!("2024-01-01", Date::ymd(2024, 1, 1).to_string());
        assert_eq!("2024-12-31", Date::ymd(2024, 12, 31).to_string());
    }

    #[test]
    fn parse() {
        assert_eq!(
            Date::ymd(2024, 4, 10),
            "2024-04-10".parse::<Date>().expect("parsing"),
        );
        assert_eq!(
            Date::ymd(2024, 1, 1),
            "2024-01-01".parse::<Date>().expect("parsing"),
        );
        assert_eq!(
            Date::ymd(2024, 12, 31),
            "2024-12-31".parse::<Date>().expect("parsing"),
        );

        assert_eq!(
            Date::ymd(2024, 4, 10),
            "20240410".parse::<Date>().expect("parsing"),
        );
        assert_eq!(
            Date::ymd(2024, 1, 1),
            "20240101".parse::<Date>().expect("parsing"),
        );
        assert_eq!(
            Date::ymd(2024, 12, 31),
            "20241231".parse::<Date>().expect("parsing"),
        );
    }

    #[test]
    fn parse_json() {
        assert_eq!(
            Date::ymd(2024, 12, 31),
            serde_json::from_str::<Date>(r#""2024-12-31""#).expect("deser")
        );

        assert_eq!(
            Date::ymd(2024, 1, 1),
            serde_json::from_str::<Date>(r#""2024-01-01""#).expect("deser")
        );

        assert_eq!(
            Date::ymd(2024, 4, 10),
            serde_json::from_str::<Date>(r#""2024-04-10""#).expect("deser")
        );

        assert_eq!(
            Date::ymd(2024, 12, 31),
            serde_json::from_str::<Date>(r#""20241231""#).expect("deser")
        );

        assert_eq!(
            Date::ymd(2024, 1, 1),
            serde_json::from_str::<Date>(r#""20240101""#).expect("deser")
        );

        assert_eq!(
            Date::ymd(2024, 4, 10),
            serde_json::from_str::<Date>(r#""20240410""#).expect("deser")
        );
    }

    #[test]
    fn fmt_json() {
        assert_eq!(
            r#""2024-12-31""#,
            serde_json::to_string(&Date::ymd(2024, 12, 31)).expect("ser"),
        );

        assert_eq!(
            r#""2024-01-01""#,
            serde_json::to_string(&Date::ymd(2024, 1, 1)).expect("ser"),
        );

        assert_eq!(
            r#""2024-04-10""#,
            serde_json::to_string(&Date::ymd(2024, 4, 10)).expect("ser"),
        );
    }
}