Business Day Calendar Reference¶
lclang.utils.calendar is an async-first, three-state calendar algebra. A
calendar maps every datetime.date to DayType.BusinessDay, DayType.Holiday,
or DayType.Undefined. Undefined means that the calendar has no opinion; it is
not another spelling for holiday.
Identity, dates, and failures¶
Every BDCalendar has one immutable CalendarID. Equality, hashing, manager
caches, dependency sets, and canonical compositions use that ID. Configuration
collections are detached and read-only. Classification and mapping caches are
mutable implementation snapshots exposed through read-only views.
get_day_type(d) classifies a date. next_bd(d) and prev_bd(d) are strict;
this_or_next_bd(d) and this_or_prev_bd(d) retain d when it is already a
business day. Functional and year-batch traversal searches at most
MAX_BUSINESS_DAY_GAP_DAYS (1,000) days. gen_year(year) accepts years 1
through 9999 and may omit undefined dates.
DateOperationOutOfScopeExceptionretainssource_dateandsource_calendar.CalendarCannotLoadExceptionretains the requestedcalendar_id.CalendarLogicExceptionretains the failingcalendar_idand chains the original traceback.UnappliedCalendarOperationExceptionreports a mapping without a source.
These are ordinary Python exceptions. Through LCL, the evaluator wraps them in
its normal source-aware LclEvaluationError.
Storage strategies¶
HardcodedBDCalendar stores an immutable explicit mapping; missing dates are
undefined. FunctionalBDCalendar supplies bounded traversal around an abstract
per-date classifier. ForwardStepBDCalendar discovers a sparse increasing
business-date sequence from first_bd. YearBatchBDCalendar loads and caches
one validated mapping per year. Custom subclasses implement the public abstract
method named by their strategy and honor the cache and failure contract.
Calendar algebra¶
| Method | Operator | Meaning |
|---|---|---|
union |
+ |
Business wins, then holiday, then undefined. |
intersect |
& |
All-undefined stays undefined; any holiday vetoes. |
minus |
- |
Matching subtrahend business days become holidays. |
fallback |
>> |
Return the first non-undefined value in order. |
revert |
~ |
Exchange business and holiday; retain undefined. |
Union, intersection, and subtraction operands are sorted and deduplicated by
calendar ID. Fallback order is significant. business_days() removes holiday
classifications; holidays() removes business classifications. Repeated
filters are idempotent, and double reversal returns the original calendar.
Builtins and factories¶
Total singletons are ALL_DAYS, ALL_WEEKDAYS, MONDAYS through SUNDAYS,
BEGIN_OF_MONTHS, END_OF_MONTHS, BEGIN_OF_YEARS, and END_OF_YEARS.
Nonmatching dates are holidays. BUILTIN_CALENDARS maps every singleton ID to
that exact object.
at(*dates) accepts date, strict YYYYMMDD strings, or padded integers.
nth_day_of_month(*n) and nth_business_day_of_month(calendar, *n) accept
-31..-1 and 1..31; negative values count backward. range_start_days and
range_end_days select boundaries of contiguous business ranges.
def_functional_calendar accepts sync or async classifier and dependency
callables and validates their results.
Date mappings¶
map_this_or_next(calendar=None), map_this_or_prev(calendar=None), and
shift_n_days(n, calendar=None) create immutable BDCalendarMapping chains.
Omitting the operation calendar binds it to the source. A standalone chain may
use SELF_CALENDAR until await mapping.apply(calendar) supplies the source.
Each primitive moves at most MAX_BUSINESS_DAY_SHIFT_DAYS (100) calendar days;
a chain may accumulate more. Zero shift has this-or-next semantics. Positive
and negative values use strict next and previous dates. map_date_reverse
returns the inclusive monotonic source range mapped to a target.
await mapping.as_calendar() creates a CalendarMapBDCalendar. A target is
business only when at least one source business date maps to it.
Named loading and retirement¶
BuiltinBDCalendarLoader returns singleton builtins.
FileSystemHardcodedBDCalendarLoader looks for
<calendar-id>.calendar.json beneath its configured directory:
{
"business_days": ["20240102", "20240103"],
"holidays": ["20240101"]
}
The UTF-8 JSON object has exactly those arrays. Dates are unique strict strings
and cannot overlap. Malformed, unsafe, or non-file matches raise
CalendarCannotLoadException; absence lets the next loader try.
BDCalendarManager.use_calendar shares one in-flight load per ID and event
loop, shields waiter cancellation, caches only success, detects dependency
cycles, and validates returned IDs. Calendar fallbacks are uncached; ID
fallbacks recurse. retire_calendar removes a cached calendar and recursive
dependants, optionally installing a replacement.
use_calendar_manager(loaders) appends a builtin loader last when needed.
use_file_system_hardcoded_calendar_loader(path) accepts Path or text.
LCL exposure¶
Canonical Frames expose the manager helpers and a read-only calendars
namespace from LCL_BUILTINS. It contains DayType, all factories, and every
singleton. Use calendars.DayType.BusinessDay. Standard iter, text, data,
and json namespaces also live in LCL_BUILTINS; LCL_ROOT contains only
definition-scoped lhs().
See errors and diagnostic codes for exception fields, specific
codes, cause chains, and executable troubleshooting examples. Ordinary library
validation uses LclValidationError; native callback and operation failures
retain their original exception in __cause__.