use crate::calendar::Calendar;
use crate::utilities::unpack_date;
use icu;
use time::{Date, Weekday};
use RustQuant_iso::*;
const JEWISH_HOLIDAYS: [(u8, u8); 16] = [
(12, 29), (1, 1), (1, 2), (1, 9), (1, 10), (1, 14), (1, 15), (1, 22), (1, 23), (6, 14), (7, 14), (7, 15), (7, 20), (7, 21), (9, 5), (9, 6), ];
pub struct IsraelCalendar;
impl IsraelCalendar {
fn is_weekend(&self, date: Date) -> bool {
let wd = date.weekday();
wd == Weekday::Friday || wd == Weekday::Saturday
}
}
impl Calendar for IsraelCalendar {
fn new() -> Self {
Self
}
fn name(&self) -> &'static str {
"Israel"
}
fn country_code(&self) -> ISO_3166 {
ISRAEL
}
fn market_identifier_code(&self) -> ISO_10383 {
XTAE
}
fn is_business_day(&self, date: Date) -> bool {
!self.is_weekend(date) && !self.is_holiday(date)
}
fn is_holiday(&self, date: Date) -> bool {
let (y, m, d, wd, _, _) = unpack_date(date, false);
let m = m as u8;
let iso_date = icu::calendar::Date::try_new_iso_date(y, m, d)
.expect("Failed to initialize ISO Date instance for constructing Hebrew date.");
let hebrew_date = iso_date.to_calendar(icu::calendar::hebrew::Hebrew);
let mut hebrew_month = hebrew_date.month().ordinal as u8;
let hebrew_day = hebrew_date.day_of_month().0 as u8;
if hebrew_date.is_in_leap_year() && hebrew_month > 7 {
hebrew_month -= 1;
}
let is_independence_or_memorial_day = matches!(
&(hebrew_month, hebrew_day, wd),
(8, 3..=4, Weekday::Thursday)
| (8, 2..=3, Weekday::Wednesday)
| (8, 5, Weekday::Monday)
| (8, 6, Weekday::Tuesday)
| (8, 5, Weekday::Wednesday)
| (8, 4, Weekday::Tuesday)
);
let is_tisha_beav = matches!(
&(hebrew_month, hebrew_day, wd),
(11, 10, Weekday::Sunday) | (11, 9, Weekday::Saturday) | (11, 9, _)
);
JEWISH_HOLIDAYS.contains(&(hebrew_month, hebrew_day))
|| is_independence_or_memorial_day
|| is_tisha_beav
}
}
#[cfg(test)]
mod test_israel {
use super::*;
use time::macros::date;
use time::Month;
#[test]
fn test_name() {
let calendar = IsraelCalendar;
assert_eq!(calendar.name(), "Israel");
}
#[test]
fn test_is_weekend() {
let calendar = IsraelCalendar;
let fri = date!(2023 - 01 - 27);
let sat = date!(2023 - 01 - 28);
assert!(!calendar.is_business_day(fri));
assert!(!calendar.is_business_day(sat));
}
#[test]
fn test_is_public_holiday() {
let calendar = IsraelCalendar;
let holidays = vec![
(2024, 3, 24), (2024, 4, 22), (2024, 4, 23), (2024, 4, 28), (2024, 4, 29), (2024, 5, 13), (2024, 5, 14), (2024, 6, 11), (2024, 6, 12), (2024, 8, 13), (2024, 10, 3), (2024, 10, 4), (2024, 10, 11), (2024, 10, 17), (2024, 10, 24), (2025, 3, 14), (2025, 4, 13), (2025, 6, 2), (2025, 8, 3), (2025, 9, 23), (2025, 9, 24), (2025, 10, 2), (2025, 10, 7), (2025, 10, 14), (2015, 3, 5), (2015, 4, 10), (2015, 4, 23), (2015, 5, 24), (2015, 7, 26), (2015, 9, 14), (2015, 9, 15), (2015, 9, 23), (2015, 9, 28), (2015, 10, 5), (2018, 3, 1), (2018, 4, 6), (2018, 4, 19), (2018, 5, 20), (2018, 7, 22), (2018, 9, 10), (2018, 9, 11), (2018, 9, 18), (2018, 9, 19), (2018, 9, 24), (2018, 10, 1), (2017, 3, 12), (2017, 4, 11), (2017, 4, 17), (2017, 5, 2), (2017, 5, 31), (2017, 8, 1), (2017, 9, 21), (2017, 9, 22), (2017, 9, 29), (2017, 10, 5), (2017, 10, 12), ];
for (y, m, d) in holidays {
let date = Date::from_calendar_date(y, Month::try_from(m).unwrap(), d).unwrap();
assert!(!calendar.is_business_day(date));
}
}
#[test]
fn test_is_regular_business_day() {
let calendar = IsraelCalendar;
let regular_day1 = date!(2021 - 08 - 04);
let regular_day2 = date!(2024 - 04 - 09);
let regular_day3 = date!(2023 - 11 - 27);
assert!(calendar.is_business_day(regular_day1));
assert!(calendar.is_business_day(regular_day2));
assert!(calendar.is_business_day(regular_day3));
}
}