epoch-rs/src/month.rs

194 lines
5.1 KiB
Rust

#[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<Self> {
let n = *self as u8 + 1;
n.try_into().ok()
}
pub fn previous(&self) -> Option<Self> {
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<u8> for Month {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
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<cmp::Ordering> {
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<Self, Self::Err> {
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);
}
}