Custom Calendars
Custom calendars let a vault store fictional or alternative dates without converting them to Gregorian dates. A calendar is declared once in .bwrb/schema.json, then date fields opt in by calendar id.
Calendar dates are stored as canonical strings in frontmatter, but Bowerbird parses them to a timezone-independent linear hour value for sorting, --where comparisons, JSON output, audit, and calendar-anchored relative-date chains.
Schema
Section titled “Schema”Declare calendars under config.calendars:
{ "config": { "calendars": { "tmi": { "label": "TMI lunar calendar", "hoursInDay": 336, "eras": [ { "name": "Before Humans", "shortName": "BH", "backwards": true }, { "name": "After Humans", "shortName": "AR" } ], "months": [ { "name": "Month One", "shortName": "M1", "days": 2 }, { "name": "Month Two", "shortName": "M2", "days": 2 } ] } } }}hoursInDay defaults to 24. Each calendar needs at least one era and one month. Month indexes are one-based in date strings.
Era support is intentionally limited in v1: a calendar can declare one era, or one backwards era plus one forward era. Calendars cannot declare more than two eras, more than one backwards: true era, or two forward-only eras.
Date Fields
Section titled “Date Fields”Opt a date field into a calendar:
{ "types": { "event": { "output_dir": "Events", "calendar_default": "tmi", "fields": { "name": { "prompt": "text", "required": true }, "when": { "prompt": "date" } } } }}calendar_default applies to date fields on the type that do not declare their
own calendar. Instead of a type default, an individual date field can opt in
with "calendar": "tmi". A calendar key is valid only on prompt: "date"
fields, and every referenced calendar id must exist in config.calendars.
Date Format
Section titled “Date Format”The canonical format is:
<eraShort> <year>-<month>-<day> [<hour>:<minute>]Examples:
when: "AR 3019-02-02 266:50"origin: "BH 12-01-01"Month and day are canonicalized to two digits. Hours may exceed 23 when the calendar’s hoursInDay is larger than a Gregorian day, but must be less than hoursInDay. Minutes must be 0-59.
Querying
Section titled “Querying”Text table output displays the canonical string. JSON output expands calendar date fields:
{ "when": { "value": "AR 3019-02-02 266:50", "calendar": "tmi", "linear": 4057466.8333333335 }}linear is the internal hour count used for sorting and comparisons. It is stable and timezone-independent.
bwrb list event --sort when --output jsonbwrb list event --where "when > 'AR 1000-01-01'" --output jsonDates from different calendars are not converted. Cross-calendar sort ties fall back to name order with a warning; cross-calendar --where comparisons do not match.
Relative Dates
Section titled “Relative Dates”Relative-date chains anchored on a calendar date resolve in that calendar’s linear hours:
position: kind: equal ref: "[[Anchor]]" field: when offset: 2dFor calendar chains, d means the calendar’s hoursInDay. The w unit is rejected for calendar chains in v1; use hours or days instead. Gregorian chains keep the existing real-time meanings: d = 24h, w = 168h.
bwrb audit validates calendar date strings against the configured calendar. It reports invalid eras, month ranges, day ranges, hours, and minutes as invalid-date-format.
Limits
Section titled “Limits”Custom calendars v1 do not support more than one backwards era and one forward era, leap cycles, weekday names, timezone concepts, or conversion between calendars.