finquant/time/calendars/
italy.rs

1// Holidays in Italy.
2
3use crate::time::calendars::Calendar;
4
5use chrono::NaiveDate;
6use serde::{Deserialize, Serialize};
7
8#[derive(Deserialize, Serialize, Debug)]
9pub enum ItalyMarket {
10    Settlement,
11    Exchange,
12}
13
14#[derive(Deserialize, Serialize, Default, Debug)]
15pub struct Italy {
16    pub market: Option<ItalyMarket>,
17}
18
19impl Italy {
20    fn settlement_is_business_day(&self, date: NaiveDate) -> bool {
21        let (d, _, m, y, dd) = self.naive_date_to_dkmy(date);
22        let em = self.easter_monday(y);
23
24        if self.is_weekend(date)
25            // New Year's Day
26            || (d == 1 && m == 1)
27            // Epiphany
28            || (d == 6 && m == 1)
29            // Easter Monday
30            || (dd == em)
31            // Liberation Day
32            || (d == 25 && m == 4)
33            // Labour Day
34            || (d == 1 && m == 5)
35            // Republic Day
36            || (d == 2 && m == 6 && y >= 2000)
37            // Assumption
38            || (d == 15 && m == 8)
39            // All Saints' Day
40            || (d == 1 && m == 11)
41            // Immaculate Conception
42            || (d == 8 && m == 12)
43            // Christmas
44            || (d == 25 && m == 12)
45            // St. Stephen
46            || (d == 26 && m == 12)
47            // 12 31st, 1999 only
48            || (d == 31 && m == 12 && y == 1999)
49        {
50            return false;
51        }
52        true
53    }
54
55    fn exchange_is_business_day(&self, date: NaiveDate) -> bool {
56        let (d, _, m, y, dd) = self.naive_date_to_dkmy(date);
57        let em = self.easter_monday(y);
58        if self.is_weekend(date)
59            // New Year's Day
60            || (d == 1 && m == 1)
61            // Good Friday
62            || (dd == em-3)
63            // Easter Monday
64            || (dd == em)
65            // Labour Day
66            || (d == 1 && m == 5)
67            // Assumption
68            || (d == 15 && m == 8)
69            // Christmas' Eve
70            || (d == 24 && m == 12)
71            // Christmas
72            || (d == 25 && m == 12)
73            // St. Stephen
74            || (d == 26 && m == 12)
75            // New Year's Eve
76            || (d == 31 && m == 12)
77        {
78            return false;
79        }
80        true
81    }
82}
83
84#[typetag::serde]
85impl Calendar for Italy {
86    fn is_business_day(&self, date: NaiveDate) -> bool {
87        match self.market {
88            Some(ItalyMarket::Settlement) => self.settlement_is_business_day(date),
89            Some(ItalyMarket::Exchange) => self.exchange_is_business_day(date),
90            None => self.settlement_is_business_day(date),
91        }
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::Italy;
98    use crate::time::calendars::Calendar;
99    use chrono::{Duration, NaiveDate};
100
101    #[test]
102    fn test_italy_holiday() {
103        // Test all results from 2023-01-01 to 2023-12-31
104        let expected_results_for_2023 = vec![
105            false, true, true, true, true, false, false, false, true, true, true, true, true,
106            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
107            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
108            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
109            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
110            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
111            false, false, true, true, true, true, true, false, false, true, true, true, true, true,
112            false, false, false, true, true, true, true, false, false, true, true, true, true,
113            true, false, false, true, false, true, true, true, false, false, false, true, true,
114            true, true, false, false, true, true, true, true, true, false, false, true, true, true,
115            true, true, false, false, true, true, true, true, true, false, false, true, true, true,
116            true, false, false, false, true, true, true, true, true, false, false, true, true,
117            true, true, true, false, false, true, true, true, true, true, false, false, true, true,
118            true, true, true, false, false, true, true, true, true, true, false, false, true, true,
119            true, true, true, false, false, true, true, true, true, true, false, false, true, true,
120            true, true, true, false, false, true, true, true, true, true, false, false, true, true,
121            true, true, true, false, false, true, false, true, true, true, false, false, true,
122            true, true, true, true, false, false, true, true, true, true, true, false, false, true,
123            true, true, true, true, false, false, true, true, true, true, true, false, false, true,
124            true, true, true, true, false, false, true, true, true, true, true, false, false, true,
125            true, true, true, true, false, false, true, true, true, true, true, false, false, true,
126            true, true, true, true, false, false, true, true, true, true, true, false, false, true,
127            true, false, true, true, false, false, true, true, true, true, true, false, false,
128            true, true, true, true, true, false, false, true, true, true, true, true, false, false,
129            true, true, true, true, true, false, false, true, true, true, true, false, false,
130            false, true, true, true, true, true, false, false, true, true, true, true, true, false,
131            false, false, false, true, true, true, false, false,
132        ];
133        let first_date = NaiveDate::from_ymd_opt(2023, 1, 1).unwrap();
134        for n in 0i32..365 {
135            let target_date = first_date + Duration::try_days(n as i64).unwrap();
136            let expected = expected_results_for_2023[n as usize];
137            assert_eq!(Italy::default().is_business_day(target_date), expected);
138        }
139    }
140}