Categorygithub.com/alex-schneider/cron
repositorypackage
0.0.0-20220930101416-9e87fa819a64
Repository: https://github.com/alex-schneider/cron.git
Documentation: pkg.go.dev

# README

The cron package

cron Go Report Card

The cron package implements a cron job scheduler with a lot of non-standard extensions. It allowes to run jobs periodically at fixed times, dates, frequencies and intervals.

Format

The cron expression is a string with 5, 6 or 7 fields separated by any number of whitespace like SP (0x20) or HT (0x09) from the ASCII table. Additionally, this cron package implements and supports a lot of Non-Standard Macros as listed below.

Fields

The standard crontab supports only 5 fields and cannot be scaled to seconds or years. The current implementation completes the fields as following:

  • If only 5 fields are present, the seconds field with value 0 is added to the begin and the year field with value * is added to the end of the fields list.
  • If only 6 fields are present, the year field with value * is added to the end of the fields list.
Field nameRequiredDescriptionAllowed valuesAllowed special characters
secondsRepresents seconds.0-59, - * / . R
minutesRepresents minutes.0-59, - * / . R
hoursRepresents hours.0-23, - * / . R
domRepresents days-of-month.1-31, - * / . R ? L W
monthRepresents months.1-12 or JAN-DEC, - * / . R
dowRepresents days-of-week.0-7 or SUN-SAT, - * / . R ? L #
yearRepresents years.1970-2099, - * / . R

Note: Both, 0 and 7 value in the dow (days-of-week) field is interpreted as SUN (Sunday).


Note: The names in month and dow (days-of-week) fields and the special characters R, L and W are case insensitive. For example, FRI is the same as Fri or fri.


Special Characters

Special CharacterDescription
,Commas are used to separate values in a field. For example, using MON,FRI,SUN in the dow (days-of-week) field means Monday, Friday and Sunday.
-Hyphen defines ranges. For example, JAN-MAR in the month field means Januar, Februar and March. The current implementation supports ranges with "range-overflows" for all expression fields excepting the year field. For example, FRI-MON in the dow (days-of-week) field means Friday, Saturday, Sunday and Monday. A mix of names and numeric values in month and dow (days-of-week) fields is supported, too. For example, JAN-MAR is the same as JAN-3.
*Asterisk is used to select all possible values within a field. For example, * in the month field means daily or every day.
/Slash can be used to specify frequencies. For example, */10 in the seconds field means every 10 seconds. And 10/15 in the minutes field means the minutes 10, 25, 40 and 55.
.Dot can be used to specify the current date or time value on the startup. For example, 0 . . * * * * would be updated to 0 9 15 * * * * if the cron is started-up at 09:15.
?Question mark is used for leaving either, dom (day-of-month) or dow (day-of-week) blank. For example, 0 0 0 15 * ? * would trigger the cronjob at 15th of every month regardless of what day-of-week it is.
RR stands for random. R can be combined with ranges, e.g. 10-30/R in the minutes field. Once generated during parsing, the random number remains constant for current field. If used in the dom (day-of-month) field without ranges, the possible values are limited to the range 1-28. To be able to use the total range set 1-31/R to the dom (day-of-month) field.
LL stands for last. When this character is used in the dom (day-of-month) field, it specifies the last day of the month. For example, 31 January or 29 February in a leap year. In the dow (day-of-week) field, it specifies the last day of the week and simply means the SAT or 6. When this character is used in the dow (day-of-week) field and is prefixed with a number, it means the last X day of the month. For example, 1L means the last Monday of the month. MONL is the same as 1L.
WW stands for weekday (Monday-Friday). W is used to specify the business day nearest the given day in the given month. It never jumps over the boundary of the month's days. For example, if 1W is a Saturday, the cronjob would trigger at Monday, the 3rd. The L and W special characters can also be combined in the dom (day-of-month) field as LW, which means last weekday of the month.
#Hash allows to specifying constructs such as the second Friday of a given month. For example, 5#3 in the dow (day-of-week) field means the third Friday of every month. The value before the # has the range 0-7 or SUN-SAT. The value after the # has the range 1-5.

Note: Be careful with the use of ? and * special characters in the dom (day-of-month) or dow (day-of-week) fields.


Note: Avoid cronjobs at daylight saving times. Cronjobs can be skiped or repeated depending on whether the time moves back or jumps forward.


Note: It is not allowed to combine the ? with other values within a field. This special character can only be used exclusively within a field.


Note: It is not allowed to define the ? special character in both, dom (days-of-month) and dow (days-of-week) fields at the same time.


Note: If both, the dom (day-of-month) and dow (day-of-week) fields contain any values excepting the ?, the day is calculated from the best possible value of the both fields.


Non-Standard Macros

MacroDescriptionEquivalent expression
@yearlyRun once a year at midnight of 1 January.0 0 0 1 1 * *
@annuallyThe same as @yearly.0 0 0 1 1 * *
@monthlyRun once a month at midnight of the first day of the month.0 0 0 1 * * *
@weeklyRun once a week at midnight on Sunday.0 0 0 * * 0 *
@dailyRun once a day at midnight.0 0 0 * * * *
@midnightThe same as @daily.0 0 0 * * * *
@hourlyRun once an hour at the beginning of the hour.0 0 * * * * *
@minutelyRun once a minute at the beginning of the minute.0 * * * * * *
@every_minuteThe same as @minutely.0 * * * * * *
@secondlyRun secondly.* * * * * * *
@every_secondThe same as @secondly.* * * * * * *
@rebootRun once at startup.

Examples

ExpressionDescription
0 11 11 11 11 ? *Run every November 11th at 11:11am.
59 59 23 31 12 ? *Run at every turn of the year.
0 0 0 ? * LW *Run at every last business day on the month.
0 0 0 ? * 5L *Run at every last Friday on the month.
0 0 0 29 2 ? *Run every February 29th on every leap year.
0 0 R * * * *Run once a day at a random hour.
0 0 2-6/R * * * *Run once a day at a random hour between 2:00am and 6:00am.

Code Example

import "github.com/alex-schneider/cron"

func main() {
	ctx := context.Background()

	ch, err := cron.NewJobCh(ctx, "@hourly")
	if err != nil {
		// Handle err
	}

myLoop:
	for {
		select {
		case job := <-ch:
			switch job.State {
			case int(cron.StateFound):
				go func() { /* ... */ }() // Trigger some job...
			case int(cron.StateNoMatches): // "* * * * * * 2021"
				fallthrough
			case int(cron.StateOnceExec): // "@reboot"
				break myLoop // Handle an end of a job...
			}
		case <-ctx.Done():
			/* ... */
		}
	}
}