melib/datetime: add mbox date format parse

This commit is contained in:
Manos Pitsidianakis 2022-08-27 22:30:11 +03:00
parent a42a6ca868
commit 29042aba59
2 changed files with 76 additions and 3 deletions

View File

@ -50,6 +50,7 @@ pub const RFC822_FMT_WITH_TIME: &str = "%a, %e %h %Y %H:%M:%S \0";
pub const RFC822_FMT: &str = "%e %h %Y %H:%M:%S \0";
pub const DEFAULT_FMT: &str = "%a, %d %b %Y %R\0";
//"Tue May 21 13:46:22 1991\n"
//"Wed Sep 9 00:27:54 2020\n"
pub const ASCTIME_FMT: &str = "%a %b %d %H:%M:%S %Y\n\0";
extern "C" {
@ -301,7 +302,7 @@ where
{
let s = CString::new(s)?;
let mut new_tm: libc::tm = unsafe { std::mem::zeroed() };
for fmt in &[RFC822_FMT_WITH_TIME, RFC822_FMT] {
for fmt in &[RFC822_FMT_WITH_TIME, RFC822_FMT, ASCTIME_FMT] {
let fmt = unsafe { CStr::from_bytes_with_nul_unchecked(fmt.as_bytes()) };
let ret = {
let _with_locale = Locale::new(

View File

@ -443,6 +443,65 @@ pub mod dates {
}
}
///e.g Wed Sep 9 00:27:54 2020
///day-of-week month day time year
///date-time = [ day-of-week "," ] date time [CFWS]
///date = day month year
///time = time-of-day zone
///time-of-day = hour ":" minute [ ":" second ]
///hour = 2DIGIT / obs-hour
///minute = 2DIGIT / obs-minute
///second = 2DIGIT / obs-second
pub fn mbox_date_time(input: &[u8]) -> IResult<&[u8], UnixTimestamp> {
let orig_input = input;
let mut accum: SmallVec<[u8; 32]> = SmallVec::new();
let (input, _) = opt(cfws)(input)?;
let (input, day_of_week) = day_of_week(input)?;
let (input, _) = opt(cfws)(input)?;
let (input, month) = month(input)?;
let (input, _) = opt(cfws)(input)?;
let (input, day) = day(input)?;
let (input, _) = opt(cfws)(input)?;
let (input, hour) = take_n_digits(2)(input)?;
let (input, _) = tag(":")(input)?;
let (input, minute) = take_n_digits(2)(input)?;
let (input, second) = opt(preceded(tag(":"), take_n_digits(2)))(input)?;
let (input, _) = fws(input)?;
let (input, zone) = opt(zone)(input)?;
let (input, _) = opt(cfws)(input)?;
let (input, year) = year(input)?;
accum.extend_from_slice(&day_of_week);
accum.extend_from_slice(b", ");
accum.extend_from_slice(&day);
accum.extend_from_slice(b" ");
accum.extend_from_slice(&month);
accum.extend_from_slice(b" ");
accum.extend_from_slice(&year);
accum.extend_from_slice(b" ");
accum.extend_from_slice(&hour);
accum.extend_from_slice(b":");
accum.extend_from_slice(&minute);
if let Some(second) = second {
accum.extend_from_slice(b":");
accum.extend_from_slice(&second);
}
if let Some((sign, zone)) = zone {
accum.extend_from_slice(b" ");
accum.extend_from_slice(&sign);
accum.extend_from_slice(&zone);
}
match crate::datetime::rfc822_to_timestamp(accum.to_vec()) {
Ok(t) => Ok((input, t)),
Err(_err) => Err(nom::Err::Error(
(
orig_input,
"mbox_date_time(): could not convert date from rfc822",
)
.into(),
)),
}
}
///`day-of-week = ([FWS] day-name) / obs-day-of-week`
///day-name = "Mon" / "Tue" / "Wed" / "Thu" /
/// "Fri" / "Sat" / "Sun"
@ -490,9 +549,9 @@ pub mod dates {
///year = (FWS 4*DIGIT FWS) / obs-year
fn year(input: &[u8]) -> IResult<&[u8], &[u8]> {
let (input, _) = fws(input)?;
let (input, _) = opt(fws)(input)?;
let (input, ret) = take_n_digits(4)(input)?;
let (input, _) = fws(input)?;
let (input, _) = opt(fws)(input)?;
Ok((input, ret))
}
@ -511,6 +570,17 @@ pub mod dates {
};
Ok((rest, ret))
})
.or_else(|_| {
let (rest, ret) = match mbox_date_time(&input) {
Ok(v) => v,
Err(_) => {
return Err(nom::Err::Error(
(input, "rfc5322_date(): invalid input").into(),
));
}
};
Ok((rest, ret))
})
.map(|(_, r)| r)
.map_err(|err: nom::Err<ParsingError<_>>| err.into())
/*
@ -532,6 +602,8 @@ pub mod dates {
assert_eq!(rfc5322_date(_s).unwrap(), rfc5322_date(__s).unwrap());
let val = b"Fri, 23 Dec 0001 21:20:36 -0800 (PST)";
assert_eq!(rfc5322_date(val).unwrap(), 0);
let val = b"Wed Sep 9 00:27:54 2020";
assert_eq!(rfc5322_date(val).unwrap(), 1599611274);
}
}