Table of Contents

Globalization & Calendars

The Globalization & Calendars topic groups the packages that resolve authored calendar rules into concrete notable dates - public holidays, observances, religious festivals, and regional events - and that make those dates usable for filtering, querying, and working-day-aware date arithmetic. At its center is a single resource-driven engine: rules are authored on the notable-date schema, loaded into an immutable, validated NotableDateResource, and queried through NotableDateService by year, date, or range and territory.

The runtime is intentionally small. Everything beyond the resolution engine - fluent rule authoring, dependency-injection registration, trust-gated plugin loading, resolved-date caching, build-time rule-pack compilation, and the curated per-region holiday data - ships as opt-in companion packages that release on their own cadence. The topic also holds Bodu.Globalization.Recurrence, an independent sibling for RFC 5545 / cron / interval schedules that shares no dependency with the calendar engine. Consumers pull in only the pieces they need: most applications reference the runtime plus one or two regional data packs and never touch the rest.

Packages in this topic

Package Status What it provides Docs
Bodu.Globalization.Calendar Stable The runtime - rule engine, resolution pipeline, built-in date-calculation algorithms, bundled common catalogues, working-day extensions. Required by every other package in this topic. Introduction
Bodu.Globalization.Calendar.Builder Stable Fluent, chainable C# API for authoring notable-date documents in code, with XML / JSON serialization and load/save. Builder guide
Bodu.Globalization.Calendar.DependencyInjection Stable IServiceCollection extensions for registering INotableDateService over a loaded resource. DI guide
Bodu.Globalization.Calendar.Plugins Stable Trust-gated loading of external assemblies that contribute custom INotableDateAlgorithm implementations. Building and extending the service
Bodu.Globalization.Calendar.Caching Stable CachingNotableDateService, a decorator over any INotableDateService serving computed dates from a per-territory, per-civil-year cache (in-memory or one TOML / JSON file per territory), with its own DI registration. Caching guide
Bodu.Globalization.Calendar.Caching.Sqlite Stable SQLite backend for the notable-date cache (SqliteNotableDateCache / AddSqliteNotableDateCache). Caching guide
Bodu.Globalization.Calendar.Caching.Distributed Stable IDistributedCache / Redis backend for the notable-date cache (DistributedNotableDateCache / AddDistributedNotableDateCache / AddRedisNotableDateCache). Caching guide
Bodu.Globalization.Calendar.Tool Preview The bodu-calendar command-line tool (dotnet tool install): lints notable-date documents with the stable BODU-CAL-* diagnostics, compiles them to sealed .bcal binary packs, and inspects compiled packs. Binary rule packs
Bodu.Globalization.Calendar.Build Preview MSBuild integration - the CompileNotableDatePack task and NotableDatePack items compile documents to .bcal packs incrementally during build via the bundled tool; a development dependency only. Binary rule packs
Bodu.Globalization.Recurrence Preview RFC 5545 recurrence rules (RecurrenceRule / RecurrenceRuleBuilder / RecurrenceSet), CronExpression, and AnchoredInterval - parsing, formatting, and next / previous occurrence queries; depends only on Bodu.Core. Recurrence guide
Bodu.Globalization.Calendar.Americas Stable Curated public-holiday rules for the Americas bundle (e.g. US, CA). Data packs guide
Bodu.Globalization.Calendar.AsiaPacific Stable Asia-Pacific bundle (e.g. AU with subdivisions, CN, IN, JP, KR, MY, NZ, SG). Data packs guide
Bodu.Globalization.Calendar.Europe Stable Europe bundle (e.g. DE, ES, FR, GB, IT, NL). Data packs guide
Bodu.Globalization.Calendar.Africa Stable Africa bundle (e.g. ZA, NG, KE, GH, ET, EG, MA). Data packs guide
Bodu.Globalization.Calendar.MiddleEast Stable Middle East bundle (e.g. AE, SA, IL, TR, QA, JO). Data packs guide

