use crate::{
Calendar, FixedDate, LastWeekday, Month, NthWeekday, Ordinal, Rule, Weekday, Weekend,
WeekendShift, Year, YearRange,
};
pub const SETTLEMENT: Calendar<'static> = Calendar {
name: "US settlement",
weekend: Weekend::SAT_SUN,
rules: &[
Rule::Fixed(FixedDate::new(Month::Jan, 1).shift(WeekendShift::SatBackSunForward)),
Rule::NthWeekday(
NthWeekday::new(Ordinal::Third, Weekday::Mon, Month::Jan)
.from_year(Year::literal(1983)),
),
Rule::Fixed(
FixedDate::new(Month::Feb, 22)
.shift(WeekendShift::SatBackSunForward)
.years(YearRange::literal_through(1970)),
),
Rule::NthWeekday(
NthWeekday::new(Ordinal::Third, Weekday::Mon, Month::Feb)
.from_year(Year::literal(1971)),
),
Rule::Fixed(
FixedDate::new(Month::May, 30)
.shift(WeekendShift::SatBackSunForward)
.years(YearRange::literal_through(1970)),
),
Rule::LastWeekday(
LastWeekday::new(Weekday::Mon, Month::May).from_year(Year::literal(1971)),
),
Rule::Fixed(
FixedDate::new(Month::Jun, 19)
.shift(WeekendShift::SatBackSunForward)
.from_year(Year::literal(2022)),
),
Rule::Fixed(FixedDate::new(Month::Jul, 4).shift(WeekendShift::SatBackSunForward)),
Rule::NthWeekday(NthWeekday::new(Ordinal::First, Weekday::Mon, Month::Sep)),
Rule::NthWeekday(
NthWeekday::new(Ordinal::Second, Weekday::Mon, Month::Oct)
.from_year(Year::literal(1971)),
),
Rule::Fixed(
FixedDate::new(Month::Nov, 11)
.shift(WeekendShift::SatBackSunForward)
.years(YearRange::literal_through(1970)),
),
Rule::NthWeekday(
NthWeekday::new(Ordinal::Fourth, Weekday::Mon, Month::Oct)
.years(YearRange::literal_between(1971, 1977)),
),
Rule::Fixed(
FixedDate::new(Month::Nov, 11)
.shift(WeekendShift::SatBackSunForward)
.from_year(Year::literal(1978)),
),
Rule::NthWeekday(NthWeekday::new(Ordinal::Fourth, Weekday::Thu, Month::Nov)),
Rule::Fixed(FixedDate::new(Month::Dec, 25).shift(WeekendShift::SatBackSunForward)),
],
};
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use crate::Date;
fn ymd(y: u16, m: Month, d: u8) -> Date {
Date::from_ymd(y, m, d).unwrap()
}
#[test]
fn settlement_holidays_2024() {
assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Jan, 1))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Jan, 15))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Feb, 19))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::May, 27))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Jun, 19))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Jul, 4))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Sep, 2))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Oct, 14))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Nov, 11))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Nov, 28))); assert!(SETTLEMENT.is_holiday(ymd(2024, Month::Dec, 25))); }
#[test]
fn settlement_2024_count_is_eleven() {
let mut count = 0;
let mut d = ymd(2024, Month::Jan, 1);
let last = ymd(2024, Month::Dec, 31);
while d.serial() <= last.serial() {
if SETTLEMENT.is_holiday(d) && !SETTLEMENT.is_weekend(d) {
count += 1;
}
d = d.add_days(1).unwrap();
}
assert_eq!(count, 11);
}
#[test]
fn mlk_effective_from_1983() {
assert!(!SETTLEMENT.is_holiday(ymd(1982, Month::Jan, 18)));
assert!(SETTLEMENT.is_holiday(ymd(1983, Month::Jan, 17)));
assert!(SETTLEMENT.is_holiday(ymd(1985, Month::Jan, 21)));
}
#[test]
fn juneteenth_effective_from_2022() {
assert!(!SETTLEMENT.is_holiday(ymd(2020, Month::Jun, 19)));
assert!(!SETTLEMENT.is_holiday(ymd(2021, Month::Jun, 18)));
assert!(!SETTLEMENT.is_holiday(ymd(2021, Month::Jun, 19))); assert!(SETTLEMENT.is_holiday(ymd(2022, Month::Jun, 20)));
assert!(SETTLEMENT.is_holiday(ymd(2023, Month::Jun, 19)));
}
#[test]
fn washington_pre_1971() {
assert!(SETTLEMENT.is_holiday(ymd(1970, Month::Feb, 23)));
assert!(SETTLEMENT.is_holiday(ymd(1970, Month::Feb, 22))); assert!(SETTLEMENT.is_holiday(ymd(1969, Month::Feb, 21)));
assert!(SETTLEMENT.is_holiday(ymd(1971, Month::Feb, 15)));
assert!(!SETTLEMENT.is_holiday(ymd(1971, Month::Feb, 22)));
}
#[test]
fn memorial_day_pre_1971() {
assert!(SETTLEMENT.is_holiday(ymd(1970, Month::May, 29)));
assert!(SETTLEMENT.is_holiday(ymd(1968, Month::May, 30)));
assert!(SETTLEMENT.is_holiday(ymd(1971, Month::May, 31)));
}
#[test]
fn veterans_day_uniform_monday_act() {
assert!(SETTLEMENT.is_holiday(ymd(1971, Month::Oct, 25)));
assert!(!SETTLEMENT.is_holiday(ymd(1971, Month::Nov, 11)));
assert!(SETTLEMENT.is_holiday(ymd(1977, Month::Oct, 24)));
assert!(!SETTLEMENT.is_holiday(ymd(1977, Month::Nov, 11)));
assert!(SETTLEMENT.is_holiday(ymd(1978, Month::Nov, 10)));
assert!(!SETTLEMENT.is_holiday(ymd(1978, Month::Oct, 23)));
assert!(SETTLEMENT.is_holiday(ymd(1970, Month::Nov, 11)));
}
#[test]
fn columbus_effective_from_1971() {
assert!(!SETTLEMENT.is_holiday(ymd(1970, Month::Oct, 12))); assert!(SETTLEMENT.is_holiday(ymd(1971, Month::Oct, 11))); }
#[test]
fn weekend_shifts() {
assert!(SETTLEMENT.is_holiday(ymd(2026, Month::Jul, 3)));
assert!(SETTLEMENT.is_holiday(ymd(2026, Month::Jul, 4))); assert!(SETTLEMENT.is_holiday(ymd(2022, Month::Dec, 26)));
assert!(SETTLEMENT.is_holiday(ymd(2022, Month::Dec, 25))); assert!(SETTLEMENT.is_holiday(ymd(2021, Month::Dec, 31)));
}
#[test]
fn business_day_navigation_around_independence_day() {
let wed = ymd(2024, Month::Jul, 3);
assert_eq!(
SETTLEMENT.next_business_day(wed),
Some(ymd(2024, Month::Jul, 5)),
);
let fri = ymd(2024, Month::Jul, 5);
assert_eq!(
SETTLEMENT.prev_business_day(fri),
Some(ymd(2024, Month::Jul, 3)),
);
}
}