nabla v2.2.0
v2.1.0 listed what it knew was still wrong and left it, because each of these changes moves results for anyone already relying on them. This release makes them right.
Nothing is renamed, and formulas written against v2.1.0 keep working. Across all 20,813 recalculated cells in the workbook, four moved, all four on the Periods demonstration sheet.
nb.Periodsλ counts the way its own examples count
It counted whole intervals, which is what DATEDIF returns, while every one of its four worked examples counts the period starts crossed between the two dates. Its description says as much: it lists "End Date is inclusive" as one of its differences from DATEDIF, and then the procedure called DATEDIF. From 31 March to 15 May is one whole month and two month starts, and the help says 2.
It now counts ordinals, the same rule for all five intervals, so a part period at the end counts once and a whole one does not count twice. All four documented examples hold for the first time: 2, -2, -12 and -53.
Dis unchanged, because a day ordinal is the serial number itself.Wfollowsnb.PeriodLabelλ's own week numbering, which restarts each 1 January and therefore labels every year with 53 weeks, the last of them one or two days long. That is what makes the fourth example -53 rather than the 52 whole weeks its two dates are apart.
This changes results. Anything measured in months, quarters, weeks or years returns one more than it did wherever the end date falls part way through a period, which is most of the time. The two demonstration cells that move are the quarters row, 4 to 5, and the weeks row, 52 to 53. If you were relying on whole-interval counts, DATEDIF is still there and still does that.
The third example was also the one line in this help nobody could copy: it passed four arguments to a function that takes three. The -12 it claims is right without the fourth.
Four more functions threw away their date conversions
The defect nb.OverLapDaysλ carried until v2.1.0. Two of them gave wrong answers for it:
nb.ScheduleValuesλcompared text period starts against converted effective dates, so nothing ever fell inside a period. It returned 0 where it should return 100.nb.ScheduleRatesλlooked up text dates in a text array, soXLOOKUPmatched them in dictionary order. Asked for the rate in force on"5/1/2026"against starts of"1/1/2026"and"10/1/2026", it returned the January 10 rate, because"5/1/2026"sorts after"10/1/2026"as text.nb.PeriodLabelλandnb.Timelineλwere saved by Excel: both feed the date straight intoTEXT,YEAR,EDATEorSEQUENCE, all of which coerce a text date themselves. Checked against every case tried, they returned the right answer before and after. Their fix is a guard, not a repair.
The workbook stopped shipping cached errors it does not reproduce
Five cells on the Periods demonstration sheet were saved holding #VALUE!. They come from the upstream workbook, which carries 65 such cells, and they have been in every tagged release from v1.2.0 on. Excel replaces them with the right answers as soon as the file opens, so no reader ever saw them and no recalculation reproduces them, but a file that disagrees with itself is a file nobody can check. They now hold the answers the formula gives.
One cached error is left, #NAME? on the Essentials About sheet, which resolves on open the same way. Its cell holds a spilled table rather than a number, so it needs the table built rather than a value written.
Gates
tools/verify_sources.py now requires that a function which converts a date argument goes on to read the conversion. It is the check that would have caught all five of these, and it could not be added before they were fixed, because it fails on them. Run against v2.1.0 it names all six bindings and the function each belongs to. A general unused-value check would need a real parser and would report a great deal more; this one asks a narrower question and gets a clean answer.
Five gates now, four of them in CI, plus the local Excel gate: 130 functions and 210 parts, src/ reproducing all 130, 117 signatures with 122 parameter tables and 76 example blocks, 130 previous_name entries one to one against the v1.2.6 baseline, and 1,129 formulas recalculated with 138 assertions.
Full detail in CHANGELOG.md. nabla.xlsx is attached below.