Day-count conventions for JavaScript/TypeScript — 30/360, 30E/360, 30E/360-ISDA, 30U/360, ACT/360, ACT/365F, ACT/ACT-ISDA, ACT/ACT-ICMA, ACT/ACT-AFB, BUS/252. Zero dependencies, cross-checked against QuantLib.
npm install day-count-conventions
Every interest accrual, swap leg, and bond coupon depends on a day-count convention, and the details are famously fiddly: does the 31st count as the 30th? Is February month-end special? Which ACT/ACT is your ACT/ACT? npm had no focused, typed implementation of the ISDA 2006 §4.16 definitions — this is that package.
import { dayCount, yearFraction } from "day-count-conventions";
yearFraction("2026-01-15", "2026-07-15", "ACT/360"); // 181/360
yearFraction("2007-01-31", "2007-02-28", "30/360"); // 28/360 (D1 31→30)
yearFraction("2003-11-01", "2004-05-01", "ACT/ACT-ISDA"); // 61/365 + 121/366
// The US Treasury coupon basis:
yearFraction("2026-05-15", "2026-07-15", "ACT/ACT-ICMA", {
periodEnd: "2026-11-15", // next coupon
frequency: 2, // semiannual
}); // 61 / (2 × 184)The year fraction between two dates. Dates are "YYYY-MM-DD" strings (recommended) or Date objects read as UTC calendar dates. Invalid or impossible dates throw RangeError.
ACT/ACT-ICMArequiresopts.frequency(coupon payments/year) andopts.periodEnd(next coupon date);opts.periodStartdefaults tostart. This is the convention for US Treasury notes and bonds. Bothstartandendmust lie withinperiodStart … periodEnd; anything else throwsRangeError(split longer accruals at coupon dates). For a short first coupon, pass the notional regular period asperiodStart/periodEnd. Long irregular coupons are not handled automatically.30E/360-ISDAacceptsopts.terminationDate: when the end date is the maturity and falls on the last day of February, it is not adjusted to 30, per ISDA 2006 §4.16(h).BUS/252requiresopts.holidays— a predicate(isoDate) => booleanor a list/Set of"YYYY-MM-DD"holiday dates. Weekends are always excluded. Business days are counted fromstart(inclusive) toend(exclusive).
| Convention | Definition |
|---|---|
30/360 |
30/360 Bond Basis, ISDA 2006 §4.16(f) |
30E/360 |
30E/360 Eurobond Basis, ISDA 2006 §4.16(g) |
30E/360-ISDA |
30E/360 (ISDA), ISDA 2006 §4.16(h) |
30U/360 |
30/360 US (SIA): Bond Basis plus the February month-end rule (QuantLib Thirty360.USA) |
ACT/360 |
ISDA 2006 §4.16(e) |
ACT/365F |
Actual/365 (Fixed), ISDA 2006 §4.16(d) |
ACT/ACT-ISDA |
ISDA 2006 §4.16(b) |
ACT/ACT-ICMA |
ISDA 2006 §4.16(c), ICMA Rule 251 (single coupon period) |
ACT/ACT-AFB |
Actual/Actual (Euro), ISDA 1998 EMU memo; French AFB basis |
BUS/252 |
Business days / 252 (Brazil) |
When end is before start the result is negative and antisymmetric (yearFraction(b, a) === -yearFraction(a, b)). For BUS/252 this differs from QuantLib, which counts reversed intervals with different endpoint inclusion.
The day count under the convention: actual calendar days for ACT conventions, the 360-basis count for the 30/360 family.
The list of supported convention strings.
- Anchored to published examples (the ISDA 1998 EMU-memo ACT/ACT and AFB cases; a live US Treasury accrual reproduced to TreasuryDirect's own published accrued interest).
- Cross-checked against QuantLib 1.43. The committed test fixtures (
test/fixtures.ts, generated bytest/generate-fixtures.py) cover every convention on 650 date pairs weighted toward month ends, 28/29/30/31 and leap Februaries, plus 400 ACT/ACT-ICMA coupon-period accruals and 300 BUS/252 intervals on QuantLib's Brazil calendar. During the audit the same comparison passed on 48,000 date pairs per convention. - All day arithmetic uses UTC calendar math — no timezone drift, no DST surprises.
Part of a small fixed-income toolkit: 32nds (Treasury quote notation) · accrued-interest · sifma-holidays (bond-market calendar) · treasurydirect (auction data client).
Built by Moshe Malka — engineering leader in New York City. Studio work at Quentin.Code.
MIT © Moshe Malka