moving command line utility here
This commit is contained in:
parent
2323c4aca0
commit
ec79af33a8
|
@ -6,7 +6,7 @@ In another project, I decided to use cron expression syntax to encode scheduling
|
||||||
|
|
||||||
The 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.
|
The 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.
|
||||||
|
|
||||||
There is also a companion command-line utility to evaluate cron time expressions: <https://github.com/gorhill/cronexprdo> (which of course uses this library).
|
There is also a companion command-line utility to evaluate cron time expressions: <https://github.com/gorhill/cronexpr/cronexpr> (which of course uses this library).
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
cronexpr: command-line utility
|
||||||
|
==============================
|
||||||
|
|
||||||
|
A command-line utility written in Go to evaluate cron time expressions.
|
||||||
|
|
||||||
|
It is based on the standalone Go library <https://github.com/gorhill/cronexpr>.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
go get github.com/gorhill/cronexpr
|
||||||
|
go install github.com/gorhill/cronexpr
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
cronexpr [options] "{cron expression}"
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
`-l`:
|
||||||
|
|
||||||
|
Go-compliant time layout to use for outputting time value(s), see <http://golang.org/pkg/time/#pkg-constants>.
|
||||||
|
|
||||||
|
Default is `"Mon, 02 Jan 2006 15:04:05 MST"`
|
||||||
|
|
||||||
|
`-n`:
|
||||||
|
|
||||||
|
Number of resulting time values to output.
|
||||||
|
|
||||||
|
Default is 1.
|
||||||
|
|
||||||
|
`-t`:
|
||||||
|
|
||||||
|
Whole or partial RFC3339 time value (i.e. `2006-01-02T15:04:05Z07:00`) against which the cron expression is evaluated. Examples of valid values include (assuming EST time zone):
|
||||||
|
|
||||||
|
`13` = 2013-01-01T00:00:00-05:00
|
||||||
|
`2013` = 2013-01-01T00:00:00-05:00
|
||||||
|
`2013-08` = 2013-08-01T00:00:00-05:00
|
||||||
|
`2013-08-31` = 2013-08-31T00:00:00-05:00
|
||||||
|
`2013-08-31T12` = 2013-08-31T12:00:00-05:00
|
||||||
|
`2013-08-31T12:40` = 2013-08-31T12:40:00-05:00
|
||||||
|
`2013-08-31T12:40:35` = 2013-08-31T12:40:35-05:00
|
||||||
|
`2013-08-31T12:40:35-10:00` = 2013-08-31T12:40:35-10:00
|
||||||
|
|
||||||
|
Default time is current time, and default time zone is local time zone.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
#### Example 1
|
||||||
|
|
||||||
|
Midnight on December 31st of any year.
|
||||||
|
|
||||||
|
Command:
|
||||||
|
|
||||||
|
cronexpr -t="2013-08-31" -n=5 "0 0 31 12 *"
|
||||||
|
|
||||||
|
Output (assuming computer is in EST time zone):
|
||||||
|
|
||||||
|
# "0 0 31 12 *" + "2013-08-31T00:00:00-04:00" =
|
||||||
|
Tue, 31 Dec 2013 00:00:00 EST
|
||||||
|
Wed, 31 Dec 2014 00:00:00 EST
|
||||||
|
Thu, 31 Dec 2015 00:00:00 EST
|
||||||
|
Sat, 31 Dec 2016 00:00:00 EST
|
||||||
|
Sun, 31 Dec 2017 00:00:00 EST
|
||||||
|
|
||||||
|
#### Example 2
|
||||||
|
|
||||||
|
2pm on February 29th of any year.
|
||||||
|
|
||||||
|
Command:
|
||||||
|
|
||||||
|
cronexpr -t=2000 -n=10 "0 14 29 2 *"
|
||||||
|
|
||||||
|
Output (assuming computer is in EST time zone):
|
||||||
|
|
||||||
|
# "0 14 29 2 *" + "2000-01-01T00:00:00-05:00" =
|
||||||
|
Tue, 29 Feb 2000 14:00:00 EST
|
||||||
|
Sun, 29 Feb 2004 14:00:00 EST
|
||||||
|
Fri, 29 Feb 2008 14:00:00 EST
|
||||||
|
Wed, 29 Feb 2012 14:00:00 EST
|
||||||
|
Mon, 29 Feb 2016 14:00:00 EST
|
||||||
|
Sat, 29 Feb 2020 14:00:00 EST
|
||||||
|
Thu, 29 Feb 2024 14:00:00 EST
|
||||||
|
Tue, 29 Feb 2028 14:00:00 EST
|
||||||
|
Sun, 29 Feb 2032 14:00:00 EST
|
||||||
|
Fri, 29 Feb 2036 14:00:00 EST
|
||||||
|
|
||||||
|
#### Example 3
|
||||||
|
|
||||||
|
12pm on the work day closest to the 15th of March and every three month
|
||||||
|
thereafter.
|
||||||
|
|
||||||
|
Command:
|
||||||
|
|
||||||
|
cronexpr -t=2013-09-01 -n=5 "0 12 15W 3/3 *"
|
||||||
|
|
||||||
|
Output (assuming computer is in EST time zone):
|
||||||
|
|
||||||
|
# "0 12 15W 3/3 *" + "2013-09-01T00:00:00-04:00" =
|
||||||
|
Mon, 16 Sep 2013 12:00:00 EDT
|
||||||
|
Mon, 16 Dec 2013 12:00:00 EST
|
||||||
|
Fri, 14 Mar 2014 12:00:00 EDT
|
||||||
|
Mon, 16 Jun 2014 12:00:00 EDT
|
||||||
|
Mon, 15 Sep 2014 12:00:00 EDT
|
||||||
|
|
||||||
|
#### Example 4
|
||||||
|
|
||||||
|
Midnight on the fifth Saturday of any month (twist: not all months have a 5th
|
||||||
|
specific day of week).
|
||||||
|
|
||||||
|
Command:
|
||||||
|
|
||||||
|
cronexpr -t=2013-09-02 -n 5 "0 0 * * 6#5"
|
||||||
|
|
||||||
|
Output (assuming computer is in EST time zone):
|
||||||
|
|
||||||
|
# "0 0 * * 6#5" + "2013-09-02T00:00:00-04:00" =
|
||||||
|
Sat, 30 Nov 2013 00:00:00 EST
|
||||||
|
Sat, 29 Mar 2014 00:00:00 EDT
|
||||||
|
Sat, 31 May 2014 00:00:00 EDT
|
||||||
|
Sat, 30 Aug 2014 00:00:00 EDT
|
||||||
|
Sat, 29 Nov 2014 00:00:00 EST
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*!
|
||||||
|
* Copyright 2013 Raymond Hill
|
||||||
|
*
|
||||||
|
* Project: github.com/gorhill/cronexprdo
|
||||||
|
* File: main.go
|
||||||
|
* Version: 1.0
|
||||||
|
* License: GPL v3 see <https://www.gnu.org/licenses/gpl.html>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorhill/cronexpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var (
|
||||||
|
usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage:\n %s [options] \"{cron expression}\"\noptions:\n", os.Args[0])
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
inTimeStr string
|
||||||
|
outTimeCount uint
|
||||||
|
outTimeLayout string
|
||||||
|
)
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.StringVar(&inTimeStr, "t", "", `whole or partial RFC3339 time value (i.e. "2006-01-02T15:04:05Z07:00") against which the cron expression is evaluated, now if not present`)
|
||||||
|
flag.UintVar(&outTimeCount, "n", 1, `number of resulting time values to output`)
|
||||||
|
flag.StringVar(&outTimeLayout, "l", "Mon, 02 Jan 2006 15:04:05 MST", `Go-compliant time layout to use for outputting time value(s), see <http://golang.org/pkg/time/#pkg-constants>`)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cronStr := flag.Arg(0)
|
||||||
|
if len(cronStr) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
inTime := time.Now()
|
||||||
|
inTimeLayout := ""
|
||||||
|
timeStrLen := len(inTimeStr)
|
||||||
|
if timeStrLen == 2 {
|
||||||
|
inTimeLayout = "06"
|
||||||
|
} else if timeStrLen >= 4 {
|
||||||
|
inTimeLayout += "2006"
|
||||||
|
if timeStrLen >= 7 {
|
||||||
|
inTimeLayout += "-01"
|
||||||
|
if timeStrLen >= 10 {
|
||||||
|
inTimeLayout += "-02"
|
||||||
|
if timeStrLen >= 13 {
|
||||||
|
inTimeLayout += "T15"
|
||||||
|
if timeStrLen >= 16 {
|
||||||
|
inTimeLayout += ":04"
|
||||||
|
if timeStrLen >= 19 {
|
||||||
|
inTimeLayout += ":05"
|
||||||
|
if timeStrLen >= 20 {
|
||||||
|
inTimeLayout += "Z07:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(inTimeLayout) > 0 {
|
||||||
|
// default to local time zone
|
||||||
|
if timeStrLen < 20 {
|
||||||
|
inTime, err = time.ParseInLocation(inTimeLayout, inTimeStr, time.Local)
|
||||||
|
} else {
|
||||||
|
inTime, err = time.Parse(inTimeLayout, inTimeStr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "# error: unparseable time value: \"%s\"\n", inTimeStr)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr, err := cronexpr.Parse(cronStr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "# %s: %s\n", os.Args[0], err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anything on the output which starts with '#' can be ignored if the caller
|
||||||
|
// is interested only in the time values. There is only one time
|
||||||
|
// value per line, and they are always in chronological ascending order.
|
||||||
|
fmt.Printf("# \"%s\" + \"%s\" =\n", cronStr, inTime.Format(time.RFC3339))
|
||||||
|
|
||||||
|
if outTimeCount < 1 {
|
||||||
|
outTimeCount = 1
|
||||||
|
}
|
||||||
|
outTimes := expr.NextN(inTime, outTimeCount)
|
||||||
|
for _, outTime := range outTimes {
|
||||||
|
fmt.Println(outTime.Format(outTimeLayout))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue