
go正则表达式
🔍 Cron 表达式格式说明(6位或5位)
字段数 | 含义 |
---|---|
5 位 | 分 时 日 月 星期 |
6 位 | 秒 分 时 日 月 星期 |
使用 cron.NewParser(cron.SecondOptional)
可以兼容 5 位和 6 位表达式。
✅ 支持的 Cron 格式示例
0 8 * * *
→ 每天 8:00*/15 * * * *
→ 每15分钟一次0 0 1 * *
→ 每月1号 0:000 0 12 * * ?
→ 支持 Quartz 风格(需开启对应 parser)
列出未来 N 个匹配的时间点
go
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
// GetNextCronTimes 解析 Cron 表达式,并返回从 start 开始的接下来 count 个触发时间
// expr: Cron 表达式(支持 5 位:分 时 日 月 星期)
// start: 起始时间(通常为 time.Now())
// count: 需要返回的时间点数量
// timezone: 时区,例如 time.Local 或 time.UTC
// 返回值:匹配的时间点切片,错误信息
func GetNextCronTimes(expr string, start time.Time, count int, loc *time.Location) ([]time.Time, error) {
// 创建支持 5 位 Cron 的解析器(秒为可选)
parser := cron.NewParser(
cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
schedule, err := parser.Parse(expr)
if err != nil {
return nil, fmt.Errorf("解析 Cron 表达式失败: %w", err)
}
// 确保时间使用指定时区
start = start.In(loc)
var times []time.Time
current := start
for i := 0; i < count; i++ {
next := schedule.Next(current)
// 防止无限循环(比如表达式无匹配)
if next.IsZero() {
break
}
times = append(times, next)
current = next
}
return times, nil
}
func main() {
expr := "0 8 * * 1" // 每周一早上 8:00
start := time.Now()
count := 5
loc := time.Local // 使用本地时区,也可用 time.UTC
times, err := GetNextCronTimes(expr, start, count, loc)
if err != nil {
panic(err)
}
fmt.Printf("Cron 表达式: %s\n", expr)
fmt.Printf("起始时间: %s\n", start.Format("2006-01-02 15:04:05"))
fmt.Println("接下来的触发时间:")
for i, t := range times {
fmt.Printf("%d: %s\n", i+1, t.Format("2006-01-02 15:04:05"))
}
}
结果:
假设今天是 2025-10-14(周二),Cron 表达式为 "0 8 * * 1"(每周一 8:00)
text
Cron 表达式: 0 8 * * 1
起始时间: 2025-10-14 22:40:01
接下来的触发时间:
1: 2025-10-20 08:00:00
2: 2025-10-27 08:00:00
3: 2025-11-03 08:00:00
4: 2025-11-10 08:00:00
5: 2025-11-17 08:00:00
匹配所有的时间点
go
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
// GetCronTimesInRange 解析 Cron 表达式,并返回在 [start, end) 时间区间内所有匹配的时间点
// expr: Cron 表达式(支持 5 位:分 时 日 月 星期)
// start: 区间起始时间(包含)
// end: 区间结束时间(不包含)
// loc: 时区(如 time.Local, time.UTC 或自定义)
// 返回值:该区间内所有触发时间的切片,按时间升序排列
func GetCronTimesInRange(expr string, start, end time.Time, loc *time.Location) ([]time.Time, error) {
// 确保输入时间使用指定时区
start = start.In(loc)
end = end.In(loc)
if end.Before(start) {
return nil, fmt.Errorf("结束时间不能早于开始时间")
}
// 创建支持 5 位 Cron 的解析器(秒可选)
parser := cron.NewParser(
cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
schedule, err := parser.Parse(expr)
if err != nil {
return nil, fmt.Errorf("解析 Cron 表达式失败: %w", err)
}
var times []time.Time
current := start
for {
next := schedule.Next(current)
if next.IsZero() || !next.Before(end) { // next >= end 或为零值则停止
break
}
times = append(times, next)
current = next
}
return times, nil
}
func main() {
expr := "0 8 * * 1" // 每周一早上 8:00
startTime := time.Date(2025, 10, 14, 0, 0, 0, 0, time.Local) // 2025-10-14(周二)
endTime := time.Date(2025, 11, 15, 0, 0, 0, 0, time.Local) // 2025-11-15
times, err := GetCronTimesInRange(expr, startTime, endTime, time.Local)
if err != nil {
panic(err)
}
fmt.Printf("Cron 表达式: %s\n", expr)
fmt.Printf("时间范围: %s 到 %s\n", startTime.Format("2006-01-02"), endTime.Format("2006-01-02"))
fmt.Println("匹配的时间点:")
for i, t := range times {
fmt.Printf("%d: %s\n", i+1, t.Format("2006-01-02 15:04:05"))
}
}
结果
text
Cron 表达式: 0 8 * * 1
时间范围: 2025-10-14 到 2025-11-15
匹配的时间点:
1: 2025-10-20 08:00:00
2: 2025-10-27 08:00:00
3: 2025-11-03 08:00:00
4: 2025-11-10 08:00:00