Calendrical version 0.6.0
[0.6.0] — 2026-05-23
Breaking changes
Calendrical.DateParseError,TimeParseError,DateTimeParseError,DateRangeParseError, andParseErrorno longer carry a:messagestruct field. The human-readable message is materialised byException.message/1from the semantic fields (:input,:locale,:calendar,:reason,:from,:to,:cause,:attempts). Pattern-match on:reason(and other structural fields) rather than parsing the rendered string.DateRangeParseErrornow declares@behaviour Localize.Exceptionand exposesreason_atoms/0for the closed set of failure categories; the:invertedreason carries:from/:toDate endpoints instead of stuffing them into:input.
Bug Fixes
-
Calendrical.Date.parse_range/2now returns aDate.Rangewhose endpoints are in the calendar named by the:calendaroption (matchingparse/2), instead of always returning Calendar.ISO endpoints.Date.Rangesupports any calendar provided both endpoints share it, so non-ISO ranges are well-formed. -
Month, day, era, quarter, and day-period name matching is now case-insensitive per CLDR TR35 §6.5 (Lenient Parsing). Previously
"23 Mai"(capitalised) failed to parse in French because the parser case-sensitively matched the lowercase CLDR form "mai";"23 mai"worked. All four parsers now accept any case for locale name fields. -
A literal space in a CLDR date pattern now requires at least one whitespace character in the input (previously zero-or-more). Inter-field gaps with no explicit pattern separator stay optional. This prevents over-greedy matches like
"mai23"binding to aMMMM d ypattern as month=mai, day=2, year=3.
Added
-
Calendrical.parse/2— unified locale-aware parser that dispatches to the appropriate sub-parser when the input shape is not known up-front. Tries interval, date, time, then datetime, and returns{:ok, value}wherevalueis aDate,Time,NaiveDateTime,DateTime, orDate.Range. Failures return{:error, Calendrical.ParseError.t()}whose:attemptsfield records each sub-parser tried. -
The
:calendaroption on all parsers now accepts either a CLDR calendar key atom (:gregorian,:hebrew, …) or a calendar module (Calendar.ISO,Calendrical.Hebrew, …). Modules are coerced via thecldr_calendar_type/0callback;Calendar.ISOis treated as:gregorian. -
Calendrical.Date.parse/2now accepts month-name + day input in either order regardless of the locale's preferred ordering. For any CLDR pattern with a name-form month (MMM/MMMM/MMMMM) and a numeric day, the parser also tries the reversed token order — so"May 23"parses in French (CLDR hasd MMM) and"23 May"parses in English (CLDR hasMMM d, y). NumericM/MMare excluded because the swap would be ambiguous withd. Applies to year-bearing and weekday-bearing variants too; non-M-and-d tokens stay in place. -
ISO 8601 forms beyond Elixir stdlib are now accepted: basic format (
20260523), ordinal date (2026-143), and ISO week date (2026-W21-6).Calendrical.Date.parse/2recognises all three in every locale as a universal escape hatch alongside the existing extended format (2026-05-23). -
Calendrical.DateTime.parse/2now accepts a space separator between date and time ("2026-05-23 14:30:00") in addition toT. Elixir stdlib'sNaiveDateTime.from_iso8601/1has accepted this form since 1.4; the gate has been relaxed so Calendrical does too. Common in SQL output, log lines, and human-readable timestamps. -
New parsing guide (
guides/parsing.md) describing what each parser accepts, how Calendrical compares to Elixir stdlib, ISO 8601 coverage, and the documented variances from CLDR (case-insensitive name matching, M↔d swap, lenient separators).