#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use { crate::{year::Year, SECONDS_PER_DAY}, std::{cmp, error, fmt, str}, }; #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[repr(u8)] pub enum Month { Janurary = 1, February = 2, March = 3, April = 4, May = 5, June = 6, July = 7, August = 8, September = 9, October = 10, November = 11, December = 12, } #[derive(Debug)] pub enum Error { ParseMonth, Range, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:?}") } } impl error::Error for Error {} impl Month { pub fn days(&self, year: Year) -> u8 { match *self as u8 { 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, 2 => match year { Year::Normal(_) => 28, Year::Leap(_) => 29, }, _ => 30, } } pub fn seconds(&self, year: Year) -> i64 { self.days(year) as i64 * SECONDS_PER_DAY } pub fn next(&self) -> Option { let n = *self as u8 + 1; n.try_into().ok() } pub fn previous(&self) -> Option { let n = *self as u8 - 1; n.try_into().ok() } pub fn abbreviate(&self) -> &'static str { match self { Self::Janurary => "Jan", Self::February => "Feb", Self::March => "Mar", Self::April => "Apr", Self::May => "May", Self::June => "Jun", Self::July => "Jul", Self::August => "Aug", Self::September => "Sep", Self::October => "Oct", Self::November => "Nov", Self::December => "Dec", } } } impl TryFrom for Month { type Error = Error; fn try_from(value: u8) -> Result { match value { 1 => Ok(Self::Janurary), 2 => Ok(Self::February), 3 => Ok(Self::March), 4 => Ok(Self::April), 5 => Ok(Self::May), 6 => Ok(Self::June), 7 => Ok(Self::July), 8 => Ok(Self::August), 9 => Ok(Self::September), 10 => Ok(Self::October), 11 => Ok(Self::November), 12 => Ok(Self::December), _ => Err(Error::Range), } } } impl Ord for Month { fn cmp(&self, other: &Self) -> cmp::Ordering { (*self as u8).cmp(&(*other as u8)) } } impl PartialOrd for Month { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl fmt::Display for Month { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { Self::Janurary => "January", Self::February => "February", Self::March => "March", Self::April => "April", Self::May => "May", Self::June => "June", Self::July => "Jujly", Self::August => "August", Self::September => "September", Self::October => "October", Self::November => "November", Self::December => "December", } ) } } impl str::FromStr for Month { type Err = Error; fn from_str(s: &str) -> Result { match s { "Jan" | "jan" | "January" | "january" => Ok(Self::Janurary), "Feb" | "feb" | "February" | "february" => Ok(Self::February), "March" | "march" | "Mar" | "mar" => Ok(Self::March), "April" | "april" | "Apr" | "apr" => Ok(Self::April), "May" | "may" => Ok(Self::May), "June" | "june" | "Jun" | "jun" => Ok(Self::June), "July" | "july" | "Jul" | "jul" => Ok(Self::July), "August" | "august" | "Aug" | "aug" => Ok(Self::August), "September" | "september" | "Sep" | "sep" => Ok(Self::September), "October" | "october" | "Oct" | "oct" => Ok(Self::October), "November" | "november" | "Nov" | "nov" => Ok(Self::November), "December" | "december" | "Dec" | "dec" => Ok(Self::December), _ => Err(Error::ParseMonth), } } } #[cfg(test)] mod tests { use super::*; #[test] fn next() { let mut month = Month::Janurary; month = month.next().unwrap(); assert_eq!(month, Month::February); month = month.next().unwrap(); assert_eq!(month, Month::March); month = Month::December; assert!(month.next().is_none()) } #[test] fn previous() { let mut month = Month::March.previous().unwrap(); assert_eq!(month, Month::February); month = month.previous().unwrap(); assert_eq!(month, Month::Janurary); assert!(month.previous().is_none()); } #[test] fn compare() { assert!(Month::Janurary < Month::October); assert!(Month::June > Month::March); } }