{
  "schemaVersion": 1,
  "slug": "countdown-days-calculator",
  "category": "date-time",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "0affa3517fae95a2803e38de809fa0c7b99f1ea22072b22f734efb7548fb7e02",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/countdown-days-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 = |round((E − S) ÷ 86400000)|;  W = Σ w_k − H  (k = 0..D)",
    "vars": [
      [
        "S",
        "Start date"
      ],
      [
        "E",
        "End date"
      ],
      [
        "p",
        "Working days per week"
      ],
      [
        "w_k",
        "Working-day indicator: w_k = 1 on a working day, else 0"
      ],
      [
        "H",
        "Holidays to subtract"
      ],
      [
        "h",
        "Hours per working day"
      ]
    ],
    "note": "Elapsed calendar-day difference excludes the start date; weekday counts include both endpoints. Five days counts Monday–Friday, six excludes Sunday, seven counts all dates, and one to four proportionally scale the Monday–Friday count. Holiday input is a count, not a dated calendar."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const valid=s=>/^\\d{4}-\\d{2}-\\d{2}$/.test(String(s))&&!Number.isNaN(new Date(s+'T00:00:00Z').getTime())&&new Date(s+'T00:00:00Z').toISOString().slice(0,10)===s;const empty={totalDays:null,workingDays:null,restDays:null,workingHours:null,weeks:null,months:null,workingWeeks:null};const p=Number(workingDaysPerWeek),h=Number(hoursPerDay),holiday=Number(holidays);if(!valid(startDate)||!valid(endDate)||!Number.isInteger(p)||p<1||p>7||!Number.isInteger(holiday)||holiday<0||!Number.isFinite(h)||h<0||h>24)return{...empty,__error:'inputError'};const a=new Date(startDate+'T00:00:00Z'),b=new Date(endDate+'T00:00:00Z'),total=Math.abs(Math.round((b-a)/86400000)),dir=b>=a?1:-1,calendarDays=total+1;let weekdayCount=0,scheduled=0;for(let k=0;k<calendarDays;k++){const dow=new Date(a.getTime()+dir*k*86400000).getUTCDay(),weekday=dow!==0&&dow!==6;if(weekday)weekdayCount++;if(p===7||(p===6&&dow!==0)||(p===5&&weekday))scheduled++;}if(p<=4)scheduled=Math.round(weekdayCount*p/5);const wd=Math.max(0,scheduled-Math.min(scheduled,holiday));return{totalDays:total,workingDays:wd,restDays:calendarDays-wd,workingHours:wd*h,weeks:total/7,months:total/30.44,workingWeeks:wd/p};",
    "inputs": [
      {
        "name": "startDate",
        "type": "date",
        "default": "@today",
        "step": 1
      },
      {
        "name": "endDate",
        "type": "date",
        "default": "@today+2m",
        "step": 1
      },
      {
        "name": "holidays",
        "type": "number",
        "default": 2,
        "min": 0,
        "max": 100,
        "step": 1,
        "slider": true
      },
      {
        "name": "workingDaysPerWeek",
        "type": "number",
        "default": 5,
        "min": 1,
        "max": 7,
        "step": 1
      },
      {
        "name": "hoursPerDay",
        "type": "number",
        "default": 8,
        "min": 0,
        "max": 24,
        "step": 0.5,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "totalDays",
        "precision": 0,
        "unit": "days"
      },
      {
        "name": "workingDays",
        "precision": 0,
        "unit": "days"
      },
      {
        "name": "restDays",
        "precision": 0,
        "unit": "days"
      },
      {
        "name": "workingHours",
        "precision": 0,
        "unit": "hours"
      },
      {
        "name": "weeks",
        "precision": 1,
        "unit": "weeks"
      },
      {
        "name": "months",
        "precision": 1,
        "unit": "months"
      },
      {
        "name": "workingWeeks",
        "precision": 1,
        "unit": "weeks"
      }
    ],
    "interpret": null
  }
}
