优化了本地定时器+下次的判断
This commit is contained in:
+189
-62
@@ -7,110 +7,237 @@ import (
|
||||
|
||||
// 计算该任务下次执行时间
|
||||
// @param job *JobData 任务数据
|
||||
// @param t time.Time 当前时间
|
||||
// @return time.Time 下次执行时间
|
||||
// @return error 错误信息
|
||||
func GetNextTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
|
||||
var next time.Time
|
||||
if err := validateJobData(job); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var next *time.Time
|
||||
var err error
|
||||
|
||||
switch job.JobType {
|
||||
case JobTypeEveryMonth:
|
||||
next = calculateNextMonthTime(t, job)
|
||||
next, err = calculateNextMonthTime(t, job)
|
||||
case JobTypeEveryWeek:
|
||||
next = calculateNextWeekTime(t, job)
|
||||
next, err = calculateNextWeekTime(t, job)
|
||||
case JobTypeEveryDay:
|
||||
next = calculateNextDayTime(t, job)
|
||||
next, err = calculateNextDayTime(t, job)
|
||||
case JobTypeEveryHour:
|
||||
next = calculateNextHourTime(t, job)
|
||||
next, err = calculateNextHourTime(t, job)
|
||||
case JobTypeEveryMinute:
|
||||
next = calculateNextMinuteTime(t, job)
|
||||
next, err = calculateNextMinuteTime(t, job)
|
||||
case JobTypeInterval:
|
||||
next = calculateNextInterval(t, job)
|
||||
next, err = calculateNextInterval(t, job)
|
||||
default:
|
||||
return nil, errors.New("未知的任务类型: " + string(job.JobType))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next, nil
|
||||
}
|
||||
|
||||
// 参数校验
|
||||
func validateJobData(job JobData) error {
|
||||
switch job.JobType {
|
||||
case JobTypeEveryMonth:
|
||||
if job.Day < 1 || job.Day > 31 {
|
||||
return ErrMonthDay
|
||||
}
|
||||
case JobTypeEveryWeek:
|
||||
if job.Weekday < time.Sunday || job.Weekday > time.Saturday {
|
||||
return ErrWeekday
|
||||
}
|
||||
case JobTypeEveryDay:
|
||||
if job.Hour < 0 || job.Hour > 23 {
|
||||
return ErrHour
|
||||
}
|
||||
case JobTypeEveryHour:
|
||||
if job.Minute < 0 || job.Minute > 59 {
|
||||
return ErrMinute
|
||||
}
|
||||
case JobTypeEveryMinute:
|
||||
if job.Second < 0 || job.Second > 59 {
|
||||
return ErrSecond
|
||||
}
|
||||
case JobTypeInterval:
|
||||
if job.IntervalTime <= 0 {
|
||||
return ErrIntervalTime
|
||||
}
|
||||
if job.CreateTime.IsZero() {
|
||||
return ErrCreateTime
|
||||
}
|
||||
}
|
||||
|
||||
if job.Hour < 0 || job.Hour > 23 {
|
||||
return ErrHour
|
||||
}
|
||||
if job.Minute < 0 || job.Minute > 59 {
|
||||
return ErrMinute
|
||||
}
|
||||
if job.Second < 0 || job.Second > 59 {
|
||||
return ErrSecond
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateNextInterval(t time.Time, job JobData) (*time.Time, error) {
|
||||
if job.CreateTime.IsZero() {
|
||||
return nil, ErrCreateTime
|
||||
}
|
||||
if job.IntervalTime <= 0 {
|
||||
return nil, ErrIntervalTime
|
||||
}
|
||||
// 计算从创建时间到当前时间经过了多少个间隔
|
||||
elapsed := t.Sub(job.CreateTime)
|
||||
intervals := elapsed / job.IntervalTime
|
||||
|
||||
// 计算下一个执行时间
|
||||
next := job.CreateTime.Add((intervals + 1) * job.IntervalTime)
|
||||
|
||||
// 确保下次执行时间不早于当前时间
|
||||
if next.Before(t) || next.Equal(t) {
|
||||
next = next.Add(job.IntervalTime)
|
||||
}
|
||||
|
||||
return &next, nil
|
||||
}
|
||||
|
||||
func calculateNextInterval(t time.Time, job JobData) time.Time {
|
||||
// 从创建的时候开始计算
|
||||
cycle := t.Sub(job.BaseTime).Microseconds() / job.IntervalTime.Microseconds()
|
||||
return job.BaseTime.Add(job.IntervalTime * time.Duration(cycle+1))
|
||||
func calculateNextMonthTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
// 尝试光剑本月的执行四件
|
||||
currentMonthTime := time.Date(t.Year(), t.Month(), job.Day, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
// 如果日期无效(比如2月30号),则调整到该月最后一天
|
||||
if currentMonthTime.Day() != job.Day {
|
||||
// 获取该月的最后一天
|
||||
lastDay := time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, t.Location()).Day()
|
||||
if job.Day > lastDay {
|
||||
currentMonthTime = time.Date(t.Year(), t.Month(), lastDay, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
}
|
||||
}
|
||||
|
||||
if currentMonthTime.After(t) {
|
||||
return ¤tMonthTime, nil
|
||||
}
|
||||
|
||||
// 计算下个月的同一天
|
||||
nextMonth := t.Month() + 1
|
||||
year := t.Year()
|
||||
if nextMonth > 12 {
|
||||
nextMonth = 1
|
||||
year++
|
||||
}
|
||||
|
||||
nextMonthTime := time.Date(year, nextMonth, job.Day, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
// 如果日期无效,调整到下个月的最后一天
|
||||
if nextMonthTime.Day() != job.Day {
|
||||
lastDay := time.Date(year, nextMonth+1, 0, 0, 0, 0, 0, t.Location()).Day()
|
||||
if job.Day > lastDay {
|
||||
nextMonthTime = time.Date(year, nextMonth, lastDay, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
}
|
||||
}
|
||||
|
||||
return &nextMonthTime, nil
|
||||
}
|
||||
|
||||
func calculateNextMonthTime(t time.Time, job JobData) time.Time {
|
||||
// 判断是否可执行并返回下一个执行时间
|
||||
func calculateNextWeekTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
currentWeekday := t.Weekday()
|
||||
targetWeekday := job.Weekday
|
||||
|
||||
if canRun(t, job) {
|
||||
return time.Date(t.Year(), t.Month(), job.Day, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
// 计算距离目标星期几的天数
|
||||
daysToAdd := int(targetWeekday - currentWeekday)
|
||||
if daysToAdd < 0 {
|
||||
daysToAdd += 7
|
||||
}
|
||||
// 下一个周期(下个月)
|
||||
return time.Date(t.Year(), t.Month()+1, job.Day, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
// 本周的目标时间
|
||||
thisWeekTime := time.Date(t.Year(), t.Month(), t.Day()+daysToAdd, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
if thisWeekTime.After(t) {
|
||||
return &thisWeekTime, nil
|
||||
}
|
||||
|
||||
// 下周的目标时间
|
||||
nextWeekTime := time.Date(t.Year(), t.Month(), t.Day()+daysToAdd+7, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
return &nextWeekTime, nil
|
||||
}
|
||||
|
||||
func calculateNextWeekTime(t time.Time, job JobData) time.Time {
|
||||
weekday := t.Weekday()
|
||||
days := int(job.Weekday - weekday)
|
||||
if days < 0 {
|
||||
days += 7
|
||||
func calculateNextDayTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
// 今天的目标时间
|
||||
todayTime := time.Date(t.Year(), t.Month(), t.Day(), job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
if todayTime.After(t) {
|
||||
return &todayTime, nil
|
||||
}
|
||||
// 判断是否可执行并返回下一个执行时间
|
||||
if canRun(t, job) {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
}
|
||||
// 下一个周期(下周)
|
||||
return time.Date(t.Year(), t.Month(), t.Day()+days+7, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
// 明天的时间
|
||||
nextDayTime := time.Date(t.Year(), t.Month(), t.Day()+1, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
return &nextDayTime, nil
|
||||
|
||||
}
|
||||
|
||||
func calculateNextDayTime(t time.Time, job JobData) time.Time {
|
||||
// 判断是否可执行并返回下一个执行时间
|
||||
if canRun(t, job) {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
func calculateNextHourTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
// 计算当前小时的目标时间
|
||||
currentHourTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
if currentHourTime.After(t) {
|
||||
return ¤tHourTime, nil
|
||||
}
|
||||
// 下一个周期(明天)
|
||||
return time.Date(t.Year(), t.Month(), t.Day()+1, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
// 下一个小时的时间
|
||||
nextHourTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour()+1, job.Minute, job.Second, 0, t.Location())
|
||||
return &nextHourTime, nil
|
||||
}
|
||||
|
||||
func calculateNextHourTime(t time.Time, job JobData) time.Time {
|
||||
// 判断是否可执行并返回下一个执行时间
|
||||
if canRun(t, job) {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), job.Minute, job.Second, 0, t.Location())
|
||||
}
|
||||
// 下一个周期(下个小时)
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour()+1, job.Minute, job.Second, 0, t.Location())
|
||||
}
|
||||
func calculateNextMinuteTime(t time.Time, job JobData) (*time.Time, error) {
|
||||
// 计算当前分钟的目标时间
|
||||
|
||||
func calculateNextMinuteTime(t time.Time, job JobData) time.Time {
|
||||
// 判断是否可执行并返回下一个执行时间
|
||||
if canRun(t, job) {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), job.Second, 0, t.Location())
|
||||
currentMinuteTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), job.Second, 0, t.Location())
|
||||
|
||||
if currentMinuteTime.After(t) {
|
||||
return ¤tMinuteTime, nil
|
||||
}
|
||||
// 下一个周期(下分钟)
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()+1, job.Second, 0, t.Location())
|
||||
|
||||
// 下一分钟的时间
|
||||
nextMinuteTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()+1, job.Second, 0, t.Location())
|
||||
return &nextMinuteTime, nil
|
||||
}
|
||||
|
||||
// 检查是否本周期可以运行
|
||||
// 检查是否本周期可以运行(已弃用,使用新的时间比较逻辑)
|
||||
// 保留此函数用于向后兼容,但建议使用新的时间计算逻辑
|
||||
func canRun(t time.Time, job JobData) bool {
|
||||
targetTime := time.Date(t.Year(), t.Month(), t.Day(), job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
|
||||
switch job.JobType {
|
||||
case JobTypeEveryMonth:
|
||||
return t.Day() < job.Day ||
|
||||
(t.Day() == job.Day && t.Hour() < job.Hour) ||
|
||||
(t.Day() == job.Day && t.Hour() == job.Hour && t.Minute() < job.Minute) ||
|
||||
(t.Day() == job.Day && t.Hour() == job.Hour && t.Minute() == job.Minute && t.Second() <= job.Second)
|
||||
// 对于月任务,需要比较日期
|
||||
targetTime = time.Date(t.Year(), t.Month(), job.Day, job.Hour, job.Minute, job.Second, 0, t.Location())
|
||||
return !targetTime.Before(t)
|
||||
case JobTypeEveryWeek:
|
||||
return t.Weekday() < job.Weekday ||
|
||||
(t.Weekday() == job.Weekday && t.Hour() < job.Hour) ||
|
||||
(t.Weekday() == job.Weekday && t.Hour() == job.Hour && t.Minute() < job.Minute) ||
|
||||
(t.Weekday() == job.Weekday && t.Hour() == job.Hour && t.Minute() == job.Minute && t.Second() <= job.Second)
|
||||
// 对于周任务,需要比较星期
|
||||
currentWeekday := t.Weekday()
|
||||
if currentWeekday < job.Weekday {
|
||||
return true
|
||||
}
|
||||
if currentWeekday == job.Weekday {
|
||||
return targetTime.After(t) || targetTime.Equal(t)
|
||||
}
|
||||
return false
|
||||
case JobTypeEveryDay:
|
||||
return t.Hour() < job.Hour ||
|
||||
(t.Hour() == job.Hour && t.Minute() < job.Minute) ||
|
||||
(t.Hour() == job.Hour && t.Minute() == job.Minute && t.Second() <= job.Second)
|
||||
return targetTime.After(t) || targetTime.Equal(t)
|
||||
case JobTypeEveryHour:
|
||||
return t.Minute() < job.Minute ||
|
||||
(t.Minute() == job.Minute && t.Second() <= job.Second)
|
||||
hourTarget := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), job.Minute, job.Second, 0, t.Location())
|
||||
return hourTarget.After(t) || hourTarget.Equal(t)
|
||||
case JobTypeEveryMinute:
|
||||
return t.Second() <= job.Second
|
||||
minuteTarget := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), job.Second, 0, t.Location())
|
||||
return minuteTarget.After(t) || minuteTarget.Equal(t)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user