• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..25-Jul-2019-

APLv2H A D25-Jul-201911.1 KiB203169

GPLv3H A D25-Jul-201934.3 KiB675553

README.mdH A D25-Jul-20196.5 KiB13593

cronexpr.goH A D25-Jul-20197 KiB267161

cronexpr_next.goH A D25-Jul-20197.6 KiB293200

cronexpr_parse.goH A D25-Jul-201916.5 KiB504417

README.md

1Golang Cron expression parser
2=============================
3Given a cron expression and a time stamp, you can get the next time stamp which satisfies the cron expression.
4
5In another project, I decided to use cron expression syntax to encode scheduling information. Thus this standalone library to parse and apply time stamps to cron expressions.
6
7The time-matching algorithm in this implementation is efficient, it avoids as much as possible to guess the next matching time stamp, a common technique seen in a number of implementations out there.
8
9There is also a companion command-line utility to evaluate cron time expressions: <https://github.com/gorhill/cronexpr/tree/master/cronexpr> (which of course uses this library).
10
11Implementation
12--------------
13The reference documentation for this implementation is found at
14<https://en.wikipedia.org/wiki/Cron#CRON_expression>, which I copy/pasted here (laziness!) with modifications where this implementation differs:
15
16    Field name     Mandatory?   Allowed values    Allowed special characters
17    ----------     ----------   --------------    --------------------------
18    Seconds        No           0-59              * / , -
19    Minutes        Yes          0-59              * / , -
20    Hours          Yes          0-23              * / , -
21    Day of month   Yes          1-31              * / , - L W
22    Month          Yes          1-12 or JAN-DEC   * / , -
23    Day of week    Yes          0-6 or SUN-SAT    * / , - L #
24    Year           No           1970–2099         * / , -
25
26#### Asterisk ( * )
27The asterisk indicates that the cron expression matches for all values of the field. E.g., using an asterisk in the 4th field (month) indicates every month.
28
29#### Slash ( / )
30Slashes describe increments of ranges. For example `3-59/15` in the minute field indicate the third minute of the hour and every 15 minutes thereafter. The form `*/...` is equivalent to the form "first-last/...", that is, an increment over the largest possible range of the field.
31
32#### Comma ( , )
33Commas are used to separate items of a list. For example, using `MON,WED,FRI` in the 5th field (day of week) means Mondays, Wednesdays and Fridays.
34
35#### Hyphen ( - )
36Hyphens define ranges. For example, 2000-2010 indicates every year between 2000 and 2010 AD, inclusive.
37
38#### L
39`L` stands for "last". When used in the day-of-week field, it allows you to specify constructs such as "the last Friday" (`5L`) of a given month. In the day-of-month field, it specifies the last day of the month.
40
41#### W
42The `W` character is allowed for the day-of-month field. This character is used to specify the business day (Monday-Friday) nearest the given day. As an example, if you were to specify `15W` as the value for the day-of-month field, the meaning is: "the nearest business day to the 15th of the month."
43
44So, if the 15th is a Saturday, the trigger fires on Friday the 14th. If the 15th is a Sunday, the trigger fires on Monday the 16th. If the 15th is a Tuesday, then it fires on Tuesday the 15th. However if you specify `1W` as the value for day-of-month, and the 1st is a Saturday, the trigger fires on Monday the 3rd, as it does not 'jump' over the boundary of a month's days.
45
46The `W` character can be specified only when the day-of-month is a single day, not a range or list of days.
47
48The `W` character can also be combined with `L`, i.e. `LW` to mean "the last business day of the month."
49
50#### Hash ( # )
51`#` is allowed for the day-of-week field, and must be followed by a number between one and five. It allows you to specify constructs such as "the second Friday" of a given month.
52
53Predefined cron expressions
54---------------------------
55(Copied from <https://en.wikipedia.org/wiki/Cron#Predefined_scheduling_definitions>, with text modified according to this implementation)
56
57    Entry       Description                                                             Equivalent to
58    @annually   Run once a year at midnight in the morning of January 1                 0 0 0 1 1 * *
59    @yearly     Run once a year at midnight in the morning of January 1                 0 0 0 1 1 * *
60    @monthly    Run once a month at midnight in the morning of the first of the month   0 0 0 1 * * *
61    @weekly     Run once a week at midnight in the morning of Sunday                    0 0 0 * * 0 *
62    @daily      Run once a day at midnight                                              0 0 0 * * * *
63    @hourly     Run once an hour at the beginning of the hour                           0 0 * * * * *
64    @reboot     Not supported
65
66Other details
67-------------
68* If only six fields are present, a `0` second field is prepended, that is, `* * * * * 2013` internally become `0 * * * * * 2013`.
69* If only five fields are present, a `0` second field is prepended and a wildcard year field is appended, that is, `* * * * Mon` internally become `0 * * * * Mon *`.
70* Domain for day-of-week field is [0-7] instead of [0-6], 7 being Sunday (like 0). This to comply with http://linux.die.net/man/5/crontab#.
71* As of now, the behavior of the code is undetermined if a malformed cron expression is supplied
72
73Install
74-------
75    go get github.com/gorhill/cronexpr
76
77Usage
78-----
79Import the library:
80
81    import "github.com/gorhill/cronexpr"
82    import "time"
83
84Simplest way:
85
86    nextTime := cronexpr.MustParse("0 0 29 2 *").Next(time.Now())
87
88Assuming `time.Now()` is "2013-08-29 09:28:00", then `nextTime` will be "2016-02-29 00:00:00".
89
90You can keep the returned Expression pointer around if you want to reuse it:
91
92    expr := cronexpr.MustParse("0 0 29 2 *")
93    nextTime := expr.Next(time.Now())
94    ...
95    nextTime = expr.Next(nextTime)
96
97Use `time.IsZero()` to find out whether a valid time was returned. For example,
98
99    cronexpr.MustParse("* * * * * 1980").Next(time.Now()).IsZero()
100
101will return `true`, whereas
102
103    cronexpr.MustParse("* * * * * 2050").Next(time.Now()).IsZero()
104
105will return `false` (as of 2013-08-29...)
106
107You may also query for `n` next time stamps:
108
109    cronexpr.MustParse("0 0 29 2 *").NextN(time.Now(), 5)
110
111which returns a slice of time.Time objects, containing the following time stamps (as of 2013-08-30):
112
113    2016-02-29 00:00:00
114    2020-02-29 00:00:00
115    2024-02-29 00:00:00
116    2028-02-29 00:00:00
117    2032-02-29 00:00:00
118
119The time zone of time values returned by `Next` and `NextN` is always the
120time zone of the time value passed as argument, unless a zero time value is
121returned.
122
123API
124---
125<http://godoc.org/github.com/gorhill/cronexpr>
126
127License
128-------
129
130License: pick the one which suits you best:
131
132- GPL v3 see <https://www.gnu.org/licenses/gpl.html>
133- APL v2 see <http://www.apache.org/licenses/LICENSE-2.0>
134
135