The authoritative dependency and status rows live in the package matrix.

How the pieces fit

Bodu.Globalization.Calendar package family - runtime, companions, and data packs

A notable date flows through the topic's packages in a fixed order:

  1. A data pack supplies rules. Each regional pack embeds per-country rule documents that import the shared common catalogues, and exposes a <Region>CalendarData factory (SupportedCountries, LoadResource(territory), CreateService(territory)). Alternatively, you author your own document - as XML / JSON text, or fluently in C# with the Builder's NotableDateDocumentBuilder.
  2. The runtime loads a resource. NotableDateResourceLoader parses the document, resolves its imports against the bundled catalogues, applies overrides, validates, and produces an immutable NotableDateResource.
  3. NotableDateService resolves dates. Built over the resource, the service computes each rule's nominal date via its strategy (a fixed date, an nth weekday, an offset from another rule, a named algorithm, or another of the 13 single-date strategies - or a frequency-based recurrence source), applies observance adjustments, settles same-day collisions, and emits resolved NotableDate occurrences for the requested year, date, or range and territory.
  4. Consumers query and compute. Results are filtered with NotableDateFilter and fed into the working-day extensions (IsWorkingDay, AddWorkingDays, NextWorkingDay, …) in Bodu.Extensions.

The companions attach at well-defined seams. Builder authors documents in step 1 without hand-writing XML. Plugins extends step 3 with custom astronomical or ecclesiastical algorithms discovered from external assemblies, admitted only under an explicit, deny-by-default trust policy. DependencyInjection registers the assembled service in a Microsoft.Extensions.DependencyInjection container, including the reloadable runtime-swap workflow. Caching decorates the registered service in step 3 so resolved years are served from a per-territory cache. Tool and Build sit before step 2, validating documents and compiling them to sealed .bcal binary packs at build time.

Which package do I need?

Scenario Reach for Notes
Resolve US / AU / GB public holidays for a year Bodu.Globalization.Calendar + the matching regional data pack AmericasCalendarData.CreateService("US") is a one-liner; query with service.Resolve(2026, "US").
Working-day arithmetic ("add 5 business days") Bodu.Globalization.Calendar + a data pack The Bodu.Extensions working-day surface ships in the runtime; see the working-days guide.
Author custom company dates (closures, fiscal events) in C# Bodu.Globalization.Calendar.Builder Build, serialize to XML / JSON, save, or materialize a resource directly; see the builder guide.
Author rules as XML / JSON documents Bodu.Globalization.Calendar alone NotableDateResourceLoader.Load(xml); see rule authoring.
Host the service in ASP.NET Core / generic-host DI Bodu.Globalization.Calendar.DependencyInjection services.AddNotableDateService(resource) or AddReloadableNotableDateService(...).
Load a custom astronomical algorithm from an external assembly Bodu.Globalization.Calendar.Plugins Trust-gated and default-deny; in-process custom algorithms need only the runtime's NotableDateAlgorithmRegistry.
Serve resolved dates from a cache (in-memory, file, SQLite, Redis) Bodu.Globalization.Calendar.Caching (+ .Sqlite / .Distributed) AddCachedNotableDateService() decorates the registered service; see the caching guide.
Lint rule documents or compile them to .bcal packs at build time Bodu.Globalization.Calendar.Tool / .Build The bodu-calendar tool for scripts and CI; the Build package for MSBuild; see binary rule packs.
Evaluate an RFC 5545 RRULE, a cron expression, or a fixed interval Bodu.Globalization.Recurrence No calendar data involved; compose holiday filtering from outside - see the recurrence guide.
Browse what dates the shipped data actually contains (documentation) The notable-date catalogue lists every concept by theme and region.

Install

The runtime plus one regional data pack covers the most common case:

dotnet add package Bodu.Globalization.Calendar
dotnet add package Bodu.Globalization.Calendar.AsiaPacific

