I need to write an regular expression that matches Cron time expressions, like these ones:
- 28 2 7 1 1
- 28 2 7 1 *
- 28 2 7 * *
- 28 2 * * *
- 28 * * * *
- * * * * *
I need to write an regular expression that matches Cron time expressions, like these ones:
To validate cron expressions in general, it'll depend greatly on the specific implementation you're using
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 | * / , -
|
<sup>*where seconds and years are non-standard and sometimes not included</sup>
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 | |
Some flavors allow using the @every <duration>
syntax with the following timespan units:
| Unit | <a href="https://en.wikipedia.org/wiki/Orders_of_magnitude_(time)">Definition</a> |
| ---------- | --------------------------------------------------------------------------------- |
| ns
| nanosecond |
| us
, µs
| microsecond |
| ms
| millisecond |
| s
| second |
| m
| minute |
| h
| hour |
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
RegexTo 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
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:
,
/
or -
*
To validate a single term, we can use the following regex:
/(\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*/
<sup>where \d+
just guarantees you have 1 or more numeric digits</sup>
Which will pass the following test cases:
1,2,3
1,2
1/2
1-2
1
*
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
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})/