use std::fmt::{Display, Formatter};
pub enum Precision {
Millenium,
Century,
Decade,
Year,
Month,
Day,
Hour,
Minute,
}
#[derive(Default, Ord, PartialOrd, Eq, Hash, PartialEq, Debug, Clone)]
pub struct TimeStamp {
millenium: u32,
century: Option<u32>,
decade: Option<u32>,
year: Option<u32>,
month: Option<u32>,
day: Option<u32>,
hour: Option<u32>,
minute: Option<u32>,
after_christ: bool,
}
impl Display for TimeStamp {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.display())
}
}
impl TimeStamp {
fn display(&self) -> String {
let era = if self.after_christ { "AD" } else { "BC" };
let cty = match self.century {
Some(c) => self.millenium * 10 + c,
None => {
let num = self.millenium + 1;
return format!("{}{} millenium {}", num, Self::suffix(num), era);
}
};
let decade = match self.decade {
Some(d) => cty * 10 + d,
None => {
if cty > 10 {
return format!("{}{} century {}", cty + 1, Self::suffix(cty + 1), era);
} else {
return format!("{}s {}", cty, era);
}
}
};
let era = if decade > 100 && self.after_christ {
""
} else {
era
};
let year = match self.year {
Some(y) => decade * 10 + y,
None => {
return format!("{}0s {}", decade, era);
}
};
let month = match self.month {
Some(m) => m,
None => {
return format!("{} {}", year, era);
}
};
let day = match self.day {
Some(d) => d,
None => {
return format!("{} {} {}", Self::month_str(month), year, era);
}
};
let hour = match self.hour {
Some(h) => h,
None => {
return format!("{} {} {} {}", day, Self::month_str(month), year, era);
}
};
match self.minute {
Some(minute) => {
format!(
"{:02}:{:02} {} {} {} {}",
hour,
minute,
day,
Self::month_str(month),
year,
era
)
}
None => {
format!(
"{} o' clock, {} {} {} {}",
hour,
day,
Self::month_str(month),
year,
era
)
}
}
}
fn month_str(m: u32) -> &'static str {
match m {
1 => "jan",
2 => "feb",
3 => "mar",
4 => "apr",
5 => "may",
6 => "jun",
7 => "jul",
8 => "aug",
9 => "sep",
10 => "okt",
11 => "nov",
12 => "dec",
_ => "INVALID MONTH",
}
}
fn suffix(num: u32) -> &'static str {
match num {
0 => "th",
1 => "st",
2 => "nd",
3 => "rd",
_ => "th",
}
}
fn parse_two_digits(iter: &mut impl Iterator<Item = char>) -> Option<u32> {
let (d1, d2) = (iter.next()?, iter.next()?);
Some(d1.to_string().parse::<u32>().ok()? * 10 + d2.to_string().parse::<u32>().ok()?)
}
pub fn serialize(&self) -> String {
let mut s = String::new();
if !self.after_christ {
s.push('-');
}
s.push_str(&self.millenium.to_string());
s.push_str(
&self
.century
.map(|c| c.to_string())
.unwrap_or("*".to_string()),
);
s.push_str(
&self
.decade
.map(|c| c.to_string())
.unwrap_or("*".to_string()),
);
s.push_str(&self.year.map(|c| c.to_string()).unwrap_or("*".to_string()));
if let Some(month) = self.month {
s.push_str(&format!("-{:02}", month));
} else {
return s;
};
if let Some(day) = self.day {
s.push_str(&format!("-{:02}", day));
} else {
return s;
};
if let Some(hour) = self.hour {
s.push_str(&format!(" {:02}", hour));
} else {
return s;
};
if let Some(minute) = self.minute {
s.push_str(&format!(":{:02}", minute));
}
s
}
pub fn from_string(s: String) -> Option<Self> {
let mut selv = Self::default();
let mut s: Vec<char> = s.chars().collect();
let first = s.first()?;
if first != &'+' && first != &'-' {
s.insert(0, '+');
}
let mut iter = s.into_iter();
match iter.next()? {
'+' => selv.after_christ = true,
'-' => selv.after_christ = false,
_ => panic!(),
}
selv.millenium = iter.next()?.to_string().parse().ok()?;
selv.century = match iter.next()? {
'*' => None,
num => Some(num.to_string().parse().ok()?),
};
selv.decade = match iter.next()? {
'*' => None,
num => Some(num.to_string().parse().ok()?),
};
selv.year = match iter.next()? {
'*' => None,
num => Some(num.to_string().parse().ok()?),
};
match iter.next() {
Some('-') => {}
Some(' ') => {}
Some(_) => None?,
None => return Some(selv),
}
selv.month = Some(Self::parse_two_digits(&mut iter)?);
match iter.next() {
Some('-') => {}
Some(' ') => {}
Some(_) => None?,
None => return Some(selv),
}
selv.day = Some(Self::parse_two_digits(&mut iter)?);
match iter.next() {
Some('-') => {}
Some(' ') => {}
Some(_) => None?,
None => return Some(selv),
}
selv.hour = Some(Self::parse_two_digits(&mut iter)?);
match iter.next() {
Some(':') => {}
Some(_) => None?,
None => return Some(selv),
}
selv.minute = Some(Self::parse_two_digits(&mut iter)?);
Some(selv)
}
}