#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum TemporalKind {
Date,
DateTime,
DateTimeLeap,
Week,
Month,
Quarter,
HalfYear,
Year,
}
impl TemporalKind {
#[must_use]
pub fn from_format(format: &str) -> Option<Self> {
let body = format.strip_prefix('%')?;
let mut chars = body.chars();
let first = chars.next()?;
match first {
'd' => Some(Self::Date),
't' => match chars.next()? {
'd' => Some(Self::Date),
'c' => Some(Self::DateTime),
'C' => Some(Self::DateTimeLeap),
'w' => Some(Self::Week),
'm' => Some(Self::Month),
'q' => Some(Self::Quarter),
'h' => Some(Self::HalfYear),
'y' => Some(Self::Year),
_ => None,
},
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bare_td_is_date() {
assert_eq!(TemporalKind::from_format("%td"), Some(TemporalKind::Date));
}
#[test]
fn bare_tc_is_datetime() {
assert_eq!(
TemporalKind::from_format("%tc"),
Some(TemporalKind::DateTime)
);
}
#[test]
fn bare_tc_uppercase_is_datetime_leap() {
assert_eq!(
TemporalKind::from_format("%tC"),
Some(TemporalKind::DateTimeLeap)
);
}
#[test]
fn bare_tw_is_week() {
assert_eq!(TemporalKind::from_format("%tw"), Some(TemporalKind::Week));
}
#[test]
fn bare_tm_is_month() {
assert_eq!(TemporalKind::from_format("%tm"), Some(TemporalKind::Month));
}
#[test]
fn bare_tq_is_quarter() {
assert_eq!(
TemporalKind::from_format("%tq"),
Some(TemporalKind::Quarter)
);
}
#[test]
fn bare_th_is_half_year() {
assert_eq!(
TemporalKind::from_format("%th"),
Some(TemporalKind::HalfYear)
);
}
#[test]
fn bare_ty_is_year() {
assert_eq!(TemporalKind::from_format("%ty"), Some(TemporalKind::Year));
}
#[test]
fn bare_d_is_legacy_date() {
assert_eq!(TemporalKind::from_format("%d"), Some(TemporalKind::Date));
}
#[test]
fn legacy_d_with_suffix() {
assert_eq!(
TemporalKind::from_format("%dCCYY-NN-DD"),
Some(TemporalKind::Date)
);
}
#[test]
fn td_with_iso_suffix() {
assert_eq!(
TemporalKind::from_format("%tdCCYY-NN-DD"),
Some(TemporalKind::Date)
);
}
#[test]
fn td_with_us_suffix() {
assert_eq!(
TemporalKind::from_format("%tdNN/DD/CCYY"),
Some(TemporalKind::Date)
);
}
#[test]
fn tc_with_time_suffix() {
assert_eq!(
TemporalKind::from_format("%tcDDmonCCYY_HH:MM:SS"),
Some(TemporalKind::DateTime)
);
}
#[test]
fn tc_uppercase_with_suffix_stays_leap() {
assert_eq!(
TemporalKind::from_format("%tCHH:MM:SS"),
Some(TemporalKind::DateTimeLeap)
);
}
#[test]
fn arbitrary_suffix_chars_ignored() {
assert_eq!(
TemporalKind::from_format("%tdgarbage!@#"),
Some(TemporalKind::Date)
);
}
#[test]
fn numeric_format_is_none() {
assert_eq!(TemporalKind::from_format("%9.0g"), None);
}
#[test]
fn numeric_format_with_commas_is_none() {
assert_eq!(TemporalKind::from_format("%9.0gc"), None);
}
#[test]
fn fixed_format_is_none() {
assert_eq!(TemporalKind::from_format("%8.2f"), None);
}
#[test]
fn exponential_format_is_none() {
assert_eq!(TemporalKind::from_format("%-12.4e"), None);
}
#[test]
fn string_format_is_none() {
assert_eq!(TemporalKind::from_format("%9s"), None);
}
#[test]
fn left_aligned_string_format_is_none() {
assert_eq!(TemporalKind::from_format("%-12s"), None);
}
#[test]
fn empty_string_is_none() {
assert_eq!(TemporalKind::from_format(""), None);
}
#[test]
fn missing_percent_is_none() {
assert_eq!(TemporalKind::from_format("td"), None);
}
#[test]
fn just_percent_is_none() {
assert_eq!(TemporalKind::from_format("%"), None);
}
#[test]
fn just_percent_t_is_none() {
assert_eq!(TemporalKind::from_format("%t"), None);
}
#[test]
fn unknown_t_subprefix_is_none() {
assert_eq!(TemporalKind::from_format("%tx"), None);
}
#[test]
fn leading_whitespace_is_none() {
assert_eq!(TemporalKind::from_format(" %td"), None);
}
#[test]
fn uppercase_outer_prefix_is_none() {
assert_eq!(TemporalKind::from_format("%TD"), None);
}
#[test]
fn uppercase_d_is_none() {
assert_eq!(TemporalKind::from_format("%D"), None);
}
#[test]
fn tc_and_tc_leap_are_distinct() {
assert_ne!(
TemporalKind::from_format("%tc"),
TemporalKind::from_format("%tC"),
);
}
}