{
  "category": "Date and time functions",
  "display_name": "EOMONTH",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.EOMONTH",
  "implementation_state": {
    "answer_bank": {
      "excel_builds": [
        "20430"
      ],
      "larger_numeric": 0,
      "last_bit": 0,
      "matched": 9838,
      "other_mismatch": 0,
      "refused": 0,
      "rows": 9838,
      "unread": 0,
      "worst_ulp": 0
    },
    "detail": "Recorded: 9,838 in the answer bank and 7 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 9,845 recorded answers",
    "workbook_corpus": {
      "cells": 7,
      "matched": 7
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/dates.rs#L300-L304",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/date_kernels.rs#L233-L243"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/dates::environment",
        "catalogue/dates::system",
        "catalogue/dates::to_1900",
        "catalogue/dates::from_1900",
        "catalogue/dates::date_arg",
        "catalogue/dates::strict_date_arg",
        "catalogue/dates::strict_num",
        "catalogue/dates::serial_out",
        "locale::days_from_civil",
        "locale::excel_serial_from_ymd",
        "ported/date_kernels::days_from_civil",
        "ported/date_kernels::civil_from_days",
        "ported/date_kernels::ymd_1900",
        "ported/date_kernels::is_leap",
        "ported/date_kernels::days_in_month",
        "ported/date_kernels::whole_serial",
        "ported/date_kernels::whole",
        "ported/date_kernels::shifted_month"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/dates.rs#L300-L304",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 9,845 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.EOMONTH.json",
  "name": "EOMONTH",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- **[EDATE](FUNC.EDATE.md)** — the same month arithmetic preserving the day-of-month rather than\n  jumping to the month end. The two coincide when `start_date` is already a month end and the\n  target month is no shorter.\n- **[DATE](FUNC.DATE.md)** — the hand-rolled equivalent is `DATE(YEAR(s), MONTH(s)+n+1, 0)`, which\n  works by `DATE`'s documented day-underflow rule (day 0 of a month is the last day of the\n  previous one). Anyone who has written that expression has been using `DATE` as an `EOMONTH`.\n- **[DAY](FUNC.DAY.md)** — `DAY(EOMONTH(s,0))` is the days-in-month idiom.\n- **[YEARFRAC](FUNC.YEARFRAC.md)** — shares the end-of-February sensitivity: Microsoft documents\n  that `YEARFRAC` \"may return an incorrect result when using the US (NASD) 30/360 basis, and the\n  start_date is the last day in February\", which is exactly the kind of date `EOMONTH` produces.\n  The two functions are frequently composed, so the interaction is real.\n- **[WORKDAY](FUNC.WORKDAY.md)** — month ends are frequently adjusted to business days afterwards.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n1. **Compute in (year, month) space and take the month length last.** Adding `months` to a\n   zero-based month index with floor-division carry, then looking up the target month's length, is\n   both simpler and less error-prone than any day-count approach.\n2. **February 1900 is the special case.** If the implementation models the leap-year artefact as a\n   coordinate shift (the recommendation on [FUNC.DAY](FUNC.DAY.md)), then the \"length of February\n   1900\" question has to be answered deliberately: the real calendar says 28, Excel's serial line\n   contains a 29th.\n3. **Truncate `months` toward zero**, per the documented word.\n4. **Do not share an error path with `EDATE`** until the documented `#NUM!`/`#VALUE!` discrepancy is\n   resolved by observation.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns a `Number`: a whole date serial with no time component.\n\n- **February.** `EOMONTH` is one of the few places in the category where correct leap-year handling\n  is directly observable in ordinary use — and where the 1900 artefact is directly reachable.\n  `EOMONTH` of a February 1900 date asks whether the implementation believes in the phantom 29\n  February; see [FUNC.DATE](FUNC.DATE.md).\n- **`months = 0`** does not return `start_date`; it returns the month end. Any time component of\n  `start_date` is not carried into the result.\n- **Result out of range** is documented as an error, unlike on the `EDATE` page — see below.\n- **Very large `months`** simply carries through years; the range check is on the result.\n\n\n\n### Errors\n\n\nAs documented on the Microsoft `EOMONTH` page:\n\n- `#NUM!` when `start_date` is not a valid date.\n- `#NUM!` when `start_date` plus `months` yields an invalid date.\n\nNote the discrepancy with the sibling: [EDATE](FUNC.EDATE.md)'s page documents **`#VALUE!`** for an\ninvalid `start_date`, and documents no result-out-of-range condition at all. Two functions of the\nsame shape, taking the same arguments, documented with different error values for the same failure.\nThis Handbook does not silently pick a winner: the divergence is stated, and resolving it against a\nrunning Excel is listed below as an unrun experiment. See\n[claim language](../model/06-claim-language.md), rule 5.\n\n`#VALUE!` from an argument that will not coerce, and propagation of an error argument, are the\nordinary behaviours described in\n[coercion and lifting](../model/02-coercion-and-lifting.md).\n\n\n",
    "sources": "\n- Microsoft 365 support, **EOMONTH function** —\n  <https://support.microsoft.com/en-us/office/eomonth-function-7314ffa1-2bc9-4005-9d66-f49db127d628>.\n  Source of the syntax, the `months` truncation rule and both documented `#NUM!` conditions.\n- Microsoft 365 support, **EDATE function** —\n  <https://support.microsoft.com/en-us/office/edate-function-3c920eb2-6e66-44e7-a1f5-753ae47ee4f5>.\n  Cited for the contrasting documented error value.\n- Microsoft 365 support, **YEARFRAC function** —\n  <https://support.microsoft.com/en-us/office/yearfrac-function-3844141e-c76d-4143-82b6-208454ddc6a8>.\n  Source of the last-day-of-February caveat quoted above.\n- [FUNC.DATE](FUNC.DATE.md) — serial model, the day-underflow rule and the leap-year artefact.\n- `data/functions/FUNC.EOMONTH.json`, `data/presence/FUNC.EOMONTH.json`,\n  `data/battery/FUNC.EOMONTH.json`.\n\n",
    "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.\n\n| Excel 16.0 build | Platform and CPU | Captured inputs |\n|---|---|---:|\n| 20430 | Windows, 64-bit, CPU not recorded | 9,838 |\n\nThe 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.\n\n[Recorded environments and comparison details](https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/5dc75391aa5125ccc5abdb095da85950980d6fd8/content/evidence/environments/FUNC.EOMONTH.json).",
    "what-it-does": "\n`EOMONTH` offsets a date by a whole number of months and returns the serial of the **last day of\nthe resulting month**. The day-of-month of `start_date` is discarded entirely: only its year and\nmonth matter.\n\nPrecisely: let `(y, m)` be the year and month of `start_date`; add `months` to `m` with carry into\n`y`; return the serial of the last day of that `(y, m)`. `EOMONTH(s, 0)` is therefore \"the end of\nthis month\" and `EOMONTH(s, -1)` is \"the end of last month\", which is why the function turns up in\nalmost every period-boundary formula in finance.\n\nTwo identities follow, and both are used constantly:\n\n- `DAY(EOMONTH(s, 0))` is the number of days in `s`'s month.\n- `EOMONTH(s, -1) + 1` is the first day of `s`'s month.\n\nThe second is the idiomatic \"start of month\" expression precisely because Excel has no `BOMONTH`.\n\n\n\n### Arguments\n\n\n`EOMONTH(start_date, months)` — both required.\n\n**start_date** — \"a date that represents the starting date\". Microsoft repeats the category\nguidance that dates \"should be entered by using the DATE function, or as results of other formulas\nor functions\" rather than as text.\n\n**months** — \"the number of months before or after start_date. A positive value for months yields a\nfuture date; a negative value yields a past date.\" The page states the conversion rule explicitly:\n**\"If months is not an integer, it is truncated.\"** Truncation is toward zero on the ordinary\nreading of the word, which makes the negative fractional case (`months = -1.5`) the one worth\ntesting.\n\nThe argument that is misunderstood is `start_date`, and specifically the belief that its day-of-\nmonth matters. It does not: `EOMONTH(DATE(2024,3,1), 0)` and `EOMONTH(DATE(2024,3,31), 0)` are the\nsame value.\n\n\n"
  },
  "signature": {
    "display": "EOMONTH(start_date, months)",
    "parameters": [
      {
        "description": null,
        "name": "start_date",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "months",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 2,
        "min": 2
      },
      "category": "Date and time functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "Last day of the month a number of months before or after a date",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the serial number of the last day of the month before or after a specified number of months",
        "microsoft_url": "https://support.microsoft.com/en-us/office/eomonth-function-7314ffa1-2bc9-4005-9d66-f49db127d628"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "EOMONTH"
        },
        {
          "locale": "bg-BG",
          "name": "EOMONTH"
        },
        {
          "locale": "cs-CZ",
          "name": "EOMONTH"
        },
        {
          "locale": "da-DK",
          "name": "SLUT.PÅ.MÅNED"
        },
        {
          "locale": "de-DE",
          "name": "EOMONTH"
        },
        {
          "locale": "el-GR",
          "name": "EOMONTH"
        },
        {
          "locale": "en-AU",
          "name": "EOMONTH"
        },
        {
          "locale": "en-GB",
          "name": "EOMONTH"
        },
        {
          "locale": "en-US",
          "name": "EOMONTH"
        },
        {
          "locale": "es-ES",
          "name": "FIN.MES"
        },
        {
          "locale": "et-EE",
          "name": "EOMONTH"
        },
        {
          "locale": "fi-FI",
          "name": "EOMONTH"
        },
        {
          "locale": "fr-FR",
          "name": "FIN.MOIS*"
        },
        {
          "locale": "he-IL",
          "name": "EOMONTH"
        },
        {
          "locale": "hr-HR",
          "name": "EOMONTH"
        },
        {
          "locale": "hu-HU",
          "name": "HÓNAP.UTOLSÓ.NAP"
        },
        {
          "locale": "id-ID",
          "name": "EOMONTH"
        },
        {
          "locale": "it-IT",
          "name": "EOMONTH"
        },
        {
          "locale": "ja-JP",
          "name": "EOMONTH"
        },
        {
          "locale": "ko-KR",
          "name": "EOMONTH"
        },
        {
          "locale": "lt-LT",
          "name": "EOMONTH"
        },
        {
          "locale": "lv-LV",
          "name": "EOMONTH"
        },
        {
          "locale": "nb-NO",
          "name": "EOMONTH"
        },
        {
          "locale": "nl-NL",
          "name": "LAATSTE.DAG"
        },
        {
          "locale": "pl-PL",
          "name": "NR.SER.OST.DN.MIES"
        },
        {
          "locale": "pt-BR",
          "name": "EOMONTH"
        },
        {
          "locale": "pt-PT",
          "name": "FIMMÊS"
        },
        {
          "locale": "ro-RO",
          "name": "EOMONTH"
        },
        {
          "locale": "ru-RU",
          "name": "КОНМЕСЯЦА"
        },
        {
          "locale": "sk-SK",
          "name": "EOMONTH"
        },
        {
          "locale": "sl-SI",
          "name": "EOMONTH"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "EOMONTH"
        },
        {
          "locale": "sv-SE",
          "name": "SLUTMÅNAD"
        },
        {
          "locale": "th-TH",
          "name": "EOMONTH"
        },
        {
          "locale": "tr-TR",
          "name": "SERİAY işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "EOMONTH"
        },
        {
          "locale": "vi-VN",
          "name": "EOMONTH"
        },
        {
          "locale": "zh-CN",
          "name": "EOMONTH"
        },
        {
          "locale": "zh-HK",
          "name": "EOMONTH"
        },
        {
          "locale": "zh-TW",
          "name": "EOMONTH"
        }
      ],
      "signature": {
        "display": "EOMONTH(start_date, months)",
        "parameters": [
          {
            "description": null,
            "name": "start_date",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "months",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "EOMONTH",
      "version_marker": null,
      "xlcall": {
        "code": "450",
        "symbol": "xlfEomonth"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/eomonth-function-7314ffa1-2bc9-4005-9d66-f49db127d628"
  },
  "try_it": {
    "formula": "=EOMONTH(DATE(2026,1,15),1)"
  },
  "url": "https://handbook.dnacalc.com/functions/EOMONTH.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "9,838 captured inputs are indexed for this environment. Capture dates: 2026-09-29 to 2026-09-29. This is a reading count, not a comparison with another build.",
      "excel_build": "16.0 build 20430",
      "platform": "Windows, 64-bit, CPU not recorded",
      "sources": [
        "https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/5dc75391aa5125ccc5abdb095da85950980d6fd8/content/evidence/environments/FUNC.EOMONTH.json"
      ]
    }
  ]
}