mod easter;
mod target;
pub use easter::western_easter;
pub use target::{TargetCalendar, TargetCoverage, TargetPolicy};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error as StdError;
use std::fmt;
use std::str::FromStr;
use crate::error::IdentifierError;
use crate::identifier::{Entry, Identifiers};
use crate::time::{Date, DateError, Period, TimeUnit, Weekday};
const ALL_WEEKDAYS: u8 = 0x7f;
const WEEKEND: u8 = (1 << 5) | (1 << 6);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[expect(
clippy::exhaustive_enums,
reason = "FS-CAL defines exactly two joint rules"
)]
pub enum JointRule {
JoinHolidays,
JoinBusinessDays,
}
impl JointRule {
pub const ALL: [Self; 2] = [Self::JoinHolidays, Self::JoinBusinessDays];
#[must_use]
pub const fn canonical_identifier(self) -> &'static str {
match self {
Self::JoinHolidays => "JoinHolidays",
Self::JoinBusinessDays => "JoinBusinessDays",
}
}
}
impl fmt::Display for JointRule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_identifier())
}
}
impl FromStr for JointRule {
type Err = IdentifierError;
fn from_str(text: &str) -> Result<Self, Self::Err> {
JOINT_IDENTIFIERS.parse(text)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[expect(
clippy::exhaustive_enums,
reason = "FS-BDC defines exactly these seven conventions"
)]
pub enum BusinessDayConvention {
Following,
ModifiedFollowing,
Preceding,
ModifiedPreceding,
Unadjusted,
HalfMonthModifiedFollowing,
Nearest,
}
impl BusinessDayConvention {
pub const ALL: [Self; 7] = [
Self::Following,
Self::ModifiedFollowing,
Self::Preceding,
Self::ModifiedPreceding,
Self::Unadjusted,
Self::HalfMonthModifiedFollowing,
Self::Nearest,
];
#[must_use]
pub const fn canonical_identifier(self) -> &'static str {
match self {
Self::Following => "Following",
Self::ModifiedFollowing => "ModifiedFollowing",
Self::Preceding => "Preceding",
Self::ModifiedPreceding => "ModifiedPreceding",
Self::Unadjusted => "Unadjusted",
Self::HalfMonthModifiedFollowing => "HalfMonthModifiedFollowing",
Self::Nearest => "Nearest",
}
}
}
impl fmt::Display for BusinessDayConvention {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_identifier())
}
}
impl FromStr for BusinessDayConvention {
type Err = IdentifierError;
fn from_str(text: &str) -> Result<Self, Self::Err> {
BDC_IDENTIFIERS.parse(text)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[expect(
clippy::exhaustive_enums,
reason = "end-of-month preservation has exactly two explicit choices"
)]
pub enum EndOfMonth {
Preserve,
Ignore,
}
impl EndOfMonth {
pub const ALL: [Self; 2] = [Self::Preserve, Self::Ignore];
#[must_use]
pub const fn canonical_identifier(self) -> &'static str {
match self {
Self::Preserve => "Preserve",
Self::Ignore => "Ignore",
}
}
}
impl fmt::Display for EndOfMonth {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_identifier())
}
}
impl FromStr for EndOfMonth {
type Err = IdentifierError;
fn from_str(text: &str) -> Result<Self, Self::Err> {
END_OF_MONTH_IDENTIFIERS.parse(text)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[expect(
clippy::exhaustive_enums,
reason = "an endpoint is either included or excluded"
)]
pub enum EndpointInclusion {
Include,
Exclude,
}
impl EndpointInclusion {
pub const ALL: [Self; 2] = [Self::Include, Self::Exclude];
#[must_use]
pub const fn canonical_identifier(self) -> &'static str {
match self {
Self::Include => "Include",
Self::Exclude => "Exclude",
}
}
}
impl fmt::Display for EndpointInclusion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_identifier())
}
}
impl FromStr for EndpointInclusion {
type Err = IdentifierError;
fn from_str(text: &str) -> Result<Self, Self::Err> {
ENDPOINT_INCLUSION_IDENTIFIERS.parse(text)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[expect(
clippy::exhaustive_enums,
reason = "weekend-classified holidays are either included or excluded"
)]
pub enum HolidayWeekendInclusion {
Include,
Exclude,
}
impl HolidayWeekendInclusion {
pub const ALL: [Self; 2] = [Self::Include, Self::Exclude];
#[must_use]
pub const fn canonical_identifier(self) -> &'static str {
match self {
Self::Include => "Include",
Self::Exclude => "Exclude",
}
}
}
impl fmt::Display for HolidayWeekendInclusion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.canonical_identifier())
}
}
impl FromStr for HolidayWeekendInclusion {
type Err = IdentifierError;
fn from_str(text: &str) -> Result<Self, Self::Err> {
HOLIDAY_WEEKEND_IDENTIFIERS.parse(text)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Calendar {
definition: Definition,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Definition {
kind: Kind,
overrides: BTreeMap<Date, bool>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Kind {
Base {
weekends: u8,
},
Target {
allow_projection: bool,
},
Joint {
members: Vec<Definition>,
join_holidays: bool,
},
}
impl Definition {
fn base(weekends: u8) -> Self {
Self {
kind: Kind::Base { weekends },
overrides: BTreeMap::new(),
}
}
fn baseline(&self, date: Date) -> bool {
match &self.kind {
Kind::Base { weekends } => weekends & weekday_bit(date.weekday()) == 0,
Kind::Target { .. } => target::target_business(date),
Kind::Joint {
members,
join_holidays,
} => {
if *join_holidays {
members.iter().all(|member| member.business(date))
} else {
members.iter().any(|member| member.business(date))
}
}
}
}
fn business(&self, date: Date) -> bool {
self.overrides
.get(&date)
.copied()
.unwrap_or_else(|| self.baseline(date))
}
fn weekend_mask(&self) -> u8 {
match &self.kind {
Kind::Base { weekends } => *weekends,
Kind::Target { .. } => WEEKEND,
Kind::Joint {
members,
join_holidays,
} => {
if *join_holidays {
members
.iter()
.fold(0, |mask, member| mask | member.weekend_mask())
} else {
members
.iter()
.fold(ALL_WEEKDAYS, |mask, member| mask & member.weekend_mask())
}
}
}
}
fn has_business_override(&self) -> bool {
self.overrides.values().any(|business| *business)
|| match &self.kind {
Kind::Base { .. } | Kind::Target { .. } => false,
Kind::Joint { members, .. } => members.iter().any(Self::has_business_override),
}
}
fn depth(&self) -> u32 {
match &self.kind {
Kind::Base { .. } | Kind::Target { .. } => 0,
Kind::Joint { members, .. } => 1 + members.iter().map(Self::depth).max().unwrap_or(0),
}
}
fn override_date(&mut self, date: Date, business: bool) {
if self.baseline(date) == business {
self.overrides.remove(&date);
} else {
self.overrides.insert(date, business);
}
}
fn validate_date(&self, date: Date) -> Result<(), CalendarError> {
match &self.kind {
Kind::Base { .. } => Ok(()),
Kind::Target { allow_projection } => target::validate_date(date, *allow_projection),
Kind::Joint { members, .. } => {
for member in members {
member.validate_date(date)?;
}
Ok(())
}
}
}
fn collect_weekday_exceptions(&self, dates: &mut BTreeSet<Date>) -> bool {
dates.extend(self.overrides.keys().copied());
match &self.kind {
Kind::Base { .. } => true,
Kind::Target { .. } => false,
Kind::Joint { members, .. } => members
.iter()
.all(|member| member.collect_weekday_exceptions(dates)),
}
}
}
impl Calendar {
fn target_rules(allow_projection: bool) -> Self {
Self {
definition: Definition {
kind: Kind::Target { allow_projection },
overrides: BTreeMap::new(),
},
}
}
fn validate_date(&self, date: Date) -> Result<(), CalendarError> {
self.definition.validate_date(date)
}
fn checked_business(&self, date: Date) -> Result<bool, CalendarError> {
self.validate_date(date)?;
Ok(self.is_business_day(date))
}
pub const MAX_CONSECUTIVE_HOLIDAYS: u32 = 366;
pub const MAX_JOINT_DEPTH: u32 = 64;
#[doc(alias = "NullCalendar")]
#[must_use]
pub fn null() -> Self {
Self {
definition: Definition::base(0),
}
}
#[doc(alias = "WeekendsOnly")]
#[must_use]
pub fn weekends_only() -> Self {
Self {
definition: Definition::base(WEEKEND),
}
}
#[must_use]
pub fn custom(
weekends: impl IntoIterator<Item = Weekday>,
holidays: impl IntoIterator<Item = Date>,
) -> Self {
let mask = weekends
.into_iter()
.fold(0, |mask, weekday| mask | weekday_bit(weekday));
let mut definition = Definition::base(mask);
for date in holidays {
definition.override_date(date, false);
}
Self { definition }
}
#[doc(alias = "JointCalendar")]
pub fn joint(calendars: Vec<Self>, rule: JointRule) -> Result<Self, CalendarError> {
if calendars.is_empty() {
return Err(CalendarError::EmptyJoint);
}
let join_holidays = rule == JointRule::JoinHolidays;
let mut members = Vec::new();
for calendar in calendars {
let definition = calendar.definition;
match definition {
Definition {
kind:
Kind::Joint {
members: nested,
join_holidays: nested_rule,
},
overrides,
} if overrides.is_empty() && nested_rule == join_holidays => members.extend(nested),
definition => members.push(definition),
}
}
members.sort_unstable();
members.dedup();
let depth = 1 + members.iter().map(Definition::depth).max().unwrap_or(0);
if depth > Self::MAX_JOINT_DEPTH {
return Err(CalendarError::NestingLimit {
depth,
maximum: Self::MAX_JOINT_DEPTH,
});
}
Ok(Self {
definition: Definition {
kind: Kind::Joint {
members,
join_holidays,
},
overrides: BTreeMap::new(),
},
})
}
#[must_use]
pub fn with_holiday(&self, date: Date) -> Self {
let mut result = self.clone();
result.definition.override_date(date, false);
result
}
#[must_use]
pub fn without_holiday(&self, date: Date) -> Self {
let mut result = self.clone();
result.definition.override_date(date, true);
result
}
#[must_use]
pub fn is_weekend(&self, date: Date) -> bool {
self.is_weekend_weekday(date.weekday())
}
#[must_use]
pub fn is_weekend_weekday(&self, weekday: Weekday) -> bool {
self.definition.weekend_mask() & weekday_bit(weekday) != 0
}
#[must_use]
pub fn is_business_day(&self, date: Date) -> bool {
self.definition.business(date)
}
#[must_use]
pub fn is_holiday(&self, date: Date) -> bool {
!self.is_business_day(date)
}
pub fn adjust(
&self,
date: Date,
convention: BusinessDayConvention,
) -> Result<Date, CalendarError> {
self.validate_date(date)?;
if convention == BusinessDayConvention::Unadjusted || self.checked_business(date)? {
return Ok(date);
}
self.require_possible_business_day()?;
match convention {
BusinessDayConvention::Unadjusted => Ok(date),
BusinessDayConvention::Following => self.search(date, 1),
BusinessDayConvention::Preceding => self.search(date, -1),
BusinessDayConvention::ModifiedFollowing => self.modified(date, 1, None),
BusinessDayConvention::ModifiedPreceding => self.modified(date, -1, None),
BusinessDayConvention::HalfMonthModifiedFollowing => {
self.modified(date, 1, if date.day() <= 15 { Some(15) } else { None })
}
BusinessDayConvention::Nearest => {
let forward = self.search(date, 1);
let backward = self.search(date, -1);
match (forward, backward) {
(Ok(forward), Ok(backward)) => {
if forward.days_since(date) <= date.days_since(backward) {
Ok(forward)
} else {
Ok(backward)
}
}
(Ok(_), Err(error)) | (Err(error), Ok(_))
if matches!(
error,
CalendarError::OutsideValidity { .. }
| CalendarError::UnverifiedCoverage { .. }
) =>
{
Err(error)
}
(Ok(result), Err(_)) | (Err(_), Ok(result)) => Ok(result),
(Err(forward), Err(backward)) => {
if matches!(
forward,
CalendarError::OutsideValidity { .. }
| CalendarError::UnverifiedCoverage { .. }
) {
Err(forward)
} else if matches!(
backward,
CalendarError::Date(_)
| CalendarError::OutsideValidity { .. }
| CalendarError::UnverifiedCoverage { .. }
) {
Err(backward)
} else {
Err(forward)
}
}
}
}
}
}
pub fn add_business_days(&self, date: Date, count: i32) -> Result<Date, CalendarError> {
self.validate_date(date)?;
if count == 0 {
return Ok(date);
}
self.require_possible_business_day()?;
date.checked_add_days(i64::from(count))?;
if matches!(self.definition.kind, Kind::Base { weekends: 0 })
&& self.definition.overrides.is_empty()
{
return Ok(date.checked_add_days(i64::from(count))?);
}
let direction = if count > 0 { 1 } else { -1 };
let mut remaining = i64::from(count).abs();
let mut current = date;
let mut rejected = 0;
let mut search_start = date;
while remaining > 0 {
current = current.checked_add_days(i64::from(direction))?;
if self.checked_business(current)? {
remaining -= 1;
rejected = 0;
search_start = current;
} else {
rejected += 1;
if rejected == Self::MAX_CONSECUTIVE_HOLIDAYS {
return Err(CalendarError::SearchLimit {
start: search_start,
direction,
rejected,
});
}
}
}
Ok(current)
}
pub fn advance(
&self,
date: Date,
period: Period,
convention: BusinessDayConvention,
end_of_month: EndOfMonth,
) -> Result<Date, CalendarError> {
self.validate_date(date)?;
if period.length() == 0 {
return self.adjust(date, convention);
}
match period.unit() {
TimeUnit::Days => self.add_business_days(date, period.length()),
TimeUnit::Weeks => self.adjust(
date.checked_add_weeks(i64::from(period.length()))?,
convention,
),
TimeUnit::Months | TimeUnit::Years => {
let target = date.checked_add_period(period)?;
self.validate_date(target)?;
if end_of_month == EndOfMonth::Preserve {
if convention == BusinessDayConvention::Unadjusted {
if date.is_end_of_month() {
let result = target.last_day_of_month();
self.validate_date(result)?;
return Ok(result);
}
} else if self.is_end_of_month(date)? {
return self.end_of_month(target);
}
}
self.adjust(target, convention)
}
}
}
pub fn start_of_month(&self, date: Date) -> Result<Date, CalendarError> {
self.validate_date(date)?;
self.search_in_month(date.first_day_of_month(), 1, None)
.map_err(|error| match error {
CalendarError::NoBusinessDayInMonth { .. } => {
CalendarError::NoBusinessDayInMonth { date }
}
error => error,
})
}
pub fn end_of_month(&self, date: Date) -> Result<Date, CalendarError> {
self.validate_date(date)?;
self.search_in_month(date.last_day_of_month(), -1, None)
.map_err(|error| match error {
CalendarError::NoBusinessDayInMonth { .. } => {
CalendarError::NoBusinessDayInMonth { date }
}
error => error,
})
}
pub fn is_start_of_month(&self, date: Date) -> Result<bool, CalendarError> {
Ok(date <= self.start_of_month(date)?)
}
pub fn is_end_of_month(&self, date: Date) -> Result<bool, CalendarError> {
Ok(date >= self.end_of_month(date)?)
}
#[must_use]
pub fn business_days_between(
&self,
start: Date,
end: Date,
include_start: EndpointInclusion,
include_end: EndpointInclusion,
) -> i32 {
if start == end {
return i32::from(
include_start == EndpointInclusion::Include
&& include_end == EndpointInclusion::Include
&& self.is_business_day(start),
);
}
if start > end {
return -self.business_days_between(end, start, include_end, include_start);
}
let include_start = include_start == EndpointInclusion::Include;
let include_end = include_end == EndpointInclusion::Include;
let mut exceptions = BTreeSet::new();
if self.definition.collect_weekday_exceptions(&mut exceptions) {
let mask = self.definition.weekend_mask();
let span = end.days_since(start) + 1;
let whole_weeks = span / 7;
let remainder = span % 7;
let first_weekday = i64::from(start.weekday().number_from_monday());
let mut count = 0;
for weekday in Weekday::ALL {
if mask & weekday_bit(weekday) == 0 {
let offset =
(i64::from(weekday.number_from_monday()) - first_weekday).rem_euclid(7);
count += whole_weeks + i32::from(offset < i64::from(remainder));
}
}
let baseline_business = |date: Date| mask & weekday_bit(date.weekday()) == 0;
count -= i32::from(!include_start && baseline_business(start));
count -= i32::from(!include_end && baseline_business(end));
for &date in exceptions.range(start..=end) {
if (date != start || include_start) && (date != end || include_end) {
count +=
i32::from(self.is_business_day(date)) - i32::from(baseline_business(date));
}
}
return count;
}
let span = end.days_since(start);
let first = i32::from(!include_start);
let last = span - i32::from(!include_end);
let mut count = 0;
for offset in first..=last {
if let Ok(date) = start.checked_add_days(i64::from(offset)) {
count += i32::from(self.is_business_day(date));
}
}
count
}
pub fn holiday_list(
&self,
start: Date,
end: Date,
include_weekends: HolidayWeekendInclusion,
) -> Result<Vec<Date>, CalendarError> {
self.date_list(start, end, |date| {
self.is_holiday(date)
&& (include_weekends == HolidayWeekendInclusion::Include || !self.is_weekend(date))
})
}
pub fn business_day_list(&self, start: Date, end: Date) -> Result<Vec<Date>, CalendarError> {
self.date_list(start, end, |date| self.is_business_day(date))
}
fn date_list(
&self,
start: Date,
end: Date,
include: impl Fn(Date) -> bool,
) -> Result<Vec<Date>, CalendarError> {
if start > end {
return Err(CalendarError::InvalidRange { start, end });
}
let mut result = Vec::new();
for offset in 0..=end.days_since(start) {
let date = start.checked_add_days(i64::from(offset))?;
if include(date) {
result.push(date);
}
}
Ok(result)
}
fn require_possible_business_day(&self) -> Result<(), CalendarError> {
if self.definition.weekend_mask() == ALL_WEEKDAYS
&& !self.definition.has_business_override()
{
Err(CalendarError::NoBusinessWeekday)
} else {
Ok(())
}
}
fn search(&self, date: Date, direction: i32) -> Result<Date, CalendarError> {
self.require_possible_business_day()?;
let mut current = date;
for rejected in 0..Self::MAX_CONSECUTIVE_HOLIDAYS {
if self.checked_business(current)? {
return Ok(current);
}
if rejected + 1 == Self::MAX_CONSECUTIVE_HOLIDAYS {
return Err(CalendarError::SearchLimit {
start: date,
direction,
rejected: rejected + 1,
});
}
current = current.checked_add_days(i64::from(direction))?;
}
Err(CalendarError::SearchLimit {
start: date,
direction,
rejected: Self::MAX_CONSECUTIVE_HOLIDAYS,
})
}
fn search_in_month(
&self,
date: Date,
direction: i32,
last_forward_day: Option<u32>,
) -> Result<Date, CalendarError> {
let mut current = date;
loop {
if self.checked_business(current)? {
return Ok(current);
}
let next = current.checked_add_days(i64::from(direction));
match next {
Ok(next)
if next.year() == date.year()
&& next.month() == date.month()
&& last_forward_day.is_none_or(|limit| next.day() <= limit) =>
{
current = next
}
_ => return Err(CalendarError::NoBusinessDayInMonth { date }),
}
}
}
fn modified(
&self,
date: Date,
direction: i32,
last_forward_day: Option<u32>,
) -> Result<Date, CalendarError> {
match self.search_in_month(date, direction, last_forward_day) {
Err(CalendarError::NoBusinessDayInMonth { .. }) => {
self.search_in_month(date, -direction, None)
}
result => result,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum CalendarError {
Date(DateError),
#[non_exhaustive]
OutsideValidity {
date: Date,
},
#[non_exhaustive]
UnverifiedCoverage {
date: Date,
},
NoBusinessWeekday,
EmptyJoint,
#[non_exhaustive]
SearchLimit {
start: Date,
direction: i32,
rejected: u32,
},
#[non_exhaustive]
NoBusinessDayInMonth {
date: Date,
},
#[non_exhaustive]
InvalidRange {
start: Date,
end: Date,
},
#[non_exhaustive]
NestingLimit {
depth: u32,
maximum: u32,
},
}
impl CalendarError {
#[must_use]
pub const fn kind(&self) -> &'static str {
match self {
Self::Date(_) => "calendar.date",
Self::OutsideValidity { .. } => "calendar.outside_validity",
Self::UnverifiedCoverage { .. } => "calendar.unverified_coverage",
Self::NoBusinessWeekday => "calendar.no_business_weekday",
Self::EmptyJoint => "calendar.empty_joint",
Self::SearchLimit { .. } => "calendar.search_limit",
Self::NoBusinessDayInMonth { .. } => "calendar.no_business_day_in_month",
Self::InvalidRange { .. } => "calendar.invalid_range",
Self::NestingLimit { .. } => "calendar.nesting_limit",
}
}
}
impl fmt::Display for CalendarError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Date(error) => fmt::Display::fmt(error, f),
Self::OutsideValidity { date } => {
write!(f, "TARGET market rules are not valid on {date}")
}
Self::UnverifiedCoverage { date } => write!(
f,
"TARGET source coverage is not verified on {date}; projection requires an explicit policy"
),
Self::NoBusinessWeekday => {
f.write_str("calendar has no business weekday or explicit business-day override")
}
Self::EmptyJoint => f.write_str("a joint calendar must have at least one member"),
Self::SearchLimit {
start,
direction,
rejected,
} => write!(
f,
"business-day search from {start} in direction {direction} rejected {rejected} consecutive dates"
),
Self::NoBusinessDayInMonth { date } => {
write!(f, "no eligible business day in the month of {date}")
}
Self::InvalidRange { start, end } => {
write!(f, "list range starts at {start}, after its end {end}")
}
Self::NestingLimit { depth, maximum } => {
write!(f, "joint calendar depth {depth} exceeds maximum {maximum}")
}
}
}
}
impl StdError for CalendarError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Date(error) => Some(error),
_ => None,
}
}
}
impl From<DateError> for CalendarError {
fn from(error: DateError) -> Self {
Self::Date(error)
}
}
const fn weekday_bit(weekday: Weekday) -> u8 {
1 << (weekday.number_from_monday() - 1)
}
const JOINT_IDENTIFIERS: Identifiers<JointRule> = Identifiers::new(
"joint rule",
&[
Entry {
value: JointRule::JoinHolidays,
canonical: "JoinHolidays",
aliases: &[],
},
Entry {
value: JointRule::JoinBusinessDays,
canonical: "JoinBusinessDays",
aliases: &[],
},
],
&[],
);
const END_OF_MONTH_IDENTIFIERS: Identifiers<EndOfMonth> = Identifiers::new(
"end-of-month option",
&[
Entry {
value: EndOfMonth::Preserve,
canonical: "Preserve",
aliases: &[],
},
Entry {
value: EndOfMonth::Ignore,
canonical: "Ignore",
aliases: &[],
},
],
&[],
);
const ENDPOINT_INCLUSION_IDENTIFIERS: Identifiers<EndpointInclusion> = Identifiers::new(
"endpoint inclusion",
&[
Entry {
value: EndpointInclusion::Include,
canonical: "Include",
aliases: &[],
},
Entry {
value: EndpointInclusion::Exclude,
canonical: "Exclude",
aliases: &[],
},
],
&[],
);
const HOLIDAY_WEEKEND_IDENTIFIERS: Identifiers<HolidayWeekendInclusion> = Identifiers::new(
"holiday weekend inclusion",
&[
Entry {
value: HolidayWeekendInclusion::Include,
canonical: "Include",
aliases: &[],
},
Entry {
value: HolidayWeekendInclusion::Exclude,
canonical: "Exclude",
aliases: &[],
},
],
&[],
);
const BDC_IDENTIFIERS: Identifiers<BusinessDayConvention> = Identifiers::new(
"business-day convention",
&[
Entry {
value: BusinessDayConvention::Following,
canonical: "Following",
aliases: &[],
},
Entry {
value: BusinessDayConvention::ModifiedFollowing,
canonical: "ModifiedFollowing",
aliases: &[],
},
Entry {
value: BusinessDayConvention::Preceding,
canonical: "Preceding",
aliases: &[],
},
Entry {
value: BusinessDayConvention::ModifiedPreceding,
canonical: "ModifiedPreceding",
aliases: &[],
},
Entry {
value: BusinessDayConvention::Unadjusted,
canonical: "Unadjusted",
aliases: &[],
},
Entry {
value: BusinessDayConvention::HalfMonthModifiedFollowing,
canonical: "HalfMonthModifiedFollowing",
aliases: &[],
},
Entry {
value: BusinessDayConvention::Nearest,
canonical: "Nearest",
aliases: &[],
},
],
&[],
);