DayCount.Net
1.1.0
dotnet add package DayCount.Net --version 1.1.0
NuGet\Install-Package DayCount.Net -Version 1.1.0
<PackageReference Include="DayCount.Net" Version="1.1.0" />
<PackageVersion Include="DayCount.Net" Version="1.1.0" />
<PackageReference Include="DayCount.Net" />
paket add DayCount.Net --version 1.1.0
#r "nuget: DayCount.Net, 1.1.0"
#:package DayCount.Net@1.1.0
#addin nuget:?package=DayCount.Net&version=1.1.0
#tool nuget:?package=DayCount.Net&version=1.1.0
DayCount.Net
Correct, zero-dependency ISDA day-count conventions for .NET. Year fractions and day counts under every standard convention, in decimal, with worked-example test vectors you can run yourself.
MIT Zero dependencies Native AOT clean
Why
Computing the year fraction between two dates is trivial until you meet the conventions real instruments use. The two ways teams do this today are both bad: pull in all of QLNet (a full QuantLib port) just to divide by 360, or hand-roll it and get the 30/360 end-of-month cases subtly wrong, silently mispricing accrued interest. DayCount.Net is the small, correct primitive in between.
Install
dotnet add package DayCount.Net
Use
using DayCount;
var start = new DateOnly(2024, 1, 15);
var end = new DateOnly(2024, 7, 15);
decimal yf = DayCounts.Actual360.YearFraction(start, end);
int days = DayCounts.Actual360.DayCount(start, end);
// Resolve by name or alias (case- and space-insensitive)
decimal e = DayCounts.Parse("30E/360").YearFraction(start, end);
Actual/Actual ICMA is the one convention that needs the enclosing coupon period:
var period = new CouponPeriod(new DateOnly(2024, 1, 15), new DateOnly(2024, 7, 15), Frequency: 2);
decimal yf = DayCounts.ActualActualIcma.YearFraction(start, end, period); // 0.5 for a regular semi-annual period
The 30/360 gotcha this removes
The same two dates give three different day counts depending on the convention. From 28 Feb 2007 to 31 Aug 2007:
| Convention | Day count |
|---|---|
| 30/360 Bond Basis | 183 |
| 30E/360 (Eurobond) | 182 |
| 30E/360 ISDA (German) | 180 |
Most in-house code only knows one of these. The differences are in the D1/D2 end-of-month adjustments, and they are exactly where accrual bugs hide.
Conventions
ACT/360, ACT/365F, ACT/ACT ISDA, ACT/ACT ICMA, ACT/ACT AFB, NL/365, 30/360 (Bond Basis), 30U/360 (SIA), 30E/360 (Eurobond), 30E/360 ISDA (German), 1/1. Each is a small class behind one IDayCountConvention interface; DayCounts.All enumerates them.
ACT/ACT AFB (the French "Actual/Actual AFB") counts whole years back from the end date, then values the remaining stub over 366 if it spans a 29 February, else 365.
30U/360 (also written 360/360, 30/360 SIA) is the US variant that adds the February end-of-month rule on top of Bond Basis, and is a distinct convention from 30/360. If both dates are the last day of February it sets D2 = 30; if the start is the last day of February it sets D1 = 30; then the normal 30/360 US rules apply. This is exactly where it diverges from 30/360 Bond Basis: 29 Feb 2008 to 28 Feb 2009 is 360 under 30U/360 but 359 under Bond Basis.
Correctness
Every claim here is backed by the test suite, which you can run in five minutes:
- ISDA worked-example vectors for the three 30/360 variants (the table above and more), asserting exact day counts against the ISDA 2006 Section 4.16 rules.
- Invariants over every convention: antisymmetry (
f(a,b) == -f(b,a)), equal dates are zero, exact day-count additivity for the actual conventions, and a full calendar year is exactly1under ACT/ACT ISDA (leap or not). decimalthroughout. No binary floating-point drift in your accruals.
Notes and limitations
decimaloutput,DateOnlyinput only. Reversed dates return negative results by design.30/360 Bond Basishere is the ISDA 4.16(f) convention with no February end-of-month special case; the30U/360(SIA) convention is that separate February end-of-month variant.ACT/ACT AFBuses the plain "count whole years back from the end" rule with calendar year subtraction (which clamps 29 Feb to 28 Feb in a non-leap target year). It does not apply the optional 28-Feb-to-29-Feb re-adjustment that some libraries (for example QuantLib) use, under which a span such as 28 Feb 2004 to 28 Feb 2008 would land on a one-day leap stub and give4 + 1/365rather than exactly4.30E/360 ISDAmodels the common non-terminal accrual case; the maturity-date-in-February exception is not yet modelled.- Calendar-only. Holidays and business days are the job of a separate library.
License
MIT. Copyright Israel Iyonsi.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.