use crate::{
Calendar, Date, EasterOffset, FixedDate, LastWeekday, Month, NthWeekday, OneOff, Ordinal, Rule,
Weekday, Weekend, WeekendShift, Year, YearRange,
};
pub const NYSE: Calendar<'static> = Calendar {
name: "New York stock exchange",
weekend: Weekend::SAT_SUN,
rules: &[
Rule::Fixed(FixedDate::new(Month::Jan, 1).shift(WeekendShift::SunForward)),
Rule::NthWeekday(
NthWeekday::new(Ordinal::Third, Weekday::Mon, Month::Jan)
.from_year(Year::literal(1998)),
),
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::Easter(EasterOffset::good_friday()),
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::Fourth, Weekday::Thu, Month::Nov)),
Rule::Fixed(FixedDate::new(Month::Dec, 25).shift(WeekendShift::SatBackSunForward)),
Rule::Custom(election_day),
Rule::Fixed(
FixedDate::new(Month::Oct, 29)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2012, 2012)),
),
Rule::Fixed(
FixedDate::new(Month::Oct, 30)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2012, 2012)),
),
Rule::Fixed(
FixedDate::new(Month::Sep, 11)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2001, 2001)),
),
Rule::Fixed(
FixedDate::new(Month::Sep, 12)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2001, 2001)),
),
Rule::Fixed(
FixedDate::new(Month::Sep, 13)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2001, 2001)),
),
Rule::Fixed(
FixedDate::new(Month::Sep, 14)
.shift(WeekendShift::None)
.years(YearRange::literal_between(2001, 2001)),
),
Rule::OneOff(OneOff::new(Date::literal(1954, Month::Dec, 24))), Rule::OneOff(OneOff::new(Date::literal(1956, Month::Dec, 24))), Rule::OneOff(OneOff::new(Date::literal(1958, Month::Dec, 26))), Rule::OneOff(OneOff::new(Date::literal(1961, Month::May, 29))), Rule::OneOff(OneOff::new(Date::literal(1963, Month::Nov, 25))), Rule::OneOff(OneOff::new(Date::literal(1965, Month::Dec, 24))), Rule::OneOff(OneOff::new(Date::literal(1968, Month::Apr, 9))), Rule::OneOff(OneOff::new(Date::literal(1968, Month::Jul, 5))), Rule::OneOff(OneOff::new(Date::literal(1969, Month::Feb, 10))), Rule::OneOff(OneOff::new(Date::literal(1969, Month::Mar, 31))), Rule::OneOff(OneOff::new(Date::literal(1969, Month::Jul, 21))), Rule::OneOff(OneOff::new(Date::literal(1972, Month::Dec, 28))), Rule::OneOff(OneOff::new(Date::literal(1973, Month::Jan, 25))), Rule::OneOff(OneOff::new(Date::literal(1977, Month::Jul, 14))), Rule::OneOff(OneOff::new(Date::literal(1985, Month::Sep, 27))), Rule::OneOff(OneOff::new(Date::literal(1994, Month::Apr, 27))), Rule::OneOff(OneOff::new(Date::literal(2004, Month::Jun, 11))), Rule::OneOff(OneOff::new(Date::literal(2007, Month::Jan, 2))), Rule::OneOff(OneOff::new(Date::literal(2018, Month::Dec, 5))), Rule::OneOff(OneOff::new(Date::literal(2025, Month::Jan, 9))), Rule::Custom(paperwork_crisis_1968),
],
};
fn election_day(d: Date) -> bool {
if !matches!(d.month(), Month::Nov) {
return false;
}
if d.day() > 7 {
return false;
}
if !matches!(d.weekday(), Weekday::Tue) {
return false;
}
let y = d.year().get();
y <= 1968 || (y <= 1980 && y.is_multiple_of(4))
}
fn paperwork_crisis_1968(d: Date) -> bool {
d.year().get() == 1968 && d.day_of_year() >= 163 && matches!(d.weekday(), Weekday::Wed)
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
fn ymd(y: u16, m: Month, d: u8) -> Date {
Date::from_ymd(y, m, d).unwrap()
}
#[test]
fn nyse_holidays_2024() {
assert!(NYSE.is_holiday(ymd(2024, Month::Jan, 1)));
assert!(NYSE.is_holiday(ymd(2024, Month::Jan, 15)));
assert!(NYSE.is_holiday(ymd(2024, Month::Feb, 19)));
assert!(NYSE.is_holiday(ymd(2024, Month::Mar, 29))); assert!(NYSE.is_holiday(ymd(2024, Month::May, 27)));
assert!(NYSE.is_holiday(ymd(2024, Month::Jun, 19)));
assert!(NYSE.is_holiday(ymd(2024, Month::Jul, 4)));
assert!(NYSE.is_holiday(ymd(2024, Month::Sep, 2)));
assert!(NYSE.is_holiday(ymd(2024, Month::Nov, 28)));
assert!(NYSE.is_holiday(ymd(2024, Month::Dec, 25)));
}
#[test]
fn nyse_excludes_columbus_and_veterans() {
assert!(!NYSE.is_holiday(ymd(2024, Month::Oct, 14))); assert!(!NYSE.is_holiday(ymd(2024, Month::Nov, 11))); }
#[test]
fn nyse_mlk_effective_from_1998() {
assert!(!NYSE.is_holiday(ymd(1997, Month::Jan, 20)));
assert!(NYSE.is_holiday(ymd(1998, Month::Jan, 19)));
}
#[test]
fn nyse_observes_good_friday() {
assert!(NYSE.is_holiday(ymd(2024, Month::Mar, 29)));
assert!(NYSE.is_holiday(ymd(2025, Month::Apr, 18)));
assert!(NYSE.is_holiday(ymd(2026, Month::Apr, 3)));
}
#[test]
fn nyse_new_year_sun_forward_only() {
assert!(NYSE.is_holiday(ymd(2012, Month::Jan, 2)));
assert!(!NYSE.is_holiday(ymd(2021, Month::Dec, 31)));
}
#[test]
fn nyse_election_days() {
assert!(NYSE.is_holiday(ymd(1968, Month::Nov, 5)));
assert!(NYSE.is_holiday(ymd(1972, Month::Nov, 7)));
assert!(NYSE.is_holiday(ymd(1976, Month::Nov, 2)));
assert!(NYSE.is_holiday(ymd(1980, Month::Nov, 4)));
assert!(!NYSE.is_holiday(ymd(1984, Month::Nov, 6)));
assert!(!NYSE.is_holiday(ymd(1970, Month::Nov, 3)));
}
#[test]
fn nyse_special_closings_sample() {
assert!(NYSE.is_holiday(ymd(2025, Month::Jan, 9))); assert!(NYSE.is_holiday(ymd(2018, Month::Dec, 5))); assert!(NYSE.is_holiday(ymd(2012, Month::Oct, 29))); assert!(NYSE.is_holiday(ymd(2012, Month::Oct, 30))); assert!(!NYSE.is_holiday(ymd(2012, Month::Oct, 31))); assert!(NYSE.is_holiday(ymd(2001, Month::Sep, 11)));
assert!(NYSE.is_holiday(ymd(2001, Month::Sep, 14)));
assert!(!NYSE.is_holiday(ymd(2001, Month::Sep, 17))); assert!(NYSE.is_holiday(ymd(1977, Month::Jul, 14))); assert!(NYSE.is_holiday(ymd(1963, Month::Nov, 25))); }
#[test]
fn nyse_paperwork_crisis_1968() {
assert!(NYSE.is_holiday(ymd(1968, Month::Jun, 12)));
assert!(!NYSE.is_holiday(ymd(1968, Month::Jun, 11)));
assert!(NYSE.is_holiday(ymd(1968, Month::Jun, 19)));
assert!(NYSE.is_holiday(ymd(1968, Month::Nov, 27)));
assert!(!NYSE.is_holiday(ymd(1969, Month::Jun, 11))); assert!(!NYSE.is_holiday(ymd(1969, Month::Jun, 18))); }
#[test]
fn nyse_christmas_eve_closures() {
assert!(NYSE.is_holiday(ymd(1954, Month::Dec, 24)));
assert!(NYSE.is_holiday(ymd(1956, Month::Dec, 24)));
assert!(NYSE.is_holiday(ymd(1965, Month::Dec, 24)));
assert!(!NYSE.is_holiday(ymd(1955, Month::Dec, 24)));
assert!(!NYSE.is_holiday(ymd(2024, Month::Dec, 24)));
}
}