Degree Days to Hatch Calculator

Degree Days to Hatch Calculator

Estimate fish egg hatch date, remaining thermal units, daily accumulation, hatch window, and viable fry count from species target, water temperature, base temperature, oxygen, and incubation progress.

📌Hatch presets

Thermal-unit inputs

Preset fills target degree-days, base temperature, and a safe incubation band.
Method affects hatch window width and survival estimate.
Use fertilization, water hardening, or observed spawn date.
Use the average temperature the eggs actually experience.
Degree-days below this threshold are counted as zero.
Enter hatch target in the active degree-day basis.
Use this for eyed eggs, shipped eggs, or samples already partway along.
Higher swings widen the likely hatch window.
Used only to estimate viable hatch count.
Enter eyed egg percentage, fertilization check, or best sample estimate.
Survival and confidence change with oxygen and sediment risk.
Adds uncertainty for calibration, logger spacing, or wild nests.

Hatch timing estimate

Days to hatch -- --
Estimated hatch date -- --
Remaining thermal units -- --
Viable hatch estimate -- --

Calculation breakdown

📊Current profile checks

🧭Temperature comparison

📘Reference tables

Species profileTypical targetUseful mean tempPlanning note
Rainbow trout300-370 C-dd8-12 C / 46-54 FColdwater eggs; avoid sudden warming late in incubation.
Brown trout390-470 C-dd6-10 C / 43-50 FLonger incubation makes logger accuracy more important.
Chinook salmon430-520 C-dd7-11 C / 45-52 FUse conservative windows for redd surveys and emergence checks.
Walleye105-150 C-dd10-15 C / 50-59 FWarmer jar systems can advance hatch quickly.
Largemouth bass80-115 C-dd20-25 C / 68-77 FShort warmwater incubation; daily checks matter.
Channel catfish120-160 C-dd24-28 C / 75-82 FEgg mass oxygen and fungus control can dominate survival.
Mean temp above baseDaily C-ddExample 120 C-dd targetInterpretation
4 C4 per day30 daysSlow, wide hatch spread; coldwater only.
8 C8 per day15 daysModerate pace for many coolwater eggs.
12 C12 per day10 daysFast enough that stage checks should be frequent.
20 C20 per day6 daysWarmwater eggs hatch fast; temperature errors matter.
26 C26 per day4.6 daysUse only for heat-tolerant species profiles.
Incubation methodWindow effectSurvival effectBest use
Flow-through trayNarrowStableTrout, salmon, and hatchery lots with controlled flow.
Upwelling jarModerateGood with clean rollWalleye, perch, and semi-buoyant egg batches.
Natural reddWideDepends on gravel flowSalmonid field estimates and emergence timing.
Pond nestWidePredation and silt sensitiveBass, bluegill, and other nest-guarding warmwater fish.
Recirculating hatcheryNarrowHigh if oxygen stableControlled studies and small production systems.
Progress bandField signDegree-day meaningCheck interval
0-25%Green eggs or fresh spawnMost target units still remainLogger review every 2-4 days
25-55%Early embryo developmentMiddle of the incubation clockCheck water quality every 1-3 days
55-80%Eyed eggs or visible embryoHatch window is approachingInspect daily when warm
80-95%Late embryo / hatch nearSmall temperature errors shift timingInspect once or twice daily

💡Practical notes

