use cal_calc::Calendar;
use chrono::{Datelike, NaiveDate};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
pub enum DayAdjust {
#[serde(rename = "none")]
None,
#[serde(rename = "following")]
Following,
#[serde(rename = "preceding")]
Preceding,
#[serde(rename = "modified")]
#[serde(alias = "modified following")]
Modified,
}
impl DayAdjust {
pub fn adjust_date(&self, date: NaiveDate, cal: &Calendar) -> NaiveDate {
match self {
DayAdjust::None => date,
DayAdjust::Following => {
if cal.is_holiday(date) {
cal.next_bday(date)
} else {
date
}
}
DayAdjust::Preceding => {
if cal.is_holiday(date) {
cal.prev_bday(date)
} else {
date
}
}
DayAdjust::Modified => {
if cal.is_business_day(date) {
date
} else {
let new_date = cal.next_bday(date);
if new_date.month() != date.month() {
cal.prev_bday(date)
} else {
new_date
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use cal_calc::Holiday;
#[test]
fn day_adjust() {
let holidays = vec![
Holiday::SingularDay(NaiveDate::from_ymd(2019, 10, 10)),
Holiday::SingularDay(NaiveDate::from_ymd(2019, 10, 31)),
];
let cal = Calendar::calc_calendar(&holidays, 2019, 2019);
let rule = DayAdjust::None;
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 1), &cal),
NaiveDate::from_ymd(2019, 10, 1)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 10), &cal),
NaiveDate::from_ymd(2019, 10, 10)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 31), &cal),
NaiveDate::from_ymd(2019, 10, 31)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 11, 30), &cal),
NaiveDate::from_ymd(2019, 11, 30)
);
let rule = DayAdjust::Following;
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 1), &cal),
NaiveDate::from_ymd(2019, 10, 1)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 10), &cal),
NaiveDate::from_ymd(2019, 10, 11)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 31), &cal),
NaiveDate::from_ymd(2019, 11, 1)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 11, 30), &cal),
NaiveDate::from_ymd(2019, 11, 30)
);
let rule = DayAdjust::Preceding;
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 1), &cal),
NaiveDate::from_ymd(2019, 10, 1)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 10), &cal),
NaiveDate::from_ymd(2019, 10, 9)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 31), &cal),
NaiveDate::from_ymd(2019, 10, 30)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 11, 30), &cal),
NaiveDate::from_ymd(2019, 11, 30)
);
let rule = DayAdjust::Modified;
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 1), &cal),
NaiveDate::from_ymd(2019, 10, 1)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 10), &cal),
NaiveDate::from_ymd(2019, 10, 11)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 10, 31), &cal),
NaiveDate::from_ymd(2019, 10, 30)
);
assert_eq!(
rule.adjust_date(NaiveDate::from_ymd(2019, 11, 30), &cal),
NaiveDate::from_ymd(2019, 11, 30)
);
}
}