Due date calculator
Estimate your due date from the first day of your last period: a period starting 1 January 2026 with a 28-day cycle gives 8 October 2026, 280 days later, plus both trimester milestones. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- First day of last period
- 2026-01-01
- Cycle length (days)
- 28
- Estimated due date
- 2026-10-08
- End of first trimester
- 2026-04-08
- End of second trimester
- 2026-07-15
free online
How the due date is estimated
The calculator applies Naegele's rule to the first day of your last menstrual period. A standard pregnancy is counted as 280 days from that date, which assumes a 28-day cycle. Because cycles vary, you can enter your own cycle length and the count is adjusted by the difference: the gestation length becomes 280 days plus your cycle length minus 28. A 30-day cycle therefore moves the due date two days later, and a 26-day cycle moves it two days earlier. With a last period that started on 1 January 2026 and the default cycle, the estimated due date is 8 October 2026. Cycle lengths from 20 to 45 days are accepted.
Trimester milestones and where they are used
Besides the due date, the result gives the total number of gestation days and two milestones: the end of the first trimester, 97 days after the first day of the last period, and the end of the second trimester, at 195 days. For a period starting on 1 January 2026, they fall on 8 April and 15 July 2026. The dates move correctly across months and years and take leap years into account, so a period that began on 15 February 2024 includes 29 February. Pregnancy apps use this to show expecting parents their due date and milestones from a single date, and clinical intake forms use it to pre-fill gestational age and due date, adjusted to each patient's cycle.
What you can do with it
Pregnancy apps
Show an expecting parent their estimated due date and trimester milestones from a single LMP entry.
Clinical intake forms
Pre-fill gestational age and due date in an EHR or booking flow, cycle-adjusted per patient.
FAQ
Does the timezone affect the result?
No. All math is UTC civil with no Date.now(), so results are fully deterministic.
How is the due date calculated?
With Naegele's rule: 280 days are added to the first day of your last menstrual period. For a period that began on 1 January 2026 and a 28-day cycle, the estimated due date is 8 October 2026.
What if my cycle is longer or shorter than 28 days?
Enter your cycle length and the date shifts by the difference: a 30-day cycle moves the due date two days later and a 26-day cycle two days earlier. Any whole number of days from 20 to 45 is accepted.
When does each trimester end?
The end of the first trimester is placed 97 days after the first day of your last period, and the end of the second at 195 days. With a period starting 1 January 2026, those dates are 8 April and 15 July 2026.
Does the due date calculator count leap years?
Yes. Dates roll correctly across months and years and include 29 February when it falls within the pregnancy, so a last period that began on 15 February 2024 counts that extra day automatically.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/due-date \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"lmp":"2026-01-01"}'const res = await fetch("https://api.kit.forhosting.com/dev/due-date", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"lmp": "2026-01-01"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/due-date",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"lmp": "2026-01-01"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/due-date", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"lmp":"2026-01-01"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"lmp":"2026-01-01"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/due-date", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"lmp": "2026-01-01"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.due_date",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Estimates a pregnancy due date from the first day of the last menstrual period (lmp) and an optional cycle_days value, returning the due date, both trimester end dates, and total gestation days.
The Naegele calculation, adjusted for your cycle
The tool applies Naegele's rule to the lmp field, the ISO date (YYYY-MM-DD) of the first day of your last menstrual period. A standard pregnancy is counted as 280 days from that date, but the calculator adjusts for your personal cycle with the formula offset = 280 + (cycle_days - 28), so a 30-day cycle pushes the due date two days later and a 26-day cycle pulls it two days earlier. cycle_days defaults to 28 and must be an integer between 20 and 45. The response returns due_date (lmp plus the offset), gestation_days (the offset itself), and two milestones: trimester1_end at lmp + 97 days and trimester2_end at lmp + 195 days. With lmp 2026-01-01 and the default cycle, due_date is 2026-10-08 and gestation_days is 280.
Pure UTC civil date arithmetic
Internally addDays parses the string with a strict regex, builds the date via Date.UTC, adds the day offset, and re-serializes with toISOString().slice(0,10), which correctly rolls across month and year boundaries and honours leap years — an lmp of 2024-02-15 counts February 29 automatically. All date math is pure UTC civil arithmetic with no wall clock: the code never calls Date.now(), so the same lmp always yields the same due_date regardless of the server's timezone or the moment of the request.
Validation and typed errors
The top-level input must itself be a plain object — arrays and null are refused. Every field is checked before any calculation runs, and any failure throws a typed invalid_input error naming the problem rather than an untyped exception. lmp must be a string matching YYYY-MM-DD with a month of 1-12 and a real calendar day; a value like 2026-02-30 is rejected because the constructed UTC date does not round-trip back to the same components. cycle_days must be an integer within 20-45, so 19, 46, or a fractional value all fail.
Integration use cases
Bulk scheduling
Batch thousands of LMP records through the API to plan appointment windows deterministically.
Technical questions
Which rule does it use?
Naegele's rule: 280 days from the LMP, adjusted by (cycle_days - 28).
Can I set a non-28-day cycle?
Yes. Pass cycle_days as an integer from 20 to 45; it defaults to 28.
What date format does lmp need?
A strict YYYY-MM-DD string; impossible dates like 2026-02-30 return invalid_input.
Is it free?
Yes in the browser widget. The API runs the same core from $0.002 per call.