Regional packs are independent - install only the regions you need:

dotnet add package Bodu.Globalization.Calendar.Americas
dotnet add package Bodu.Globalization.Calendar.Europe
dotnet add package Bodu.Globalization.Calendar.Africa
dotnet add package Bodu.Globalization.Calendar.MiddleEast

The companions are opt-in:

dotnet add package Bodu.Globalization.Calendar.Builder
dotnet add package Bodu.Globalization.Calendar.DependencyInjection
dotnet add package Bodu.Globalization.Calendar.Plugins
dotnet add package Bodu.Globalization.Calendar.Caching
dotnet add package Bodu.Globalization.Calendar.Caching.Sqlite         # optional durable backend
dotnet add package Bodu.Globalization.Calendar.Caching.Distributed    # optional IDistributedCache / Redis backend

The rule-pack toolchain - Bodu.Globalization.Calendar.Tool (the bodu-calendar CLI) and Bodu.Globalization.Calendar.Build (its MSBuild integration) - is not published to nuget.org; build both from a clone.

The recurrence sibling stands alone:

dotnet add package Bodu.Globalization.Recurrence

A taste of the surface

using Bodu.Globalization.Calendar;
using Bodu.Extensions;                      // working-day arithmetic - not auto-imported

NotableDateService service = AsiaPacificCalendarData.CreateService("AU");

// All NSW public holidays for 2026:
IReadOnlyList<NotableDate> holidays = service.Resolve(
    2026, "AU-NSW", NotableDateFilter.ForCategory(NotableDateCategory.PublicHoliday));

// Working-day arithmetic that skips weekends and resolved holidays:
DateOnly today  = DateOnly.FromDateTime(DateTime.Today);
DateOnly inFive = today.AddWorkingDays(5, service, "AU-NSW");

Territory codes are hierarchical - a query for AU-NSW returns rules authored for AU as well as rules specific to AU-NSW, so national and regional rules compose naturally.

The companions follow the same grain. Hosting the service in a DI container is one registration:

using Bodu.Globalization.Calendar;
using Microsoft.Extensions.DependencyInjection;

builder.Services.AddNotableDateService(AsiaPacificCalendarData.LoadResource("AU"));
// or reloadable, for runtime rule swaps:
// builder.Services.AddReloadableNotableDateService(AsiaPacificCalendarData.LoadResource("AU"));

And authoring a custom date with the Builder produces the same kind of document the data packs embed - see the builder guide for the fluent surface and its XML / JSON round-trip.

Key types across the family

Type Package Role
NotableDateService / INotableDateService Runtime Main entry point - resolves and queries notable dates for a date, range, or year.
NotableDate Runtime Resolved output - observed date, calculated date, name, category, territory, optional multi-day span.
NotableDateResource / NotableDateResourceLoader Runtime The immutable loaded document, and the loader that parses, imports, validates, and produces it.
NotableDateFilter Runtime Composable query predicate - ForCategory, WithTag, InDateRange, combined with And / Or / Not.
TerritoryCode Runtime Strongly-typed ISO 3166 country / subdivision code with containment semantics.
NotableDateOnlyExtensions Runtime Working-day arithmetic over DateOnly - IsWorkingDay, AddWorkingDays, NextWorkingDay, …
AmericasCalendarData · AsiaPacificCalendarData · EuropeCalendarData · MiddleEastCalendarData · AfricaCalendarData Data packs Static per-region factories over the embedded country packs.
NotableDateDocumentBuilder Builder Fluent C# authoring of a document - build, serialize (XML / JSON), save, or materialize a resource.
NotableDatePluginLoader Plugins Trust-gated discovery of external algorithm assemblies.
INotableDateAlgorithm / NotableDateAlgorithmRegistry Runtime The pluggable algorithm contract behind <Algorithm key="…"> rules, and its registry.

Where to go next