{
  "schemaVersion": 1,
  "slug": "leap-year-calculator",
  "category": "date-time",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "f4fae092e3a6f134ac9b0692ebb42e4a6ef1c221318a4f618c0ba1f1993b0492",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/leap-year-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "leap = ((y mod 4 = 0) ∧ (y mod 100 ≠ 0)) ∨ (y mod 400 = 0); days = {366, leap = 1; 365, leap = 0}",
    "vars": [
      [
        "y",
        "calendar year (integer)"
      ],
      [
        "leap",
        "leap-year flag (1 = leap year, 0 = common year)"
      ],
      [
        "days",
        "days in the year"
      ],
      [
        "next",
        "next year satisfying the rule"
      ]
    ],
    "note": "The next leap year is found by counting upward from y + 1 until the rule is true; February has 29 days in a leap year, otherwise 28."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-28",
    "sources": [
      {
        "name": "MDN — Date and UTC calendar operations",
        "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date"
      }
    ],
    "referenceRole": "definition",
    "implementationHash": "f4fae092e3a6f134ac9b0692ebb42e4a6ef1c221318a4f618c0ba1f1993b0492",
    "basis": "leap = ((y mod 4 = 0) ∧ (y mod 100 ≠ 0)) ∨ (y mod 400 = 0); days = {366, leap = 1; 365, leap = 0} P1 consolidation retains the core model and adds input modes or derived outputs. The migration report records the input/output union and known-answer checks.",
    "limitations": "The references explain definitions and methods; any extra preset must be checked against the assumptions on this page. Added display totals and migration adapters are implementation behavior, not independently validated claims."
  },
  "contract": {
    "compute": "const mergedResult=(()=>{\nif((true&&(!Number.isFinite(year)||year<1||year>9999))||(true&&(!Number.isFinite(dayOfYear)||dayOfYear<1||dayOfYear>366)))return{__error:'inputError'};\nconst bad={leapStatus:null,daysInYear:null,daysInFebruary:null,nextLeapYear:null,previousLeapYear:null,ruleApplied:null,dayOfYearDate:null,__error:'inputError'};if(!Number.isInteger(year)||year<1||year>9999)return bad;const isLeap=y=>y%4===0&&(y%100!==0||y%400===0),leap=isLeap(year);if(!Number.isInteger(dayOfYear)||dayOfYear<1||dayOfYear>(leap?366:365))return bad;let next=year+1,prev=year-1;while(!isLeap(next))next++;while(prev>0&&!isLeap(prev))prev--;const d=new Date(0);d.setUTCHours(0,0,0,0);d.setUTCFullYear(year,0,dayOfYear);return{leapStatus:leap?'Yes':'No',daysInYear:leap?366:365,daysInFebruary:leap?29:28,nextLeapYear:next,previousLeapYear:prev>0?prev:null,ruleApplied:year%400===0?'Divisible by 400 — leap year despite being a century year':year%100===0?'Divisible by 100 but not 400 — common year':year%4===0?'Divisible by 4 and not by 100 — leap year':'Not divisible by 4 — common year',dayOfYearDate:d.toISOString().slice(0,10)};\n})();return mergedResult.__error?{\"leapStatus\":null,\"daysInYear\":null,\"daysInFebruary\":null,\"nextLeapYear\":null,\"previousLeapYear\":null,\"ruleApplied\":null,\"dayOfYearDate\":null,...mergedResult}:mergedResult;",
    "inputs": [
      {
        "name": "year",
        "type": "number",
        "default": 2028,
        "min": 1,
        "max": 9999,
        "step": 1,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "dayOfYear",
        "type": "number",
        "default": 1,
        "min": 1,
        "max": 366,
        "step": 1,
        "requiredValue": true,
        "strictRange": true,
        "advanced": true
      }
    ],
    "outputs": [
      {
        "name": "leapStatus",
        "type": "text",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "daysInYear",
        "precision": 0,
        "unit": "days",
        "trimTrailingZeros": true
      },
      {
        "name": "daysInFebruary",
        "precision": 0,
        "unit": "days",
        "trimTrailingZeros": true
      },
      {
        "name": "nextLeapYear",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "previousLeapYear",
        "precision": 0,
        "unit": "",
        "type": "number",
        "optional": true
      },
      {
        "name": "ruleApplied",
        "precision": 0,
        "unit": "",
        "type": "text",
        "optional": false
      },
      {
        "name": "dayOfYearDate",
        "precision": 0,
        "unit": "",
        "type": "text",
        "optional": false
      }
    ],
    "interpret": [
      {
        "max": 365.5,
        "key": "common"
      },
      {
        "max": 1000000000,
        "key": "leap"
      }
    ]
  }
}
