use crate::{PosixNs, RenderZone};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum DateStyle {
#[default]
Iso8601,
SpaceSeparated,
Rfc2822,
UsStyle,
}
#[must_use]
pub fn format_instant(instant: PosixNs, zone: &RenderZone, style: DateStyle) -> String {
const OUT_OF_RANGE: &str = "<out of civil range>";
let pattern = match style {
DateStyle::Iso8601 => return instant.render(zone).unwrap_or_else(|| OUT_OF_RANGE.into()),
DateStyle::SpaceSeparated => "%Y-%m-%d %H:%M:%S %Z",
DateStyle::Rfc2822 => "%a, %d %b %Y %H:%M:%S %z",
DateStyle::UsStyle => "%m/%d/%Y %I:%M:%S %p %Z",
};
let Ok(ts) = jiff::Timestamp::from_nanosecond(instant.0) else {
return OUT_OF_RANGE.into();
};
let tz = match zone {
RenderZone::Utc => jiff::tz::TimeZone::UTC,
RenderZone::Fixed(offset) => jiff::tz::TimeZone::fixed(*offset),
RenderZone::Named(tz) => tz.clone(),
};
ts.to_zoned(tz).strftime(pattern).to_string()
}
#[must_use]
pub fn format_naive(instant: PosixNs, style: DateStyle) -> String {
const OUT_OF_RANGE: &str = "<out of civil range>";
let pattern = match style {
DateStyle::Iso8601 => {
return instant.render(&RenderZone::Utc).map_or_else(
|| OUT_OF_RANGE.to_string(),
|s| s.trim_end_matches('Z').to_string(),
)
}
DateStyle::SpaceSeparated => "%Y-%m-%d %H:%M:%S",
DateStyle::Rfc2822 => "%a, %d %b %Y %H:%M:%S",
DateStyle::UsStyle => "%m/%d/%Y %I:%M:%S %p",
};
let Ok(ts) = jiff::Timestamp::from_nanosecond(instant.0) else {
return OUT_OF_RANGE.to_string();
};
ts.to_zoned(jiff::tz::TimeZone::UTC)
.strftime(pattern)
.to_string()
}