katec 0.1.0

generating string representations of dates and times.
Documentation
use chrono::{DateTime, Datelike, Local};
use radix_fmt::radix_36;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Katetime {
    pub show_date: bool,
    pub show_time: bool,
    pub url_safe: bool,
}

impl Katetime {
    fn new(show_date: bool, show_time: bool, url_safe: bool) -> Self {
        Self {
            show_date: show_date,
            show_time: show_time,
            url_safe: url_safe,
        }
    }

    pub fn now_date_human() -> String {
        Self::new(true, false, false).generate_now()
    }

    pub fn now_time_human() -> String {
        Self::new(false, true, false).generate_now()
    }

    pub fn now_date_time_human() -> String {
        Self::new(true, true, false).generate_now()
    }

    pub fn now_date() -> String {
        Self::new(true, false, true).generate_now()
    }

    pub fn now_time() -> String {
        Self::new(false, true, true).generate_now()
    }

    pub fn now_date_time() -> String {
        Self::new(true, true, true).generate_now()
    }

    pub fn generate_now(&self) -> String {
        self.generate(&Local::now())
    }

    pub fn generate(&self, dt: &DateTime<Local>) -> String {
        if !self.show_date && !self.show_time {
            return String::with_capacity(0);
        }
        let mut s = String::with_capacity(17);
        if self.show_date {
            s.push_str(&match dt.year() - 2022 {
                yr @ i32::MIN..=-1 => {
                    format!(
                        "{}{}",
                        radix_36(yr.rem_euclid(200) / 10 + 10),
                        yr.rem_euclid(10),
                    )
                }
                yr => format!("{:#}{}", radix_36((yr % 200) / 10 + 10), yr % 10),
            });
            s.push_str(&match self.url_safe {
                true => dt.format("%m%d").to_string(),
                false => dt.format("~%m/%d").to_string(),
            });
            if self.show_time {
                s.push_str(match self.url_safe {
                    true => "-",
                    false => " ",
                })
            }
        }
        if self.show_time {
            match self.url_safe {
                true => {
                    s.push_str(&dt.format("%H%M-%S").to_string());
                    s.push_str(&format!("{:02}", dt.timestamp_subsec_millis() / 10));
                }
                false => s.push_str(&dt.format("%H:%M:%S").to_string()),
            }
        }
        s
    }
}

mod tests {

    #[test]
    fn test() {
        let kt_safe = crate::Katetime::new(true, true, true);
        let kt_human = crate::Katetime::new(true, true, false);

        let time = chrono::NaiveTime::from_hms_milli_opt(4, 56, 7, 890).unwrap();

        let date = [
            chrono::NaiveDate::from_ymd_opt(1970, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2000, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2010, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2021, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2022, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2033, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2221, 11, 23),
            chrono::NaiveDate::from_ymd_opt(2222, 11, 23),
        ];

        date.iter()
            .map(|date| {
                chrono::NaiveDateTime::new(date.unwrap(), time)
                    .and_local_timezone(chrono::Local)
                    .unwrap()
            })
            .zip(
                [
                    "o81123-0456-0789",
                    "r81123-0456-0789",
                    "s81123-0456-0789",
                    "t91123-0456-0789",
                    "A01123-0456-0789",
                    "B11123-0456-0789",
                    "T91123-0456-0789",
                    "A01123-0456-0789",
                ]
                .into_iter(),
            )
            .for_each(|(dt, ans)| assert_eq!(kt_safe.generate(&dt), ans));

        date.iter()
            .map(|date| {
                chrono::NaiveDateTime::new(date.unwrap(), time)
                    .and_local_timezone(chrono::Local)
                    .unwrap()
            })
            .zip(
                [
                    "o8~11/23 04:56:07",
                    "r8~11/23 04:56:07",
                    "s8~11/23 04:56:07",
                    "t9~11/23 04:56:07",
                    "A0~11/23 04:56:07",
                    "B1~11/23 04:56:07",
                    "T9~11/23 04:56:07",
                    "A0~11/23 04:56:07",
                ]
                .into_iter(),
            )
            .for_each(|(dt, ans)| assert_eq!(kt_human.generate(&dt), ans));
    }
}