use chrono::{Datelike, Days, NaiveDate, NaiveDateTime, Utc};
use super::{day_offset::DayOffset, wallclock_time::WallClockTime};
#[derive(Debug, PartialEq, Clone)]
pub enum FlexiDate {
Date(NaiveDate),
DayOffset(DayOffset),
}
#[derive(Debug, PartialEq, Clone)]
pub struct AbsoluteTime {
time: WallClockTime,
date: FlexiDate,
}
impl AbsoluteTime {
pub fn new(time: WallClockTime, date: FlexiDate) -> Self {
Self { time, date }
}
pub fn to_chrono(&self) -> NaiveDateTime {
let mut datetime = Utc::now()
.naive_utc()
.date()
.and_time(self.time.to_naive_time());
datetime = match &self.date {
FlexiDate::Date(date) => date.and_time(datetime.time()),
FlexiDate::DayOffset(DayOffset::Fixed(days)) => {
if *days < 0 {
datetime.checked_sub_days(Days::new(-days as u64)).unwrap()
} else {
datetime.checked_add_days(Days::new(*days as u64)).unwrap()
}
}
FlexiDate::DayOffset(DayOffset::NextDayOccurrence(weekday)) => {
let current_day = datetime.weekday();
let offset = 7 - current_day.days_since(weekday.clone());
datetime.checked_add_days(Days::new(offset.into())).unwrap()
}
};
datetime
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct AbsoluteTimeBuilder {
time: Option<WallClockTime>,
date: Option<FlexiDate>,
}
impl AbsoluteTimeBuilder {
pub fn new() -> Self {
Self {
time: None,
date: None,
}
}
pub fn time(mut self, time: WallClockTime) -> Self {
self.time = Some(time);
self
}
pub fn date(mut self, date: FlexiDate) -> Self {
self.date = Some(date);
self
}
pub fn build(self) -> Result<AbsoluteTime, String> {
match (self.time, self.date) {
(Some(time), Some(date)) => Ok(AbsoluteTime { time, date }),
_ => Err("Missing required fields".to_string()),
}
}
}