Hangfire Cron Job Running on the Wrong Day
The expression parses. It validates. Hangfire's dashboard shows a perfectly reasonable next-run time. And it still fires on the wrong day of the week. This is almost always a day-of-week numbering mismatch — and the fix depends on knowing which scheduler's convention you actually copied the number from.
// three schedulers, three numbering conventions
1 means Monday in a Hangfire/Cronos expression, but Sunday in a Quartz.NET expression. Copy a "run every Monday" example from a Quartz.NET tutorial straight into RecurringJob.AddOrUpdate and the job will run every Sunday instead — with no error, because 1 is a valid day-of-week value in both systems, just a different day.RecurringJob.AddOrUpdate("weekly-report", () => SendReport(), "0 6 * * 1");
No exception, no validation warning -- Hangfire's dashboard shows a perfectly valid next run time. The job fires every Sunday, not Monday.
RecurringJob.AddOrUpdate("weekly-report", () => SendReport(), Cron.Weekly(DayOfWeek.Monday, 6)); // no ambiguous digit to get wrong
// the fix that isn't a cron expression
If you're calling RecurringJob.AddOrUpdate with a helper instead of a raw string — Cron.Daily(), Cron.Weekly(DayOfWeek.Monday) — you're using .NET's own System.DayOfWeek enum, not a cron digit at all. DayOfWeek.Sunday is 0 and DayOfWeek.Saturday is 6, which happens to line up with Cronos's 0–6 range exactly. This whole class of bug only exists for hand-written cron strings — the helper methods can't have this problem, because there's no ambiguous digit for the compiler to accept.
0 6 * * 1Cron.Weekly(DayOfWeek.Monday, 6)0 0 6 ? * 2// how to actually check which one you're looking at
- Find the day-of-week field — it's the last field in a 5-field expression, or the last of six in a Quartz.NET expression that starts with a seconds field.
- Check whether the same expression has a
?anywhere. Only Quartz.NET uses?, so its presence confirms the 1=Sunday convention applies. - No
?, and it's a 5-field expression? It's standard cron — either Cronos's 0–7 or traditional 0–6, which only disagree on whether7is a second way to write Sunday or invalid. For anything Hangfire actually runs, that's Cronos.
When in doubt, don't count fields by hand — paste the expression into the Cron Builder & Explainer and it'll say which day it actually means, for both dialects, before anything gets deployed.
// frequently asked questions
Why does a Hangfire cron job run on the wrong day even though it validates?
Almost always a day-of-week numbering mismatch, not a syntax error. Hangfire's Cronos engine accepts 0–7 where both 0 and 7 mean Sunday. Quartz.NET uses 1–7 where 1 means Sunday. Traditional Unix cron uses 0–6 where 0 means Sunday. Copying a "run every Monday" example from a Quartz.NET tutorial straight into a Hangfire expression makes the job run every Sunday instead, with no error, because the digit is valid in both systems — just a different day.
What does 1 mean in Hangfire's day-of-week field?
Monday. Hangfire's Cronos engine treats 1 through 6 as Monday through Saturday, with 0 or 7 meaning Sunday. This is different from Quartz.NET, where 1 means Sunday.
Does DayOfWeek.Monday in Cron.Weekly() use the same numbering as a raw cron string?
No conflict to worry about — using a helper like Cron.Weekly(DayOfWeek.Monday) uses .NET's own System.DayOfWeek enum, not a cron digit at all. DayOfWeek.Sunday is 0 and DayOfWeek.Saturday is 6, which happens to line up with Cronos's 0–6 range. This class of bug only exists for hand-written cron strings.
How do I tell which cron dialect an expression uses?
Check whether the expression has a ? anywhere — only Quartz.NET uses it, confirming the 1=Sunday convention applies. No ? and it's a 5-field expression means standard cron, and for anything Hangfire actually runs, that's Cronos's 0–7 range. When in doubt, paste it into a tool that states the day explicitly rather than counting fields by hand.
Hangfire has used the Cronos library to parse cron expressions since Hangfire 1.7. Cronos accepts day-of-week values 0 through 7, where both 0 and 7 mean Sunday (the Vixie cron convention) and 1–6 are Monday through Saturday. Quartz.NET uses a different range entirely: 1 through 7, where 1 means Sunday and 7 means Saturday. Traditional Unix cron — what most blog posts and Stack Overflow answers are actually demonstrating — uses 0 through 6, 0 for Sunday.