1use crate::time::calendars::Calendar;
4
5use chrono::NaiveDate;
6use serde::{Deserialize, Serialize};
7
8#[derive(Deserialize, Serialize, Default, Debug)]
9pub struct Indonesia;
10
11#[typetag::serde]
12impl Calendar for Indonesia {
13 fn is_business_day(&self, date: NaiveDate) -> bool {
14 let (d, _, 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 && m == 1)
20 || (dd == em-3)
22 || (dd == em+38)
24 || (d == 17 && m == 8)
26 || (d == 25 && m == 12)
28 {
29 return false;
30 }
31
32 if (y == 2005) & ((d == 21 && m == 1)
34 || (d == 9 && m == 2)
36 || (d == 10 && m == 2)
38 || (d == 11 && m == 3)
40 || (d == 22 && m == 4)
42 || (d == 24 && m == 5)
44 || (d == 2 && m == 9)
46 || ((d == 3 || d == 4) && m == 11)
48 || ((d == 2 || d == 7 || d == 8) && m == 11)
50 || (d == 26 && m == 12))
51 {
52 return false;
53 }
54
55 if (y == 2006) & (!(m != 1 || d != 10 && d != 31)
57 || (d == 30 && m == 3)
59 || (d == 10 && m == 4)
61 || (d == 21 && m == 8)
63 || ((d == 24 || d == 25) && m == 10)
65 || ((d == 23 || d == 26 || d == 27) && m == 10))
67 {
68 return false;
69 }
70
71 if (y == 2007) & ((d == 19 && m == 3)
73 || (d == 1 && m == 6)
75 || (d == 20 && m == 12)
77 || (d == 18 && m == 5)
79 || ((d == 12 || d == 15 || d == 16) && m == 10)
80 || ((d == 21 || d == 24) && m == 10))
81 {
82 return false;
83 }
84
85 if (y == 2008) & (((d == 10 || d == 11) && m == 1)
87 || ((d == 7 || d == 8) && m == 2)
89 || (d == 7 && m == 3)
91 || (d == 20 && m == 3)
93 || (d == 20 && m == 5)
95 || (d == 30 && m == 7)
97 || (d == 18 && m == 8)
99 || (d == 30 && m == 9)
101 || ((d == 1 || d == 2 || d == 3) && m == 10)
102 || (d == 8 && m == 12)
104 || (d == 29 && m == 12)
106 || (d == 31 && m == 12))
108 {
109 return false;
110 }
111
112 if (y == 2009) & (!(m != 1 || d != 2 && d != 26)
114 || (d == 9 && m == 3)
116 || (d == 26 && m == 3)
118 || (d == 9 && m == 4)
120 || (d == 20 && m == 7)
122 || ((18..=23).contains(&d) && m == 9)
124 || (d == 27 && m == 11)
126 || (d == 18 && m == 12)
128 || (d == 24 && m == 12)
130 || (d == 31 && m == 12))
132 {
133 return false;
134 }
135
136 if (y == 2010) & ((d == 26 && m == 2)
138 || (d == 16 && m == 3)
140 || (d == 28 && m == 5)
142 || ((8..=14).contains(&d) && m == 9)
144 || (d == 17 && m == 11)
146 || (d == 7 && m == 12)
148 || (d == 24 && m == 12)
150 || (d == 31 && m == 12))
152 {
153 return false;
154 }
155
156 if (y == 2011) & (!(m != 2 || d != 3 && d != 15)
158 || (d == 17 && m == 5)
160 || (d == 29 && m == 6)
162 || (d >= 29 && m == 8)
164 || (d <= 2 && m == 9)
165 || (d == 26 && m == 12))
167 {
168 return false;
169 }
170
171 if (y == 2012) & (!(d != 23 || m != 1 && m != 3)
173 || ((20..=22).contains(&d) && m == 8)
175 || (d == 26 && m == 10)
177 || ((15..=16).contains(&d) && m == 11)
179 || (d == 24 && m == 12)
181 || (d == 31 && m == 12))
183 {
184 return false;
185 }
186
187 if (y == 2013) & ((d == 24 && m == 1)
189 || (d == 12 && m == 3)
191 || (d == 6 && m == 6)
193 || ((5..=9).contains(&d) && m == 8)
195 || ((14..=15).contains(&d) && m == 10)
197 || (d == 5 && m == 11)
199 || (d == 26 && m == 12)
201 || (d == 31 && m == 12))
203 {
204 return false;
205 }
206
207 if (y == 2014) & (!(m != 1 || d != 14 && d != 31)
209 || (d == 31 && m == 3)
211 || (d == 1 && m == 5)
213 || (d == 15 && m == 5)
215 || (d == 27 && m == 5)
217 || (d == 29 && m == 5)
219 || ((d >= 28 && m == 7) || (d == 1 && m == 8))
221 || (d == 26 && m == 12)
223 || (d == 31 && m == 12))
225 {
226 return false;
227 }
228
229 true
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::Indonesia;
236 use crate::time::calendars::Calendar;
237 use chrono::{Duration, NaiveDate};
238
239 #[test]
240 fn test_indonesia_holiday() {
241 let expected_results_for_2023 = vec![
243 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
244 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
245 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
246 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
247 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
248 false, true, true, true, true, true, false, false, true, true, true, true, true, false,
249 false, true, true, true, true, true, false, false, true, true, true, true, false,
250 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
251 false, false, true, true, true, true, true, false, false, true, true, true, true, true,
252 false, false, true, true, true, true, true, false, false, true, true, true, false,
253 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
254 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
255 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
256 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
257 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
258 true, false, false, true, true, true, true, true, false, false, true, true, true, true,
259 true, false, false, true, true, true, false, true, false, false, true, true, true,
260 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
261 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
262 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
263 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
264 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
265 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
266 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
267 true, true, false, false, true, true, true, true, true, false, false, true, true, true,
268 true, true, false, false, true, true, true, true, true, false, false, false, true,
269 true, true, true, false, false,
270 ];
271 let first_date = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap();
272 for n in 0i32..365 {
273 let target_date = first_date + Duration::try_days(n as i64).unwrap();
274 let expected = expected_results_for_2023[n as usize];
275 assert_eq!(Indonesia.is_business_day(target_date), expected);
276 }
277 }
278}