Paste a cron expression to see what it means in plain English and exactly when it will run next. Built for Hangfire recurring jobs, which use the Cronos format — 5 fields, or 6 with seconds — but it works for standard Unix cron as well.
—
Runs entirely in your browser — nothing is sent anywhere. Share a link by appending ?expr=0%203%20*%20*%20* to the URL.
A cron expression is a list of fields separated by spaces. Each field restricts when the job may run; a job fires at every moment where all fields match.
| Position | Field | Allowed values |
|---|---|---|
| (1) | Second — optional, only in 6-field expressions | 0-59 |
| 1 | Minute | 0-59 |
| 2 | Hour | 0-23 |
| 3 | Day of month | 1-31, L, W |
| 4 | Month | 1-12 or JAN-DEC |
| 5 | Day of week | 0-7 (0 and 7 = Sunday) or SUN-SAT, L, # |
Special characters: * any value, , list (1,15), - range (MON-FRI), / step (*/15 = every 15), ? same as * in the day fields. Macros like @daily, @hourly and @weekly work too.
| Schedule | Expression | Hangfire helper |
|---|---|---|
| Every minute | * * * * * | Cron.Minutely() |
| Every 15 minutes | */15 * * * * | — |
| Every hour, on the hour | 0 * * * * | Cron.Hourly() |
| Every day at 03:30 | 30 3 * * * | Cron.Daily(3, 30) |
| Weekdays at 07:00 | 0 7 * * 1-5 | — |
| Every Monday at midnight | 0 0 * * 1 | Cron.Weekly() |
| First day of every month | 0 0 1 * * | Cron.Monthly() |
| Never (disabled) | 0 0 31 2 * | Cron.Never() |
The most common recurring-job incident is not a wrong expression — it is a correct expression that silently stopped firing: the server hosting the scheduler was scaled down, a deploy left no worker running, or the job threw on every attempt and nobody saw it. None of that shows up in the cron expression. It takes an external check that notices when the expected work does not happen. That is the idea behind heartbeat monitoring, and what QueueHawk does for Hangfire.
Yes. Recurring jobs are evaluated in UTC unless you pass a time zone, for example new RecurringJobOptions { TimeZone = TimeZoneInfo.Local } or a specific zone via TimeZoneInfo.FindSystemTimeZoneById. With a local time zone, daylight saving time changes can skip or repeat a run in the affected hour.
Hangfire accepts 6-field cron expressions with seconds, such as */30 * * * * *. Recurring jobs are triggered by a polling scheduler, though, so treat sub-minute schedules as approximate and avoid them for anything that needs precise timing.
The job runs when either one matches. 0 0 1,15 * 1 fires on the 1st and 15th of every month and on every Monday, not only on Mondays that fall on the 1st or 15th. This is classic cron behaviour and trips people up regularly.
Cron.Minutely() is * * * * *, Cron.Hourly() is 0 * * * *, Cron.Daily() is 0 0 * * * (midnight UTC), Cron.Weekly() is 0 0 * * 1 (Monday), Cron.Monthly() is 0 0 1 * * and Cron.Yearly() is 0 0 1 1 *. Most helpers accept arguments, for example Cron.Daily(3, 30) for 03:30.
A cron expression only says when a job should run. Whether it did is a monitoring question: a scheduler that is down or a server that is gone produces no error at all. A heartbeat check per application and a job history that survives deploys answer it.
Heartbeat and error-rate alerts for Hangfire recurring jobs. Free for one application.