Skip to the page
Tecyfy

One schedule, in every cron dialect

Every weekday at 06:30 is 30 6 * * MON-FRI in Airflow and Snowflake, but 0 30 6 ? * MON-FRI in Databricks, which reads Quartz cron with seconds first and a question mark for the unused day.

Choose when a job runs, or paste an expression you already have. The builder writes it for Airflow, a Databricks job and a Snowflake task, puts it in code you can copy, reads it back in words, and lists its next runs in your time zone, marking the runs the clocks skip or repeat.

The cron builder

06:30
:30
Time zone

In words

At 06:30, Monday to Friday, Europe/Berlin time.

Airflowschedule
30 6 * * MON-FRI
Databricks Jobsquartz_cron_expression
0 30 6 ? * MON-FRI
Snowflake taskUSING CRON
30 6 * * MON-FRI
Save as dags/load_orders.py
import pendulum
from airflow.sdk import DAG

with DAG(
    dag_id="load_orders",
    schedule="30 6 * * MON-FRI",
    start_date=pendulum.datetime(2026, 1, 1, tz="Europe/Berlin"),
    catchup=False,
):
    ...

The next 10 runs

The next runs of the schedule, in its time zone and in UTC
DateLocal timeUTCClocks
Working out the next runs from now.
  • Airflow 3 starts a cron run at its time. Airflow 2 started it at the end of the interval, one period later.

How the 3 dialects differ

Airflow takes a standard cron expression of 5 fields: minute, hour, day of the month, month and day of the week. It reads it with the croniter library, which adds L for the last day of the month, L5 for the last Friday and MON#1 for the first Monday. Snowflake takes the same 5 fields after USING CRON, with L for the last day, followed by a time zone.

Databricks Jobs reads Quartz cron instead. Quartz puts a seconds field first and allows a year at the end, numbers the days of the week 1 (Sunday) to 7 rather than 0 to 6, and needs a question mark in either the day of the month or the day of the week. Writing days as names (MON-FRI) avoids the numbering trap, and the builder does. Quartz also has W, the weekday nearest a date, which cron lacks.

In cron, setting both a day of the month and a day of the week runs on either one: 0 2 1 * MON runs on the 1st and on every Monday. Quartz cannot say that in 1 expression, so the builder says when a schedule needs 2 Databricks jobs.

A schedule in a time zone with summer time meets 2 awkward nights a year. When the clocks go forward, times in the skipped hour do not exist; when they go back, an hour happens twice. The builder finds the next 2 changes in the zone you choose and the runs they touch. Databricks advises UTC for a job that must run every hour, and Airflow recommends authoring Dags in UTC.

Questions

What is the cron expression for every weekday at 6:30?
30 6 * * MON-FRI in Airflow and in a Snowflake task (USING CRON 30 6 * * MON-FRI followed by a time zone). Databricks Jobs needs Quartz syntax, 0 30 6 ? * MON-FRI, with seconds first and a question mark for the day of the month.
What is the difference between cron and Quartz cron?
Quartz has 6 or 7 fields: seconds come first and a year may come last. It numbers the days of the week 1 (Sunday) to 7 where cron uses 0 to 6, and one of the 2 day fields must be a question mark. It also adds W for the nearest weekday and L-3 for 3 days before the end of the month.
Why does a Databricks cron expression need a question mark?
Databricks Jobs uses Quartz cron, and Quartz does not support setting both a day of the month and a day of the week. A question mark in one of them means no specific value, so 0 0 9 ? * MON runs every Monday and 0 0 9 1 * ? on the 1st of each month.
How do I schedule a job for the last day of the month?
Use L in the day of the month: 0 0 L * * in Airflow and Snowflake, 0 0 0 L * ? in Databricks. A day such as 31 skips every month that has fewer days. For the last Friday, Airflow takes 0 0 * * L5 and Databricks 0 0 0 ? * 6L; Snowflake documents no form for it.
Which time zone does an Airflow cron schedule use?
The Dag's time zone, from a pendulum start_date such as pendulum.datetime(2026, 1, 1, tz="Europe/Berlin"), or the default_timezone setting, which is UTC in a new install. A Dag in a time zone with summer time keeps its local hour, so 0 0 * * * in US Eastern time runs at 04:00 UTC in summer and 05:00 in winter.
What happens to a scheduled job when the clocks change?
A run in the hour the clocks skip may not happen or may be moved, and a run in the hour they repeat may happen twice, depending on the scheduler. Databricks warns that an hourly job can be skipped or seem an hour or 2 late, and advises UTC for jobs that must run every hour.
How do I schedule a Snowflake task with cron?
Set SCHEDULE = 'USING CRON <expression> <time zone>' in CREATE TASK, for example USING CRON 30 6 * * MON-FRI Europe/Berlin. A new task is created suspended, so run ALTER TASK <name> RESUME to start it.
When does an Airflow cron Dag run, at the time or after the interval?
In Airflow 3, at the time: a bare cron schedule uses a trigger timetable by default. In Airflow 2 the default was a data interval timetable, so the run for an interval started when it ended, one period after the time in the expression. The create_cron_data_intervals setting chooses between the 2.

Put this calculator on your own site

Copy the code into any web page: a blog post, a course page or your team's wiki. The calculator runs in a frame and shows the same figures as this page, so when the prices change here they change on your page too. It is free and needs no account, and nothing a reader types is sent anywhere.

The code opens the calculator with the settings you have chosen above.

The short script at the end lets the frame grow and shrink with the calculator. Where a page cannot take scripts, choose a fixed height and the frame scrolls.

<iframe src="https://tecyfy.com/embed/cron-builder" title="Cron expression builder" width="100%" height="2300" style="border:0;display:block" loading="lazy" allow="clipboard-write"></iframe>
<p><a href="https://tecyfy.com/data-engineering/cron-builder">Cron expression builder</a> by Tecyfy</p>
<script>addEventListener("message",function(e){if(e.origin!=="https://tecyfy.com"||!e.data||e.data.type!=="tecyfy:height")return;var h=Number(e.data.height);if(!(h>0))return;document.querySelectorAll("iframe").forEach(function(f){if(f.contentWindow===e.source)f.style.height=Math.min(h,20000)+"px"})})</script>