1use crate::time::calendars::Calendar;
4
5use chrono::{NaiveDate, Weekday};
6use serde::{Deserialize, Serialize};
7
8#[derive(Deserialize, Serialize, Default, Debug)]
9pub struct Botswana;
10
11#[typetag::serde]
12impl Calendar for Botswana {
13 fn is_business_day(&self, date: NaiveDate) -> bool {
14 let (d, w, m, y, dd) = self.naive_date_to_dkmy(date);
15 let em = self.easter_monday(y);
16
17 if self.is_weekend(date)
18 || ((d == 1 || (d == 2 && w == Weekday::Mon) || (d == 3 && w == Weekday::Tue))
20 && m == 1)
21 || (dd == em - 3)
23 || (dd == em)
25 || ((d == 1 || (d == 2 && w == Weekday::Mon))
27 && m == 5)
28 || (dd == em + 38)
30 || ((d == 1 || (d == 2 && w == Weekday::Mon))
32 && m == 7)
33 || ((15..=21).contains(&d) && w == Weekday::Mon && m == 7)
35 || ((d == 30 && m == 9) ||
37 (d == 1 && w == Weekday::Mon && m == 10))
38 || ((d == 1 || (d == 2 && w == Weekday::Mon) || (d == 3 && w == Weekday::Tue))
40 && m == 10)
41 || (d == 25 && m == 12)
43 || ((d == 26 || (d == 27 && w == Weekday::Mon))
45 && m == 12)
46 {
47 return false;
48 }
49 true
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::Botswana;
56 use crate::time::calendars::Calendar;
57 use chrono::{Duration, NaiveDate};
58
59 #[test]
60 fn test_botswana_holiday() {
61 let expected_results_for_2023 = vec![
63 false, false, false, true, true, true, false, false, true, true, true, true, true,
64 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
65 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
66 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
67 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
68 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
69 false, false, true, true, true, true, true, false, false, true, true, true, true,
70 false, false, false, false, true, true, true, true, false, false, true, true, true,
71 true, true, false, false, true, true, true, true, true, false, false, false, true,
72 true, true, true, false, false, true, true, true, true, true, false, false, true, true,
73 true, false, true, false, false, true, true, true, true, true, false, false, true,
74 true, true, true, true, false, false, true, true, true, true, true, false, false, true,
75 true, true, true, true, false, false, true, true, true, true, true, false, false, true,
76 true, true, true, true, false, false, true, true, true, true, true, false, false, true,
77 true, true, true, true, false, false, false, true, true, true, true, false, false,
78 true, true, true, true, true, false, false, true, true, true, true, true, false, false,
79 true, true, true, true, true, false, false, true, true, true, true, true, false, false,
80 true, true, true, true, true, false, false, true, true, true, true, true, false, false,
81 true, true, true, true, true, false, false, true, true, true, true, true, false, false,
82 true, true, true, true, true, false, false, true, true, true, true, true, false, false,
83 false, false, true, true, true, false, false, true, true, true, true, true, false,
84 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
85 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
86 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
87 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
88 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
89 false, false, false, true, true, true, false, false,
90 ];
91 let first_date = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap();
92 for n in 0i32..365 {
93 let target_date = first_date + Duration::try_days(n as i64).unwrap();
94 let expected = expected_results_for_2023[n as usize];
95 assert_eq!(Botswana.is_business_day(target_date), expected);
96 }
97 }
98}