use crate::time::calendars::Calendar;
use chrono::{NaiveDate, Weekday};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
pub enum NewZealandMarket {
Wellington,
Auckland,
}
#[derive(Deserialize, Serialize, Default, Debug)]
pub struct NewZealand {
pub market: Option<NewZealandMarket>,
}
impl NewZealand {
fn common_is_business_day(&self, date: NaiveDate) -> bool {
let (d, w, m, y, dd) = self.naive_date_to_dkmy(date);
let em = self.easter_monday(y);
if self.is_weekend(date)
|| ((d == 1 || (d == 3 && (w == Weekday::Mon || w == Weekday::Tue))) &&
m == 1)
|| ((d == 2 || (d == 4 && (w == Weekday::Mon || w == Weekday::Tue))) &&
m == 1)
|| (d == 6 && m == 2)
|| ((d == 7 || d == 8) && w == Weekday::Mon && m == 2 && y > 2013)
|| (dd == em-3)
|| (dd == em)
|| (d == 25 && m == 4)
|| ((d == 26 || d == 27) && w == Weekday::Mon && m == 4 && y > 2013)
|| (d <= 7 && w == Weekday::Mon && m == 6)
|| ((22..=28).contains(&d) && w == Weekday::Mon && m == 10)
|| ((d == 25 || (d == 27 && (w == Weekday::Mon || w == Weekday::Tue)))
&& m == 12)
|| ((d == 26 || (d == 28 && (w == Weekday::Mon || w == Weekday::Tue)))
&& m == 12)
|| (d == 20 && m == 6 && y == 2025)
|| (d == 21 && m == 6 && (y == 2030 || y == 2052))
|| (d == 24 && m == 6 && (y == 2022 || y == 2033 || y == 2044))
|| (d == 25 && m == 6 && (y == 2027 || y == 2038 || y == 2049))
|| (d == 28 && m == 6 && y == 2024)
|| (d == 29 && m == 6 && (y == 2035 || y == 2046))
|| (d == 30 && m == 6 && y == 2051)
|| (d == 2 && m == 7 && y == 2032)
|| (d == 3 && m == 7 && (y == 2043 || y == 2048))
|| (d == 6 && m == 7 && (y == 2029 || y == 2040))
|| (d == 7 && m == 7 && (y == 2034 || y == 2045))
|| (d == 10 && m == 7 && (y == 2026 || y == 2037))
|| (d == 11 && m == 7 && (y == 2031 || y == 2042))
|| (d == 14 && m == 7 && (y == 2023 || y == 2028))
|| (d == 15 && m == 7 && (y == 2039 || y == 2050))
|| (d == 18 && m == 7 && y == 2036)
|| (d == 19 && m == 7 && (y == 2041 || y == 2047))
|| (d == 26 && m == 9 && y == 2022)
{
false
} else {
true
}
}
fn wellington_is_business_day(&self, date: NaiveDate) -> bool {
if !self.common_is_business_day(date) {
return false;
}
let (d, w, m, _, _) = self.naive_date_to_dkmy(date);
!((19..=25).contains(&d) && w == Weekday::Mon && m == 1)
}
fn auckland_is_business_day(&self, date: NaiveDate) -> bool {
if !self.common_is_business_day(date) {
return false;
}
let (d, w, m, _, _) = self.naive_date_to_dkmy(date);
!(((d >= 26) && w == Weekday::Mon && m == 1) || ((d == 1) && w == Weekday::Mon && m == 2))
}
}
#[typetag::serde]
impl Calendar for NewZealand {
fn is_business_day(&self, date: NaiveDate) -> bool {
match self.market {
Some(NewZealandMarket::Wellington) => self.wellington_is_business_day(date),
Some(NewZealandMarket::Auckland) => self.auckland_is_business_day(date),
None => self.wellington_is_business_day(date),
}
}
}
#[cfg(test)]
mod tests {
use super::{NewZealand, NewZealandMarket};
use crate::time::calendars::Calendar;
use chrono::{Duration, NaiveDate};
#[test]
fn test_mexico_holiday() {
let expected_results_for_2023 = vec![
false, false, false, true, true, true, false, false, true, true, true, true, true,
false, false, true, true, true, true, true, false, false, false, true, true, true,
true, false, false, true, true, true, true, true, false, false, false, true, true,
true, true, false, false, true, true, true, true, true, false, false, true, true, true,
true, true, false, false, true, true, true, true, true, false, false, true, true, true,
true, true, false, false, true, true, true, true, true, false, false, true, true, true,
true, true, false, false, true, true, true, true, true, false, false, true, true, true,
true, false, false, false, false, true, true, true, true, false, false, true, true,
true, true, true, false, false, true, false, true, true, true, false, false, true,
true, true, true, true, false, false, true, true, true, true, true, false, false, true,
true, true, true, true, false, false, true, true, true, true, true, false, false, true,
true, true, true, true, false, false, false, true, true, true, true, false, false,
true, true, true, true, true, false, false, true, true, true, true, true, false, false,
true, true, true, true, true, false, false, true, true, true, true, true, false, false,
true, true, true, true, false, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, true, true, true, true, true, false,
false, true, true, true, true, true, false, false, false, true, true, true, true,
false, false, true, true, true, true, true, false, false, true, true, true, true, true,
false, false, true, true, true, true, true, false, false, true, true, true, true, true,
false, false, true, true, true, true, true, false, false, true, true, true, true, true,
false, false, true, true, true, true, true, false, false, true, true, true, true, true,
false, false, false, false, true, true, true, false, false,
];
let first_date = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap();
for n in 0i32..365 {
let target_date = first_date + Duration::try_days(n as i64).unwrap();
let expected = expected_results_for_2023[n as usize];
assert_eq!(NewZealand::default().is_business_day(target_date), expected);
assert_eq!(
NewZealand {
market: Some(NewZealandMarket::Wellington)
}
.is_business_day(target_date),
expected
);
}
}
}