Go定时器cron的使用详解

2020-01-28 12:54:41丽君

spec.go

结构体及关键方法:


// SpecSchedule specifies a duty cycle (to the second granularity), based on a
// traditional crontab specification. It is computed initially and stored as bit sets.
type SpecSchedule struct {
  // 表达式中锁表明的,秒,分,时,日,月,周,每个都是uint64
  // Dom:Day of Month,Dow:Day of week
  Second, Minute, Hour, Dom, Month, Dow uint64
}

// bounds provides a range of acceptable values (plus a map of name to value).
// 定义了表达式的结构体
type bounds struct {
  min, max uint
  names  map[string]uint
}


// The bounds for each field.
// 这样就能看出各个表达式的范围
var (
    seconds = bounds{0, 59, nil}
    minutes = bounds{0, 59, nil}
    hours  = bounds{0, 23, nil}
    dom   = bounds{1, 31, nil}
    months = bounds{1, 12, map[string]uint{
       "jan": 1,
       "feb": 2,
       "mar": 3,
       "apr": 4,
       "may": 5,
       "jun": 6,
       "jul": 7,
       "aug": 8,
       "sep": 9,
       "oct": 10,
       "nov": 11,
       "dec": 12,
    }}
    dow = bounds{0, 6, map[string]uint{
       "sun": 0,
       "mon": 1,
       "tue": 2,
       "wed": 3,
       "thu": 4,
       "fri": 5,
       "sat": 6,
    }}
)

const (
    // Set the top bit if a star was included in the expression.
    starBit = 1 << 63
)

看了上面的东西肯定有人疑惑为什么秒分时这些都是定义了unit64,以及定义了一个常量starBit = 1 << 63这种写法,这是逻辑运算符。表示二进制1向左移动63位。原因如下:

cron表达式是用来表示一系列时间的,而时间是无法逃脱自己的区间的 , 分,秒 0 - 59 , 时 0 - 23 , 天/月 0 - 31 , 天/周 0 - 6 , 月0 - 11 。 这些本质上都是一个点集合,或者说是一个整数区间。 那么对于任意的整数区间 , 可以描述cron的如下部分规则。

    * | ? 任意 , 对应区间上的所有点。 ( 额外注意 日/周 , 日 / 月 的相互干扰。) 纯数字 , 对应一个具体的点。 / 分割的两个数字 a , b, 区间上符合 a + n * b 的所有点 ( n >= 0 )。 - 分割的两个数字, 对应这两个数字决定的区间内的所有点。 L | W 需要对于特定的时间特殊判断, 无法通用的对应到区间上的点。

至此, robfig/cron为什么不支持 L | W的原因已经明了了。去除这两条规则后, 其余的规则其实完全可以使用点的穷举来通用表示。 考虑到最大的区间也不过是60个点,那么使用一个uint64的整数的每一位来表示一个点便很合适了。所以定义unit64不为过

下面是go中cron表达式的方法:


/* 
  ------------------------------------------------------------
  第64位标记任意 , 用于 日/周 , 日 / 月 的相互干扰。
  63 - 0 为 表示区间 [63 , 0] 的 每一个点。
  ------------------------------------------------------------

  假设区间是 0 - 63 , 则有如下的例子 :

  比如 0/3 的表示如下 : (表示每隔两位为1)
  * / ?    
  +---+--------------------------------------------------------+
  | 0 | 1 0 0 1 0 0 1 ~~ ~~          1 0 0 1 0 0 1 |
  +---+--------------------------------------------------------+  
    63 ~ ~                      ~~ 0

  比如 2-5 的表示如下 : (表示从右往左2-5位上都是1)
  * / ?    
  +---+--------------------------------------------------------+
  | 0 | 0 0 0 0 ~ ~   ~~      ~  0 0 0 1 1 1 1 0 0 |
  +---+--------------------------------------------------------+  
    63 ~ ~                      ~~ 0

 比如 * 的表示如下 : (表示所有位置上都为1)
  * / ?    
  +---+--------------------------------------------------------+
  | 1 | 1 1 1 1 1 ~ ~         ~  1 1 1 1 1 1 1 1 1 |
  +---+--------------------------------------------------------+  
    63 ~ ~                      ~~ 0 
*/