Why forecast_hour Skips Around: Understanding Model Run Timing and What It Means for Your API Requests

If you’ve logged consecutive hourly API responses and watched the forecast data shift in a jump rather than a smooth slide, you’ve seen model run timing in action. Not a bug. That’s how numerical weather prediction actually works — and once you understand the cycle, it changes how you structure requests and caching in ways that aren’t obvious until you’ve been bitten by them.

Models Don’t Update Continuously

GFS runs four times per day: 00Z, 06Z, 12Z, 18Z. HRRR — NOAA’s high-resolution rapid refresh model, covering the CONUS on a 3km grid — runs every hour, but each run takes time to complete, process, and propagate. ECMWF’s high-resolution deterministic model runs twice daily at 00Z and 12Z, with output typically available a few hours after initialization. These are batch jobs with real latency from observation cutoff to ingested output, not live streams.

What that means in practice: a call at 14:30 UTC is probably returning data from the GFS 12Z run, initialized two and a half hours ago, not from something that started at 14:00. The 17:00 UTC forecast in that response was computed from atmospheric state data that was already hours old when the model started. Every forecast hour past initialization accumulates error on top of that initial state uncertainty — so the 17:00 forecast from a 12Z run is effectively T+5 uncertainty-wise, not T+2.5. That distinction matters more than most integrations account for.

What Gets Served When You Hit the API

Our GRIB2 ingestion pipeline processes HRRR, NAM, GFS, and ECMWF output as it becomes available. For any given location request, the response blends model output depending on what’s most recent and what resolution best covers that point. HRRR’s 3km grid matters a lot for US locations — that resolution captures mesoscale features like sea breezes and orographic lift that GFS at roughly 13km smooths over. But HRRR only covers the CONUS, so outside that domain, NAM or GFS becomes the higher-resolution option.

The practical consequence: which model backs the data you receive depends on where you’re querying, where you are relative to recent model run completions, and how ingestion has processed that run. Two calls five minutes apart could draw from the same initialization — or, if a new run just cleared processing, from different ones.

You can’t control this from the API side, and you shouldn’t try to. But you can design your integration so it isn’t surprised by it.

Practical Consequences for Integration Patterns

Don’t Treat Forecast Hour Offsets as Wall Clock Math

A common mistake is treating forecast_hour + current_time as a precise physical timestamp. T+6 is not equivalent in uncertainty to T+1, even though both arrive in the same API response. If you’re building something that distinguishes near-term from later-today — an outdoor activity planner, an HVAC pre-conditioning scheduler, anything with a decision threshold — that distinction needs to live in your logic, not in assumptions about the forecast hours themselves.

For anything within two hours, HRRR’s rapid update cycle gives you substantially more defensible numbers for US locations than GFS does. Past six hours, the model differences narrow. Past 48 hours, you’re in medium-range territory where ECMWF generally outperforms NOAA’s operational models on standard verification metrics — ECMWF publishes those benchmarks directly if you want to check the specifics.

Cache Invalidation Should Follow Model Run Cycles, Not Clock Hours

A TTL of 3600 seconds sounds clean. But if a new GFS run completes and gets ingested at 16:45 UTC and you cached a response at 16:30 with a one-hour TTL, you’ll serve stale data until 17:30. For slowly-changing conditions, that’s fine. For a location where the new run has shifted precipitation timing by 90 minutes — which happens regularly — it isn’t.

A better approach is to align cache invalidation loosely with expected model run availability. GFS output is typically available around 3.5 to 4 hours post-initialization. HRRR is faster, usually within 45 to 60 minutes of its initialization time. If your use case is sensitive to forecast updates rather than just absolute values, polling on model-run-aware intervals beats a fixed TTL. Static TTLs are a blunt instrument; the right answer depends on what decisions you’re actually making with the data.

The Six-Hour Horizon Is a Meaningful Boundary

HRRR assimilates radar and surface observations into each hourly initialization — that’s why it can capture a convective cell that formed two hours ago. GFS doesn’t have that rapid data assimilation cycle. So for thunderstorm-relevant forecasting (convective initiation timing, precipitation onset), treating HRRR-backed data as qualitatively different for the sub-6-hour window is a reasonable engineering assumption, even when you can’t see directly which model is behind a given response. Past six hours, assume GFS-class uncertainty regardless of what the response field says.

One Thing Worth Watching For

Cold starts at the top of a new model run can produce brief inconsistencies — particularly around precipitation fields — where the model is spinning up its internal state from new initial conditions. HRRR is more prone to this than GFS simply because it initializes so frequently. If you’re polling at high frequency and logging precipitation values, you may occasionally see a transient spike or drop in the first one to two forecast hours of a new HRRR run before it settles. We haven’t fully filtered for this in ingestion — it’s genuinely hard to distinguish a real rapid-onset event from a spin-up artifact without ground truth comparison. Worth knowing if you’re building precipitation alert logic that keys off small threshold crossings.

What to Actually Do With This

Three things help if you want your integration to behave well across model run boundaries:

  • Build in tolerance for small discontinuities between consecutive hourly fetches rather than assuming monotonic change. A jump in forecast precipitation between calls isn’t always an API anomaly — sometimes a new model run just landed.
  • Weight your confidence in forecast hours by distance from initialization, not just by how many hours from now they are. A T+2 forecast from a 6-hour-old model run carries T+8 uncertainty.
  • For CONUS locations where timing precision matters, treat the sub-6-hour window as a qualitatively different regime, because HRRR’s rapid data assimilation genuinely makes it one.

If any of this is affecting something you’re building — especially precipitation alerting or HVAC scheduling where threshold crossings matter — it’s worth auditing which model run is actually backing your responses before assuming the data itself is the problem.

Scroll to Top