A cron expression looks portable. Five or six fields, stars and numbers, the same everywhere. It is not portable, and the ways it differs are quiet: no scheduler rejects an expression written for a different one, because the expression is syntactically valid in both. It simply means something else.
Days are numbered differently
Unix cron numbers days of the week 0 to 6 starting at Sunday. Quartz and AWS EventBridge number them 1 to 7, also starting at Sunday. Every numeric day is therefore off by one between them.
0 0 * * 1-5
Unix → Monday, Tuesday, Wednesday, Thursday, Friday
Quartz → Sunday, Monday, Tuesday, Wednesday, ThursdayA weekday batch job moved from a crontab into a Java scheduler now runs on Sunday and does not run on Friday. Nothing fails. The Sunday run is unattended and the missing Friday run is noticed at the end of the month, by which point the expression has been reviewed twice and looks correct — because it is correct, for the other scheduler.
Field counts differ too
Unix cron and Kubernetes CronJobs take five fields, starting at minutes. Quartz and Spring take six, starting at seconds. AWS EventBridge takes six, ending with a year.
Paste a five-field Unix expression into Quartz and every field shifts left. The minute becomes the second, the hour becomes the minute, and the day-of-month becomes the hour. A job meant to run at 02:30 once a day runs every minute, forever, until somebody looks at the bill or the logs.
30 2 * * * Unix: 02:30 every day
30 2 * * * Quartz: rejected — six fields expected
0 30 2 * * ? Quartz: 02:30 every dayThe OR rule nobody expects
When both day-of-month and day-of-week are restricted, Unix cron ORs them rather than ANDing them. 0 0 1 * 1 does not mean "the first of the month, if it is a Monday". It means the first of the month, and additionally every Monday — roughly five times as many runs as intended.
Quartz and EventBridge sidestep this by requiring a ? in exactly one of the two fields, which forces you to say which one you meant. It is a better design, and it is also why a converted expression grows a question mark that was not in the original.
- Unix and Kubernetes — 5 fields, days 0-6 from Sunday, day fields ORed.
- Quartz — 6 or 7 fields with seconds first, days 1-7 from Sunday, ? required in one day field.
- AWS EventBridge — 6 fields with a year, days 1-7 from Sunday, ? required in one day field.
- Spring @Scheduled — 6 fields with seconds first, days 0-7 from Sunday, no ?.
Unix has no L, W or #, so "last day of the month" and "the second Tuesday" cannot be expressed at all — a converter that emits something anyway is producing a plausible expression that does something else. Saying the translation is lossy is more useful than hiding it.