Calendrical version 0.4.0
[0.4.0] — 2026-05-17
Bug Fixes
-
Calendrical.LunarJapanese.new/3,Calendrical.Chinese.new/3, andCalendrical.Korean.new/3rejected valid{m, :leap}inputs in the documented traditional notation — the validator compared the user's traditional month number against the ordinal position returned byleap_month/1, which is always off by one. The check now correctly converts ordinal to traditional before comparing, the private helper has been renamedvalid_traditional_date?/5to disambiguate from the 3-arityvalid_date?/3callback used byDate.new/4, and the publicDate.new/4ordinal contract is unchanged. -
Test support module renamed from
Calendrical.DatetoCalendrical.Test.DateGeneratorto free theCalendrical.Datenamespace for the new parser module. Affectstest/property_test.exsandtest/day_of_week_test.exsonly — no public API impact.
Added
-
traditional_leap_month/1on each of the three lunisolar calendars (Calendrical.LunarJapanese,Calendrical.Chinese,Calendrical.Korean), returning the traditional (1..12) number of the intercalary month — the number the leap month repeats — as a companion toleap_month/1which returns the ordinal position (1..13). -
Calendrical.Time.parse/2andCalendrical.DateTime.parse/2— locale-aware time and date-time parsers completing the parser trio alongsideCalendrical.Date.parse/2, TR35-compliant for hour-cycle resolution, day-period names, fractional seconds, and CLDR glue patterns. See the moduledocs for the day-period inheritance and datetime-glue backtracking strategy. -
Calendrical.TimeParseErrorandCalendrical.DateTimeParseError— structured errors carrying:inputand:locale. -
Calendrical.Date.parse/2— locale-aware parser for user-typed date strings across every Calendar-behaviour module exposingcldr_calendar_type/0(Gregorian, Buddhist, Japanese imperial, Islamic, Persian, Hebrew, ROC, Coptic, Ethiopic, Indian, …). Handles CLDRlenient-scope-dateseparator equivalences, non-Latin digit transliteration, 2-digit year pivoting, and era markers — seeCalendrical.Date.Parserfor the full strategy. -
Calendrical.Date.parse_range/2— locale-aware range parser. Accepts either a single string (split on CLDR'sintervalFormatFallbackseparator) or a{from, to}tuple, with CLDR interval-skeleton inheritance so"May 5 – May 10, 2026"parses even though the left endpoint has no year. -
Calendrical.DateParseErrorandCalendrical.DateRangeParseError— structured errors carrying:input,:locale,:calendar, plus:reasonand:causefor ranges.
Documentation
-
Each lunisolar calendar's moduledoc now has a "Two month numbering conventions" section explaining the difference between ordinal months (used by
Date.t,Date.new/4,Date.convert/2, and theCalendarcallbacks) and traditional months (used bynew/3and the return value oflunar_month_of_year/1). The previous undocumented dichotomy could silently produce dates one full lunar month off after the intercalary in leap years. -
The
new/3andnew!/3docstrings on each lunisolar calendar now state explicitly that thelunar_monthargument is traditional (1..12 with{m, :leap}for the intercalary), with examples showing how the traditional number maps to the ordinal stored on the resultingDate.tstruct.