ODDFPRICE
Quirk foundCategory: Financial · Last tested 2026-09-01
Real compatibility results for the ODDFPRICE function: executed in Excel for the web, Google Sheets and LibreOffice Calc, with desktop Excel behavior from Microsoft’s official documentation (we do not run desktop Excel — Excel for the web is a different application and is executed separately). Syntax and links to that documentation are below.
Support matrix
| Engine | Documented | Live-tested | Verdict |
|---|---|---|---|
| Excel (desktop) | Yes | No — documented only | n/a |
| Excel for the web | — | Yes (recalc, 2026-09-01) | Supported, behaves as documented |
| Google Sheets | No | Yes (Drive import, 2026-08-31) | Unsupported (not recognized) |
| LibreOffice Calc | Yes | Yes (25.8.7.3, 2026-08-31) | Quirk found |
LibreOffice version history
We executed the same test cases under each LibreOffice release to show exactly when ODDFPRICE’s support changed — not documentation claims, real results.
| LibreOffice version | Verdict | Tested |
|---|---|---|
| 24.2.0.3 | Quirk found | 2026-08-31 |
| 24.8.7.2 | Quirk found | 2026-08-31 |
| 25.2.0.3 | Quirk found | 2026-08-31 |
| 25.8.7.3 | Quirk found | 2026-08-31 |
Why isn't ODDFPRICE working in LibreOffice?
ODDFPRICE exists in LibreOffice 25.8.7.3, but it is not a drop-in match for
Excel — our executed tests found real behavioral differences (detailed in the test results on this
page). If a formula that works in Excel or Google Sheets misbehaves in LibreOffice, compare your usage
against the failing cases above before assuming your data is wrong.
Why isn’t ODDFPRICE working in Google Sheets?
Google Sheets does not implement ODDFPRICE: we imported the formula into
Sheets on 2026-08-31 and every case came back #NAME?
(unrecognized function). Sheets is a rolling service with no version to pin, so this is a
statement about the service on that date, and Google’s own
function list does not document it either. Rewrite the formula with a documented
Sheets equivalent — see the
Excel ↔ Sheets equivalents table.
Discovered quirks
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),2) on
Google Sheets returned
#NAME?, but the documented/expected
result is 113.6.
Provenance
Microsoft publishes =ODDFPRICE(A2, A3, A4, A5, A6, A7, A8, A9, A10) = $ 113.60 for a bond settled 2008-11-11, maturing 2021-03-01, issued 2008-10-15, first coupon 2009-03-01, 7.85% coupon, 6.25% yield, redemption 100, semiannual, actual/actual basis. DERIVATION, clean-room, from the odd-short-first-coupon formula Microsoft prints as an image on the page: price = redemption/(1+yld/f)^(N-1+DSC/E) + 100*(rate/f)*(DFC/E)/(1+yld/f)^(DSC/E) + sum over k = 2..N of 100*(rate/f)/(1+yld/f)^(k-1+DSC/E) - 100*(rate/f)*(A/E), with A = days from the start of the coupon period to settlement, DSC = days from settlement to the next coupon, DFC = days from the start of the odd first coupon to the first coupon date, E = days in the coupon period, and N = coupons payable between settlement and redemption. The quasi-coupon period is generated by walking BACK from first_coupon on the frequency grid, which puts the period at 2008-09-01 to 2009-03-01. On basis 1 (actual/actual) that is E = 181 actual days, with A = 27 (2008-10-15 to 2008-11-11), DSC = 110 (2008-11-11 to 2009-03-01), DFC = 137 (2008-10-15 to 2009-03-01) and N = 25 semiannual coupons from 2009-03-01 through 2021-03-01. The odd first period is SHORT -- 137 days against a 181-day quasi-period -- which is what selects this branch of the formula over the odd-long-first-coupon branch. The day counts come from a clean-room implementation of OpenFormula 1.3 section 4.11.7 -- Procedure A for US (NASD) 30/360 with its four order-dependent endpoint adjustments, Procedure B for actual days, Procedure C for European 30/360, and Procedures D/E/F for days-in-year -- written for this batch and used by no engine; the arithmetic is mpmath at 50 digits over exact rational day-count ratios. The independent computation gives 113.5977174740789..., which is 113.60 at the two decimals Microsoft prints -- the published figure, reproduced from the formula rather than copied. Microsoft's page was re-read live on 2026-08-31 at https://support.microsoft.com/en-us/excel/functions/oddfprice-function (the /en-us/office/<name>-function-<guid> path was returning Microsoft's 'Sorry, the page you're looking for can't be found' body throughout this batch, and the working path serves an 87 KB stub about half the time, so pages were fetched with retries until the payload exceeded 150 KB). EXECUTED RESULT -- NOT IMPLEMENTED, AND NOT SIGNALLED AS SUCH: LibreOffice returns #VALUE! on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3), which agree case for case -- for this case, for every other case in this file, and for every argument combination probed while preparing the batch (five bases, three frequencies, settlement before and after the first coupon, dates as serials, as DATE() calls and as text, and a bond whose first period is deliberately regular). Not one input produced a number. The name is RECOGNISED -- the plain spelling parses, while _xlfn.ODDFPRICE, COM.MICROSOFT.ODDFPRICE and ORG.OPENOFFICE.ODDFPRICE are all #NAME? -- so this is not a storage-form artefact, and it is not an .xlsx import artefact either: the same #VALUE! comes back when the formula is parsed natively by LibreOffice's own parser rather than read from OOXML, on a run where ODDLPRICE and PRICE in the same file computed correctly. LibreOffice's source says why, in as many words: scaddins/source/analysis/analysishelper.cxx defines GetOddfprice() and GetOddfyield() as bodies that do nothing but `throw uno::RuntimeException()`, and financial.cxx wraps both call sites in SAL_WNOUNREACHABLE_CODE_PUSH under the comment "Encapsulation violation: We *know* that GetOddfprice() always throws." The argument validation in front of them is real (rate < 0, frequency, date ordering are all checked) but every path that survives it ends in the same exception, which is why the error cases in this file also come back #VALUE! instead of the documented #NUM!. So: the function is listed, documented in LibreOffice's own help, and computes nothing. Its ODDL* siblings, by contrast, compute the documented values exactly.; MISMATCH vs expected: expected 113.6, got '#NAME?'
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),8) on
Google Sheets returned
#NAME?, but the documented/expected
result is 113.59771747.
Provenance
Two published decimals cannot distinguish a correct odd-period price from one whose quasi-coupon schedule is off by a day, so the derived value is asserted at eight places: 113.59771747. This is the assertion that actually constrains the day counts.; MISMATCH vs expected: expected 113.59771747, got '#NAME?'
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,0),8) on
Google Sheets returned
#NAME?, but the documented/expected
result is 113.59920583.
Provenance
The same bond on basis 0, where every day count is taken under Procedure A instead of actual days: E = 180, A = 26, DSC = 106, DFC = 136. The derived price is 113.5992058282384..., asserted at eight places. The two bases MUST differ here -- unlike the MDURATION case in batch E, settlement does not fall on a coupon date, so the ratios genuinely change -- and the pair of cases pins which basis the engine applied. A basis argument that is silently ignored produces the basis-0 number for the basis-1 case, and this file catches that.; MISMATCH vs expected: expected 113.59920583, got '#NAME?'
-
=ODDFPRICE(A2,A3,A4,A5,-0.0785,A7,A8,A9,A10) on
Google Sheets returned
#NAME?, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "If rate < 0 or if yld < 0, ODDFPRICE returns the #NUM! error value."; MISMATCH vs expected: expected '#NUM!', got '#NAME?'
-
=ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,5) on
Google Sheets returned
#NAME?, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "If basis < 0 or if basis > 4, ODDFPRICE returns the #NUM! error value." The basis table stops at 4 (European 30/360).; MISMATCH vs expected: expected '#NUM!', got '#NAME?'
-
=ODDFPRICE(A5,A3,A4,A2,A6,A7,A8,A9,A10) on
Google Sheets returned
#NAME?, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "The following date condition must be satisfied; otherwise, ODDFPRICE returns the #NUM! error value: maturity > first_coupon > settlement > issue." Swapping the settlement and first-coupon arguments puts settlement (2009-03-01) after first_coupon (2008-11-11) and also before issue, breaking the chain in two places at once.; MISMATCH vs expected: expected '#NUM!', got '#NAME?'
-
=ODDFPRICE("not a date",A3,A4,A5,A6,A7,A8,A9,A10) on
Google Sheets returned
#NAME?, but the documented/expected
result is #VALUE!.
Provenance
Microsoft documents: "If settlement, maturity, issue, or first_coupon is not a valid date, ODDFPRICE returns the #VALUE! error value." The page uses #VALUE! for a malformed date and #NUM! for every out-of-range or mis-ordered argument, so the two codes are asserted separately.; MISMATCH vs expected: expected '#VALUE!', got '#NAME?'
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),2) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is 113.6.
Provenance
Microsoft publishes =ODDFPRICE(A2, A3, A4, A5, A6, A7, A8, A9, A10) = $ 113.60 for a bond settled 2008-11-11, maturing 2021-03-01, issued 2008-10-15, first coupon 2009-03-01, 7.85% coupon, 6.25% yield, redemption 100, semiannual, actual/actual basis. DERIVATION, clean-room, from the odd-short-first-coupon formula Microsoft prints as an image on the page: price = redemption/(1+yld/f)^(N-1+DSC/E) + 100*(rate/f)*(DFC/E)/(1+yld/f)^(DSC/E) + sum over k = 2..N of 100*(rate/f)/(1+yld/f)^(k-1+DSC/E) - 100*(rate/f)*(A/E), with A = days from the start of the coupon period to settlement, DSC = days from settlement to the next coupon, DFC = days from the start of the odd first coupon to the first coupon date, E = days in the coupon period, and N = coupons payable between settlement and redemption. The quasi-coupon period is generated by walking BACK from first_coupon on the frequency grid, which puts the period at 2008-09-01 to 2009-03-01. On basis 1 (actual/actual) that is E = 181 actual days, with A = 27 (2008-10-15 to 2008-11-11), DSC = 110 (2008-11-11 to 2009-03-01), DFC = 137 (2008-10-15 to 2009-03-01) and N = 25 semiannual coupons from 2009-03-01 through 2021-03-01. The odd first period is SHORT -- 137 days against a 181-day quasi-period -- which is what selects this branch of the formula over the odd-long-first-coupon branch. The day counts come from a clean-room implementation of OpenFormula 1.3 section 4.11.7 -- Procedure A for US (NASD) 30/360 with its four order-dependent endpoint adjustments, Procedure B for actual days, Procedure C for European 30/360, and Procedures D/E/F for days-in-year -- written for this batch and used by no engine; the arithmetic is mpmath at 50 digits over exact rational day-count ratios. The independent computation gives 113.5977174740789..., which is 113.60 at the two decimals Microsoft prints -- the published figure, reproduced from the formula rather than copied. Microsoft's page was re-read live on 2026-08-31 at https://support.microsoft.com/en-us/excel/functions/oddfprice-function (the /en-us/office/<name>-function-<guid> path was returning Microsoft's 'Sorry, the page you're looking for can't be found' body throughout this batch, and the working path serves an 87 KB stub about half the time, so pages were fetched with retries until the payload exceeded 150 KB). EXECUTED RESULT -- NOT IMPLEMENTED, AND NOT SIGNALLED AS SUCH: LibreOffice returns #VALUE! on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3), which agree case for case -- for this case, for every other case in this file, and for every argument combination probed while preparing the batch (five bases, three frequencies, settlement before and after the first coupon, dates as serials, as DATE() calls and as text, and a bond whose first period is deliberately regular). Not one input produced a number. The name is RECOGNISED -- the plain spelling parses, while _xlfn.ODDFPRICE, COM.MICROSOFT.ODDFPRICE and ORG.OPENOFFICE.ODDFPRICE are all #NAME? -- so this is not a storage-form artefact, and it is not an .xlsx import artefact either: the same #VALUE! comes back when the formula is parsed natively by LibreOffice's own parser rather than read from OOXML, on a run where ODDLPRICE and PRICE in the same file computed correctly. LibreOffice's source says why, in as many words: scaddins/source/analysis/analysishelper.cxx defines GetOddfprice() and GetOddfyield() as bodies that do nothing but `throw uno::RuntimeException()`, and financial.cxx wraps both call sites in SAL_WNOUNREACHABLE_CODE_PUSH under the comment "Encapsulation violation: We *know* that GetOddfprice() always throws." The argument validation in front of them is real (rate < 0, frequency, date ordering are all checked) but every path that survives it ends in the same exception, which is why the error cases in this file also come back #VALUE! instead of the documented #NUM!. So: the function is listed, documented in LibreOffice's own help, and computes nothing. Its ODDL* siblings, by contrast, compute the documented values exactly.; MISMATCH vs expected: expected 113.6, got '#VALUE!'
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),8) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is 113.59771747.
Provenance
Two published decimals cannot distinguish a correct odd-period price from one whose quasi-coupon schedule is off by a day, so the derived value is asserted at eight places: 113.59771747. This is the assertion that actually constrains the day counts.; MISMATCH vs expected: expected 113.59771747, got '#VALUE!'
-
=ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,0),8) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is 113.59920583.
Provenance
The same bond on basis 0, where every day count is taken under Procedure A instead of actual days: E = 180, A = 26, DSC = 106, DFC = 136. The derived price is 113.5992058282384..., asserted at eight places. The two bases MUST differ here -- unlike the MDURATION case in batch E, settlement does not fall on a coupon date, so the ratios genuinely change -- and the pair of cases pins which basis the engine applied. A basis argument that is silently ignored produces the basis-0 number for the basis-1 case, and this file catches that.; MISMATCH vs expected: expected 113.59920583, got '#VALUE!'
-
=ODDFPRICE(A2,A3,A4,A5,-0.0785,A7,A8,A9,A10) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "If rate < 0 or if yld < 0, ODDFPRICE returns the #NUM! error value."; MISMATCH vs expected: expected '#NUM!', got '#VALUE!'
-
=ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,5) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "If basis < 0 or if basis > 4, ODDFPRICE returns the #NUM! error value." The basis table stops at 4 (European 30/360).; MISMATCH vs expected: expected '#NUM!', got '#VALUE!'
-
=ODDFPRICE(A5,A3,A4,A2,A6,A7,A8,A9,A10) on
LibreOffice Calc returned
#VALUE!, but the documented/expected
result is #NUM!.
Provenance
Microsoft documents: "The following date condition must be satisfied; otherwise, ODDFPRICE returns the #NUM! error value: maturity > first_coupon > settlement > issue." Swapping the settlement and first-coupon arguments puts settlement (2009-03-01) after first_coupon (2008-11-11) and also before issue, breaking the chain in two places at once.; MISMATCH vs expected: expected '#NUM!', got '#VALUE!'
Executed test cases
Excel for the web (executed 2026-09-01 via OneDrive recalculation)
These values come from Excel for the web, not from desktop Excel. They are two different implementations of the calculation engine, and this run measured only the web one: the corpus was uploaded to OneDrive as .xlsx, recalculated by Excel for the web on open, and downloaded again for readback. Excel for the web is a rolling service with no pinnable version, so the run is identified by its date. Where a value here disagrees with the Expected column — which is Microsoft’s documentation of the desktop product — we cannot tell you whether the web engine diverges from the desktop one or the documentation is wrong about both, because we do not run desktop Excel.
| Formula | Description | Result | Expected | Verdict |
|---|---|---|---|---|
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),2) | Microsoft's documented worked example, at the two decimals Microsoft publishes | 113.6 | 113.6ProvenanceMicrosoft publishes =ODDFPRICE(A2, A3, A4, A5, A6, A7, A8, A9, A10) = $ 113.60 for a bond settled 2008-11-11, maturing 2021-03-01, issued 2008-10-15, first coupon 2009-03-01, 7.85% coupon, 6.25% yield, redemption 100, semiannual, actual/actual basis. DERIVATION, clean-room, from the odd-short-first-coupon formula Microsoft prints as an image on the page: price = redemption/(1+yld/f)^(N-1+DSC/E) + 100*(rate/f)*(DFC/E)/(1+yld/f)^(DSC/E) + sum over k = 2..N of 100*(rate/f)/(1+yld/f)^(k-1+DSC/E) - 100*(rate/f)*(A/E), with A = days from the start of the coupon period to settlement, DSC = days from settlement to the next coupon, DFC = days from the start of the odd first coupon to the first coupon date, E = days in the coupon period, and N = coupons payable between settlement and redemption. The quasi-coupon period is generated by walking BACK from first_coupon on the frequency grid, which puts the period at 2008-09-01 to 2009-03-01. On basis 1 (actual/actual) that is E = 181 actual days, with A = 27 (2008-10-15 to 2008-11-11), DSC = 110 (2008-11-11 to 2009-03-01), DFC = 137 (2008-10-15 to 2009-03-01) and N = 25 semiannual coupons from 2009-03-01 through 2021-03-01. The odd first period is SHORT -- 137 days against a 181-day quasi-period -- which is what selects this branch of the formula over the odd-long-first-coupon branch. The day counts come from a clean-room implementation of OpenFormula 1.3 section 4.11.7 -- Procedure A for US (NASD) 30/360 with its four order-dependent endpoint adjustments, Procedure B for actual days, Procedure C for European 30/360, and Procedures D/E/F for days-in-year -- written for this batch and used by no engine; the arithmetic is mpmath at 50 digits over exact rational day-count ratios. The independent computation gives 113.5977174740789..., which is 113.60 at the two decimals Microsoft prints -- the published figure, reproduced from the formula rather than copied. Microsoft's page was re-read live on 2026-08-31 at https://support.microsoft.com/en-us/excel/functions/oddfprice-function (the /en-us/office/<name>-function-<guid> path was returning Microsoft's 'Sorry, the page you're looking for can't be found' body throughout this batch, and the working path serves an 87 KB stub about half the time, so pages were fetched with retries until the payload exceeded 150 KB). EXECUTED RESULT -- NOT IMPLEMENTED, AND NOT SIGNALLED AS SUCH: LibreOffice returns #VALUE! on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3), which agree case for case -- for this case, for every other case in this file, and for every argument combination probed while preparing the batch (five bases, three frequencies, settlement before and after the first coupon, dates as serials, as DATE() calls and as text, and a bond whose first period is deliberately regular). Not one input produced a number. The name is RECOGNISED -- the plain spelling parses, while _xlfn.ODDFPRICE, COM.MICROSOFT.ODDFPRICE and ORG.OPENOFFICE.ODDFPRICE are all #NAME? -- so this is not a storage-form artefact, and it is not an .xlsx import artefact either: the same #VALUE! comes back when the formula is parsed natively by LibreOffice's own parser rather than read from OOXML, on a run where ODDLPRICE and PRICE in the same file computed correctly. LibreOffice's source says why, in as many words: scaddins/source/analysis/analysishelper.cxx defines GetOddfprice() and GetOddfyield() as bodies that do nothing but `throw uno::RuntimeException()`, and financial.cxx wraps both call sites in SAL_WNOUNREACHABLE_CODE_PUSH under the comment "Encapsulation violation: We *know* that GetOddfprice() always throws." The argument validation in front of them is real (rate < 0, frequency, date ordering are all checked) but every path that survives it ends in the same exception, which is why the error cases in this file also come back #VALUE! instead of the documented #NUM!. So: the function is listed, documented in LibreOffice's own help, and computes nothing. Its ODDL* siblings, by contrast, compute the documented values exactly. |
Matched |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),8) | The same example carried to eight decimal places | 113.59771747 | 113.59771747ProvenanceTwo published decimals cannot distinguish a correct odd-period price from one whose quasi-coupon schedule is off by a day, so the derived value is asserted at eight places: 113.59771747. This is the assertion that actually constrains the day counts. |
Matched |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,0),8) | The identical bond priced on basis 0 (US 30/360) instead of actual/actual | 113.59920583 | 113.59920583ProvenanceThe same bond on basis 0, where every day count is taken under Procedure A instead of actual days: E = 180, A = 26, DSC = 106, DFC = 136. The derived price is 113.5992058282384..., asserted at eight places. The two bases MUST differ here -- unlike the MDURATION case in batch E, settlement does not fall on a coupon date, so the ratios genuinely change -- and the pair of cases pins which basis the engine applied. A basis argument that is silently ignored produces the basis-0 number for the basis-1 case, and this file catches that. |
Matched |
| =ODDFPRICE(A2,A3,A4,A5,-0.0785,A7,A8,A9,A10) | A negative coupon rate, which the page excludes | #NUM! | #NUM!ProvenanceMicrosoft documents: "If rate < 0 or if yld < 0, ODDFPRICE returns the #NUM! error value." |
Matched |
| =ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,5) | A basis of 5, one past the documented range | #NUM! | #NUM!ProvenanceMicrosoft documents: "If basis < 0 or if basis > 4, ODDFPRICE returns the #NUM! error value." The basis table stops at 4 (European 30/360). |
Matched |
| =ODDFPRICE(A5,A3,A4,A2,A6,A7,A8,A9,A10) | Settlement and first_coupon swapped, breaking the documented date ordering | #NUM! | #NUM!ProvenanceMicrosoft documents: "The following date condition must be satisfied; otherwise, ODDFPRICE returns the #NUM! error value: maturity > first_coupon > settlement > issue." Swapping the settlement and first-coupon arguments puts settlement (2009-03-01) after first_coupon (2008-11-11) and also before issue, breaking the chain in two places at once. |
Matched |
| =ODDFPRICE("not a date",A3,A4,A5,A6,A7,A8,A9,A10) | A settlement date that is not a date | #VALUE! | #VALUE!ProvenanceMicrosoft documents: "If settlement, maturity, issue, or first_coupon is not a valid date, ODDFPRICE returns the #VALUE! error value." The page uses #VALUE! for a malformed date and #NUM! for every out-of-range or mis-ordered argument, so the two codes are asserted separately. |
Matched |
Google Sheets (executed 2026-08-31 via Drive import)
Google Sheets is a rolling service with no pinnable version, so this run is identified by its date. The corpus was imported to Drive as .xlsx, recalculated by Sheets, and exported back for readback.
| Formula | Description | Result | Expected | Verdict |
|---|---|---|---|---|
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),2) | Microsoft's documented worked example, at the two decimals Microsoft publishes | #NAME? | 113.6ProvenanceMicrosoft publishes =ODDFPRICE(A2, A3, A4, A5, A6, A7, A8, A9, A10) = $ 113.60 for a bond settled 2008-11-11, maturing 2021-03-01, issued 2008-10-15, first coupon 2009-03-01, 7.85% coupon, 6.25% yield, redemption 100, semiannual, actual/actual basis. DERIVATION, clean-room, from the odd-short-first-coupon formula Microsoft prints as an image on the page: price = redemption/(1+yld/f)^(N-1+DSC/E) + 100*(rate/f)*(DFC/E)/(1+yld/f)^(DSC/E) + sum over k = 2..N of 100*(rate/f)/(1+yld/f)^(k-1+DSC/E) - 100*(rate/f)*(A/E), with A = days from the start of the coupon period to settlement, DSC = days from settlement to the next coupon, DFC = days from the start of the odd first coupon to the first coupon date, E = days in the coupon period, and N = coupons payable between settlement and redemption. The quasi-coupon period is generated by walking BACK from first_coupon on the frequency grid, which puts the period at 2008-09-01 to 2009-03-01. On basis 1 (actual/actual) that is E = 181 actual days, with A = 27 (2008-10-15 to 2008-11-11), DSC = 110 (2008-11-11 to 2009-03-01), DFC = 137 (2008-10-15 to 2009-03-01) and N = 25 semiannual coupons from 2009-03-01 through 2021-03-01. The odd first period is SHORT -- 137 days against a 181-day quasi-period -- which is what selects this branch of the formula over the odd-long-first-coupon branch. The day counts come from a clean-room implementation of OpenFormula 1.3 section 4.11.7 -- Procedure A for US (NASD) 30/360 with its four order-dependent endpoint adjustments, Procedure B for actual days, Procedure C for European 30/360, and Procedures D/E/F for days-in-year -- written for this batch and used by no engine; the arithmetic is mpmath at 50 digits over exact rational day-count ratios. The independent computation gives 113.5977174740789..., which is 113.60 at the two decimals Microsoft prints -- the published figure, reproduced from the formula rather than copied. Microsoft's page was re-read live on 2026-08-31 at https://support.microsoft.com/en-us/excel/functions/oddfprice-function (the /en-us/office/<name>-function-<guid> path was returning Microsoft's 'Sorry, the page you're looking for can't be found' body throughout this batch, and the working path serves an 87 KB stub about half the time, so pages were fetched with retries until the payload exceeded 150 KB). EXECUTED RESULT -- NOT IMPLEMENTED, AND NOT SIGNALLED AS SUCH: LibreOffice returns #VALUE! on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3), which agree case for case -- for this case, for every other case in this file, and for every argument combination probed while preparing the batch (five bases, three frequencies, settlement before and after the first coupon, dates as serials, as DATE() calls and as text, and a bond whose first period is deliberately regular). Not one input produced a number. The name is RECOGNISED -- the plain spelling parses, while _xlfn.ODDFPRICE, COM.MICROSOFT.ODDFPRICE and ORG.OPENOFFICE.ODDFPRICE are all #NAME? -- so this is not a storage-form artefact, and it is not an .xlsx import artefact either: the same #VALUE! comes back when the formula is parsed natively by LibreOffice's own parser rather than read from OOXML, on a run where ODDLPRICE and PRICE in the same file computed correctly. LibreOffice's source says why, in as many words: scaddins/source/analysis/analysishelper.cxx defines GetOddfprice() and GetOddfyield() as bodies that do nothing but `throw uno::RuntimeException()`, and financial.cxx wraps both call sites in SAL_WNOUNREACHABLE_CODE_PUSH under the comment "Encapsulation violation: We *know* that GetOddfprice() always throws." The argument validation in front of them is real (rate < 0, frequency, date ordering are all checked) but every path that survives it ends in the same exception, which is why the error cases in this file also come back #VALUE! instead of the documented #NUM!. So: the function is listed, documented in LibreOffice's own help, and computes nothing. Its ODDL* siblings, by contrast, compute the documented values exactly. |
Mismatch |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),8) | The same example carried to eight decimal places | #NAME? | 113.59771747ProvenanceTwo published decimals cannot distinguish a correct odd-period price from one whose quasi-coupon schedule is off by a day, so the derived value is asserted at eight places: 113.59771747. This is the assertion that actually constrains the day counts. |
Mismatch |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,0),8) | The identical bond priced on basis 0 (US 30/360) instead of actual/actual | #NAME? | 113.59920583ProvenanceThe same bond on basis 0, where every day count is taken under Procedure A instead of actual days: E = 180, A = 26, DSC = 106, DFC = 136. The derived price is 113.5992058282384..., asserted at eight places. The two bases MUST differ here -- unlike the MDURATION case in batch E, settlement does not fall on a coupon date, so the ratios genuinely change -- and the pair of cases pins which basis the engine applied. A basis argument that is silently ignored produces the basis-0 number for the basis-1 case, and this file catches that. |
Mismatch |
| =ODDFPRICE(A2,A3,A4,A5,-0.0785,A7,A8,A9,A10) | A negative coupon rate, which the page excludes | #NAME? | #NUM!ProvenanceMicrosoft documents: "If rate < 0 or if yld < 0, ODDFPRICE returns the #NUM! error value." |
Mismatch |
| =ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,5) | A basis of 5, one past the documented range | #NAME? | #NUM!ProvenanceMicrosoft documents: "If basis < 0 or if basis > 4, ODDFPRICE returns the #NUM! error value." The basis table stops at 4 (European 30/360). |
Mismatch |
| =ODDFPRICE(A5,A3,A4,A2,A6,A7,A8,A9,A10) | Settlement and first_coupon swapped, breaking the documented date ordering | #NAME? | #NUM!ProvenanceMicrosoft documents: "The following date condition must be satisfied; otherwise, ODDFPRICE returns the #NUM! error value: maturity > first_coupon > settlement > issue." Swapping the settlement and first-coupon arguments puts settlement (2009-03-01) after first_coupon (2008-11-11) and also before issue, breaking the chain in two places at once. |
Mismatch |
| =ODDFPRICE("not a date",A3,A4,A5,A6,A7,A8,A9,A10) | A settlement date that is not a date | #NAME? | #VALUE!ProvenanceMicrosoft documents: "If settlement, maturity, issue, or first_coupon is not a valid date, ODDFPRICE returns the #VALUE! error value." The page uses #VALUE! for a malformed date and #NUM! for every out-of-range or mis-ordered argument, so the two codes are asserted separately. |
Mismatch |
LibreOffice Calc 25.8.7.3 (tested 2026-08-31)
| Formula | Description | Result | Expected | Verdict |
|---|---|---|---|---|
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),2) | Microsoft's documented worked example, at the two decimals Microsoft publishes | #VALUE! | 113.6ProvenanceMicrosoft publishes =ODDFPRICE(A2, A3, A4, A5, A6, A7, A8, A9, A10) = $ 113.60 for a bond settled 2008-11-11, maturing 2021-03-01, issued 2008-10-15, first coupon 2009-03-01, 7.85% coupon, 6.25% yield, redemption 100, semiannual, actual/actual basis. DERIVATION, clean-room, from the odd-short-first-coupon formula Microsoft prints as an image on the page: price = redemption/(1+yld/f)^(N-1+DSC/E) + 100*(rate/f)*(DFC/E)/(1+yld/f)^(DSC/E) + sum over k = 2..N of 100*(rate/f)/(1+yld/f)^(k-1+DSC/E) - 100*(rate/f)*(A/E), with A = days from the start of the coupon period to settlement, DSC = days from settlement to the next coupon, DFC = days from the start of the odd first coupon to the first coupon date, E = days in the coupon period, and N = coupons payable between settlement and redemption. The quasi-coupon period is generated by walking BACK from first_coupon on the frequency grid, which puts the period at 2008-09-01 to 2009-03-01. On basis 1 (actual/actual) that is E = 181 actual days, with A = 27 (2008-10-15 to 2008-11-11), DSC = 110 (2008-11-11 to 2009-03-01), DFC = 137 (2008-10-15 to 2009-03-01) and N = 25 semiannual coupons from 2009-03-01 through 2021-03-01. The odd first period is SHORT -- 137 days against a 181-day quasi-period -- which is what selects this branch of the formula over the odd-long-first-coupon branch. The day counts come from a clean-room implementation of OpenFormula 1.3 section 4.11.7 -- Procedure A for US (NASD) 30/360 with its four order-dependent endpoint adjustments, Procedure B for actual days, Procedure C for European 30/360, and Procedures D/E/F for days-in-year -- written for this batch and used by no engine; the arithmetic is mpmath at 50 digits over exact rational day-count ratios. The independent computation gives 113.5977174740789..., which is 113.60 at the two decimals Microsoft prints -- the published figure, reproduced from the formula rather than copied. Microsoft's page was re-read live on 2026-08-31 at https://support.microsoft.com/en-us/excel/functions/oddfprice-function (the /en-us/office/<name>-function-<guid> path was returning Microsoft's 'Sorry, the page you're looking for can't be found' body throughout this batch, and the working path serves an 87 KB stub about half the time, so pages were fetched with retries until the payload exceeded 150 KB). EXECUTED RESULT -- NOT IMPLEMENTED, AND NOT SIGNALLED AS SUCH: LibreOffice returns #VALUE! on all four pinned builds (24.2.0.3, 24.8.7.2, 25.2.0.3, 25.8.7.3), which agree case for case -- for this case, for every other case in this file, and for every argument combination probed while preparing the batch (five bases, three frequencies, settlement before and after the first coupon, dates as serials, as DATE() calls and as text, and a bond whose first period is deliberately regular). Not one input produced a number. The name is RECOGNISED -- the plain spelling parses, while _xlfn.ODDFPRICE, COM.MICROSOFT.ODDFPRICE and ORG.OPENOFFICE.ODDFPRICE are all #NAME? -- so this is not a storage-form artefact, and it is not an .xlsx import artefact either: the same #VALUE! comes back when the formula is parsed natively by LibreOffice's own parser rather than read from OOXML, on a run where ODDLPRICE and PRICE in the same file computed correctly. LibreOffice's source says why, in as many words: scaddins/source/analysis/analysishelper.cxx defines GetOddfprice() and GetOddfyield() as bodies that do nothing but `throw uno::RuntimeException()`, and financial.cxx wraps both call sites in SAL_WNOUNREACHABLE_CODE_PUSH under the comment "Encapsulation violation: We *know* that GetOddfprice() always throws." The argument validation in front of them is real (rate < 0, frequency, date ordering are all checked) but every path that survives it ends in the same exception, which is why the error cases in this file also come back #VALUE! instead of the documented #NUM!. So: the function is listed, documented in LibreOffice's own help, and computes nothing. Its ODDL* siblings, by contrast, compute the documented values exactly. |
Mismatch |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,A10),8) | The same example carried to eight decimal places | #VALUE! | 113.59771747ProvenanceTwo published decimals cannot distinguish a correct odd-period price from one whose quasi-coupon schedule is off by a day, so the derived value is asserted at eight places: 113.59771747. This is the assertion that actually constrains the day counts. |
Mismatch |
| =ROUND(ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,0),8) | The identical bond priced on basis 0 (US 30/360) instead of actual/actual | #VALUE! | 113.59920583ProvenanceThe same bond on basis 0, where every day count is taken under Procedure A instead of actual days: E = 180, A = 26, DSC = 106, DFC = 136. The derived price is 113.5992058282384..., asserted at eight places. The two bases MUST differ here -- unlike the MDURATION case in batch E, settlement does not fall on a coupon date, so the ratios genuinely change -- and the pair of cases pins which basis the engine applied. A basis argument that is silently ignored produces the basis-0 number for the basis-1 case, and this file catches that. |
Mismatch |
| =ODDFPRICE(A2,A3,A4,A5,-0.0785,A7,A8,A9,A10) | A negative coupon rate, which the page excludes | #VALUE! | #NUM!ProvenanceMicrosoft documents: "If rate < 0 or if yld < 0, ODDFPRICE returns the #NUM! error value." |
Mismatch |
| =ODDFPRICE(A2,A3,A4,A5,A6,A7,A8,A9,5) | A basis of 5, one past the documented range | #VALUE! | #NUM!ProvenanceMicrosoft documents: "If basis < 0 or if basis > 4, ODDFPRICE returns the #NUM! error value." The basis table stops at 4 (European 30/360). |
Mismatch |
| =ODDFPRICE(A5,A3,A4,A2,A6,A7,A8,A9,A10) | Settlement and first_coupon swapped, breaking the documented date ordering | #VALUE! | #NUM!ProvenanceMicrosoft documents: "The following date condition must be satisfied; otherwise, ODDFPRICE returns the #NUM! error value: maturity > first_coupon > settlement > issue." Swapping the settlement and first-coupon arguments puts settlement (2009-03-01) after first_coupon (2008-11-11) and also before issue, breaking the chain in two places at once. |
Mismatch |
| =ODDFPRICE("not a date",A3,A4,A5,A6,A7,A8,A9,A10) | A settlement date that is not a date | #VALUE! | #VALUE!ProvenanceMicrosoft documents: "If settlement, maturity, issue, or first_coupon is not a valid date, ODDFPRICE returns the #VALUE! error value." The page uses #VALUE! for a malformed date and #NUM! for every out-of-range or mis-ordered argument, so the two codes are asserted separately. |
Matched |
Docs & syntax
- Excel (desktop): official documentation
- LibreOffice Calc: official documentation
Where ODDFPRICE behaves differently
- Bond and treasury functions after a migration: what actually breaks
Executed across 26 fixed-income functions and 161 cases: ODDFPRICE and ODDFYIELD are literal stubs in LibreOffice, TBILLPRICE prices a two-year bill, INTRATE's default basis loses a day, and MDURATION is wrong on actual/actual. 83 of 84 documented #NUM! cases arrive as #VALUE!. Google Sheets matched 127 of 161.