YEARFRAC converts the interval between two dates into a fraction of a year, under a
selectable day-count convention. It is the time axis of fixed-income arithmetic: every accrual,
every discount factor, every bill price ultimately asks "how much of a year is this", and this
function is where Excel answers.
Structurally it is a quotient:
YEARFRAC(start, end, basis) = (days between, counted by basis) / (days in a year, per
basis)
Both the numerator and the denominator depend on the basis, and — this is the part that surprises
people — for one basis the denominator is not a constant.
basis
Convention
Numerator
Denominator
0 or omitted
US (NASD) 30/360
30/360-adjusted day count
360
1
Actual/actual
actual calendar days
actual — depends on the period
2
Actual/360
actual calendar days
360
3
Actual/365
actual calendar days
365
4
European 30/360
30/360-adjusted day count
360
The two 30/360 bases are the conventions documented verbatim on the
DAYS360 page — basis 0 is the US (NASD) method with its asymmetric,
start-date-dependent end-date rule, and basis 4 is the symmetric European method that adjusts only
the 31st. YEARFRAC(a, b, 0) and DAYS360(a, b, FALSE)/360 are the same quantity on the documented
reading of both pages.
Basis 1 is the hard one. "Actual/actual" does not name a single algorithm. The denominator must
be some notion of "the length of the year the interval sits in", and when an interval spans several
years, or a leap day, or starts and ends in years of different lengths, there are several defensible
constructions — averaging the lengths of the spanned years, using the length of the year containing
the start, using 365 or 366 according to whether a leap day falls inside the period, and others.
Excel's exact rule is not stated on the documentation page, and this Handbook has not
established it. That gap is the single most important open question about this function, because
basis 1 is the one regulated instruments most often specify.
Arguments
YEARFRAC(start_date, end_date, [basis]) — two required arguments and one optional.
start_date — "a date that represents the start date".
end_date — "a date that represents the end date".
basis — optional; the day-count convention, per the table above. Omitted means 0, the US
(NASD) 30/360 convention. Microsoft states a general conversion rule for this function that the
rest of the category does not state so plainly: "All arguments are truncated to integers." So
fractional serials contribute no fractional days, and a fractional basis truncates.
The misunderstood argument is basis, and specifically its default. A workbook written against an
Actual/365 instrument that omits basis silently gets 30/360 answers, which are close enough to
look right and wrong enough to matter over a portfolio.
Try it
Quirks
Result and edge cases
Returns a Number: a fraction of a year, which may exceed 1 for intervals longer than a year. It
is not negative when end_date precedes start_date: reversed dates give the same answer as in
order (FN-YEARFRAC-001).
Microsoft documents a defect in this function. Verbatim: YEARFRAC "may return an incorrect
result when using the US (NASD) 30/360 basis, and the start_date is the last day in February".
That is the vendor stating that basis 0 is wrong on a named input class. The Handbook records it
as documented; it has not been characterized here — nobody has determined which February end
dates misbehave, by how much, or whether the same inputs affect DAYS360, which
implements the same adjustment rules.
Basis 1 across a leap day is where the undocumented denominator rule becomes visible. An
interval of exactly one calendar year should give 1 under any sensible actual/actual construction;
an interval spanning 29 February is where constructions diverge.
Equal dates give 0.
Reversed intervals give the same fraction as in order (FN-YEARFRAC-001); unlike
DATEDIF, no error is documented for them.
Floating point. The result is a quotient of small integers by 360, 365, 366 or an
actual/actual denominator. Division by 360 and 365 is inexact in binary, so the last bits of the
result depend on the order in which the quotient is formed — which makes YEARFRAC one of the few
functions in this category with genuine last-bit content, and one where an
excel-bitexact implementation has something real to match.
Errors
As documented on the Microsoft page:
#VALUE! when start_date or end_date is not a valid date.
#NUM! when basis is less than 0 or greater than 4.
Note that the invalid-date condition is #VALUE! here, where several siblings in this category
document #NUM! for an out-of-range date. The Handbook records the family's inconsistent
documented error values rather than harmonizing them; see
claim language, rule 5.
Ordinary coercion failures and error propagation follow the engine rules in
coercion and lifting.
An empty cell as a first date is serial 0, but a logical in that cell is #VALUE!
A reference to an empty cell as the first date of these functions reads as serial 0 and gives a normal answer: NETWORKDAYS(B1,5) is 4 and WORKDAY(B1,2) is 3. YEARFRAC(B1,5,0) is 5/360. TRUE in the same cell gives #VALUE!, as a direct TRUE does, so a blank is not treated as the logical FALSE either.
Formula
Excel
Mathematical value
=NETWORKDAYS(B1,5) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: (empty cell)
4 0x4010000000000000
—
=NETWORKDAYS(B1,5) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: TRUE
#VALUE!
—
=WORKDAY(B1,2) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: (empty cell)
3 0x4008000000000000
—
=WORKDAY(B1,2) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: TRUE
#VALUE!
—
=NETWORKDAYS.INTL(B1,5,1) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: (empty cell)
4 0x4010000000000000
—
=WORKDAY.INTL(B1,2,1) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: (empty cell)
3 0x4008000000000000
—
=YEARFRAC(B1,5,0) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
B1: (empty cell)
0.013888888888888888 0x3f8c71c71c71c71c
—
=TBILLEQ(B1,5,0.1) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
On basis 1 the fictitious 1900-02-29 is not a leap day, and YEARFRAC takes serial 0 as a date
Excel's calendar holds a 29 February 1900, serial 60, that never existed. On basis 1 (actual/actual) it does not make 1900 a leap year: YEARFRAC(59,60,1) is 1/365, where the real 1904-02-29 gives YEARFRAC(1520,1521,1) = 1/366. Serial 0 is accepted as a date: YEARFRAC(0,5,0) is 5/360 and YEARFRAC(0,60,1) is 60/365. Reversed dates give the same answer as in order. ACCRINTM, DISC, INTRATE, PRICEDISC and RECEIVED take the same 365 and 366 on those dates: DISC(59,60,99,100,1) is about 3.65 and DISC(1520,1521,99,100,1) about 3.66.
Formula
Excel
Mathematical value
YEARFRAC(59, 60, 1) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Number supplied through a cell.
start_date: 59 0x404d800000000000
end_date: 60 0x404e000000000000
basis: 1 0x3ff0000000000000
0.0027397260273972603 0x3f66719f3601671a
—
YEARFRAC(1520, 1521, 1) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Number supplied through a cell.
start_date: 1520 0x4097c00000000000
end_date: 1521 0x4097c40000000000
basis: 1 0x3ff0000000000000
0.00273224043715847 0x3f6661ec6a5122f9
—
YEARFRAC(0, 5, 0) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Number supplied through a cell.
start_date: 0 0x0000000000000000
end_date: 5 0x4014000000000000
basis: 0 0x0000000000000000
0.013888888888888888 0x3f8c71c71c71c71c
—
YEARFRAC(0, 60, 1) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Number supplied through a cell.
start_date: 0 0x0000000000000000
end_date: 60 0x404e000000000000
basis: 1 0x3ff0000000000000
0.1643835616438356 0x3fc50a8542a150a8
—
DISC(59, 60, 99, 100, 1) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Number supplied through a cell.
settlement: 59 0x404d800000000000
maturity: 60 0x404e000000000000
pr: 99 0x4058c00000000000
redemption: 100 0x4059000000000000
basis: 1 0x3ff0000000000000
3.650000000000003 0x400d33333333333a
—
DISC(1520, 1521, 99, 100, 1) Excel 16.0.20527.20088, Windows, bitness and CPU not recorded in this reading fileInputs and reference value
Basis 1 needs a written-down definition before it needs code. Pick a construction, state it
precisely (which years, how leap days are counted, what happens for multi-year intervals), and
do not claim compatibility until it has been checked. This is the one place in this assignment
where "we implemented what seemed right" is guaranteed to diverge from something.
Share the 30/360 adjustment code with DAYS360. Bases 0 and 4 are exactly that function's
two methods; two implementations of one rule will eventually disagree, and Microsoft's own
documented caveat suggests Excel may already contain such a divergence.
Truncate every argument to an integer first, per the documented rule, including basis.
Form the quotient in a fixed, documented order. The numerator is a small integer and the
denominator is 360, 365, 366 or a computed value; different groupings give different last bits.
For a portable-reproducible flavour this must be pinned explicitly.
Validate basis against 0…4 before anything else, since it is the one documented #NUM!.
Rust code
Show the CalcFunc source of this function
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
No implementation has been published with a Handbook test suite for this function.
Version differences
The recorded environments below distinguish a reading from a same-input comparison. Counts describe captured inputs in each environment; overlapping captures and comparisons are not totals of unique worksheet calls.
Excel 16.0 build
Platform and CPU
Captured inputs
20430
Windows, 64-bit, AMD Ryzen 7 4800H with Radeon Graphics
3,003
The record contains no same-input comparison between these environments. Reading different inputs on different builds does not establish either a version change or cross-build agreement.
Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA
=YEARFRAC(B1,5,0) returned 0.013888888888888888 (0x3f8c71c71c71c71c). Inputs were supplied through cells using Value2. These are controls from this environment, not a same-input comparison with another build.
Windows, bitness and CPU not recorded in this reading file
YEARFRAC(59, 60, 1) returned 0.0027397260273972603 (0x3f66719f3601671a). YEARFRAC(1520, 1521, 1) returned 0.00273224043715847 (0x3f6661ec6a5122f9). 2 further recorded controls are attached. Inputs were supplied through cells using Value2. These are controls from this environment, not a same-input comparison with another build.
Windows, 64-bit, AMD Ryzen 7 4800H with Radeon Graphics
3,003 captured inputs are indexed for this environment. Capture dates: 2026-09-24 to 2026-09-25. This is a reading count, not a comparison with another build.
Alternatives
Relationships
DAYS360 — the same two 30/360 conventions, expressed as a day count rather
than a year fraction. YEARFRAC(a,b,0) should be DAYS360(a,b,FALSE)/360 and YEARFRAC(a,b,4)
should be DAYS360(a,b,TRUE)/360. Testing those two identities is the cheapest way to probe the
documented last-day-of-February defect, since it localizes the disagreement to one of the two
functions.
DATEDIF with "Y" — whole elapsed years rather than a fraction. Frequently
substituted for YEARFRAC in age calculations, with different answers.
DAYS — the raw calendar interval that bases 1, 2 and 3 use as their numerator.
EOMONTH — a common source of the exact end-of-February dates Microsoft's
caveat names.