Temperature logging: Degree-days should be based on the mean temperature at egg depth, not nearby air temperature or surface readings during sunny afternoons.
Species calibration: Treat published degree-day targets as planning ranges. Local broodstock, oxygen, pH, and egg handling can shift actual hatch by several days.
This calculator is a planning model for hatch timing, field survey timing, and incubation comparisons. It does not replace hatchery records, local biosecurity procedures, or species-specific production protocols.
'; } g('ddhCompareGrid').innerHTML = html; } function calculate() { var speciesKey = g('ddhSpecies').value; var profile = profiles[speciesKey] || profiles.custom; var method = methodData[g('ddhMethod').value] || methodData.tray; var oxygen = oxygenData[g('ddhOxygen').value] || oxygenData.good; var meanC = toC(num('ddhMeanTemp', profile.temp)); var baseC = toC(num('ddhBaseTemp', profile.base)); var targetC = ddToC(num('ddhTargetDD', profile.target)); var progressPct = clamp(num('ddhProgress', 0), 0, 95); var swingC = unitMode === 'imperial' ? num('ddhSwing', 2.7) * 5 / 9 : num('ddhSwing', 1.5); var eggs = Math.max(1, num('ddhEggCount', 10000)); var fertilePct = clamp(num('ddhFertilized', 85), 0, 100); var bufferPct = clamp(num('ddhBuffer', 10), 0, 40); var band = thermalBand(meanC, baseC, swingC); var completedC = targetC * progressPct / 100; var remainingC = Math.max(0, targetC - completedC); var days = remainingC / Math.max(0.05, band.daily); var lowDays = remainingC / Math.max(0.05, band.highDaily); var highDays = remainingC / Math.max(0.05, band.lowDaily); var windowFactor = method.window + bufferPct / 100 + swingC * 0.018; var windowPad = Math.max(0.6, days * windowFactor * 0.5); var earliest = Math.max(0, lowDays - windowPad); var latest = highDays + windowPad; var startDate = readStartDate(); var hatchDate = datePlusDays(startDate, days); var earlyDate = datePlusDays(startDate, earliest); var lateDate = datePlusDays(startDate, latest); var tempPenalty = 1; var tempGap = 0; if (meanC < profile.min) { tempGap = profile.min - meanC; tempPenalty = clamp(1 - tempGap * 0.06, 0.45, 1); } if (meanC > profile.max) { tempGap = meanC - profile.max; tempPenalty = clamp(1 - tempGap * 0.10, 0.30, 1); } var survival = clamp(profile.survival * method.survival * oxygen.survival * tempPenalty * fertilePct / 100, 0, 0.98); var viable = Math.round(eggs * survival); var confidence = clamp(82 + oxygen.confidence - Math.abs(meanC - ((profile.min + profile.max) / 2)) * 2.2 - bufferPct * 0.35 - swingC * 1.8, 20, 96); var status = tempStatus(meanC, profile); g('ddhDaysResult').innerHTML = fmt(days, 1); g('ddhDaysUnit').innerHTML = 'Window: ' + fmt(earliest, 1) + ' to ' + fmt(latest, 1) + ' days'; g('ddhDateResult').innerHTML = formatDate(hatchDate); g('ddhDateUnit').innerHTML = formatDate(earlyDate) + ' to ' + formatDate(lateDate); g('ddhRemainingResult').innerHTML = fmt(ddFromC(remainingC), 0); g('ddhRemainingUnit').innerHTML = ddUnit() + ' remaining; ' + fmt(ddFromC(band.daily), 1) + ' per day'; g('ddhFryResult').innerHTML = fmt(viable, 0); g('ddhFryUnit').innerHTML = survivalText(survival) + ' survival estimate at ' + fmt(survival * 100, 0) + '%'; buildBreakdown([ { label: 'Species profile', value: profile.label + ' - ' + profile.stage }, { label: 'Thermal target', value: fmt(ddFromC(targetC), 0) + ' ' + ddUnit() + ' (' + fmt(targetC, 0) + ' C-dd internal)' }, { label: 'Completed progress', value: fmt(progressPct, 0) + '% = ' + fmt(ddFromC(completedC), 0) + ' ' + ddUnit() }, { label: 'Daily accumulation', value: 'Mean temp ' + fmt(fromC(meanC), 1) + ' ' + tempUnit() + ' minus base ' + fmt(fromC(baseC), 1) + ' ' + tempUnit() + ' = ' + fmt(ddFromC(band.daily), 1) + ' ' + ddUnit() + '/day' }, { label: 'Hatch window logic', value: method.label + ', swing ' + fmt(unitMode === 'imperial' ? swingC * 9 / 5 : swingC, 1) + ' ' + tempUnit() + ', buffer ' + fmt(bufferPct, 0) + '%' }, { label: 'Temperature status', value: status + ' for this profile (' + fmt(fromC(profile.min), 1) + '-' + fmt(fromC(profile.max), 1) + ' ' + tempUnit() + ')' }, { label: 'Viable hatch count', value: fmt(eggs, 0) + ' eggs x ' + fmt(fertilePct, 0) + '% viable x incubation factors = ' + fmt(viable, 0) }, { label: 'Confidence rating', value: confidenceText(confidence) + ' (' + fmt(confidence, 0) + '/100)' } ]); buildSpecGrid([ { label: 'Daily heat units', value: fmt(ddFromC(band.daily), 1), note: ddUnit() + ' accumulated each day at the entered mean temperature.' }, { label: 'Temperature band', value: status, note: 'Profile band is ' + fmt(fromC(profile.min), 1) + '-' + fmt(fromC(profile.max), 1) + ' ' + tempUnit() + '.' }, { label: 'Incubation method', value: method.note, note: 'Window multiplier follows the selected egg handling setting.' }, { label: 'Confidence', value: confidenceText(confidence), note: 'Driven by oxygen, temperature band, swing, and safety buffer.' } ]); buildCompareGrid(profile, targetC, completedC, baseC, swingC); } var changeIds = ['ddhMethod','ddhMeanTemp','ddhBaseTemp','ddhTargetDD','ddhProgress','ddhSwing','ddhEggCount','ddhFertilized','ddhOxygen','ddhBuffer','ddhStartDate']; var i; for (i = 0; i < changeIds.length; i += 1) { g(changeIds[i]).addEventListener('input', calculate); g(changeIds[i]).addEventListener('change', calculate); } g('ddhSpecies').addEventListener('change', speciesChanged); window.ddhSetUnits = setUnits; window.ddhApplyPreset = applyPreset; window.ddhCalculate = calculate; setDefaultDate(); updateLabels(); calculate(); })();

