Cron L, W, # and ?: the Quartz characters this parser rejects
L, W, # and ? are Quartz extensions, not standard cron syntax. This parser rejects any field containing one and names the field, rather than guessing at an interpretation.
At a glance
- L
- Quartz: last. Last day of the month, or last given weekday. Rejected here.
- W
- Quartz: nearest weekday to a given date. Rejected here.
- #
- Quartz: the nth given weekday of the month, as in 6#3. Rejected here.
- ?
- Quartz: no specific value, used in one date field. Rejected here.
- Detection
- Any of the four characters anywhere in a field, in either case, triggers the error.
- Standard replacement
- A date range in the expression plus a test in the command.
In detail
Quartz is a scheduler with its own cron dialect, and a lot of the cron expressions circulating on the internet are written in it rather than in standard cron. Four characters mark the difference, and none of them belongs to the syntax the system crontab understands.
L means last, so L in the day of month field is the last day of the month and 6L in the day of week field is the last Friday. W means the nearest weekday to a date, so 15W is the working day closest to the 15th. The hash gives the nth weekday of the month, so 6#3 is the third Friday. The question mark means no specific value, and it exists because Quartz refuses to let both date fields carry a restriction at once.
None of them is standard cron syntax, and this parser rejects a field containing any of them with a message naming the field rather than ignoring the character or guessing. That is the useful behaviour: a silently ignored L would turn a last day of month schedule into a daily one, which is a much worse outcome than a clear error.
The replacement pattern is the same in every case. Put a date range in the expression that is wide enough to contain every possible answer, then have the command test the exact condition and exit if it does not hold. For the last day of the month, schedule on days 28 to 31 and check whether tomorrow is the 1st. For the third Friday, schedule on days 15 to 21 and check the weekday.
The question mark needs no replacement at all. It exists in Quartz because that dialect refuses to let you restrict the day of month and day of week fields at the same time. Standard cron allows it and applies the OR rule instead, so wherever a Quartz expression has a question mark, an asterisk is the direct equivalent.
Examples
0 0 L * *
0 0 15W * *
0 9 ? * 6#3
0 9 ? * MONEach reports that L, W, # and ? are not supported, naming the field it found the character in.
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /opt/app/bin/job.sh0 9 15-21 * * [ "$(date +\%u)" = "5" ] && /opt/app/bin/job.shThings that catch people out
- Expressions copied from Quartz documentation often have six or seven fields as well as these characters, so the field count error appears before the character error.
- A question mark translates to an asterisk, but the resulting expression then falls under the OR rule that Quartz was avoiding. Restrict only one date field.
- 6L in Quartz is the last Friday, while 6#5 is the fifth Friday, which does not exist in most months. They are not interchangeable.
Try it: Cron Expression Parser
Paste any five or six field expression to get a plain English description, a per field breakdown and the next run times in your local time.
Cron Expression Parser
LOCAL · Browser-OnlyParse cron expressions and see the next scheduled run times
Supports 5-field (minute hour day month weekday), 6-field (with seconds), named values (JAN, MON), and @macros (@daily, @hourly, ...)
Use the dropdowns below to build your cron expression visually, or type a custom value in each field.
Human-Readable Description
Every 5 minutes
Field Breakdown
| Field | Allowed | Value | Meaning |
|---|---|---|---|
| Minute | 0-59 | */5 | every 5 minute(s) |
| Hour | 0-23 | * | every hour |
| Day of Month | 1-31 | * | every day of month |
| Month | 1-12 | * | every month |
| Day of Week | 0-7 | * | every day of week |
Related cron expressions
All cron expressions →Cron on the last day of the month: the L workaround
This parser rejects the Quartz L character, so the last day of the month needs a date range plus a script guard that checks whether tomorrow is the 1st.
Cron on the last Friday of the month: no # or L support
The Quartz forms 6L and 6#5 are rejected here. Schedule every Friday and let the script check whether the following Friday is in the next month.
Cron day of month and day of week: the OR rule
When both date fields are restricted, cron fires if either matches, not both. This turns narrowing expressions into much wider ones without any error.
Cron on the first Monday of the month: the OR rule trap
0 9 1-7 * 1 does not mean the first Monday. Because both date fields are restricted, it fires on days 1 to 7 and on every Monday as well.
Cron every minute: * * * * *
* * * * * fires 1,440 times a day, once at the top of every minute. Why it is the fastest a five field crontab goes, and how to stop runs stacking.
Cron every 2 minutes: */2 * * * *
*/2 * * * * fires 720 times a day on even minutes only. How to run on odd minutes instead with 1-59/2, and what the even alignment costs you.
Tools for this
- Cron Expression Parser Free online cron expression parser - parse cron expressions and see the next scheduled run times
- Crontab Generator Free online crontab generator - build cron expressions visually with an intuitive interface