api changes
This commit is contained in:
parent
d82ef99c55
commit
8a78e8f901
@ -4,6 +4,15 @@ version = "0.1.1"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
publish = ["kellnr"]
|
publish = ["kellnr"]
|
||||||
|
|
||||||
|
# [features]
|
||||||
|
# default = ["de"]
|
||||||
|
# # Includes Germany
|
||||||
|
# de = []
|
||||||
|
# # Includes France
|
||||||
|
# fr = []
|
||||||
|
# # Includes The United States
|
||||||
|
# us = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
time = "0.3.41"
|
time = "0.3.41"
|
||||||
strum = { version = "0.27.2", features = ["derive"] }
|
strum = { version = "0.27.2", features = ["derive"] }
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use time::{Date, Duration, Month, Weekday};
|
use time::{Date, Duration, Month, Weekday};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
countries::{CountryHolidays, StateList},
|
countries::StateList,
|
||||||
holiday::{Activity, HDate, Holiday},
|
holiday::{Activity, HDate, Holiday},
|
||||||
utils::{self},
|
utils::{self},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct GermanHolidays;
|
pub(crate) struct GermanHolidays(pub Vec<Holiday<GermanState>>);
|
||||||
|
|
||||||
#[derive(strum::Display, Hash, PartialEq, Eq)]
|
#[derive(Debug, strum::Display, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum GermanState {
|
pub enum GermanState {
|
||||||
/// Baden-Württemberg
|
/// Baden-Württemberg
|
||||||
BW,
|
BW,
|
||||||
@ -52,164 +52,162 @@ impl super::StateList for GermanState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountryHolidays<GermanState> for GermanHolidays {
|
impl GermanHolidays {
|
||||||
fn new() -> (String, Vec<Holiday>) {
|
pub(crate) fn new() -> Self {
|
||||||
use GermanState::*;
|
use GermanState::*;
|
||||||
use time::Month::*;
|
use time::Month::*;
|
||||||
(
|
|
||||||
GermanState::all_states_identifier(),
|
|
||||||
vec![
|
|
||||||
// New Years Day
|
|
||||||
Holiday {
|
|
||||||
name: "Neujahrstag".to_string(),
|
|
||||||
date: HDate::Fixed(January, 1),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Epiphany
|
|
||||||
Holiday {
|
|
||||||
name: "Heilige drei Könige".to_string(),
|
|
||||||
date: HDate::Fixed(January, 6),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(BW, &[Activity::after(1990)]),
|
|
||||||
(BY, &[Activity::after(1990)]),
|
|
||||||
(ST, &[Activity::after(1990)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// International Women's Day
|
|
||||||
Holiday {
|
|
||||||
name: "Internationaler Frauentag".to_string(),
|
|
||||||
date: HDate::Fixed(March, 8),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(BE, &[Activity::after(2019)]),
|
|
||||||
(MV, &[Activity::after(2023)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// Good Friday
|
|
||||||
Holiday {
|
|
||||||
name: "Karfreitag".to_string(),
|
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) - Duration::days(3)),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Easter Monday
|
|
||||||
Holiday {
|
|
||||||
name: "Ostermontag".to_string(),
|
|
||||||
date: HDate::Calculated(utils::easter_monday),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Labour Day
|
|
||||||
Holiday {
|
|
||||||
name: "Tag der Arbeit".to_string(),
|
|
||||||
date: HDate::Fixed(May, 1),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Ascension Day
|
|
||||||
Holiday {
|
|
||||||
name: "Christi Himmelfahrt".to_string(),
|
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(38)),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Whit Monday
|
|
||||||
Holiday {
|
|
||||||
name: "Pfingstmontag".to_string(),
|
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(49)),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Corpus Christi
|
|
||||||
Holiday {
|
|
||||||
name: "Fronleichnam".to_string(),
|
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(59)),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(BW, &[Activity::after(1990)]),
|
|
||||||
(BY, &[Activity::after(1990)]),
|
|
||||||
(HE, &[Activity::after(1990)]),
|
|
||||||
(NW, &[Activity::after(1990)]),
|
|
||||||
(RP, &[Activity::after(1990)]),
|
|
||||||
(SL, &[Activity::after(1990)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// Assumption Day
|
|
||||||
Holiday {
|
|
||||||
name: "Mariä Himmelfahrt".to_string(),
|
|
||||||
date: HDate::Fixed(August, 15),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(BY, &[Activity::after(1990)]),
|
|
||||||
(SL, &[Activity::after(1990)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// World Children's Day
|
|
||||||
Holiday {
|
|
||||||
name: "Weltkindertag".to_string(),
|
|
||||||
date: HDate::Fixed(September, 20),
|
|
||||||
states: GermanState::list(&[(TH, &[Activity::after(2019)])]),
|
|
||||||
},
|
|
||||||
// German Unity Day
|
|
||||||
Holiday {
|
|
||||||
name: "Tag der Deutschen Einheit".to_string(),
|
|
||||||
date: HDate::Fixed(October, 3),
|
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
|
||||||
},
|
|
||||||
// Reformation Day
|
|
||||||
Holiday {
|
|
||||||
name: "Reformationstag".to_string(),
|
|
||||||
date: HDate::Fixed(October, 31),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(ANY, &[Activity::range(2017, 2017)]),
|
|
||||||
(BB, &[Activity::after(1990)]),
|
|
||||||
(MV, &[Activity::after(1990)]),
|
|
||||||
(SN, &[Activity::after(1990)]),
|
|
||||||
(ST, &[Activity::after(1990)]),
|
|
||||||
(TH, &[Activity::after(1990)]),
|
|
||||||
(HB, &[Activity::after(2018)]),
|
|
||||||
(HH, &[Activity::after(2018)]),
|
|
||||||
(NI, &[Activity::after(2018)]),
|
|
||||||
(SH, &[Activity::after(2018)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// All Saints Day
|
|
||||||
Holiday {
|
|
||||||
name: "Allerheiligen".to_string(),
|
|
||||||
date: HDate::Fixed(November, 1),
|
|
||||||
states: GermanState::list(&[
|
|
||||||
(BW, &[Activity::after(1990)]),
|
|
||||||
(BY, &[Activity::after(1990)]),
|
|
||||||
(NW, &[Activity::after(1990)]),
|
|
||||||
(RP, &[Activity::after(1990)]),
|
|
||||||
(SL, &[Activity::after(1990)]),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
// Repentance And Prayer Day
|
|
||||||
Holiday {
|
|
||||||
name: "Buß- und Bettag".to_string(),
|
|
||||||
date: HDate::Calculated(|year| {
|
|
||||||
// Der Buß- und Bettag ist immer ein Mittwoch, er liegt zwischen dem 16. und 22. November
|
|
||||||
let november_22 = Date::from_calendar_date(year, Month::November, 22)
|
|
||||||
.expect("22 Nov should exist every year");
|
|
||||||
|
|
||||||
if november_22.weekday() == Weekday::Wednesday {
|
Self(vec![
|
||||||
november_22
|
// New Years Day
|
||||||
} else {
|
Holiday {
|
||||||
november_22.prev_occurrence(Weekday::Wednesday)
|
name: "Neujahrstag".to_string(),
|
||||||
}
|
date: HDate::Fixed(January, 1),
|
||||||
}),
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
states: GermanState::list(&[
|
},
|
||||||
(ANY, &[Activity::range(1990, 1994)]),
|
// Epiphany
|
||||||
(SN, &[Activity::after(1990)]),
|
Holiday {
|
||||||
]),
|
name: "Heilige drei Könige".to_string(),
|
||||||
},
|
date: HDate::Fixed(January, 6),
|
||||||
// Christmas Day
|
states: GermanState::list(&[
|
||||||
Holiday {
|
(BW, &[Activity::after(1990)]),
|
||||||
name: "Erster Weihnachtstag".to_string(),
|
(BY, &[Activity::after(1990)]),
|
||||||
date: HDate::Fixed(December, 25),
|
(ST, &[Activity::after(1990)]),
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
]),
|
||||||
},
|
},
|
||||||
// Second Day Of Christmas
|
// International Women's Day
|
||||||
Holiday {
|
Holiday {
|
||||||
name: "Zweiter Weihnachtstag".to_string(),
|
name: "Internationaler Frauentag".to_string(),
|
||||||
date: HDate::Fixed(December, 26),
|
date: HDate::Fixed(March, 8),
|
||||||
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
states: GermanState::list(&[
|
||||||
},
|
(BE, &[Activity::after(2019)]),
|
||||||
],
|
(MV, &[Activity::after(2023)]),
|
||||||
)
|
]),
|
||||||
|
},
|
||||||
|
// Good Friday
|
||||||
|
Holiday {
|
||||||
|
name: "Karfreitag".to_string(),
|
||||||
|
date: HDate::Calculated(|year| utils::easter_monday(year) - Duration::days(3)),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Easter Monday
|
||||||
|
Holiday {
|
||||||
|
name: "Ostermontag".to_string(),
|
||||||
|
date: HDate::Calculated(utils::easter_monday),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Labour Day
|
||||||
|
Holiday {
|
||||||
|
name: "Tag der Arbeit".to_string(),
|
||||||
|
date: HDate::Fixed(May, 1),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Ascension Day
|
||||||
|
Holiday {
|
||||||
|
name: "Christi Himmelfahrt".to_string(),
|
||||||
|
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(38)),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Whit Monday
|
||||||
|
Holiday {
|
||||||
|
name: "Pfingstmontag".to_string(),
|
||||||
|
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(49)),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Corpus Christi
|
||||||
|
Holiday {
|
||||||
|
name: "Fronleichnam".to_string(),
|
||||||
|
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(59)),
|
||||||
|
states: GermanState::list(&[
|
||||||
|
(BW, &[Activity::after(1990)]),
|
||||||
|
(BY, &[Activity::after(1990)]),
|
||||||
|
(HE, &[Activity::after(1990)]),
|
||||||
|
(NW, &[Activity::after(1990)]),
|
||||||
|
(RP, &[Activity::after(1990)]),
|
||||||
|
(SL, &[Activity::after(1990)]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
// Assumption Day
|
||||||
|
Holiday {
|
||||||
|
name: "Mariä Himmelfahrt".to_string(),
|
||||||
|
date: HDate::Fixed(August, 15),
|
||||||
|
states: GermanState::list(&[
|
||||||
|
(BY, &[Activity::after(1990)]),
|
||||||
|
(SL, &[Activity::after(1990)]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
// World Children's Day
|
||||||
|
Holiday {
|
||||||
|
name: "Weltkindertag".to_string(),
|
||||||
|
date: HDate::Fixed(September, 20),
|
||||||
|
states: GermanState::list(&[(TH, &[Activity::after(2019)])]),
|
||||||
|
},
|
||||||
|
// German Unity Day
|
||||||
|
Holiday {
|
||||||
|
name: "Tag der Deutschen Einheit".to_string(),
|
||||||
|
date: HDate::Fixed(October, 3),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Reformation Day
|
||||||
|
Holiday {
|
||||||
|
name: "Reformationstag".to_string(),
|
||||||
|
date: HDate::Fixed(October, 31),
|
||||||
|
states: GermanState::list(&[
|
||||||
|
(ANY, &[Activity::range(2017, 2017)]),
|
||||||
|
(BB, &[Activity::after(1990)]),
|
||||||
|
(MV, &[Activity::after(1990)]),
|
||||||
|
(SN, &[Activity::after(1990)]),
|
||||||
|
(ST, &[Activity::after(1990)]),
|
||||||
|
(TH, &[Activity::after(1990)]),
|
||||||
|
(HB, &[Activity::after(2018)]),
|
||||||
|
(HH, &[Activity::after(2018)]),
|
||||||
|
(NI, &[Activity::after(2018)]),
|
||||||
|
(SH, &[Activity::after(2018)]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
// All Saints Day
|
||||||
|
Holiday {
|
||||||
|
name: "Allerheiligen".to_string(),
|
||||||
|
date: HDate::Fixed(November, 1),
|
||||||
|
states: GermanState::list(&[
|
||||||
|
(BW, &[Activity::after(1990)]),
|
||||||
|
(BY, &[Activity::after(1990)]),
|
||||||
|
(NW, &[Activity::after(1990)]),
|
||||||
|
(RP, &[Activity::after(1990)]),
|
||||||
|
(SL, &[Activity::after(1990)]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
// Repentance And Prayer Day
|
||||||
|
Holiday {
|
||||||
|
name: "Buß- und Bettag".to_string(),
|
||||||
|
date: HDate::Calculated(|year| {
|
||||||
|
// Der Buß- und Bettag ist immer ein Mittwoch, er liegt zwischen dem 16. und 22. November
|
||||||
|
let november_22 = Date::from_calendar_date(year, Month::November, 22)
|
||||||
|
.expect("22 Nov should exist every year");
|
||||||
|
|
||||||
|
if november_22.weekday() == Weekday::Wednesday {
|
||||||
|
november_22
|
||||||
|
} else {
|
||||||
|
november_22.prev_occurrence(Weekday::Wednesday)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
states: GermanState::list(&[
|
||||||
|
(ANY, &[Activity::range(1990, 1994)]),
|
||||||
|
(SN, &[Activity::after(1990)]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
// Christmas Day
|
||||||
|
Holiday {
|
||||||
|
name: "Erster Weihnachtstag".to_string(),
|
||||||
|
date: HDate::Fixed(December, 25),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
// Second Day Of Christmas
|
||||||
|
Holiday {
|
||||||
|
name: "Zweiter Weihnachtstag".to_string(),
|
||||||
|
date: HDate::Fixed(December, 26),
|
||||||
|
states: GermanState::list(&[(ANY, &[Activity::after(1990)])]),
|
||||||
|
},
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,12 +217,12 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HolidayChecker,
|
HolidayChecker,
|
||||||
countries::{CountryCode, de::GermanState},
|
countries::{CountryState, de::GermanState},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_number_of_holidays() {
|
fn test_number_of_holidays() {
|
||||||
let checker = HolidayChecker::new(vec![CountryCode::DE]);
|
let checker = HolidayChecker::new();
|
||||||
|
|
||||||
let tests = [
|
let tests = [
|
||||||
(GermanState::BW, 12),
|
(GermanState::BW, 12),
|
||||||
@ -246,7 +244,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
for (state, num) in tests {
|
for (state, num) in tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
checker.number_of_holidays(CountryCode::DE, &state.to_string(), 2025),
|
checker.number_of_holidays(CountryState::DE(state), 2025),
|
||||||
num
|
num
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -254,27 +252,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_holidays() {
|
fn test_holidays() {
|
||||||
let checker = HolidayChecker::new(vec![CountryCode::DE]);
|
let checker = HolidayChecker::new();
|
||||||
let country = CountryCode::DE;
|
let country = CountryState::DE(GermanState::ANY);
|
||||||
let state = GermanState::ANY.to_string();
|
|
||||||
|
|
||||||
// New Years Day
|
// New Years Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 01 - 01))
|
.is_holiday(country, 2025, date!(2025 - 01 - 01))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Epiphany
|
// Epiphany
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 01 - 06))
|
.is_holiday(country, 2025, date!(2025 - 01 - 06))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::BW),
|
||||||
&GermanState::BW.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 01 - 06)
|
date!(2025 - 01 - 06)
|
||||||
)
|
)
|
||||||
@ -283,14 +279,13 @@ mod tests {
|
|||||||
// International Women's Day
|
// International Women's Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 03 - 08))
|
.is_holiday(country, 2025, date!(2025 - 03 - 08))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::BE),
|
||||||
&GermanState::BE.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 03 - 08)
|
date!(2025 - 03 - 08)
|
||||||
)
|
)
|
||||||
@ -299,44 +294,43 @@ mod tests {
|
|||||||
// Good Friday
|
// Good Friday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 04 - 18))
|
.is_holiday(country, 2025, date!(2025 - 04 - 18))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Easter Monday
|
// Easter Monday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 04 - 21))
|
.is_holiday(country, 2025, date!(2025 - 04 - 21))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Labour Day
|
// Labour Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 05 - 01))
|
.is_holiday(country, 2025, date!(2025 - 05 - 01))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Ascension Day
|
// Ascension Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 05 - 29))
|
.is_holiday(country, 2025, date!(2025 - 05 - 29))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Whit Monday
|
// Whit Monday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 06 - 09))
|
.is_holiday(country, 2025, date!(2025 - 06 - 09))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Corpus Christi
|
// Corpus Christi
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 06 - 19))
|
.is_holiday(country, 2025, date!(2025 - 06 - 19))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::BW),
|
||||||
&GermanState::BW.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 06 - 19)
|
date!(2025 - 06 - 19)
|
||||||
)
|
)
|
||||||
@ -345,14 +339,13 @@ mod tests {
|
|||||||
// Assumption Day
|
// Assumption Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 08 - 15))
|
.is_holiday(country, 2025, date!(2025 - 08 - 15))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::BY),
|
||||||
&GermanState::BY.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 08 - 15)
|
date!(2025 - 08 - 15)
|
||||||
)
|
)
|
||||||
@ -361,14 +354,13 @@ mod tests {
|
|||||||
// World Children's Day
|
// World Children's Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 09 - 20))
|
.is_holiday(country, 2025, date!(2025 - 09 - 20))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::TH),
|
||||||
&GermanState::TH.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 09 - 20)
|
date!(2025 - 09 - 20)
|
||||||
)
|
)
|
||||||
@ -377,20 +369,19 @@ mod tests {
|
|||||||
// German Unity Day
|
// German Unity Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 10 - 03))
|
.is_holiday(country, 2025, date!(2025 - 10 - 03))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Reformation Day
|
// Reformation Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 10 - 31))
|
.is_holiday(country, 2025, date!(2025 - 10 - 31))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::HH),
|
||||||
&GermanState::HH.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 10 - 31)
|
date!(2025 - 10 - 31)
|
||||||
)
|
)
|
||||||
@ -399,14 +390,13 @@ mod tests {
|
|||||||
// All Saints Day
|
// All Saints Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 11 - 01))
|
.is_holiday(country, 2025, date!(2025 - 11 - 01))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::BW),
|
||||||
&GermanState::BW.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 11 - 01)
|
date!(2025 - 11 - 01)
|
||||||
)
|
)
|
||||||
@ -415,14 +405,13 @@ mod tests {
|
|||||||
// Repentance And Prayer Day
|
// Repentance And Prayer Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 11 - 19))
|
.is_holiday(country, 2025, date!(2025 - 11 - 19))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::DE(GermanState::SN),
|
||||||
&GermanState::SN.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 11 - 19)
|
date!(2025 - 11 - 19)
|
||||||
)
|
)
|
||||||
@ -431,13 +420,13 @@ mod tests {
|
|||||||
// Christmas Day
|
// Christmas Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 12 - 25))
|
.is_holiday(country, 2025, date!(2025 - 12 - 25))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Second Day Of Christmas
|
// Second Day Of Christmas
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 12 - 26))
|
.is_holiday(country, 2025, date!(2025 - 12 - 26))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
countries::{CountryHolidays, StateList},
|
countries::StateList,
|
||||||
holiday::{Activity, HDate, Holiday},
|
holiday::{Activity, HDate, Holiday},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct FrenchHolidays;
|
pub(crate) struct FrenchHolidays(pub Vec<Holiday<FrenchState>>);
|
||||||
|
|
||||||
#[derive(strum::Display, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, strum::Display, Hash, PartialEq, Eq)]
|
||||||
pub enum FrenchState {
|
pub enum FrenchState {
|
||||||
/// Bas-Rhin
|
/// Bas-Rhin
|
||||||
BasRhin,
|
BasRhin,
|
||||||
@ -26,101 +26,99 @@ impl super::StateList for FrenchState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountryHolidays<FrenchState> for FrenchHolidays {
|
impl FrenchHolidays {
|
||||||
fn new() -> (String, Vec<Holiday>) {
|
pub(crate) fn new() -> Self {
|
||||||
use FrenchState::*;
|
use FrenchState::*;
|
||||||
use time::Month::*;
|
use time::Month::*;
|
||||||
(
|
|
||||||
FrenchState::all_states_identifier(),
|
Self(vec![
|
||||||
vec![
|
// New Years Day
|
||||||
// New Years Day
|
Holiday {
|
||||||
Holiday {
|
name: "Jour de l'an".to_string(),
|
||||||
name: "Jour de l'an".to_string(),
|
date: HDate::Fixed(January, 1),
|
||||||
date: HDate::Fixed(January, 1),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Good Friday
|
||||||
// Good Friday
|
Holiday {
|
||||||
Holiday {
|
name: "Vendredi saint".to_string(),
|
||||||
name: "Vendredi saint".to_string(),
|
date: HDate::Calculated(|year| utils::easter_monday(year) - Duration::days(3)),
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) - Duration::days(3)),
|
states: FrenchState::list(&[
|
||||||
states: FrenchState::list(&[
|
(BasRhin, &[Activity::unlimited()]),
|
||||||
(BasRhin, &[Activity::unlimited()]),
|
(HautRhin, &[Activity::unlimited()]),
|
||||||
(HautRhin, &[Activity::unlimited()]),
|
(Moselle, &[Activity::unlimited()]),
|
||||||
(Moselle, &[Activity::unlimited()]),
|
]),
|
||||||
]),
|
},
|
||||||
},
|
// Easter Monday
|
||||||
// Easter Monday
|
Holiday {
|
||||||
Holiday {
|
name: "Lundi de Pâques".to_string(),
|
||||||
name: "Lundi de Pâques".to_string(),
|
date: HDate::Calculated(utils::easter_monday),
|
||||||
date: HDate::Calculated(utils::easter_monday),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Labour Day
|
||||||
// Labour Day
|
Holiday {
|
||||||
Holiday {
|
name: "Fête du travail".to_string(),
|
||||||
name: "Fête du travail".to_string(),
|
date: HDate::Fixed(May, 1),
|
||||||
date: HDate::Fixed(May, 1),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Victory Day (Second World War)
|
||||||
// Victory Day (Second World War)
|
Holiday {
|
||||||
Holiday {
|
name: "Victoire 1945".to_string(),
|
||||||
name: "Victoire 1945".to_string(),
|
date: HDate::Fixed(May, 8),
|
||||||
date: HDate::Fixed(May, 8),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Ascension Day
|
||||||
// Ascension Day
|
Holiday {
|
||||||
Holiday {
|
name: "Ascension".to_string(),
|
||||||
name: "Ascension".to_string(),
|
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(38)),
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(38)),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Whit Monday
|
||||||
// Whit Monday
|
Holiday {
|
||||||
Holiday {
|
name: "Lundi de Pentecôte".to_string(),
|
||||||
name: "Lundi de Pentecôte".to_string(),
|
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(49)),
|
||||||
date: HDate::Calculated(|year| utils::easter_monday(year) + Duration::days(49)),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// National Day (14th July)
|
||||||
// National Day (14th July)
|
Holiday {
|
||||||
Holiday {
|
name: "Fête nationale".to_string(),
|
||||||
name: "Fête nationale".to_string(),
|
date: HDate::Fixed(July, 14),
|
||||||
date: HDate::Fixed(July, 14),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Assumption Day
|
||||||
// Assumption Day
|
Holiday {
|
||||||
Holiday {
|
name: "Assomption".to_string(),
|
||||||
name: "Assomption".to_string(),
|
date: HDate::Fixed(August, 15),
|
||||||
date: HDate::Fixed(August, 15),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// All Saints Day
|
||||||
// All Saints Day
|
Holiday {
|
||||||
Holiday {
|
name: "Toussaint".to_string(),
|
||||||
name: "Toussaint".to_string(),
|
date: HDate::Fixed(November, 1),
|
||||||
date: HDate::Fixed(November, 1),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Victory Day (First World War)
|
||||||
// Victory Day (First World War)
|
Holiday {
|
||||||
Holiday {
|
name: "Armistice 1918".to_string(),
|
||||||
name: "Armistice 1918".to_string(),
|
date: HDate::Fixed(November, 11),
|
||||||
date: HDate::Fixed(November, 11),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Christmas Day
|
||||||
// Christmas Day
|
Holiday {
|
||||||
Holiday {
|
name: "Jour de Noël".to_string(),
|
||||||
name: "Jour de Noël".to_string(),
|
date: HDate::Fixed(December, 25),
|
||||||
date: HDate::Fixed(December, 25),
|
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
states: FrenchState::list(&[(ANY, &[Activity::unlimited()])]),
|
},
|
||||||
},
|
// Second Day Of Christmas
|
||||||
// Second Day Of Christmas
|
Holiday {
|
||||||
Holiday {
|
name: "Saint Étienne".to_string(),
|
||||||
name: "Saint Étienne".to_string(),
|
date: HDate::Fixed(December, 26),
|
||||||
date: HDate::Fixed(December, 26),
|
states: FrenchState::list(&[
|
||||||
states: FrenchState::list(&[
|
(BasRhin, &[Activity::unlimited()]),
|
||||||
(BasRhin, &[Activity::unlimited()]),
|
(HautRhin, &[Activity::unlimited()]),
|
||||||
(HautRhin, &[Activity::unlimited()]),
|
(Moselle, &[Activity::unlimited()]),
|
||||||
(Moselle, &[Activity::unlimited()]),
|
]),
|
||||||
]),
|
},
|
||||||
},
|
])
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,12 +128,12 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HolidayChecker,
|
HolidayChecker,
|
||||||
countries::{CountryCode, fr::FrenchState},
|
countries::{CountryState, fr::FrenchState},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_number_of_holidays() {
|
fn test_number_of_holidays() {
|
||||||
let checker = HolidayChecker::new(vec![CountryCode::FR]);
|
let checker = HolidayChecker::new();
|
||||||
|
|
||||||
let tests = [
|
let tests = [
|
||||||
(FrenchState::BasRhin, 14),
|
(FrenchState::BasRhin, 14),
|
||||||
@ -145,7 +143,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
for (state, num) in tests {
|
for (state, num) in tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
checker.number_of_holidays(CountryCode::FR, &state.to_string(), 2025),
|
checker.number_of_holidays(CountryState::FR(state), 2025),
|
||||||
num
|
num
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -153,27 +151,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_holidays() {
|
fn test_holidays() {
|
||||||
let checker = HolidayChecker::new(vec![CountryCode::FR]);
|
let checker = HolidayChecker::new();
|
||||||
let country = CountryCode::FR;
|
let country = CountryState::FR(FrenchState::ANY);
|
||||||
let state = FrenchState::ANY.to_string();
|
|
||||||
|
|
||||||
// New Years Day
|
// New Years Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 01 - 01))
|
.is_holiday(country, 2025, date!(2025 - 01 - 01))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Good Friday
|
// Good Friday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 04 - 18))
|
.is_holiday(country, 2025, date!(2025 - 04 - 18))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::FR(FrenchState::BasRhin),
|
||||||
&FrenchState::BasRhin.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 04 - 18)
|
date!(2025 - 04 - 18)
|
||||||
)
|
)
|
||||||
@ -182,74 +178,73 @@ mod tests {
|
|||||||
// Easter Monday
|
// Easter Monday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 04 - 21))
|
.is_holiday(country, 2025, date!(2025 - 04 - 21))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Labour Day
|
// Labour Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 05 - 01))
|
.is_holiday(country, 2025, date!(2025 - 05 - 01))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Victory Day (Second World War)
|
// Victory Day (Second World War)
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 05 - 08))
|
.is_holiday(country, 2025, date!(2025 - 05 - 08))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Ascension Day
|
// Ascension Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 05 - 29))
|
.is_holiday(country, 2025, date!(2025 - 05 - 29))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Whit Monday
|
// Whit Monday
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 06 - 09))
|
.is_holiday(country, 2025, date!(2025 - 06 - 09))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// National Day (14th July)
|
// National Day (14th July)
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 07 - 14))
|
.is_holiday(country, 2025, date!(2025 - 07 - 14))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Assumption Day
|
// Assumption Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 08 - 15))
|
.is_holiday(country, 2025, date!(2025 - 08 - 15))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// All Saints Day
|
// All Saints Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 11 - 01))
|
.is_holiday(country, 2025, date!(2025 - 11 - 01))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Victory Day (First World War)
|
// Victory Day (First World War)
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 11 - 11))
|
.is_holiday(country, 2025, date!(2025 - 11 - 11))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Christmas Day
|
// Christmas Day
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 12 - 25))
|
.is_holiday(country, 2025, date!(2025 - 12 - 25))
|
||||||
.is_some()
|
.is_some()
|
||||||
);
|
);
|
||||||
// Second Day Of Christmas
|
// Second Day Of Christmas
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(country, &state, 2025, date!(2025 - 12 - 26))
|
.is_holiday(country, 2025, date!(2025 - 12 - 26))
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
checker
|
checker
|
||||||
.is_holiday(
|
.is_holiday(
|
||||||
country,
|
CountryState::FR(FrenchState::BasRhin),
|
||||||
&FrenchState::BasRhin.to_string(),
|
|
||||||
2025,
|
2025,
|
||||||
date!(2025 - 12 - 26)
|
date!(2025 - 12 - 26)
|
||||||
)
|
)
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
mod de;
|
pub mod de;
|
||||||
mod fr;
|
pub mod fr;
|
||||||
mod us;
|
pub mod us;
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Display, hash::Hash};
|
use std::{collections::HashMap, fmt::Display, hash::Hash};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
countries::{de::GermanHolidays, fr::FrenchHolidays, us::USHolidays},
|
countries::{
|
||||||
|
de::{GermanHolidays, GermanState},
|
||||||
|
fr::{FrenchHolidays, FrenchState},
|
||||||
|
us::{USHolidays, USState},
|
||||||
|
},
|
||||||
holiday::{Activity, Holiday},
|
holiday::{Activity, Holiday},
|
||||||
};
|
};
|
||||||
|
|
||||||
trait CountryHolidays<T>
|
|
||||||
where
|
|
||||||
T: StateList,
|
|
||||||
{
|
|
||||||
/// Returns a Tuple consisting of the identifier for all states and the holiday days
|
|
||||||
fn new() -> (String, Vec<Holiday>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents country codes for holiday calculations
|
/// Represents country codes for holiday calculations
|
||||||
///
|
///
|
||||||
/// # Variants
|
/// # Variants
|
||||||
@ -27,35 +23,25 @@ where
|
|||||||
/// # Purpose
|
/// # Purpose
|
||||||
/// Provides a type-safe way to specify countries for holiday-related operations
|
/// Provides a type-safe way to specify countries for holiday-related operations
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum CountryCode {
|
pub enum CountryState {
|
||||||
/// Germany
|
/// Germany
|
||||||
DE,
|
DE(GermanState),
|
||||||
|
|
||||||
/// The United States
|
/// The United States
|
||||||
US,
|
US(USState),
|
||||||
|
|
||||||
/// France
|
/// France
|
||||||
FR,
|
FR(FrenchState),
|
||||||
}
|
|
||||||
|
|
||||||
impl CountryCode {
|
|
||||||
pub(crate) fn get_holidays(&self) -> (String, Vec<Holiday>) {
|
|
||||||
match self {
|
|
||||||
CountryCode::DE => GermanHolidays::new(),
|
|
||||||
CountryCode::US => USHolidays::new(),
|
|
||||||
CountryCode::FR => FrenchHolidays::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait StateList
|
pub(crate) trait StateList
|
||||||
where
|
where
|
||||||
Self: Sized + Display + Hash + Eq,
|
Self: Sized + Display + Hash + Eq + Clone + Copy,
|
||||||
{
|
{
|
||||||
fn list(states: &[(Self, &[Activity])]) -> HashMap<String, Vec<Activity>> {
|
fn list(states: &[(Self, &[Activity])]) -> HashMap<Self, Vec<Activity>> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for state in states {
|
for state in states {
|
||||||
map.insert(state.0.to_string(), state.1.to_vec());
|
map.insert(state.0, state.1.to_vec());
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use time::{Date, Month, Weekday};
|
use time::{Date, Month, Weekday};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
countries::{CountryHolidays, StateList},
|
countries::StateList,
|
||||||
holiday::{Activity, HDate, Holiday},
|
holiday::{Activity, HDate, Holiday},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct USHolidays;
|
pub(crate) struct USHolidays(pub Vec<Holiday<USState>>);
|
||||||
|
|
||||||
#[derive(strum::Display, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, strum::Display, Hash, PartialEq, Eq)]
|
||||||
pub enum USState {
|
pub enum USState {
|
||||||
// Northeast
|
// Northeast
|
||||||
Maine,
|
Maine,
|
||||||
@ -82,93 +82,91 @@ impl super::StateList for USState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CountryHolidays<USState> for USHolidays {
|
impl USHolidays {
|
||||||
fn new() -> (String, Vec<Holiday>) {
|
pub(crate) fn new() -> Self {
|
||||||
use USState::*;
|
use USState::*;
|
||||||
use time::Month::*;
|
use time::Month::*;
|
||||||
(
|
|
||||||
USState::all_states_identifier(),
|
|
||||||
vec![
|
|
||||||
// NATIONAL HOLIDAYS
|
|
||||||
|
|
||||||
// New Years Day
|
Self(vec![
|
||||||
Holiday {
|
// NATIONAL HOLIDAYS
|
||||||
name: "New Year's Day".to_string(),
|
|
||||||
date: HDate::Fixed(January, 1),
|
// New Years Day
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "New Year's Day".to_string(),
|
||||||
// Birthday of Martin Luther King, Jr. (Third Monday in January)
|
date: HDate::Fixed(January, 1),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Martin Luther King, Jr. Day".to_string(),
|
},
|
||||||
date: HDate::Calculated(|year| {
|
// Birthday of Martin Luther King, Jr. (Third Monday in January)
|
||||||
utils::nth_weekday_in_month(year, Month::January, Weekday::Monday, 3)
|
Holiday {
|
||||||
}),
|
name: "Martin Luther King, Jr. Day".to_string(),
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
date: HDate::Calculated(|year| {
|
||||||
},
|
utils::nth_weekday_in_month(year, Month::January, Weekday::Monday, 3)
|
||||||
// Inauguration Day (January 20, every 4 years following a presidential election)
|
}),
|
||||||
// Washington's Birthday (Also known as Presidents Day; third Monday in February)
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
Holiday {
|
},
|
||||||
name: "Washington's Birthday".to_string(),
|
// Inauguration Day (January 20, every 4 years following a presidential election)
|
||||||
date: HDate::Calculated(|year| {
|
// Washington's Birthday (Also known as Presidents Day; third Monday in February)
|
||||||
utils::nth_weekday_in_month(year, Month::February, Weekday::Monday, 3)
|
Holiday {
|
||||||
}),
|
name: "Washington's Birthday".to_string(),
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
date: HDate::Calculated(|year| {
|
||||||
},
|
utils::nth_weekday_in_month(year, Month::February, Weekday::Monday, 3)
|
||||||
// Memorial Day (Last Monday in May)
|
}),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Memorial Day".to_string(),
|
},
|
||||||
date: HDate::Calculated(|year| utils::last_monday_in_month(year, Month::May)),
|
// Memorial Day (Last Monday in May)
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "Memorial Day".to_string(),
|
||||||
// Juneteenth National Independence Day (June 19)
|
date: HDate::Calculated(|year| utils::last_monday_in_month(year, Month::May)),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Juneteenth".to_string(),
|
},
|
||||||
date: HDate::Fixed(Month::June, 19),
|
// Juneteenth National Independence Day (June 19)
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "Juneteenth".to_string(),
|
||||||
// Independence Day (July 4)
|
date: HDate::Fixed(Month::June, 19),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Independence Day".to_string(),
|
},
|
||||||
date: HDate::Fixed(Month::July, 4),
|
// Independence Day (July 4)
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "Independence Day".to_string(),
|
||||||
// Labor Day (First Monday in September)
|
date: HDate::Fixed(Month::July, 4),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Labor Day".to_string(),
|
},
|
||||||
date: HDate::Calculated(|year| {
|
// Labor Day (First Monday in September)
|
||||||
utils::nth_weekday_in_month(year, Month::September, Weekday::Monday, 1)
|
Holiday {
|
||||||
}),
|
name: "Labor Day".to_string(),
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
date: HDate::Calculated(|year| {
|
||||||
},
|
utils::nth_weekday_in_month(year, Month::September, Weekday::Monday, 1)
|
||||||
// Columbus Day (Second Monday in October)
|
}),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Columbus Day".to_string(),
|
},
|
||||||
date: HDate::Calculated(|year| {
|
// Columbus Day (Second Monday in October)
|
||||||
utils::nth_weekday_in_month(year, Month::October, Weekday::Monday, 2)
|
Holiday {
|
||||||
}),
|
name: "Columbus Day".to_string(),
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
date: HDate::Calculated(|year| {
|
||||||
},
|
utils::nth_weekday_in_month(year, Month::October, Weekday::Monday, 2)
|
||||||
// Veterans Day (November 11)
|
}),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Veterans Day".to_string(),
|
},
|
||||||
date: HDate::Fixed(Month::November, 11),
|
// Veterans Day (November 11)
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "Veterans Day".to_string(),
|
||||||
// Thanksgiving Day (Fourth Thursday in November)
|
date: HDate::Fixed(Month::November, 11),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Thanksgiving Day".to_string(),
|
},
|
||||||
date: HDate::Calculated(|year| {
|
// Thanksgiving Day (Fourth Thursday in November)
|
||||||
utils::nth_weekday_in_month(year, Month::November, Weekday::Thursday, 4)
|
Holiday {
|
||||||
}),
|
name: "Thanksgiving Day".to_string(),
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
date: HDate::Calculated(|year| {
|
||||||
},
|
utils::nth_weekday_in_month(year, Month::November, Weekday::Thursday, 4)
|
||||||
// Christmas Day (December 25)
|
}),
|
||||||
Holiday {
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
name: "Christmas Day".to_string(),
|
},
|
||||||
date: HDate::Fixed(Month::December, 25),
|
// Christmas Day (December 25)
|
||||||
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
Holiday {
|
||||||
},
|
name: "Christmas Day".to_string(),
|
||||||
],
|
date: HDate::Fixed(Month::December, 25),
|
||||||
)
|
states: USState::list(&[(ANY, &[Activity::unlimited()])]),
|
||||||
|
},
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
use time::{Date, Month};
|
use time::{Date, Month};
|
||||||
|
|
||||||
|
use crate::HolidayDate;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Activity {
|
pub(crate) struct Activity {
|
||||||
unlimited: bool,
|
unlimited: bool,
|
||||||
@ -49,22 +51,49 @@ pub(crate) enum HDate {
|
|||||||
Calculated(fn(i32) -> Date),
|
Calculated(fn(i32) -> Date),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
impl HDate {
|
||||||
pub(crate) struct Holiday {
|
pub(crate) fn to_date(&self, year: i32, name: &str) -> HolidayDate {
|
||||||
pub(crate) name: String,
|
match self {
|
||||||
pub(crate) date: HDate,
|
HDate::Calculated(calc_fn) => {
|
||||||
pub(crate) states: HashMap<String, Vec<Activity>>,
|
// For holidays with calculation function
|
||||||
|
HolidayDate {
|
||||||
|
date: calc_fn(year),
|
||||||
|
name: name.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HDate::Fixed(month, day) => {
|
||||||
|
// For fixed date holidays
|
||||||
|
HolidayDate {
|
||||||
|
date: Date::from_calendar_date(year, *month, *day).unwrap(),
|
||||||
|
name: name.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Holiday {
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) fn is_active(&self, year: i32, all_states_identifier: &str, state: &str) -> bool {
|
pub(crate) struct Holiday<T>
|
||||||
if let Some(all_states) = self.states.get(all_states_identifier) {
|
where
|
||||||
|
T: Hash + Eq,
|
||||||
|
{
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) date: HDate,
|
||||||
|
pub(crate) states: HashMap<T, Vec<Activity>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Holiday<T>
|
||||||
|
where
|
||||||
|
T: Hash + Eq,
|
||||||
|
{
|
||||||
|
pub(crate) fn is_active(&self, year: i32, all_states_identifier: T, state: T) -> bool {
|
||||||
|
if let Some(all_states) = self.states.get(&all_states_identifier) {
|
||||||
// if holiday is valid for all states and is active in that year
|
// if holiday is valid for all states and is active in that year
|
||||||
if all_states.iter().any(|activity| activity.is_active(year)) {
|
if all_states.iter().any(|activity| activity.is_active(year)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(all_states) = self.states.get(state) {
|
if let Some(all_states) = self.states.get(&state) {
|
||||||
// if holiday is only valid for this states and is active in that year
|
// if holiday is only valid for this states and is active in that year
|
||||||
if all_states.iter().any(|activity| activity.is_active(year)) {
|
if all_states.iter().any(|activity| activity.is_active(year)) {
|
||||||
return true;
|
return true;
|
||||||
|
165
src/lib.rs
165
src/lib.rs
@ -1,18 +1,21 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub use time::Date;
|
pub use time::Date;
|
||||||
|
|
||||||
|
use crate::countries::de::{GermanHolidays, GermanState};
|
||||||
|
use crate::countries::fr::{FrenchHolidays, FrenchState};
|
||||||
|
use crate::countries::us::{USHolidays, USState};
|
||||||
use crate::holiday::{HDate, Holiday};
|
use crate::holiday::{HDate, Holiday};
|
||||||
|
|
||||||
mod countries;
|
mod countries;
|
||||||
mod holiday;
|
mod holiday;
|
||||||
pub(crate) mod utils;
|
pub(crate) mod utils;
|
||||||
|
|
||||||
pub use countries::CountryCode;
|
use countries::CountryState;
|
||||||
|
|
||||||
/// A struct to manage and check holidays for different countries
|
/// A struct to manage and check holidays for different countries
|
||||||
pub struct HolidayChecker {
|
pub struct HolidayChecker {
|
||||||
countries: HashMap<CountryCode, (String, Vec<Holiday>)>,
|
de: GermanHolidays,
|
||||||
|
us: USHolidays,
|
||||||
|
fr: FrenchHolidays,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HolidayChecker {
|
impl HolidayChecker {
|
||||||
@ -23,15 +26,12 @@ impl HolidayChecker {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A new HolidayChecker instance with holidays for the specified countries
|
/// A new HolidayChecker instance with holidays for the specified countries
|
||||||
pub fn new(countries: Vec<CountryCode>) -> Self {
|
pub fn new() -> Self {
|
||||||
let mut map = HashMap::new();
|
Self {
|
||||||
|
de: GermanHolidays::new(),
|
||||||
for country in countries {
|
fr: FrenchHolidays::new(),
|
||||||
let holidays = country.get_holidays();
|
us: USHolidays::new(),
|
||||||
map.insert(country, holidays);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { countries: map }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves a list of holidays for a specific country, state, and year
|
/// Retrieves a list of holidays for a specific country, state, and year
|
||||||
@ -43,14 +43,8 @@ impl HolidayChecker {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A vector of HolidayDate for the specified country, state, and year
|
/// A vector of HolidayDate for the specified country, state, and year
|
||||||
pub fn holiday_list(&self, country: CountryCode, state: &str, year: i32) -> Vec<HolidayDate> {
|
pub fn holiday_list(&self, country: CountryState, year: i32) -> Vec<HolidayDate> {
|
||||||
Self::get_years_holidays(
|
self.get_years_holidays(country, year)
|
||||||
self.countries
|
|
||||||
.get(&country)
|
|
||||||
.unwrap_or(&(String::new(), vec![])),
|
|
||||||
year,
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counts the number of holidays for a specific country, state, and year
|
/// Counts the number of holidays for a specific country, state, and year
|
||||||
@ -62,15 +56,8 @@ impl HolidayChecker {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The number of holidays for the specified country, state, and year
|
/// The number of holidays for the specified country, state, and year
|
||||||
pub fn number_of_holidays(&self, country: CountryCode, state: &str, year: i32) -> usize {
|
pub fn number_of_holidays(&self, country: CountryState, year: i32) -> usize {
|
||||||
Self::get_years_holidays(
|
self.get_years_holidays(country, year).len()
|
||||||
self.countries
|
|
||||||
.get(&country)
|
|
||||||
.unwrap_or(&(String::new(), vec![])),
|
|
||||||
year,
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
.len()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a specific date is a holiday for a given country, state, and year
|
/// Checks if a specific date is a holiday for a given country, state, and year
|
||||||
@ -83,26 +70,14 @@ impl HolidayChecker {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// An Option containing the HolidayDate if the date is a holiday, None otherwise
|
/// An Option containing the HolidayDate if the date is a holiday, None otherwise
|
||||||
pub fn is_holiday(
|
pub fn is_holiday(&self, country: CountryState, year: i32, date: Date) -> Option<HolidayDate> {
|
||||||
&self,
|
self.get_years_holidays(country, year)
|
||||||
country: CountryCode,
|
.iter()
|
||||||
state: &str,
|
.find(|holiday| holiday.date == date)
|
||||||
year: i32,
|
.map(|holiday| HolidayDate {
|
||||||
date: Date,
|
name: holiday.name.clone(),
|
||||||
) -> Option<HolidayDate> {
|
date,
|
||||||
Self::get_years_holidays(
|
})
|
||||||
self.countries
|
|
||||||
.get(&country)
|
|
||||||
.unwrap_or(&(String::new(), vec![])),
|
|
||||||
year,
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
.iter()
|
|
||||||
.find(|holiday| holiday.date == date)
|
|
||||||
.map(|holiday| HolidayDate {
|
|
||||||
name: holiday.name.clone(),
|
|
||||||
date,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal method to retrieve holidays for a specific year and state
|
/// Internal method to retrieve holidays for a specific year and state
|
||||||
@ -114,37 +89,71 @@ impl HolidayChecker {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A vector of HolidayDate for the specified year and state
|
/// A vector of HolidayDate for the specified year and state
|
||||||
fn get_years_holidays(
|
fn get_years_holidays(&self, country: CountryState, year: i32) -> Vec<HolidayDate> {
|
||||||
holidays: &(String, Vec<Holiday>),
|
match country {
|
||||||
year: i32,
|
CountryState::DE(state) => self
|
||||||
state: &str,
|
.de
|
||||||
) -> Vec<HolidayDate> {
|
.0
|
||||||
let (all_states_identifier, holidays) = holidays;
|
.iter()
|
||||||
holidays
|
.filter_map(|holiday| {
|
||||||
.iter()
|
// check if holiday is active
|
||||||
.filter_map(|holiday| {
|
if !holiday.is_active(year, GermanState::ANY, state) {
|
||||||
// check if holiday is active
|
return None;
|
||||||
if !holiday.is_active(year, all_states_identifier, state) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
match holiday.date {
|
|
||||||
HDate::Calculated(calc_fn) => {
|
|
||||||
// For holidays with calculation function
|
|
||||||
Some(HolidayDate {
|
|
||||||
date: calc_fn(year),
|
|
||||||
name: holiday.name.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
HDate::Fixed(month, day) => {
|
Some(holiday.date.to_date(year, &holiday.name))
|
||||||
// For fixed date holidays
|
})
|
||||||
Some(HolidayDate {
|
.collect(),
|
||||||
date: Date::from_calendar_date(year, month, day).unwrap(),
|
CountryState::US(state) => self
|
||||||
name: holiday.name.clone(),
|
.us
|
||||||
})
|
.0
|
||||||
|
.iter()
|
||||||
|
.filter_map(|holiday| {
|
||||||
|
// check if holiday is active
|
||||||
|
if !holiday.is_active(year, USState::ANY, state) {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
Some(holiday.date.to_date(year, &holiday.name))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect(),
|
||||||
|
CountryState::FR(state) => self
|
||||||
|
.fr
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.filter_map(|holiday| {
|
||||||
|
// check if holiday is active
|
||||||
|
if !holiday.is_active(year, FrenchState::ANY, state) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(holiday.date.to_date(year, &holiday.name))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// holidays
|
||||||
|
// .iter()
|
||||||
|
// .filter_map(|holiday| {
|
||||||
|
// // check if holiday is active
|
||||||
|
// if !holiday.is_active(year, all_states_identifier, state) {
|
||||||
|
// return None;
|
||||||
|
// }
|
||||||
|
// match holiday.date {
|
||||||
|
// HDate::Calculated(calc_fn) => {
|
||||||
|
// // For holidays with calculation function
|
||||||
|
// Some(HolidayDate {
|
||||||
|
// date: calc_fn(year),
|
||||||
|
// name: holiday.name.clone(),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// HDate::Fixed(month, day) => {
|
||||||
|
// // For fixed date holidays
|
||||||
|
// Some(HolidayDate {
|
||||||
|
// date: Date::from_calendar_date(year, month, day).unwrap(),
|
||||||
|
// name: holiday.name.clone(),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user