Create a regular expression for Cron statement
To validate cron expressions in general, it'll depend greatly on the specific implementation you're using
Rules
General Format
In general, most adhere to the the following format:
Field name | Mandatory? | Allowed values | Special characters |
---|---|---|---|
Seconds | No* | 0-59 | * / , - |
Minutes | Yes | 0-59 | * / , - |
Hours | Yes | 0-23 | * / , - |
Day of month | Yes | 1-31 | * / , - L W |
Month | Yes | 1-12 or JAN-DEC | * / , - |
Day of week | Yes | 0-6 or SUN-SAT | * / , - L # |
Year | No* | 1970–2099 | * / , - |
*where seconds and years are non-standard and sometimes not included
Predefined Scheduling Macros:
Some flavors allow predefined time periods like this:
Entry | Equivalent to |
---|---|
@annually | 0 0 0 1 1 * * |
@yearly | 0 0 0 1 1 * * |
@monthly | 0 0 0 1 * * * |
@weekly | 0 0 0 * * 0 * |
@daily | 0 0 0 * * * * |
@hourly | 0 0 * * * * * |
@reboot |
Intervals
Some flavors allow using the @every <duration>
syntax with the following timespan units:
Unit | Definition |
---|---|
ns |
nanosecond |
us , µs |
microsecond |
ms |
millisecond |
s |
second |
m |
minute |
h |
hour |
Validating
Predefined Macros Regex
To validate predefined macros, you can use the following regex:
/@(annually|yearly|monthly|weekly|daily|hourly|reboot)/
Which will pass the following test cases:
@daily
@hourly
@every
Regex
To validate @every
durations, you can use the following regex:
/@every (\d+(ns|us|µs|ms|s|m|h))+/
Which will pass the following test cases:
@every 5s
@every 20h30m
Individual Cron Terms
Validating cron terms in the regular expression is a little trickier since there are so many variations.
Just focusing in on a single term, the following are all valid:
- Two or more numbers separated by a
,
- Two numbers separated by a
/
or-
- A 1-2 digit number
- A single
*
To validate a single term, we can use the following regex:
/(\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*/
where \d+
just guarantees you have 1 or more numeric digits
Which will pass the following test cases:
1,2,3
1,2
1/2
1-2
1
*
Combining Cron Terms
To check the full expression, we can just make sure we have {5,7}
terms with the following regex:
/(((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7}/
If we wanted to distinguish between each term, we'd need to validate numbers within a certain range:
Allowed values | Regex |
---|---|
0-59 | [1-5]?[0-9] |
0-23 | 2[0-3]|1[0-9]|[0-9] |
1-31 | 3[01]|[12][0-9]|[1-9] |
1-12 | 1[0-2]|[1-9] |
0-6 | [0-6] |
1970–2099 | 19[7-9][0-9]|20[0-9][0-9] |
If however, we just want to make sure something looks like a regex expression without worrying about which term is days vs. hours, the expression stays a lot cleaner, so that's what I'll go with for simplicity
Putting it all together
By combining the above statements, we can have a relatively simple sanity check that the term looks regex-y with the following expression:
/(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})/
Additional Resources
- crontab.guru
- regexr.com
I just finished writing one, so here is mine, hope it helps.
This should allow the * or */num and also limit the number values to their logical range (1-12 for months, 0-24 for hours, and so on)
/^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$/