You've already forked parse_datetime
mirror of
https://github.com/uutils/parse_datetime.git
synced 2026-06-10 16:13:15 -07:00
upgrade winnow to 0.7.10
This commit is contained in:
Generated
+2
-12
@@ -118,15 +118,6 @@ version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -147,7 +138,6 @@ name = "parse_datetime"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"num-traits",
|
||||
"regex",
|
||||
"winnow",
|
||||
@@ -353,9 +343,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
+1
-2
@@ -10,6 +10,5 @@ readme = "README.md"
|
||||
[dependencies]
|
||||
regex = "1.10.4"
|
||||
chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] }
|
||||
nom = "8.0.0"
|
||||
winnow = "0.5.34"
|
||||
winnow = "0.7.10"
|
||||
num-traits = "0.2.19"
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
//! > seconds are allowed, with either comma or period preceding the fraction.
|
||||
//! > ISO 8601 fractional minutes and hours are not supported. Typically, hosts
|
||||
//! > support nanosecond timestamp resolution; excess precision is silently discarded.
|
||||
use winnow::{combinator::alt, seq, trace::trace, PResult, Parser};
|
||||
use winnow::{
|
||||
combinator::{alt, trace},
|
||||
seq, ModalResult, Parser,
|
||||
};
|
||||
|
||||
use crate::items::space;
|
||||
|
||||
@@ -29,7 +32,7 @@ pub struct DateTime {
|
||||
pub(crate) time: Time,
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> PResult<DateTime> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<DateTime> {
|
||||
seq!(DateTime {
|
||||
date: trace("date iso", alt((date::iso1, date::iso2))),
|
||||
// Note: the `T` is lowercased by the main parse function
|
||||
|
||||
+14
-15
@@ -27,16 +27,15 @@
|
||||
//! > ‘September’.
|
||||
|
||||
use winnow::{
|
||||
ascii::{alpha1, dec_uint},
|
||||
combinator::{alt, opt, preceded},
|
||||
ascii::alpha1,
|
||||
combinator::{alt, opt, preceded, trace},
|
||||
seq,
|
||||
stream::AsChar,
|
||||
token::{take, take_while},
|
||||
trace::trace,
|
||||
PResult, Parser,
|
||||
ModalResult, Parser,
|
||||
};
|
||||
|
||||
use super::s;
|
||||
use super::{dec_uint, s};
|
||||
use crate::ParseDateTimeError;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Default)]
|
||||
@@ -46,14 +45,14 @@ pub struct Date {
|
||||
pub year: Option<u32>,
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> PResult<Date> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Date> {
|
||||
alt((iso1, iso2, us, literal1, literal2)).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse `YYYY-MM-DD` or `YY-MM-DD`
|
||||
///
|
||||
/// This is also used by [`combined`](super::combined).
|
||||
pub fn iso1(input: &mut &str) -> PResult<Date> {
|
||||
pub fn iso1(input: &mut &str) -> ModalResult<Date> {
|
||||
seq!(Date {
|
||||
year: year.map(Some),
|
||||
_: s('-'),
|
||||
@@ -67,7 +66,7 @@ pub fn iso1(input: &mut &str) -> PResult<Date> {
|
||||
/// Parse `YYYYMMDD`
|
||||
///
|
||||
/// This is also used by [`combined`](super::combined).
|
||||
pub fn iso2(input: &mut &str) -> PResult<Date> {
|
||||
pub fn iso2(input: &mut &str) -> ModalResult<Date> {
|
||||
s((
|
||||
take(4usize).try_map(|s: &str| s.parse::<u32>()),
|
||||
take(2usize).try_map(|s: &str| s.parse::<u32>()),
|
||||
@@ -82,7 +81,7 @@ pub fn iso2(input: &mut &str) -> PResult<Date> {
|
||||
}
|
||||
|
||||
/// Parse `MM/DD/YYYY`, `MM/DD/YY` or `MM/DD`
|
||||
fn us(input: &mut &str) -> PResult<Date> {
|
||||
fn us(input: &mut &str) -> ModalResult<Date> {
|
||||
seq!(Date {
|
||||
month: month,
|
||||
_: s('/'),
|
||||
@@ -93,7 +92,7 @@ fn us(input: &mut &str) -> PResult<Date> {
|
||||
}
|
||||
|
||||
/// Parse `14 November 2022`, `14 Nov 2022`, "14nov2022", "14-nov-2022", "14-nov2022", "14nov-2022"
|
||||
fn literal1(input: &mut &str) -> PResult<Date> {
|
||||
fn literal1(input: &mut &str) -> ModalResult<Date> {
|
||||
seq!(Date {
|
||||
day: day,
|
||||
_: opt(s('-')),
|
||||
@@ -104,7 +103,7 @@ fn literal1(input: &mut &str) -> PResult<Date> {
|
||||
}
|
||||
|
||||
/// Parse `November 14, 2022` and `Nov 14, 2022`
|
||||
fn literal2(input: &mut &str) -> PResult<Date> {
|
||||
fn literal2(input: &mut &str) -> ModalResult<Date> {
|
||||
seq!(Date {
|
||||
month: literal_month,
|
||||
day: day,
|
||||
@@ -115,7 +114,7 @@ fn literal2(input: &mut &str) -> PResult<Date> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub fn year(input: &mut &str) -> PResult<u32> {
|
||||
pub fn year(input: &mut &str) -> ModalResult<u32> {
|
||||
// 2147485547 is the maximum value accepted
|
||||
// by GNU, but chrono only behaves like GNU
|
||||
// for years in the range: [0, 9999], so we
|
||||
@@ -140,7 +139,7 @@ pub fn year(input: &mut &str) -> PResult<u32> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn month(input: &mut &str) -> PResult<u32> {
|
||||
fn month(input: &mut &str) -> ModalResult<u32> {
|
||||
s(dec_uint)
|
||||
.try_map(|x| {
|
||||
(1..=12)
|
||||
@@ -151,7 +150,7 @@ fn month(input: &mut &str) -> PResult<u32> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn day(input: &mut &str) -> PResult<u32> {
|
||||
fn day(input: &mut &str) -> ModalResult<u32> {
|
||||
s(dec_uint)
|
||||
.try_map(|x| {
|
||||
(1..=31)
|
||||
@@ -163,7 +162,7 @@ fn day(input: &mut &str) -> PResult<u32> {
|
||||
}
|
||||
|
||||
/// Parse the name of a month (case-insensitive)
|
||||
fn literal_month(input: &mut &str) -> PResult<u32> {
|
||||
fn literal_month(input: &mut &str) -> ModalResult<u32> {
|
||||
s(alpha1)
|
||||
.verify_map(|s: &str| {
|
||||
Some(match s {
|
||||
|
||||
+75
-42
@@ -34,18 +34,18 @@ mod relative;
|
||||
mod time;
|
||||
mod weekday;
|
||||
mod epoch {
|
||||
use winnow::{ascii::dec_int, combinator::preceded, PResult, Parser};
|
||||
use winnow::{combinator::preceded, ModalResult, Parser};
|
||||
|
||||
use super::s;
|
||||
pub fn parse(input: &mut &str) -> PResult<i32> {
|
||||
use super::{dec_int, s};
|
||||
pub fn parse(input: &mut &str) -> ModalResult<i32> {
|
||||
s(preceded("@", dec_int)).parse_next(input)
|
||||
}
|
||||
}
|
||||
mod timezone {
|
||||
use super::time;
|
||||
use winnow::PResult;
|
||||
use winnow::ModalResult;
|
||||
|
||||
pub(crate) fn parse(input: &mut &str) -> PResult<time::Offset> {
|
||||
pub(crate) fn parse(input: &mut &str) -> ModalResult<time::Offset> {
|
||||
time::timezone(input)
|
||||
}
|
||||
}
|
||||
@@ -53,15 +53,14 @@ mod timezone {
|
||||
use chrono::NaiveDate;
|
||||
use chrono::{DateTime, Datelike, FixedOffset, TimeZone, Timelike};
|
||||
|
||||
use winnow::error::{AddContext, ParserError, StrContext};
|
||||
use winnow::error::{ContextError, ErrMode};
|
||||
use winnow::trace::trace;
|
||||
use winnow::error::{StrContext, StrContextValue};
|
||||
use winnow::{
|
||||
ascii::multispace0,
|
||||
combinator::{alt, delimited, not, peek, preceded, repeat, separated},
|
||||
ascii::{digit1, multispace0},
|
||||
combinator::{alt, delimited, not, opt, peek, preceded, repeat, separated, trace},
|
||||
error::{ContextError, ErrMode, ParserError},
|
||||
stream::AsChar,
|
||||
token::{none_of, take_while},
|
||||
PResult, Parser,
|
||||
token::{none_of, one_of, take_while},
|
||||
ModalResult, Parser,
|
||||
};
|
||||
|
||||
use crate::ParseDateTimeError;
|
||||
@@ -93,7 +92,7 @@ where
|
||||
/// Parse the space in-between tokens
|
||||
///
|
||||
/// You probably want to use the [`s`] combinator instead.
|
||||
fn space<'a, E>(input: &mut &'a str) -> PResult<(), E>
|
||||
fn space<'a, E>(input: &mut &'a str) -> winnow::Result<(), E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
@@ -110,7 +109,7 @@ where
|
||||
/// The last comment should be ignored.
|
||||
///
|
||||
/// The plus is undocumented, but it seems to be ignored.
|
||||
fn ignored_hyphen_or_plus<'a, E>(input: &mut &'a str) -> PResult<(), E>
|
||||
fn ignored_hyphen_or_plus<'a, E>(input: &mut &'a str) -> winnow::Result<(), E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
@@ -127,7 +126,7 @@ where
|
||||
///
|
||||
/// A comment is given between parentheses, which must be balanced. Any other
|
||||
/// tokens can be within the comment.
|
||||
fn comment<'a, E>(input: &mut &'a str) -> PResult<(), E>
|
||||
fn comment<'a, E>(input: &mut &'a str) -> winnow::Result<(), E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
@@ -139,8 +138,45 @@ where
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a signed decimal integer.
|
||||
///
|
||||
/// Rationale for not using `winnow::ascii::dec_int`: When upgrading winnow from
|
||||
/// 0.5 to 0.7, we discovered that `winnow::ascii::dec_int` now accepts only the
|
||||
/// following two forms:
|
||||
///
|
||||
/// - 0
|
||||
/// - [+-][1-9][0-9]*
|
||||
///
|
||||
/// Inputs like [+-]0[0-9]* (e.g., `+012`) are therefore rejected. We provide a
|
||||
/// custom implementation to support such zero-prefixed integers.
|
||||
fn dec_int<'a, E>(input: &mut &'a str) -> winnow::Result<i32, E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
(opt(one_of(['+', '-'])), digit1)
|
||||
.void()
|
||||
.take()
|
||||
.verify_map(|s: &str| s.parse().ok())
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse an unsigned decimal integer.
|
||||
///
|
||||
/// See the rationale for `dec_int` for why we don't use
|
||||
/// `winnow::ascii::dec_uint`.
|
||||
fn dec_uint<'a, E>(input: &mut &'a str) -> winnow::Result<u32, E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
digit1
|
||||
.void()
|
||||
.take()
|
||||
.verify_map(|s: &str| s.parse().ok())
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
// Parse an item
|
||||
pub fn parse_one(input: &mut &str) -> PResult<Item> {
|
||||
pub fn parse_one(input: &mut &str) -> ModalResult<Item> {
|
||||
trace(
|
||||
"parse_one",
|
||||
alt((
|
||||
@@ -157,7 +193,7 @@ pub fn parse_one(input: &mut &str) -> PResult<Item> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> PResult<Vec<Item>> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
let mut items = Vec::new();
|
||||
let mut date_seen = false;
|
||||
let mut time_seen = false;
|
||||
@@ -170,12 +206,13 @@ pub fn parse(input: &mut &str) -> PResult<Vec<Item>> {
|
||||
match item {
|
||||
Item::DateTime(ref dt) => {
|
||||
if date_seen || time_seen {
|
||||
return Err(ErrMode::Backtrack(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(
|
||||
winnow::error::StrContextValue::Description(
|
||||
"date or time cannot appear more than once",
|
||||
)),
|
||||
)));
|
||||
),
|
||||
));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
|
||||
date_seen = true;
|
||||
@@ -186,12 +223,11 @@ pub fn parse(input: &mut &str) -> PResult<Vec<Item>> {
|
||||
}
|
||||
Item::Date(ref d) => {
|
||||
if date_seen {
|
||||
return Err(ErrMode::Backtrack(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"date cannot appear more than once",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"date cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
|
||||
date_seen = true;
|
||||
@@ -201,34 +237,31 @@ pub fn parse(input: &mut &str) -> PResult<Vec<Item>> {
|
||||
}
|
||||
Item::Time(_) => {
|
||||
if time_seen {
|
||||
return Err(ErrMode::Backtrack(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"time cannot appear more than once",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"time cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
time_seen = true;
|
||||
}
|
||||
Item::Year(_) => {
|
||||
if year_seen {
|
||||
return Err(ErrMode::Backtrack(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"year cannot appear more than once",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"year cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
year_seen = true;
|
||||
}
|
||||
Item::TimeZone(_) => {
|
||||
if tz_seen {
|
||||
return Err(ErrMode::Backtrack(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"timezone cannot appear more than once",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"timezone cannot appear more than once",
|
||||
)));
|
||||
return Err(ErrMode::Backtrack(ctx_err));
|
||||
}
|
||||
tz_seen = true;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ use super::s;
|
||||
use winnow::{
|
||||
ascii::{alpha1, dec_uint},
|
||||
combinator::{alt, opt},
|
||||
PResult, Parser,
|
||||
ModalResult, Parser,
|
||||
};
|
||||
|
||||
pub fn ordinal(input: &mut &str) -> PResult<i32> {
|
||||
pub fn ordinal(input: &mut &str) -> ModalResult<i32> {
|
||||
alt((text_ordinal, number_ordinal)).parse_next(input)
|
||||
}
|
||||
|
||||
fn number_ordinal(input: &mut &str) -> PResult<i32> {
|
||||
fn number_ordinal(input: &mut &str) -> ModalResult<i32> {
|
||||
let sign = opt(alt(('+'.value(1), '-'.value(-1)))).map(|s| s.unwrap_or(1));
|
||||
(s(sign), s(dec_uint))
|
||||
.verify_map(|(s, u): (i32, u32)| {
|
||||
@@ -22,7 +22,7 @@ fn number_ordinal(input: &mut &str) -> PResult<i32> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn text_ordinal(input: &mut &str) -> PResult<i32> {
|
||||
fn text_ordinal(input: &mut &str) -> ModalResult<i32> {
|
||||
s(alpha1)
|
||||
.verify_map(|s: &str| {
|
||||
Some(match s {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
use winnow::{
|
||||
ascii::{alpha1, float},
|
||||
combinator::{alt, opt},
|
||||
PResult, Parser,
|
||||
ModalResult, Parser,
|
||||
};
|
||||
|
||||
use super::{ordinal::ordinal, s};
|
||||
@@ -63,7 +63,7 @@ impl Relative {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> PResult<Relative> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Relative> {
|
||||
alt((
|
||||
s("tomorrow").value(Relative::Days(1)),
|
||||
s("yesterday").value(Relative::Days(-1)),
|
||||
@@ -76,7 +76,7 @@ pub fn parse(input: &mut &str) -> PResult<Relative> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn seconds(input: &mut &str) -> PResult<Relative> {
|
||||
fn seconds(input: &mut &str) -> ModalResult<Relative> {
|
||||
(
|
||||
opt(alt((s(float), ordinal.map(|x| x as f64)))),
|
||||
s(alpha1).verify(|s: &str| matches!(s, "seconds" | "second" | "sec" | "secs")),
|
||||
@@ -86,17 +86,17 @@ fn seconds(input: &mut &str) -> PResult<Relative> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn other(input: &mut &str) -> PResult<Relative> {
|
||||
fn other(input: &mut &str) -> ModalResult<Relative> {
|
||||
(opt(ordinal), integer_unit, ago)
|
||||
.map(|(n, unit, ago)| unit.mul(n.unwrap_or(1) * if ago { -1 } else { 1 }))
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn ago(input: &mut &str) -> PResult<bool> {
|
||||
fn ago(input: &mut &str) -> ModalResult<bool> {
|
||||
opt(s("ago")).map(|o| o.is_some()).parse_next(input)
|
||||
}
|
||||
|
||||
fn integer_unit(input: &mut &str) -> PResult<Relative> {
|
||||
fn integer_unit(input: &mut &str) -> ModalResult<Relative> {
|
||||
s(alpha1)
|
||||
.verify_map(|s: &str| {
|
||||
Some(match s.strip_suffix('s').unwrap_or(s) {
|
||||
|
||||
+31
-34
@@ -41,16 +41,16 @@ use std::fmt::Display;
|
||||
|
||||
use chrono::FixedOffset;
|
||||
use winnow::{
|
||||
ascii::{dec_uint, digit1, float},
|
||||
ascii::{digit1, float},
|
||||
combinator::{alt, opt, peek, preceded},
|
||||
error::{AddContext, ContextError, ErrMode, StrContext},
|
||||
error::{ContextError, ErrMode, StrContext, StrContextValue},
|
||||
seq,
|
||||
stream::AsChar,
|
||||
token::take_while,
|
||||
PResult, Parser,
|
||||
ModalResult, Parser,
|
||||
};
|
||||
|
||||
use super::{relative, s};
|
||||
use super::{dec_uint, relative, s};
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Default)]
|
||||
pub struct Offset {
|
||||
@@ -132,14 +132,14 @@ enum Suffix {
|
||||
Pm,
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut &str) -> PResult<Time> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Time> {
|
||||
alt((am_pm_time, iso)).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse an ISO 8601 time string
|
||||
///
|
||||
/// Also used by the [`combined`](super::combined) module
|
||||
pub fn iso(input: &mut &str) -> PResult<Time> {
|
||||
pub fn iso(input: &mut &str) -> ModalResult<Time> {
|
||||
alt((
|
||||
(hour24, timezone).map(|(hour, offset)| Time {
|
||||
hour,
|
||||
@@ -161,7 +161,7 @@ pub fn iso(input: &mut &str) -> PResult<Time> {
|
||||
/// Parse a time ending with AM or PM
|
||||
///
|
||||
/// The hours are restricted to 12 or lower in this format
|
||||
fn am_pm_time(input: &mut &str) -> PResult<Time> {
|
||||
fn am_pm_time(input: &mut &str) -> ModalResult<Time> {
|
||||
seq!(
|
||||
hour12,
|
||||
opt(preceded(colon, minute)),
|
||||
@@ -189,36 +189,36 @@ fn am_pm_time(input: &mut &str) -> PResult<Time> {
|
||||
}
|
||||
|
||||
/// Parse a colon preceded by whitespace
|
||||
fn colon(input: &mut &str) -> PResult<()> {
|
||||
fn colon(input: &mut &str) -> ModalResult<()> {
|
||||
s(':').void().parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a number of hours in `0..24`(preceded by whitespace)
|
||||
fn hour24(input: &mut &str) -> PResult<u32> {
|
||||
fn hour24(input: &mut &str) -> ModalResult<u32> {
|
||||
s(dec_uint).verify(|x| *x < 24).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a number of hours in `0..=12` (preceded by whitespace)
|
||||
fn hour12(input: &mut &str) -> PResult<u32> {
|
||||
fn hour12(input: &mut &str) -> ModalResult<u32> {
|
||||
s(dec_uint).verify(|x| *x <= 12).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a number of minutes (preceded by whitespace)
|
||||
fn minute(input: &mut &str) -> PResult<u32> {
|
||||
fn minute(input: &mut &str) -> ModalResult<u32> {
|
||||
s(dec_uint).verify(|x| *x < 60).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a number of seconds (preceded by whitespace)
|
||||
fn second(input: &mut &str) -> PResult<f64> {
|
||||
fn second(input: &mut &str) -> ModalResult<f64> {
|
||||
s(float).verify(|x| *x < 60.0).parse_next(input)
|
||||
}
|
||||
|
||||
pub(crate) fn timezone(input: &mut &str) -> PResult<Offset> {
|
||||
pub(crate) fn timezone(input: &mut &str) -> ModalResult<Offset> {
|
||||
alt((timezone_num, timezone_name_offset)).parse_next(input)
|
||||
}
|
||||
|
||||
/// Parse a timezone starting with `+` or `-`
|
||||
fn timezone_num(input: &mut &str) -> PResult<Offset> {
|
||||
fn timezone_num(input: &mut &str) -> ModalResult<Offset> {
|
||||
// Strings like "+8 years" are ambiguous, they can either be parsed as a
|
||||
// timezone offset "+8" and a relative time "years", or just a relative time
|
||||
// "+8 years". GNU date parses them the second way, so we do the same here.
|
||||
@@ -232,21 +232,19 @@ fn timezone_num(input: &mut &str) -> PResult<Offset> {
|
||||
.parse_next(input)
|
||||
.and_then(|(negative, (hours, minutes))| {
|
||||
if !(0..=12).contains(&hours) {
|
||||
return Err(ErrMode::Cut(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"timezone hour between 0 and 12",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"timezone hour between 0 and 12",
|
||||
)));
|
||||
return Err(ErrMode::Cut(ctx_err));
|
||||
}
|
||||
|
||||
if !(0..=60).contains(&minutes) {
|
||||
return Err(ErrMode::Cut(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"timezone minute between 0 and 60",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"timezone minute between 0 and 60",
|
||||
)));
|
||||
return Err(ErrMode::Cut(ctx_err));
|
||||
}
|
||||
|
||||
Ok(Offset {
|
||||
@@ -258,7 +256,7 @@ fn timezone_num(input: &mut &str) -> PResult<Offset> {
|
||||
}
|
||||
|
||||
/// Parse a timezone offset with a colon separating hours and minutes
|
||||
fn timezone_colon(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
fn timezone_colon(input: &mut &str) -> ModalResult<(u32, u32)> {
|
||||
seq!(
|
||||
s(take_while(1..=2, AsChar::is_dec_digit)).try_map(|x: &str| {
|
||||
// parse will fail on empty input
|
||||
@@ -275,15 +273,14 @@ fn timezone_colon(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
}
|
||||
|
||||
/// Parse a timezone offset without colon
|
||||
fn timezone_colonless(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
fn timezone_colonless(input: &mut &str) -> ModalResult<(u32, u32)> {
|
||||
if let Ok(x) = peek(s(digit1::<&str, ContextError>)).parse_next(input) {
|
||||
if x.len() > 4 {
|
||||
return Err(ErrMode::Cut(ContextError::new().add_context(
|
||||
&input,
|
||||
StrContext::Expected(winnow::error::StrContextValue::Description(
|
||||
"timezone offset cannot be more than 4 digits",
|
||||
)),
|
||||
let mut ctx_err = ContextError::new();
|
||||
ctx_err.push(StrContext::Expected(StrContextValue::Description(
|
||||
"timezone offset cannot be more than 4 digits",
|
||||
)));
|
||||
return Err(ErrMode::Cut(ctx_err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +301,7 @@ fn timezone_colonless(input: &mut &str) -> PResult<(u32, u32)> {
|
||||
}
|
||||
|
||||
/// Parse a timezone by name
|
||||
fn timezone_name_offset(input: &mut &str) -> PResult<Offset> {
|
||||
fn timezone_name_offset(input: &mut &str) -> ModalResult<Offset> {
|
||||
/// I'm assuming there are no timezone abbreviations with more
|
||||
/// than 6 charactres
|
||||
const MAX_TZ_SIZE: usize = 6;
|
||||
@@ -331,7 +328,7 @@ fn timezone_name_offset(input: &mut &str) -> PResult<Offset> {
|
||||
|
||||
/// Timezone list extracted from:
|
||||
/// https://www.timeanddate.com/time/zones/
|
||||
fn tzname_to_offset(input: &str) -> PResult<Offset> {
|
||||
fn tzname_to_offset(input: &str) -> ModalResult<Offset> {
|
||||
let mut offset_str = match input {
|
||||
"z" => Ok("+0"),
|
||||
"yekt" => Ok("+5"),
|
||||
@@ -568,7 +565,7 @@ fn tzname_to_offset(input: &str) -> PResult<Offset> {
|
||||
}
|
||||
|
||||
/// Parse the plus or minus character and return whether it was negative
|
||||
fn plus_or_minus(input: &mut &str) -> PResult<bool> {
|
||||
fn plus_or_minus(input: &mut &str) -> ModalResult<bool> {
|
||||
s(alt(("+".value(false), "-".value(true)))).parse_next(input)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
//! >
|
||||
//! > A comma following a day of the week item is ignored.
|
||||
|
||||
use winnow::{ascii::alpha1, combinator::opt, seq, PResult, Parser};
|
||||
use winnow::{ascii::alpha1, combinator::opt, seq, ModalResult, Parser};
|
||||
|
||||
use super::{ordinal::ordinal, s};
|
||||
|
||||
@@ -55,7 +55,7 @@ impl From<Day> for chrono::Weekday {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn parse(input: &mut &str) -> PResult<Weekday> {
|
||||
pub fn parse(input: &mut &str) -> ModalResult<Weekday> {
|
||||
seq!(Weekday {
|
||||
offset: opt(ordinal).map(|o| o.unwrap_or_default()),
|
||||
day: day,
|
||||
@@ -63,7 +63,7 @@ pub fn parse(input: &mut &str) -> PResult<Weekday> {
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn day(input: &mut &str) -> PResult<Day> {
|
||||
fn day(input: &mut &str) -> ModalResult<Day> {
|
||||
s(alpha1)
|
||||
.verify_map(|s: &str| {
|
||||
Some(match s {
|
||||
|
||||
Reference in New Issue
Block a user