{
  "schemaVersion": 1,
  "slug": "growing-season-calculator",
  "category": "weather",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "64f65b951f4b5e8a5ae6c1cab5ec2ba942012b6e03c8d27e0fcccf39a95e91de",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/growing-season-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": "D = t₁ − t₀; W = max(0, D − L); t_d = t₁ − L",
    "vars": [
      [
        "t_0",
        "Last spring frost date"
      ],
      [
        "t_1",
        "First autumn frost date"
      ],
      [
        "D",
        "Frost-free days"
      ],
      [
        "L",
        "Transplant lead time, days"
      ],
      [
        "W",
        "Planting window, days"
      ],
      [
        "t_d",
        "Latest safe harvest date"
      ]
    ],
    "note": "Requires a valid spring date earlier than the autumn date. Crop lead times are rough planning assumptions, not a local frost forecast."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-12",
    "sources": [
      {
        "name": "NOAA NCEI — Frost and freeze climate normals",
        "url": "https://www.ncei.noaa.gov/products/land-based-station/us-climate-normals"
      }
    ],
    "referenceRole": "input",
    "implementationHash": "64f65b951f4b5e8a5ae6c1cab5ec2ba942012b6e03c8d27e0fcccf39a95e91de",
    "basis": "D = t₁ − t₀; W = max(0, D − L); t_d = t₁ − L",
    "limitations": "Use the cited guidance and your own measurements, bills or product specifications to choose inputs. Sample defaults are not current local data."
  },
  "contract": {
    "compute": "const parseDate = (s) => { if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(String(s))) return null; const d = new Date(s + 'T00:00:00Z'); return Number.isNaN(d.getTime()) || d.toISOString().slice(0,10) !== s ? null : d; }; const a = parseDate(lastFrost); const b = parseDate(firstFrost); if (!a || !b || b <= a) return { seasonDays: null, seasonWeeks: null, seasonMonths: null, plantingWindow: null, harvestDeadline: null, cropsSuitable: null, frostFree: null, __error: 'inputError' }; const days = Math.round((b - a)/86400000); const lead = cropType === 'tropical' ? 0 : cropType === 'warm' ? 14 : cropType === 'cool' ? 21 : 35; const window = Math.max(0, days - lead); const deadline = new Date(b.getTime() - lead*86400000); const suitable = days >= 150 ? 'Nearly everything, including heat lovers' : days >= 120 ? 'Warm-season crops and most vegetables' : days >= 90 ? 'Cool-season crops and fast warm crops' : 'Hardy greens, roots and quick salad crops'; return { seasonDays: days, seasonWeeks: days/7, seasonMonths: days/30.44, plantingWindow: window, harvestDeadline: deadline.toISOString().slice(0, 10), cropsSuitable: suitable, frostFree: 'Dates in order' };",
    "inputs": [
      {
        "name": "lastFrost",
        "type": "date",
        "default": "@today+7m",
        "step": 1
      },
      {
        "name": "firstFrost",
        "type": "date",
        "default": "@today+12m",
        "step": 1
      },
      {
        "name": "cropType",
        "type": "select",
        "default": "warm",
        "options": [
          {
            "value": "hardy"
          },
          {
            "value": "cool"
          },
          {
            "value": "warm"
          },
          {
            "value": "tropical"
          }
        ]
      }
    ],
    "outputs": [
      {
        "name": "seasonDays",
        "precision": 0,
        "unit": "days"
      },
      {
        "name": "seasonWeeks",
        "precision": 1,
        "unit": "weeks"
      },
      {
        "name": "seasonMonths",
        "precision": 1,
        "unit": "months"
      },
      {
        "name": "plantingWindow",
        "precision": 0,
        "unit": "days"
      },
      {
        "name": "harvestDeadline",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "cropsSuitable",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "frostFree",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
