///|
/// Combine a primary calendar with a fallback calendar.
pub fn Calendar::merge(
primary : Calendar,
secondary : Calendar,
) -> Result[Calendar, CalendarValidationError] {
let holidays = normalize_dates(
concat_dates(primary.holidays, secondary.holidays),
)
let extra_workdays = normalize_dates(
concat_dates(primary.extra_workdays, secondary.extra_workdays),
)
let filtered_holidays = remove_dates(holidays, extra_workdays)
let merged = Calendar::new(
name=primary.name + "+" + secondary.name,
version=primary.version + "+" + secondary.version,
weekend=primary.weekend,
holidays=filtered_holidays,
extra_workdays~,
)
let observed_holidays = normalize_dates(
concat_dates(primary.observed_holidays, secondary.observed_holidays),
)
let merged = {
..merged,
region: primary.region,
source: primary.source,
valid_from: primary.valid_from,
valid_to: primary.valid_to,
versioned: primary.versioned,
observed_holidays,
}
merged.validate().map(fn(_) { merged })
}
///|
fn concat_dates(left : Array[Date], right : Array[Date]) -> Array[Date] {
let result = left.copy()
for date in right {
result.push(date)
}
result
}
///|
fn remove_dates(dates : Array[Date], removed : Array[Date]) -> Array[Date] {
let result = Array::new()
for date in dates {
if !removed.contains(date) {
result.push(date)
}
}
result
}
///|
/// Explain the classification of one date under this calendar.
pub fn Calendar::query(self : Calendar, date : Date) -> CalendarDayInfo {
let kind = if self.extra_workdays.contains(date) {
BusinessDay
} else if self.holidays.contains(date) {
Holiday
} else if self.observed_holidays.contains(date) {
ObservedHoliday
} else if self.weekend.is_weekend(date.weekday()) {
Weekend
} else {
BusinessDay
}
{ date, kind, calendar_name: self.name, calendar_version: self.version }
}
///|
/// Date returned by a calendar query.
pub fn CalendarDayInfo::date(self : CalendarDayInfo) -> Date {
self.date
}
///|
/// Classification returned by a calendar query.
pub fn CalendarDayInfo::kind(self : CalendarDayInfo) -> CalendarDayKind {
self.kind
}
///|
/// Calendar identity returned by a query.
pub fn CalendarDayInfo::calendar_name(self : CalendarDayInfo) -> String {
self.calendar_name
}
///|
/// Calendar version returned by a query.
pub fn CalendarDayInfo::calendar_version(self : CalendarDayInfo) -> String {
self.calendar_version
}