Match a job Paths Subjects Questions Quizzes Pricing
Intermediate Open Free

The DAG Run Labeled 'Jan 15' Doesn't Run On Jan 15

A daily DAG is scheduled schedule="0 7 * * *". An engineer writes a task that emails "here is the {{ ds }} sales report," assuming {{ ds }} will render as "today's date" — the day the email actually goes out. They're confused when the run that fires on the morning of January 16 renders {{ ds }} as 2026-01-15, and the report it generates only contains data through the end of January 15, nothing from January 16.

Nothing is broken. What does {{ ds }} — and the DAG run's logical/execution date more generally — actually represent?

Solution

The start of the data interval the run covers, not the execution day.

Airflow's scheduling model isn't "run today, dated today" — it's interval-based. Each daily DAG run represents responsibility for one 24-hour data interval, and by design that run doesn't fire until the interval has fully closed, so there's a complete interval's worth of data to process. {{ ds }} (and the run's data_interval_start, what older Airflow versions called execution_date) is the start of that interval — for a daily schedule, midnight of the day the run is "for" — not the calendar day the run's tasks actually execute on.

So the run that Airflow labels 2026-01-15 covers the interval [2026-01-15 00:00, 2026-01-16 00:00). Because that interval doesn't close until midnight on the 16th, the scheduler doesn't fire this run's tasks until after that — at 0 7 * * *, that's 07:00 on January 16. The run executes on the 16th, is labeled the 15th, and processes data from the 15th — three different things that happen to share a date only by coincidence of a daily schedule, and diverge further for hourly, weekly, or custom-interval DAGs. The email correctly reports "the 15th's sales" because that's the interval this run owns — it isn't supposed to contain the 16th's data, since the 16th's own run (which will itself execute on the 17th) is responsible for that.

This is one of the most common sources of Airflow confusion precisely because the name execution_date (used in Airflow 1.x and still present as a deprecated alias) actively suggests "the date this executes," when it always meant "the start of the interval this run covers" — Airflow 2.2+ renamed the concept to data_interval_start/ data_interval_end specifically to stop implying the wrong thing. The practical rule: never read a DAG run's date as "when this ran" — read it as "which interval of source data this run is accountable for," and check the schedule to work out when it actually executed.

Share this question

← Back to Airflow & Workflow Orchestration practice

We use cookies for product analytics to improve OmniAtlas. See our Privacy Policy.