Skip to content

v0.1.11

Choose a tag to compare

@github-actions github-actions released this 31 Aug 13:15
· 22 commits to main since this release

Stop tracking the relocated cargo target

A git add -A swept up a target symlink pointing into a local build
directory, so CI checked it out as a symlink and cargo could not create the
directory it needed: "failed to create directory .../target — Not a directory".
The napi build died before compiling anything.

target/ was already ignored, but that pattern matches a directory only.

Make diff answer a - b, signed and fractional

diff subtracted the wrong way round: a date two days ahead answered -2, the
opposite sign of every other library in this space, and the test that covered
it asserted only the magnitude with a comment saying the direction depended on
the engine — which is how it stayed unnoticed. It also returned an i64, so a
gap of five and a half months came back as five, the half silently gone.

Months and years are counted on the calendar rather than an averaged length:
whole steps first, then the remainder measured against the month it actually
falls in, so 15 days into February is 15/28 of a month and not 15/30. A month
reached by clamping counts as whole — January 31st plus one month is February
28th, so the gap between them is one month, where the truncating version said
zero.

Every value in the tests was taken from a reference implementation and matches
to the last digit. months_between had no caller left after the rewrite.

Write a README that documents the library, and name Interval's units

The README was a title, an install line and one example. It now covers
DateTime, Duration, Interval, recurrence and the Atlas adapter, and every
example in it was run against the built package before being written down —
which is how the two below turned up.

Interval.length keyed its unit table in the plural and answered 1 for anything
else, so length('day') returned 2592000000: milliseconds, presented as days.
The rest of chronos spells units in the singular, so the spelling most callers
would reach for was the one that silently lied. splitBy had the same fallback,
where an unrecognised unit becomes a one-millisecond step — 2.6 billion
sub-intervals over a month.

Both now resolve singular and plural, as Luxon does, and refuse a unit they do
not know. TypeScript already rejects one at the call site; the guard is for
JavaScript consumers, and the tests reach it the way those consumers do.

Refuse a calendar date that does not exist instead of sliding forward

DateTime.from('2026-02-30') answered 2026-03-02 while DateTime.from('2026-13-45')
threw. Both dates are equally impossible, and the inconsistency was the
dangerous half: a caller wrapping this in try/catch — the natural reading of
the lines that throw — had covered the loud case and left the one that writes
something false to the database.

The overflow comes from Date, and it is right for arithmetic: adding a month
to January 31st has to land somewhere, and chronos already clamps that to the
28th as Luxon does. It is wrong for reading input, where the same slide turns
a typo into a fact.

fromObject has always refused this exact input by checking that the date it
built is the date it was given. This is that check on the door that was
missing it, with a message naming the month's real length. Only the written
date is examined, never the instant it resolves to, so an offset that
legitimately moves the UTC day is untouched, and a real leap day still parses.

The leap-year table had a second copy in the calendar getter; both now read
from one helper.


Changes since v0.1.10.