use time::{
format_description::well_known::{Rfc2822, Rfc3339},
Date, OffsetDateTime, PrimitiveDateTime, Time,
};
pub fn parse_timestamp_or_relative_time(
s: &str,
assume_negative_offset: bool,
) -> Result<OffsetDateTime, anyhow::Error> {
parse_timestamp_or_relative_time_based(s, OffsetDateTime::now_utc(), assume_negative_offset)
}
pub fn parse_timestamp_or_relative_time_negative_offset(
s: &str,
) -> Result<OffsetDateTime, anyhow::Error> {
parse_timestamp_or_relative_time(s, true)
}
pub fn parse_timestamp_or_relative_time_based(
s: &str,
base: OffsetDateTime,
assume_negative_offset: bool,
) -> Result<OffsetDateTime, anyhow::Error> {
if let Ok(t) = OffsetDateTime::parse(s, &Rfc3339) {
return Ok(t);
}
if let Ok(t) = OffsetDateTime::parse(s, &Rfc2822) {
return Ok(t);
}
if let Ok(t) = Date::parse(s, time::macros::format_description!("[year]-[month]-[day]")) {
return Ok(PrimitiveDateTime::new(t, Time::MIDNIGHT).assume_utc());
}
if let Ok(t) = OffsetDateTime::parse(s, time::macros::format_description!("[unix_timestamp]")) {
return Ok(t);
}
let (is_negative, v) = match s.strip_prefix('-') {
Some(rest) => (true, rest),
None => (assume_negative_offset, s.trim_start_matches('+')),
};
if let Ok(duration) = humantime::parse_duration(v) {
let time = if is_negative {
base - duration
} else {
base + duration
};
return Ok(time);
}
anyhow::bail!("Unable to parse the timestamp - no known format matched")
}