rewrite datetime parsing
This commit is contained in:
parent
1527b41ab4
commit
1f5d9ebf78
1 changed files with 99 additions and 3 deletions
102
src/datetime.rs
102
src/datetime.rs
|
@ -1,10 +1,106 @@
|
|||
use chrono::{DateTime, FixedOffset};
|
||||
use nom::IResult;
|
||||
use chrono::{DateTime, FixedOffset, NaiveDate};
|
||||
use nom::{
|
||||
IResult,
|
||||
bytes::complete::take_while_m_n,
|
||||
character::is_digit,
|
||||
};
|
||||
use crate::misc_token;
|
||||
|
||||
pub fn section(input: &str) -> IResult<&str, DateTime<FixedOffset>> {
|
||||
/// date-time = [ day-of-week "," ] date time [CFWS]
|
||||
/// @FIXME: if parsing fails, Option::None is silently returned...
|
||||
pub fn section(input: &str) -> IResult<&str, Option<DateTime<FixedOffset>>> {
|
||||
let (input, (_, date, time, _) = tuple((
|
||||
opt(terminated(day_of_week), tag(",")),
|
||||
date, time,
|
||||
opt(cfws)))(input)?;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// @FIXME want to extract datetime our way in the future
|
||||
// to better handle obsolete/bad cases instead of returning raw text.
|
||||
let (input, raw_date) = misc_token::unstructured(input)?;
|
||||
Ok((input, DateTime::parse_from_rfc2822(&raw_date).unwrap()))
|
||||
}
|
||||
|
||||
/// day-of-week = ([FWS] day-name) / obs-day-of-week
|
||||
fn day_of_week(input: &str) -> IResult<&str, &str> {
|
||||
alt((day_of_week_strict, obs_day_of_week))(input)
|
||||
}
|
||||
|
||||
fn day_of_week_strict(input: &str) -> IResult<&str, &str> {
|
||||
preceded(opt(fws), day_name)(input)
|
||||
}
|
||||
|
||||
fn obs_day_of_week(input: &str) -> IResult<&str, &str> {
|
||||
delimited(obs(cfws), day_name, obs(cfws))(input)
|
||||
}
|
||||
|
||||
/// day-name = "Mon" / "Tue" / "Wed" / "Thu" /
|
||||
/// "Fri" / "Sat" / "Sun"
|
||||
|
||||
fn day_name(input: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
tag_no_case("Mon"),
|
||||
tag_no_case("Tue"),
|
||||
tag_no_case("Wed"),
|
||||
tag_no_case("Thu"),
|
||||
tag_no_case("Fri"),
|
||||
tag_no_case("Sat"),
|
||||
tag_no_case("Sun"),
|
||||
))(input)
|
||||
}
|
||||
|
||||
/// date = day month year
|
||||
fn date(input: &str) -> IResult<&str, Option<NaiveDate>> {
|
||||
map(
|
||||
tuple((day, month, year)),
|
||||
|(d, m, y)| NaiveDate::from_ymd_opt(y, m, d)
|
||||
)(input)
|
||||
}
|
||||
|
||||
/// day = ([FWS] 1*2DIGIT FWS) / obs-day
|
||||
/// obs-day = [CFWS] 1*2DIGIT [CFWS]
|
||||
fn day(input: &str) -> IResult<&str, u32> {
|
||||
alt((day_strict, obs_day))(input)
|
||||
}
|
||||
|
||||
fn day_strict(input: &str) -> IResult<&str, u32) {
|
||||
delimited(opt(fws), day_digit, fws)(input)
|
||||
}
|
||||
|
||||
fn obs_day(input: &str) -> IResult<&str, u32) {
|
||||
delimited(opt(cfws), day_digit, opt(cfws))(input)
|
||||
}
|
||||
|
||||
fn day_digit(input: &str) -> IRresult<&str, u32) {
|
||||
map(take_while_m_n(1, 2, is_digit), |d| d.parse::<u32>().unwrap())(input)
|
||||
}
|
||||
|
||||
/// month = "Jan" / "Feb" / "Mar" / "Apr" /
|
||||
/// "May" / "Jun" / "Jul" / "Aug" /
|
||||
/// "Sep" / "Oct" / "Nov" / "Dec"
|
||||
fn month(input: &str) -> IResult<&str, u32) {
|
||||
alt((
|
||||
value(1, tag_no_case("Jan")),
|
||||
value(2, tag_no_case("Feb")),
|
||||
value(3, tag_no_case("Mar")),
|
||||
value(4, tag_no_case("Apr")),
|
||||
value(5, tag_no_case("May")),
|
||||
value(6, tag_no_case("Jun")),
|
||||
value(7, tag_no_case("Jul")),
|
||||
value(8, tag_no_case("Aug")),
|
||||
value(9, tag_no_case("Sep")),
|
||||
value(10, tag_no_case("Oct")),
|
||||
value(11, tag_no_case("Nov")),
|
||||
value(12, tag_no_case("Dec")),
|
||||
))(input)
|
||||
}
|
||||
|
||||
/// year = (FWS 4*DIGIT FWS) / obs-year
|
||||
/// obs-year = [CFWS] 2*DIGIT [CFWS]
|
||||
fn year(input: &str) -> IResult<&str, i32> {
|
||||
alt((
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue