Hangfire cron format
Hangfire parses schedules with Cronos and picks the format from the number of fields: five for minute to day-of-week, or six with a seconds field in front.
| Field | Allowed values | Special characters |
|---|---|---|
| Second | 0–59 (optional, comes first) | , - * / |
| Minute | 0–59 | , - * / |
| Hour | 0–23 | , - * / |
| Day of month | 1–31 | , - * ? / L W |
| Month | 1–12 or JAN–DEC | , - * / |
| Day of week | 0–7 or SUN–SAT (0 and 7 = Sunday) | , - * ? / L # |
Special characters
| Symbol | Meaning |
|---|---|
L | Last. In day-of-month, L is the last day of the month and L-2 two days before it. In day-of-week, 5L or FRIL is the last Friday of the month; L on its own is not allowed there. |
W | The weekday (Monday to Friday) nearest to a date, without leaving the month: 15W. LW is the last weekday of the month, and L-3W the weekday nearest to three days before the end. |
# | The nth weekday of the month: 1#1 is the first Monday, FRI#3 the third Friday. |
? | Same as *. It is optional, so a six-field Quartz-style expression such as 0 0 12 ? * MON still parses. |
- | Ranges, which may wrap around: 22-2 in the hour field runs from 22:00 to 02:59, and FRI-MON from Friday to Monday. |
@ | Macros: @every_second, @every_minute, @hourly, @daily, @weekly, @monthly and @yearly. |
Hangfire cron examples
Click an expression to load it into the generator above.
| Expression | Schedule |
|---|---|
| Every 5 minutes. | |
| Every 30 seconds. | |
| At 8:00 AM, Monday through Friday. | |
| Every 15 minutes, between 10:00 PM and 2:59 AM. | |
| At 12:00 AM, on the last day of the month. | |
| At 6:00 PM, on the last weekday (Monday to Friday) of the month. | |
| At 9:00 AM, on the first Monday of the month. | |
| At 5:00 PM, on the last Friday of the month. | |
| At 12:00 AM, on day 13 of the month, but only if that day is a Friday. | |
| At 12:00 AM. |
How Hangfire cron differs from Unix cron
- If you set both day fields, both must match.
0 0 13 * 5runs only on Friday the 13th in Hangfire; Linux cron runs it on every 13th and on every Friday. - A sixth field means seconds, not Quartz.
0 0 12 ? * 2parses, but2is Tuesday here and Monday in Quartz, and a seventh field (the Quartz year) is rejected. - Schedules use UTC unless you set
RecurringJobOptions.TimeZone. Daylight saving time is handled for you: a job due at 02:30 on the night the clocks go forward runs at 03:00 instead of being skipped. - Second-level schedules work, but the scheduler checks for due recurring jobs every 15 seconds by default (
SchedulePollingInterval), so*/5 * * * * *will not really fire every five seconds.
Use it in C#
Register the job once at startup. Pass the time zone in RecurringJobOptions; without it, Hangfire uses UTC:
RecurringJob.AddOrUpdate<ReportService>(
"weekday-report",
service => service.SendDailyReport(),
"0 8 * * 1-5",
new RecurringJobOptions
{
TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Riyadh")
});
The same syntax works without Hangfire through the Cronos package:
using Cronos;
var expression = CronExpression.Parse("*/30 * * * * *", CronFormat.IncludeSeconds);
DateTime? next = expression.GetNextOccurrence(DateTime.UtcNow); // in UTC
The Cron helper class writes common expressions for you: Cron.Daily(2, 30) returns 30 2 * * *, Cron.Weekly(DayOfWeek.Monday, 9) returns 0 9 * * 1, and Cron.Never() returns 0 0 31 2 *, which keeps a job registered without ever running it.
Frequently asked questions
Does Hangfire support seconds in cron expressions?
Yes. Hangfire counts the fields: five means minute to day-of-week, and six adds seconds at the start, so */30 * * * * * runs every 30 seconds. The recurring job scheduler checks every 15 seconds by default, so lower SchedulePollingInterval in BackgroundJobServerOptions if shorter intervals have to be kept.
Which time zone does a Hangfire recurring job use?
UTC, unless you set one: new RecurringJobOptions { TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Asia/Dubai") }. Hangfire then follows that zone, including its daylight saving time changes if it has any.
Why does 0 0 13 * 5 run less often in Hangfire than in crontab?
Cronos, the parser behind Hangfire, requires both day fields to match, so the job runs only on a Friday the 13th. Linux cron runs it on every 13th and every Friday. To get the crontab behaviour, register two recurring jobs: 0 0 13 * * and 0 0 * * 5.
Is a Hangfire cron expression the same as a Quartz.NET one?
No. Quartz.NET puts seconds first, counts Sunday as 1, needs ? in one of the day fields and allows a year. Hangfire takes standard five-field cron with optional seconds. For Quartz.NET triggers, use the Quartz generator linked below.
Can I use this cron syntax without Hangfire?
Yes. Install the Cronos package from NuGet and call CronExpression.Parse("0 8 * * 1-5"), adding CronFormat.IncludeSeconds for six fields. GetNextOccurrence(DateTime.UtcNow) returns the next run in UTC.
Cron generators for other platforms
*/15 8-18 * * 1-5
Quartz Cron Expression Generator
0 0 8 ? * MON-FRI
Spring Cron Expression Generator
0 0 8 * * MON-FRI
AWS Cron Expression Generator
0 8 ? * MON-FRI *
Jenkins Cron Expression Generator
H 2 * * 1-5
Salesforce Cron Expression Generator
0 0 8 ? * MON-FRI
Airflow Cron Expression Generator
0 6 * * 1-5
node-cron Expression Generator
0 30 8 * * 1-5