{
  "schemaVersion": 1,
  "slug": "dog-pregnancy-calculator",
  "category": "pets",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "ce49a880bc1619e3de2c6214c37c8876784a6ae35c84b8133998caa133e47254",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/dog-pregnancy-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": "estimate = reference event + selected days; mating window = +58..72 d; ovulation = +62..64 d; LH / initial progesterone rise = +64..66 d",
    "vars": [],
    "note": "The reference date affects elapsed/remaining days only. These estimates cannot diagnose pregnancy or predict labor; ask a veterinarian."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-31",
    "sources": [
      {
        "name": "Merck Veterinary Manual — whelping and date bases",
        "url": "https://www.merckvetmanual.com/management-and-nutrition/management-of-reproduction-dogs-and-cats/whelping-and-queening-in-bitches-and-queens"
      },
      {
        "name": "Merck Veterinary Manual — reproductive management",
        "url": "https://www.merckvetmanual.com/dog-owners/reproductive-disorders-of-dogs/management-of-reproduction-in-dogs"
      }
    ],
    "referenceRole": "definition",
    "implementationHash": "ce49a880bc1619e3de2c6214c37c8876784a6ae35c84b8133998caa133e47254",
    "basis": "Choose the actual date basis. First mating uses an illustrative 65-day midpoint within a broad 58–72-day window; ovulation uses 63 days with a 62–64-day window; LH surge / initial progesterone rise uses 65 days with 64–66. A custom day count retains the broad mating window and is not a hormone-based prediction. The reference date affects elapsed/remaining days only. These estimates cannot diagnose pregnancy or predict labor; ask a veterinarian.",
    "limitations": "The reference date affects elapsed/remaining days only. These estimates cannot diagnose pregnancy or predict labor; ask a veterinarian."
  },
  "contract": {
    "compute": "try{if((([\"custom\"].includes(String(method)))&&(!Number.isFinite(gestationDays)||gestationDays<58||gestationDays>72)))throw new Error('inputError');const calculate=function(){const h=(function context() {\n  const DAY=86400000;\n  const own=(o,k)=>Object.prototype.hasOwnProperty.call(o,k);\n  const fail=()=>{throw new Error('inputError');};\n  const num=(v,min=-Infinity,max=Infinity,integer=false)=>{\n    if(!Number.isFinite(v)||v<min||v>max||(integer&&!Number.isInteger(v)))fail();return v;\n  };\n  const choice=(v,values)=>{if(!values.includes(v))fail();return v;};\n  const date=s=>{if(typeof s!=='string'||!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)||s.startsWith('0000'))fail();const d=new Date(s+'T00:00:00Z');if(!Number.isFinite(+d)||d.toISOString().slice(0,10)!==s)fail();return d;};\n  const iso=d=>{if(!Number.isFinite(+d)||d.getUTCFullYear()<1||d.getUTCFullYear()>9999)fail();return d.toISOString().slice(0,10);};\n  const shift=(d,n)=>{const r=new Date(+d+n*DAY);iso(r);return r;};\n  const month=(d,n)=>{const r=new Date(+d);r.setUTCDate(1);r.setUTCMonth(r.getUTCMonth()+n);const end=new Date(+r);end.setUTCMonth(end.getUTCMonth()+1,0);r.setUTCDate(Math.min(d.getUTCDate(),end.getUTCDate()));iso(r);return r;};\n  const weekdays=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];\n  const work=(d,count)=>{let n=Math.floor(count/7)*5;for(let k=0;k<count%7;k++){const w=(d.getUTCDay()+k)%7;if(w!==0&&w!==6)n++;}return n;};\n  const wholeMonths=(a,b)=>{let n=(b.getUTCFullYear()-a.getUTCFullYear())*12+b.getUTCMonth()-a.getUTCMonth();if(n>=0&&+month(a,n)>+b)n--;if(n<0&&+month(a,n)<+b)n++;return n;};\n  return {DAY,own,fail,num,choice,date,iso,shift,month,weekdays,work,wholeMonths};\n})();const result=(function(v,h){\n    const {date,choice,num,shift,iso,DAY}=h,a=date(v.matingDate),ref=date(v.asOf);choice(v.method,['custom','mating','ovulation','progesterone']);if(v.method==='custom')num(v.gestationDays,58,72,true);\n    const cfg={mating:[65,58,72],ovulation:[63,62,64],progesterone:[65,64,66],custom:[v.gestationDays,58,72]}[v.method];\n    return {dueDate:iso(shift(a,cfg[0])),rangeStart:iso(shift(a,cfg[1])),rangeEnd:iso(shift(a,cfg[2])),daysElapsed:Math.round((ref-a)/DAY),daysRemaining:Math.round((shift(a,cfg[0])-ref)/DAY)};\n  })({\"matingDate\":(matingDate),\"gestationDays\":(gestationDays),\"asOf\":(asOf),\"method\":(method)},h);return result;};const out=calculate();return Object.fromEntries([\"dueDate\",\"rangeStart\",\"rangeEnd\",\"daysElapsed\",\"daysRemaining\"].map(k=>[k,out[k]??null]).concat(Object.entries(out).filter(([k])=>k.startsWith('__'))));}catch(error){return Object.assign(Object.fromEntries([\"dueDate\",\"rangeStart\",\"rangeEnd\",\"daysElapsed\",\"daysRemaining\"].map(k=>[k,null])),{__error:error.message==='openingsExceedWallArea'?'openingsExceedWallArea':'inputError'});}",
    "inputs": [
      {
        "name": "matingDate",
        "type": "date",
        "default": "@today",
        "step": 1,
        "preserveEmpty": true,
        "requiredValue": true
      },
      {
        "name": "gestationDays",
        "type": "number",
        "default": 63,
        "min": 58,
        "max": 72,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true,
        "showWhen": {
          "method": [
            "custom"
          ]
        }
      },
      {
        "type": "date",
        "default": "@today",
        "preserveEmpty": true,
        "advanced": true,
        "name": "asOf",
        "requiredValue": true
      },
      {
        "type": "select",
        "default": "custom",
        "options": [
          {
            "value": "custom"
          },
          {
            "value": "mating"
          },
          {
            "value": "ovulation"
          },
          {
            "value": "progesterone"
          }
        ],
        "advanced": true,
        "name": "method"
      }
    ],
    "outputs": [
      {
        "name": "dueDate",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "rangeStart",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "rangeEnd",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "daysElapsed",
        "precision": 0,
        "unit": "days",
        "notation": "auto"
      },
      {
        "name": "daysRemaining",
        "precision": 0,
        "unit": "days",
        "notation": "auto"
      }
    ],
    "interpret": null
  }
}
