{
  "category": "Date and time functions",
  "display_name": "EDATE",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.EDATE",
  "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 8 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 9,846 recorded answers",
    "workbook_corpus": {
      "cells": 8,
      "matched": 8
    }
  },
  "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#L295-L299",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/date_kernels.rs#L221-L231"
      ],
      "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#L295-L299",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 9,846 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.EDATE.json",
  "name": "EDATE",
  "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- **[EOMONTH](FUNC.EOMONTH.md)** — the same month offset, but landing on the last day of the target\n  month instead of preserving the day-of-month. `EOMONTH(s, n)` and `EDATE(s, n)` coincide exactly\n  when `s` is already a month end and the target month is no shorter.\n- **[DATE](FUNC.DATE.md)** — the constructor whose month rollover is the *carrying* alternative to\n  `EDATE`'s (expected) clamping.\n- **[WORKDAY](FUNC.WORKDAY.md)** — offsetting by working days rather than months.\n- **[DATEDIF](FUNC.DATEDIF.md) with unit `\"M\"`** — the inverse question: how many whole months lie\n  between two dates.\n- **Confusable.** `EDATE` and `EOMONTH` are near-interchangeable in appearance and never in\n  meaning; and `EDATE(s, 12)` is not the same as `DATE(YEAR(s)+1, MONTH(s), DAY(s))` if the\n  clamping hypothesis holds and `s` is 29 February.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n1. **Write the end-of-month rule down explicitly**, whichever way you implement it. It is the one\n   behaviour of this function that a reader cannot infer from the documentation, and therefore the\n   one a compatibility consumer most needs stated.\n2. **Truncate `months` toward zero**, matching the documented word \"truncated\" — do not floor.\n   `-1.9` truncates to `-1` and floors to `-2`; the two give different answers for every negative\n   fractional offset.\n3. **Do the arithmetic in (year, month) space**, not by adding approximate day counts. Convert the\n   serial to `(y, m, d)`, add `months` to a zero-based month index with a floor-division carry,\n   then reconstruct — clamping `d` at the target month's length if that is the chosen rule.\n4. **Do not assume the sibling's error value.** Until the `#VALUE!`/`#NUM!` discrepancy above is\n   resolved, an implementation that shares one error path between `EDATE` and `EOMONTH` is making\n   an unverified compatibility bet.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns a `Number`: a whole date serial, with no time component.\n\n- **Day-of-month preservation is the defining behaviour** — and the end-of-month case is the\n  undocumented one described above.\n- **`months = 0`** returns the start date's own serial (with any time component dropped), which\n  makes `EDATE(s,0)` a serviceable \"floor to whole day\" idiom.\n- **Fractional `months`** is truncated, per the documented rule.\n- **Fractional `start_date`** — the page does not say whether the time component is truncated\n  before or after the offset. For whole-month arithmetic the two agree, so this is a low-stakes\n  gap, but it is a gap.\n- **The 1900 boundary.** An offset that lands below serial 1 is out of range; see\n  [FUNC.DATE](FUNC.DATE.md) for the serial model, and note that months landing in January or\n  February 1900 interact with the phantom leap day.\n\n\n\n### Errors\n\n\nAs documented on the Microsoft `EDATE` page:\n\n- `#VALUE!` when `start_date` is not a valid date.\n\nThat is the only condition the page states — and it is worth noticing that the sibling\n[EOMONTH](FUNC.EOMONTH.md) page documents `#NUM!` for the corresponding situation, plus a second\n`#NUM!` when `start_date` plus `months` yields an invalid date. Two functions of identical shape,\ndocumented with different error values for the same failure. Whether Excel actually behaves\ndifferently, or whether one of the two pages is simply wrong, is **an open documentation\ndiscrepancy that nobody has resolved against a running Excel for this Handbook.** It is exactly the\nkind of divergence [claim-language rule 5](../model/06-claim-language.md) exists to keep visible\nrather than silently harmonized.\n\n`EDATE`'s page does not document what happens when the *result* is out of range, though `EOMONTH`'s\ndoes for the same operation.\n\n\n",
    "sources": "\n- Microsoft 365 support, **EDATE function** —\n  <https://support.microsoft.com/en-us/office/edate-function-3c920eb2-6e66-44e7-a1f5-753ae47ee4f5>.\n  Source of the syntax, the `months` truncation rule, and the `#VALUE!` condition; it documents no\n  end-of-month rule and no result-out-of-range condition.\n- Microsoft 365 support, **EOMONTH function** —\n  <https://support.microsoft.com/en-us/office/eomonth-function-7314ffa1-2bc9-4005-9d66-f49db127d628>.\n  Cited here for the contrasting documented error values.\n- [FUNC.DATE](FUNC.DATE.md) — serial model and the documented day-carry rule.\n- Handbook chapter [06 claim language](../model/06-claim-language.md), rule 5 (documentation and\n  behaviour shown side by side rather than harmonized).\n- `data/functions/FUNC.EDATE.json`, `data/presence/FUNC.EDATE.json`,\n  `data/battery/FUNC.EDATE.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.EDATE.json).",
    "what-it-does": "\n`EDATE` moves a date by a whole number of months, keeping the day-of-month. The serial it returns\ndenotes the day with the same day-of-month, in the month `months` steps away from `start_date`'s\nmonth.\n\nThe interesting part of that sentence is what it does *not* say, and the documentation does not say\nit either. When the target month has no such day-of-month — 31 January offset by one month, or 29\nFebruary offset by twelve — some rule has to apply. Calendars generally clamp to the last day of\nthe target month, and `EDATE` is widely understood to clamp. **Microsoft's `EDATE` page does not\nstate a rule for that case, and this Handbook has not verified Excel's behaviour.** It is stated\nhere as the expected behaviour and nothing stronger.\n\nThat gap is the whole reason `EDATE` is not simply `DATE(YEAR(s), MONTH(s)+n, DAY(s))`. `DATE`\ncarries excess days *forward* — its documented rule turns a 31st in a 30-day month into the 1st of\nthe next month. If `EDATE` clamps, the two expressions disagree on exactly the dates people build\npayment schedules from. If it does not clamp, `EDATE` is redundant. Either way, the answer is\nload-bearing and it is not written down.\n\n\n\n### Arguments\n\n\n`EDATE(start_date, months)` — both required.\n\n**start_date** — the date to offset. Microsoft's page repeats the category guidance: supply dates\n\"by using the DATE function, or as results of other formulas or functions\", not as text.\n\n**months** — \"the number of months before or after start_date. A positive value for months yields\na future date; a negative value yields a past date.\" The page states the conversion rule\nexplicitly: **\"If months is not an integer, it is truncated.\"** Truncation, not rounding — so\n`EDATE(s, 1.9)` is one month, and `EDATE(s, -1.9)` is, on the ordinary meaning of truncation, minus\none month rather than minus two. The behaviour of truncation on negative values is the part worth\ntesting, because languages disagree about it.\n\n\n"
  },
  "signature": {
    "display": "EDATE(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": "Date a number of months before or after a start date",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the serial number of the date that is the indicated number of months before or after the start date",
        "microsoft_url": "https://support.microsoft.com/en-us/office/edate-function-3c920eb2-6e66-44e7-a1f5-753ae47ee4f5"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "EDATE"
        },
        {
          "locale": "bg-BG",
          "name": "EDATE"
        },
        {
          "locale": "cs-CZ",
          "name": "EDATE"
        },
        {
          "locale": "da-DK",
          "name": "EDATO"
        },
        {
          "locale": "de-DE",
          "name": "EDATE"
        },
        {
          "locale": "el-GR",
          "name": "EDATE"
        },
        {
          "locale": "en-AU",
          "name": "EDATE"
        },
        {
          "locale": "en-GB",
          "name": "EDATE"
        },
        {
          "locale": "en-US",
          "name": "EDATE"
        },
        {
          "locale": "es-ES",
          "name": "FECHA.MES"
        },
        {
          "locale": "et-EE",
          "name": "EDATE"
        },
        {
          "locale": "fi-FI",
          "name": "EDATE"
        },
        {
          "locale": "fr-FR",
          "name": "MOIS.DECALER*"
        },
        {
          "locale": "he-IL",
          "name": "EDATE"
        },
        {
          "locale": "hr-HR",
          "name": "EDATE"
        },
        {
          "locale": "hu-HU",
          "name": "KALK.DÁTUM"
        },
        {
          "locale": "id-ID",
          "name": "EDATE"
        },
        {
          "locale": "it-IT",
          "name": "EDATE"
        },
        {
          "locale": "ja-JP",
          "name": "EDATE"
        },
        {
          "locale": "ko-KR",
          "name": "EDATE"
        },
        {
          "locale": "lt-LT",
          "name": "EDATE"
        },
        {
          "locale": "lv-LV",
          "name": "EDATE"
        },
        {
          "locale": "nb-NO",
          "name": "DAG.ETTER (funksjon)"
        },
        {
          "locale": "nl-NL",
          "name": "ZELFDE.DAG"
        },
        {
          "locale": "pl-PL",
          "name": "NR.SER.DATY"
        },
        {
          "locale": "pt-BR",
          "name": "EDATE"
        },
        {
          "locale": "pt-PT",
          "name": "DATAM"
        },
        {
          "locale": "ro-RO",
          "name": "EDATE"
        },
        {
          "locale": "ru-RU",
          "name": "ДАТАМЕС"
        },
        {
          "locale": "sk-SK",
          "name": "EDATE"
        },
        {
          "locale": "sl-SI",
          "name": "EDATE"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "EDATE"
        },
        {
          "locale": "sv-SE",
          "name": "EDATUM"
        },
        {
          "locale": "th-TH",
          "name": "EDATE"
        },
        {
          "locale": "tr-TR",
          "name": "SERİTARİH işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "EDATE"
        },
        {
          "locale": "vi-VN",
          "name": "EDATE"
        },
        {
          "locale": "zh-CN",
          "name": "EDATE"
        },
        {
          "locale": "zh-HK",
          "name": "EDATE"
        },
        {
          "locale": "zh-TW",
          "name": "EDATE"
        }
      ],
      "signature": {
        "display": "EDATE(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": "EDATE",
      "version_marker": null,
      "xlcall": {
        "code": "449",
        "symbol": "xlfEdate"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/edate-function-3c920eb2-6e66-44e7-a1f5-753ae47ee4f5"
  },
  "try_it": {
    "formula": "=EDATE(DATE(2026,1,31),1)"
  },
  "url": "https://handbook.dnacalc.com/functions/EDATE.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.EDATE.json"
      ]
    }
  ]
}