The minute you hear the splash from the spawning run is the moment before you see the fish. Every spring it begin like this. Thousands of tiny lives is suspended in water not even warm enough to be called water. Trout push against gravel in a chilly stream, and a couple of bass digs a nest.

When will they hatch? By now, you are asking yourself. In years past, we guessed and went by the calendar. But the calendar doesn’t consider weather. And temperature nearly completly determines how fast an egg develop; how much heat they take in determines their development, which makes degree days the common tongue among those who hope to predict hatches with some level of precision.

Using Degree Days to Predict Fish Hatching

You can explain it over coffee if you’d like but it’s a pretty simple concept. Each species of fish has what we call a lower developmental threshold, meaning that below this temperature, development simply ceases. In trout, this tends to be somewhere around zero Celsius. Above this temperature, any warming of the water build up as a unit called a thermal unit. This continues until these accumulated thermal units reaches a certain level and eggs hatch.

Not magic, but man does it feel that way when you nail the date on the nose. You don’t have to pull out a spreadsheet and sit at a desk running numbers. The calculator above will do it all for you by taking raw water temperatures and spitting back out a clear hatch window. All you have to do is understand what the numbers mean and how they shifts your expectations.

The problem is most folks think about what the hot part of the day will be and plug in the mean temperature. Here is where people go wrong: you aren’t trying to figure out average of the hottest part of the day. You want the average of the temperature the eggs actualy experience, and in most cases that’s going to be nearer the minimum at night than the maximum during the afternoon. That makes all the difference if you check a stream gauge or have a logger set up in a hatchery tray.

A sharp upward swing in warm water will narrow window quite a bit and push things ahead of the curve so much quicker then expected. Cold water will stretch it out and provide you with additional time but less precision. The graph on the page do a good job illustrating just how big a few degrees can make a difference.

And then there’s this survival thing. Sure, you know they’ll hatch at the right temperature. But will they hatch healthy? This is where flow conditions and oxygen levels matters most. Eggs can suffocate even before reaching their thermal target in silty streams or still ponds. You may compute the ideal hatch day, but instead of fry, you find only a gooey mess of shells covered in fungus.

The tool prompts you for oxygen conditions because it knows this make a huge difference. If your water quality isn’t good, you can assume fewer will survive, a hard truth, reminding us that fish need more than just heat. You could of had every degree day on earth, but unless there’s clean flow coursing through those eggs, you’re simply cooking up dead stock.

The form the result takes also depends on incubation method. Eggs that are buried in a natural redd versus sitting in an upwelling jar will behave different. The jar insulates them and keeps them in an environment where there’s always some oxygen, so the hatch window is tighter. In a wild nest, they’ll experience being hunted, silt buildup, and gravel shifting, which widens the window and decreases survival rate.

Interpreting the result correctly requires knowing what environment you put the eggs in. If it was a narrow window, then you’d better be prepared for an abrupt fry rush. If it was a wide window, expect a trickle of fry over a few days that will require you to watch them or protect them for longer.

Fish farming’s a variable balancing act; we tend to think of it as an exact science, but it isn’t. Sure, you can control the temperature somewhat and measure the oxygen, but nature has its own rhythm. Degree days help get our human planning matched up with that biological clock. It takes the “when” out of guess work and lets us go back to focusing on the “how.”

When you begin tracking thermal units instead of chasing calendar dates, the entire process becomes clearer. You’ll know exactly when to worry about predators, when to check the trays, and when to prepare for the next stage. It goes from a hopeful wait to a managed process. And that splash in your head? From a mystery it becomes a scheduled event.

Degree Days to Hatch Calculator

Leave a Comment