{
  "schemaVersion": 1,
  "slug": "pregnancy-due-date-calculator",
  "category": "health",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "4c4436416def3b34029aa28f87b7033dd9ffcbad8dafc6debe7a9673fe0428c3",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/pregnancy-due-date-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 = LMP + 280 + (C − 28); Con ≈ LMP + (C − 14); w = (reference − LMP)/7; T2 = LMP + 98; T3 = LMP + 196",
    "vars": [],
    "note": "Dates are date-only, without UTC/local-day drift. A clinician and early ultrasound establish clinical dating; this cannot confirm pregnancy."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-31",
    "basis": "Use the first day of the last menstrual period and an editable reference date. The estimate is LMP + 280 days + (cycle length − 28), assuming a regular cycle; conception is an approximate cycle-length-minus-14 offset, not a confirmed date. Trimester landmarks use 14 weeks 0 days and 28 weeks 0 days from LMP in both entries. Dates are date-only, without UTC/local-day drift. A clinician and early ultrasound establish clinical dating; this cannot confirm pregnancy.",
    "limitations": "Dates are date-only, without UTC/local-day drift. A clinician and early ultrasound establish clinical dating; this cannot confirm pregnancy.",
    "implementationHash": "4c4436416def3b34029aa28f87b7033dd9ffcbad8dafc6debe7a9673fe0428c3",
    "sources": [
      {
        "name": "ACOG — methods for estimating the due date",
        "url": "https://www.acog.org/clinical/clinical-guidance/committee-opinion/articles/2017/05/methods-for-estimating-the-due-date"
      },
      {
        "name": "ACOG — trimester landmarks",
        "url": "https://www.acog.org/womens-health/faqs/how-your-fetus-grows-during-pregnancy"
      }
    ],
    "referenceRole": "definition"
  },
  "contract": {
    "compute": "try{if(((true)&&(!Number.isFinite(cycleLength)||cycleLength<20||cycleLength>45)))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,num,shift,iso,DAY,fail}=h,a=date(v.lastPeriod),ref=date(v.today);num(v.cycleLength,20,45,true);if(+a>+ref)fail();\n    const due=shift(a,280+v.cycleLength-28),daysPregnant=Math.round((ref-a)/DAY),daysRemaining=Math.round((due-ref)/DAY);\n    return {dueDate:iso(due),conceptionDate:iso(shift(a,v.cycleLength-14)),secondTrimester:iso(shift(a,98)),thirdTrimester:iso(shift(a,196)),daysPregnant,weeksPregnant:daysPregnant/7,gestationalWeeks:daysPregnant/7,gestationBreakdown:Math.floor(daysPregnant/7)+' weeks '+daysPregnant%7+' days',daysRemaining,weeksRemaining:daysRemaining/7};\n  })({\"lastPeriod\":(lastPeriod),\"cycleLength\":(cycleLength),\"today\":(today)},h);return result;};const out=calculate();return Object.fromEntries([\"dueDate\",\"conceptionDate\",\"secondTrimester\",\"thirdTrimester\",\"daysPregnant\",\"weeksPregnant\",\"daysRemaining\",\"weeksRemaining\"].map(k=>[k,out[k]??null]).concat(Object.entries(out).filter(([k])=>k.startsWith('__'))));}catch(error){return Object.assign(Object.fromEntries([\"dueDate\",\"conceptionDate\",\"secondTrimester\",\"thirdTrimester\",\"daysPregnant\",\"weeksPregnant\",\"daysRemaining\",\"weeksRemaining\"].map(k=>[k,null])),{__error:error.message==='openingsExceedWallArea'?'openingsExceedWallArea':'inputError'});}",
    "inputs": [
      {
        "name": "lastPeriod",
        "type": "date",
        "default": "@today-4w",
        "step": 1,
        "preserveEmpty": true,
        "requiredValue": true
      },
      {
        "name": "cycleLength",
        "type": "number",
        "default": 28,
        "min": 20,
        "max": 45,
        "step": 1,
        "slider": true,
        "strictRange": true,
        "requiredValue": true
      },
      {
        "type": "date",
        "default": "@today",
        "preserveEmpty": true,
        "advanced": true,
        "name": "today",
        "requiredValue": true
      }
    ],
    "outputs": [
      {
        "name": "dueDate",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "conceptionDate",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "secondTrimester",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "thirdTrimester",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "daysPregnant",
        "precision": 0,
        "unit": "days",
        "notation": "auto"
      },
      {
        "name": "weeksPregnant",
        "precision": 1,
        "unit": "weeks",
        "notation": "auto"
      },
      {
        "name": "daysRemaining",
        "precision": 0,
        "unit": "days",
        "notation": "auto"
      },
      {
        "name": "weeksRemaining",
        "precision": 1,
        "unit": "weeks",
        "notation": "auto"
      }
    ],
    "interpret": null
  }
}
