use chrono::NaiveDate;
pub use day_offset::DayOffset;
use nom::{
Parser, branch::alt, character::complete::space0, combinator::map, multi::fold_many1,
sequence::delimited,
};
pub use wallclock_time::{TimePeriod, WallClockTime};
mod day_offset;
mod month_offset;
mod time;
pub use time::{AbsoluteTime, AbsoluteTimeBuilder, FlexiDate};
use crate::error::FlexitimeResult2;
pub mod date;
pub mod wallclock_time;
pub enum AbsoluteTimePart {
DayOffset(DayOffset),
Date(NaiveDate),
WallClockTime(WallClockTime),
}
pub fn parse_absolute_time(input: &str) -> FlexitimeResult2<&str, AbsoluteTime> {
fold_many1(
delimited(
space0,
alt((
map(day_offset::parse_day_offset, AbsoluteTimePart::DayOffset),
map(
wallclock_time::parse_wall_clock_time,
AbsoluteTimePart::WallClockTime,
),
map(date::parse_date, AbsoluteTimePart::Date),
)),
space0,
),
|| AbsoluteTimeBuilder::new(),
|acc, part| match part {
AbsoluteTimePart::DayOffset(offset) => acc.date(FlexiDate::DayOffset(offset)),
AbsoluteTimePart::Date(date) => acc.date(FlexiDate::Date(date)),
AbsoluteTimePart::WallClockTime(wall_clock_time) => acc.time(wall_clock_time),
},
)
.map(|builder| builder.build().unwrap())
.parse(input)
}
#[cfg(test)]
mod tests {
use chrono::Weekday;
use crate::parser::absolute::wallclock_time::TimePeriod;
use super::*;
#[test]
fn test_parse_time_and_day_offset() {
assert_eq!(
parse_absolute_time("tuesday 9:00pm").unwrap(),
(
"",
AbsoluteTimeBuilder::new()
.date(FlexiDate::DayOffset(DayOffset::NextDayOccurrence(
Weekday::Tue
)))
.time(WallClockTime::new(9, 0, 0, Some(TimePeriod::Pm)).unwrap())
.build()
.unwrap()
)
)
}
#[test]
fn test_parse_date_and_time() {
assert_eq!(
parse_absolute_time("25/10/2025 11:25am").unwrap(),
(
"",
AbsoluteTimeBuilder::new()
.date(FlexiDate::Date(
NaiveDate::from_ymd_opt(2025, 10, 25).unwrap()
))
.time(WallClockTime::new(11, 25, 0, Some(TimePeriod::Am)).unwrap())
.build()
.unwrap()
)
)
}
}