package service import ( "strconv" "strings" "time" ) // parseClock 解析 HH:MM,非法输入回退 09:00。 func parseClock(at string) (int, int) { parts := strings.SplitN(at, ":", 2) if len(parts) != 2 { return 9, 0 } h, e1 := strconv.Atoi(parts[0]) m, e2 := strconv.Atoi(parts[1]) if e1 != nil || e2 != nil || h < 0 || h > 23 || m < 0 || m > 59 { return 9, 0 } return h, m } // DigestDue 判断团队日报摘要是否到达自动生成时间:now 已过当天 at(HH:MM)。 func DigestDue(at string, now time.Time) bool { hh, mm := parseClock(at) due := time.Date(now.Year(), now.Month(), now.Day(), hh, mm, 0, 0, now.Location()) return !now.Before(due) } // NextAutoUpdate 计算下一次自动更新的时间点(纯函数,便于测试)。 // mode: daily | everyNDays | everyNHours;at 为 HH:MM;last 为上次执行时间(调用方保证非零)。 func NextAutoUpdate(mode string, interval int, at string, last, now time.Time) time.Time { if interval < 1 { interval = 1 } hh, mm := parseClock(at) switch mode { case "everyNHours": return last.Add(time.Duration(interval) * time.Hour) case "everyNDays": return time.Date(last.Year(), last.Month(), last.Day(), hh, mm, 0, 0, last.Location()).AddDate(0, 0, interval) default: // daily:今天的 HH:MM;若上次已在该时点之后执行过,则推到明天。 t := time.Date(now.Year(), now.Month(), now.Day(), hh, mm, 0, 0, now.Location()) if !last.Before(t) { t = t.AddDate(0, 0, 1) } return t } }