func (s *SpecSchedule) Next(t time.Time) time.Time { // General approach: // For Month, Day, Hour, Minute, Second: // Check if the time value matches. If yes, continue to the next field. // If the field doesn't match the schedule, then increment the field until it matches. // While incrementing the field, a wrap-around brings it back to the beginning // of the field list (since it is necessary to re-verify previous field // values) // 下一次每次取最近1s的时间 t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) // This flag indicates whether a field has been incremented. added := false // If no time is found within five years, return zero. yearLimit := t.Year() + 5 WRAP: if t.Year() > yearLimit { return time.Time{} } // Find the first applicable month. // If it's this month, then do nothing. //通过指数法逼近值,并通过从sec到min到hour到day到mon到year的不断逼近 for 1<<uint(t.Month())&s.Month == 0 { // If we have to add a month, reset the other parts to 0. if !added { added = true // Otherwise, set the date at the beginning (since the current time is irrelevant). t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location()) } t = t.AddDate(0, 1, 0) // Wrapped around. if t.Month() == time.January { goto WRAP } } // Now get a day in that month. for !dayMatches(s, t) { if !added { added = true t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) } t = t.AddDate(0, 0, 1) if t.Day() == 1 { goto WRAP } } for 1<<uint(t.Hour())&s.Hour == 0 { if !added { added = true t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location()) } t = t.Add(1 * time.Hour) if t.Hour() == 0 { goto WRAP } } for 1<<uint(t.Minute())&s.Minute == 0 { if !added { added = true t = t.Truncate(time.Minute) } t = t.Add(1 * time.Minute) if t.Minute() == 0 { goto WRAP } } for 1<<uint(t.Second())&s.Second == 0 { if !added { added = true t = t.Truncate(time.Second) } t = t.Add(1 * time.Second) if t.Second() == 0 { goto WRAP } } return t }
代码里面最经典的还是这种位运算:
1<<uint(t.Month())&s.Month
//转化为计算公式为: 2^t.Month & s.Month
//比如t.Month = 3, s.Month = 4 2^t.Month = 8 > s.Month 并且此时与操作为0
//说明此时t.Month与s.Month差距不多,当t.Month=1的时候 2^t.Month = 2 此时与操作结果不为0
//当t.Month=2的时候 也是如此
//总结就是 2^t.Month > s.Month的时候操作结果为0,需要轮转到比它小很多的位置,
//然后Month的更新再依赖于下面的day的更新
有疑问加站长微信联系(非本文作者)