193 lines
5.1 KiB
Rust
193 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);
|
|
}
|
|
}
|