use std::ops::RangeInclusive; use crate::parser::error::CustomError; use crate::parser::prelude::*; use crate::parser::trivia::from_utf8_unchecked; use toml_datetime::{Date, Datetime, Offset, Time}; use winnow::combinator::alt; use winnow::combinator::cut_err; use winnow::combinator::opt; use winnow::combinator::preceded; use winnow::combinator::trace; use winnow::stream::Stream as _; use winnow::token::one_of; use winnow::token::take_while; // ;; Date and Time (as defined in RFC 3339) // date-time = offset-date-time / local-date-time / local-date / local-time // offset-date-time = full-date time-delim full-time // local-date-time = full-date time-delim partial-time // local-date = full-date // local-time = partial-time // full-time = partial-time time-offset pub(crate) fn date_time(input: &mut Input<'_>) -> PResult { trace( "date-time", alt(( (full_date, opt((time_delim, partial_time, opt(time_offset)))) .map(|(date, opt)| { match opt { // Offset Date-Time Some((_, time, offset)) => Datetime { date: Some(date), time: Some(time), offset, }, // Local Date None => Datetime { date: Some(date), time: None, offset: None, }, } }) .context(StrContext::Label("date-time")), partial_time .map(|t| t.into()) .context(StrContext::Label("time")), )), ) .parse_next(input) } // full-date = date-fullyear "-" date-month "-" date-mday pub(crate) fn full_date(input: &mut Input<'_>) -> PResult { trace("full-date", full_date_).parse_next(input) } fn full_date_(input: &mut Input<'_>) -> PResult { let year = date_fullyear.parse_next(input)?; let _ = b'-'.parse_next(input)?; let month = cut_err(date_month).parse_next(input)?; let _ = cut_err(b'-').parse_next(input)?; let day_start = input.checkpoint(); let day = cut_err(date_mday).parse_next(input)?; let is_leap_year = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); let max_days_in_month = match month { 2 if is_leap_year => 29, 2 => 28, 4 | 6 | 9 | 11 => 30, _ => 31, }; if max_days_in_month < day { input.reset(&day_start); return Err(winnow::error::ErrMode::from_external_error( input, winnow::error::ErrorKind::Verify, CustomError::OutOfRange, ) .cut()); } Ok(Date { year, month, day }) } // partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] pub(crate) fn partial_time(input: &mut Input<'_>) -> PResult