CronTrigger ( Cron表达式格式 )笔记250930
Quartz CronTrigger 与 Cron 表达式完全详解
1. Cron 表达式核心概念
1.1 基本结构 Quartz Cron 表达式由 6 个或 7 个字段组成,字段之间用空格分隔:
秒 分 时 日 月 星期 [年]
1.2 字段详解表
| 位置 | 字段 | 允许值 | 特殊字符 | 说明与示例 |
|---|---|---|---|---|
| 1 | 秒 | 0-59 | , - * / | 一分钟内的秒数0,30 = 0秒和30秒时触发 |
| 2 | 分 | 0-59 | , - * / | 一小时内的分钟数0/15 = 从0分开始每15分钟 |
| 3 | 时 | 0-23 | , - * / | 一天内的小时数9-17 = 9点到17点之间 |
| 4 | 日 | 1-31 | , - * ? / L W C | 一月内的日期L = 最后一天15W = 最接近15日的工作日 |
| 5 | 月 | 1-12 或 JAN-DEC | , - * / | 一年内的月份JAN,MAR,MAY = 1月、3月、5月 |
| 6 | 星期 | 1-7 或 SUN-SAT | , - * ? / L C # | 一周内的星期几2#3 = 第3个星期一6L = 最后一个星期五 |
| 7 | 年 (可选) | 1970-2099 | , - * / | 年份2024-2025 = 2024和2025年 |
2. 特殊字符深度解析
2.1 基础字符详解
* - 所有值
// 每分钟的每一秒都触发
"* * * * * ?"
// 每小时的每一分钟都触发
"0 * * * * ?"
// 每天的每一小时都触发
"0 0 * * * ?"
? - 不指定值
// 正确:每天12点,不指定具体日期
"0 0 12 * * ?"
// 正确:每周一12点,不指定具体日期
"0 0 12 ? * MON"
// 错误:日和星期同时指定具体值(冲突)
"0 0 12 1 * MON" // 不要这样写!
- - 范围
// 工作时间内每小时执行
"0 0 9-17 * * ?"
// 每小时的15-30分和45-59分执行
"0 15-30,45-59 * * * ?"
// 季度初执行(1月、4月、7月、10月)
"0 0 8 1 1,4,7,10 ?"
, - 列举值
// 每天的6点、12点、18点执行
"0 0 6,12,18 * * ?"
// 周一、周三、周五的9点和17点执行
"0 0 9,17 ? * MON,WED,FRI"
// 每月1号、15号、最后一天执行
"0 0 12 1,15,L * ?"
/ - 增量
// 从0秒开始,每10秒执行
"0/10 * * * * ?"
// 从5分开始,每30分钟执行(5分、35分)
"0 5/30 * * * ?"
// 从6点开始,每3小时执行(6点、9点、12点...)
"0 0 6/3 * * ?"
2.2 高级字符详解
L - 最后
// 每月最后一天23点执行
"0 0 23 L * ?"
// 每月倒数第3天执行
"0 0 12 L-2 * ?"
// 每周六执行(7=周六,L表示最后)
"0 0 12 ? * 6L" // 错误写法!L在星期字段表示周六
"0 0 12 ? * L" // 正确:每周六执行
"0 0 12 ? * 6" // 正确:每周六执行
W - 工作日
// 最接近10号的工作日执行
"0 0 9 10W * ?"
// 如果10号是周六 → 9号(周五)执行
// 如果10号是周日 → 11号(周一)执行
// 如果10号是工作日 → 10号执行
// 最接近月底的工作日执行
"0 0 18 LW * ?"
# - 第几个
// 每月第2个周一执行
"0 0 9 ? * 2#2"
// 每月第1个和第3个周五执行
"0 0 12 ? * 6#1,6#3"
// 每月最后一个周一执行(使用L)
"0 0 12 ? * 2L"
3. 完整代码示例
3.1 综合 Cron 表达式示例
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.*;
public class ComprehensiveCronExample {
public static class CronDemoJob implements Job {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext context) {
JobDataMap data = context.getMergedJobDataMap();
String jobId = data.getString("jobId");
String description = data.getString("description");
String expression = data.getString("expression");
System.out.printf("[%s] %s: %s (表达式: %s)%n",
sdf.format(new Date()), jobId, description, expression);
}
}
public static void main(String[] args) throws Exception {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
System.out.println("=== Quartz CronTrigger 综合示例 ===");
// 1. 基础间隔任务
scheduleJob(scheduler, "secondly", "每秒执行", "* * * * * ?");
scheduleJob(scheduler, "minutely", "每分钟执行", "0 * * * * ?");
scheduleJob(scheduler, "hourly", "每小时执行", "0 0 * * * ?");
// 2. 固定时间任务
scheduleJob(scheduler, "daily-9am", "每天9点执行", "0 0 9 * * ?");
scheduleJob(scheduler, "daily-6pm", "每天18点执行", "0 0 18 * * ?");
// 3. 工作日任务
scheduleJob(scheduler, "workday-morning", "工作日9点执行", "0 0 9 ? * MON-FRI");
scheduleJob(scheduler, "workday-evening", "工作日18点执行", "0 0 18 ? * MON-FRI");
// 4. 复杂日期组合
scheduleJob(scheduler, "multi-day", "每月1号和15号执行", "0 0 12 1,15 * ?");
scheduleJob(scheduler, "month-end", "每月最后一天执行", "0 0 12 L * ?");
// 5. 增量任务
scheduleJob(scheduler, "every-15s", "每15秒执行", "0/15 * * * * ?");
scheduleJob(scheduler, "every-30min", "每30分钟执行", "0 0/30 * * * ?");
// 6. 时间段任务
scheduleJob(scheduler, "business-hours", "工作时间内每30分钟", "0 0/30 9-17 ? * MON-FRI");
// 7. 高级日期任务
scheduleJob(scheduler, "nearest-15th", "最接近15号的工作日", "0 0 9 15W * ?");
scheduleJob(scheduler, "second-monday", "每月第2个周一", "0 0 9 ? * 2#2");
scheduleJob(scheduler, "last-friday", "每月最后一个周五", "0 0 12 ? * 6L");
// 8. 带年份限制
scheduleJob(scheduler, "year-2024", "2024年每天执行", "0 0 9 * * ? 2024");
// 运行3分钟观察结果
Thread.sleep(180000);
scheduler.shutdown(true);
}
private static void scheduleJob(Scheduler scheduler, String jobId,
String description, String expression)
throws SchedulerException {
JobDetail job = JobBuilder.newJob(CronDemoJob.class)
.withIdentity(jobId, "cron-demo")
.usingJobData("jobId", jobId)
.usingJobData("description", description)
.usingJobData("expression", expression)
.build();
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobId + "-trigger", "cron-demo")
.withSchedule(CronScheduleBuilder.cronSchedule(expression))
.build();
scheduler.scheduleJob(job, trigger);
Date nextTime = trigger.getNextFireTime();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
System.out.printf("✓ %-25s → 下次执行: %s%n",
description, sdf.format(nextTime));
}
}
3.2 高级 CronTrigger 配置
public class AdvancedCronTriggerConfig {
public static void main(String[] args) throws Exception {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(CronDemoJob.class)
.withIdentity("advanced-cron-job", "demo")
.usingJobData("jobId", "advanced-config")
.usingJobData("description", "高级 CronTrigger 配置演示")
.build();
// 创建具有完整配置的 CronTrigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("advanced-cron-trigger", "demo")
.withDescription("演示时区、错过触发策略等高级配置")
// Cron 表达式:工作时间内每15分钟执行
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/15 9-17 ? * MON-FRI")
// 设置时区
.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
// 错过触发处理策略
.withMisfireHandlingInstructionFireAndProceed()
)
// 开始和结束时间
.startAt(DateBuilder.todayAt(8, 0, 0)) // 今天8点开始
.endAt(DateBuilder.dateOf(23, 59, 59)) // 今天23:59结束
// 优先级
.withPriority(8)
.build();
scheduler.scheduleJob(job, trigger);
// 输出触发器详细信息
printTriggerInfo(trigger);
Thread.sleep(60000);
scheduler.shutdown(true);
}
private static void printTriggerInfo(CronTrigger trigger) {
System.out.println("=== CronTrigger 详细信息 ===");
System.out.println("触发器Key: " + trigger.getKey());
System.out.println("描述: " + trigger.getDescription());
System.out.println("Cron表达式: " + trigger.getCronExpression());
System.out.println("表达式摘要: " + trigger.getExpressionSummary());
System.out.println("时区: " + trigger.getTimeZone().getDisplayName());
System.out.println("开始时间: " + trigger.getStartTime());
System.out.println("结束时间: " + trigger.getEndTime());
System.out.println("下次触发: " + trigger.getNextFireTime());
System.out.println("最终触发: " + trigger.getFinalFireTime());
System.out.println("优先级: " + trigger.getPriority());
}
}
4. Cron 表达式实用参考手册
4.1 常用表达式速查表
| 业务场景 | Cron 表达式 | 说明 |
|---|---|---|
| 系统监控 | 0/30 * * * * ? | 每30秒执行一次监控 |
| 数据同步 | 0 0/5 * * * ? | 每5分钟同步数据 |
| 缓存刷新 | 0 0 0/2 * * ? | 每2小时刷新缓存 |
| 日报生成 | 0 0 2 * * ? | 每天凌晨2点生成日报 |
| 周报生成 | 0 0 9 ? * MON | 每周一9点生成周报 |
| 月报生成 | 0 0 10 1 * ? | 每月1号10点生成月报 |
| 数据备份 | 0 0 3 * * ? | 每天凌晨3点备份数据 |
| 日志清理 | 0 0 4 * * ? | 每天凌晨4点清理日志 |
| 统计任务 | 0 0 1 * * ? | 每天凌晨1点执行统计 |
| 定时提醒 | 0 0 9,12,18 * * ? | 每天9、12、18点提醒 |
4.2 企业级应用模板
public class EnterpriseCronTemplates {
// 金融业务
public static final String FINANCIAL_SETTLEMENT = "0 30 17 ? * MON-FRI"; // 工作日17:30结算
public static final String RISK_MONITORING = "0 0/10 9-18 ? * MON-FRI"; // 工作时间每10分钟风险监控
// 电商业务
public static final String ORDER_SYNC = "0 0/5 * * * ?"; // 每5分钟同步订单
public static final String INVENTORY_UPDATE = "0 0 2 * * ?"; // 每天2点更新库存
public static final String PROMOTION_PUSH = "0 0 9,12,18 * * ?"; // 促销推送
// 数据业务
public static final String DATA_BACKUP = "0 0 3 * * ?"; // 每天3点数据备份
public static final String DATA_CLEANUP = "0 0 4 * * ?"; // 每天4点数据清理
public static final String REPORT_GENERATION = "0 0 6 * * ?"; // 每天6点生成报表
// 系统运维
public static final String HEALTH_CHECK = "0 0/5 * * * ?"; // 每5分钟健康检查
public static final String METRICS_COLLECTION = "0 0/1 * * * ?"; // 每分钟收集指标
public static final String LOG_ROTATION = "0 0 0 * * ?"; // 每天零点日志轮转
}
5. Cron 表达式验证与调试
5.1 表达式验证工具
import org.quartz.CronExpression;
import java.text.ParseException;
import java.util.*;
public class CronExpressionValidator {
/**
* 验证 Cron 表达式有效性
*/
public static ValidationResult validateCronExpression(String cronExpression) {
ValidationResult result = new ValidationResult();
try {
CronExpression cron = new CronExpression(cronExpression);
result.isValid = true;
result.expression = cron;
// 分析字段
String[] fields = cronExpression.split(" ");
result.fieldCount = fields.length;
result.hasYearField = fields.length == 7;
} catch (ParseException e) {
result.isValid = false;
result.errorMessage = e.getMessage();
}
return result;
}
/**
* 获取未来执行时间
*/
public static List<Date> getNextExecutionTimes(String cronExpression, int count) {
List<Date> executionTimes = new ArrayList<>();
try {
CronExpression cron = new CronExpression(cronExpression);
Date currentTime = new Date();
for (int i = 0; i < count; i++) {
currentTime = cron.getNextValidTimeAfter(currentTime);
if (currentTime == null) break;
executionTimes.add(currentTime);
}
} catch (ParseException e) {
System.err.println("无效的 Cron 表达式: " + e.getMessage());
}
return executionTimes;
}
/**
* 详细分析表达式
*/
public static void analyzeCronExpression(String cronExpression) {
System.out.println("=== Cron 表达式分析 ===");
System.out.println("表达式: " + cronExpression);
ValidationResult result = validateCronExpression(cronExpression);
if (!result.isValid) {
System.out.println("❌ 无效表达式");
System.out.println("错误: " + result.errorMessage);
return;
}
System.out.println("✅ 表达式有效");
System.out.println("字段数量: " + result.fieldCount);
System.out.println("包含年份: " + result.hasYearField);
// 显示未来执行时间
List<Date> nextTimes = getNextExecutionTimes(cronExpression, 5);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("未来5次执行时间:");
for (int i = 0; i < nextTimes.size(); i++) {
System.out.printf(" %d. %s%n", i + 1, sdf.format(nextTimes.get(i)));
}
}
static class ValidationResult {
boolean isValid;
String errorMessage;
CronExpression expression;
int fieldCount;
boolean hasYearField;
}
public static void main(String[] args) {
// 测试各种表达式
String[] testExpressions = {
"0 0 12 * * ?", // 有效
"0 0 12 * * ? 2024", // 有效(带年份)
"0 60 * * * ?", // 无效(分钟超出范围)
"0 0 12 * * MON", // 无效(日和星期冲突)
"0 0 12 32 * ?", // 无效(日期超出范围)
"0 0/15 9-17 ? * MON-FRI" // 有效(复杂表达式)
};
for (String expr : testExpressions) {
analyzeCronExpression(expr);
System.out.println();
}
}
}
5.2 表达式调试器
public class CronExpressionDebugger {
public static void debug(String cronExpression) {
System.out.println("🔍 调试 Cron 表达式: " + cronExpression);
// 基本验证
if (!CronExpression.isValidExpression(cronExpression)) {
System.out.println("❌ 表达式无效");
suggestFixes(cronExpression);
return;
}
try {
CronExpression cron = new CronExpression(cronExpression);
// 获取执行时间样本
Date baseTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss");
System.out.println("✅ 表达式有效");
System.out.println("执行时间样本:");
for (int i = 1; i <= 5; i++) {
baseTime = cron.getNextValidTimeAfter(baseTime);
if (baseTime == null) {
System.out.println(" " + i + ". 无更多执行时间");
break;
}
System.out.println(" " + i + ". " + sdf.format(baseTime));
}
} catch (ParseException e) {
System.out.println("❌ 解析错误: " + e.getMessage());
}
}
private static void suggestFixes(String cronExpression) {
System.out.println("💡 修复建议:");
String[] fields = cronExpression.split(" ");
// 检查字段数量
if (fields.length < 6) {
System.out.println(" - 字段数量不足,Cron 表达式需要6-7个字段");
}
if (fields.length > 7) {
System.out.println(" - 字段数量过多,Cron 表达式最多7个字段");
}
// 检查常见冲突
if (fields.length >= 6) {
String dayField = fields[3]; // 日字段
String weekField = fields[5]; // 星期字段
if (!"?".equals(dayField) && !"?".equals(weekField) &&
!"*".equals(dayField) && !"*".equals(weekField)) {
System.out.println(" - 日字段和星期字段冲突,将其中一个改为 '?'");
System.out.println(" 例如: " +
cronExpression.replaceFirst("(\\d+|\\*|L|W)", "?"));
}
}
}
public static void main(String[] args) {
// 调试有问题的表达式
String[] problematic = {
"0 0 12 * * MON", // 日和星期冲突
"0 60 * * * ?", // 分钟值错误
"0 0 12", // 字段不足
"0 0 12 ? * MON-FRI", // 正确的表达式
};
for (String expr : problematic) {
debug(expr);
System.out.println();
}
}
}
6. 常见问题与解决方案
6.1 常见错误及修正
| 错误表达式 | 问题描述 | 修正方案 |
|---|---|---|
0 0 12 * * MON | 日和星期字段同时指定具体值 | 0 0 12 ? * MON |
0 60 * * * ? | 分钟值60超出范围(0-59) | 0 0/59 * * * ? |
0 0 12 32 * ? | 日期值32超出范围(1-31) | 0 0 12 L * ? |
* * * * * | 缺少秒字段,字段数量不足 | * * * * * ? |
0 0 12 L * SUN | L和具体值冲突 | 0 0 12 ? * SUN |
0 0 12 ? * 8 | 星期值8超出范围(1-7) | 0 0 12 ? * 7 |
6.2 最佳实践建议
- 始终验证表达式:在生产环境使用前,使用验证工具测试表达式
- 避免日和星期冲突:确保其中一个字段使用
? - 考虑时区影响:明确指定时区,避免跨时区问题
- 测试边界情况:测试月末、闰年等特殊情况
- 添加监控告警:对关键任务添加执行监控和失败告警
通过这份完整的 CronTrigger 和 Cron 表达式指南,您可以:
- 深入理解 Cron 表达式的语法和语义
- 掌握各种特殊字符的使用场景
- 创建满足复杂业务需求的调度规则
- 有效验证和调试 Cron 表达式
- 避免常见的配置错误和陷阱
1️⃣ 参考 1
CronTrigger 与 Cron 表达式详解
什么是 CronTrigger?
CronTrigger 是基于日历的作业调度器,使用 Cron 表达式来定义调度规则。它允许在特定的日期和时间执行任务,支持复杂的调度模式。
Cron 表达式格式
基本语法格式
秒 分 时 日 月 周 年(可选)
标准格式(6位): 秒 分 时 日 月 周
完整格式(7位): 秒 分 时 日 月 周 年
各字段含义
| 字段 | 必填 | 允许值 | 允许特殊字符 | |
|---|---|---|---|---|
| 秒 | 是 | 0-59 | , - * / | |
| 分 | 是 | 0-59 | , - * / | |
| 时 | 是 | 0-23 | , - * / | |
| 日 | 是 | 1-31 | , - * ? / L W | |
| 月 | 是 | 1-12 或 JAN-DEC | , - * / | |
| 周 | 是 | 1-7 或 SUN-SAT | , - * ? / L # | |
| 年 | 否 | 1970-2099 | , - * / |
特殊字符详解
1. * - 任意值 表示匹配该字段的所有可能值
示例:
0 * * * * ?- 每分钟的0秒执行0 0 * * * ?- 每小时的0分0秒执行
2. ? - 不指定值 只能用在"日"和"周"字段,表示不关心该字段的值
示例:
0 0 12 * * ?- 每天12:00执行(不关心是周几)0 0 10 ? * MON- 每周一10:00执行(不关心是几号)
3. - - 范围 指定一个值的范围
示例:
0 0 9-17 * * ?- 每天9点到17点整点执行0 0 8-18/2 * * ?- 每天8点到18点之间每2小时执行
4. , - 列举值 指定多个值
示例:
0 0 12,18 * * ?- 每天12点和18点执行0 0 9 ? * MON,WED,FRI- 每周一、三、五9点执行
5. / - 步长 指定增量
示例:
0/5 * * * * ?- 每5秒执行一次0 0/30 * * * ?- 每30分钟执行一次
6. L - 最后 表示最后一天或最后一周
示例:
0 0 18 L * ?- 每月最后一天18:00执行0 0 10 ? * 5L- 每月最后一个周五10:00执行
7. W - 工作日 最近的工作日
示例:
0 0 12 15W * ?- 每月15号最近的工作日12:00执行
8. # - 第几个 指定月的第几个周几
示例:
0 0 10 ? * 6#3- 每月第三个周五10:00执行
常用表达式示例
基础调度
// 每5秒执行
"0/5 * * * * ?"
// 每分钟执行
"0 * * * * ?"
// 每5分钟执行
"0 0/5 * * * ?"
// 每小时执行
"0 0 * * * ?"
// 每天12:00执行
"0 0 12 * * ?"
// 每天18:30执行
"0 30 18 * * ?"
工作日调度
// 工作日9:00执行
"0 0 9 ? * MON-FRI"
// 每月15号最近的工作日
"0 0 12 15W * ?"
复杂调度
// 每周一至周五 9:00-17:00 每30分钟执行
"0 0/30 9-17 ? * MON-FRI"
// 每月1号和15号
"0 0 10 1,15 * ?"
// 季度第一个月1号
"0 0 12 1 1,4,7,10 ?"
在代码中的使用示例
Java (Spring Framework)
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Scheduled(cron = "0 0 9 * * MON-FRI")
public void dailyTask() {
// 工作日9:00执行的任务
}
@Scheduled(cron = "0 0/30 * * * ?")
public void halfHourTask() {
// 每30分钟执行的任务
}
}
Java (Quartz Scheduler)
public class QuartzExample {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}
Python
from crontab import CronTab
# <font size=5 color=black ><b>创建cron任务</b></font>
cron = CronTab(user=True)
job = cron.new(command='python /path/to/script.py')
job.setall('0 0 * * *') # <font size=5 color=black ><b>每天执行</b></font>
cron.write()
注意事项
1. 字段冲突
"日"和"周"字段不能同时指定具体值,必须有一个使用 ?
错误: 0 0 12 1 * MON
正确: 0 0 12 1 * ? 或 0 0 12 ? * MON
2. 时区考虑 Cron 表达式基于系统时区,跨时区应用需要特别注意
3. 闰秒处理 Cron 表达式不处理闰秒,59秒后直接跳到00秒
4. 性能考虑 过于频繁的调度(如每秒)可能影响系统性能
验证工具
在线验证工具
代码验证
import org.quartz.CronExpression;
public class CronValidator {
public static boolean isValid(String cronExpression) {
return CronExpression.isValidExpression(cronExpression);
}
}
最佳实践
- 明确业务需求 - 根据实际业务场景设计合理的调度频率
- 避免过度调度 - 不要设置过于频繁的任务
- 考虑系统负载 - 在系统低峰期执行重量级任务
- 日志记录 - 记录任务执行情况便于监控和调试
- 异常处理 - 确保任务异常不会影响调度器运行
掌握 Cron 表达式对于实现复杂的定时任务调度至关重要,合理使用可以大大提高系统的自动化程度和可靠性。
2️⃣ 参考 2
CronTrigger 与 Cron 表达式详解
什么是 CronTrigger
CronTrigger 是基于日历的作业调度器,使用 Cron 表达式来定义调度规则。它比简单的基于时间间隔的触发器(如 SimpleTrigger)更强大,可以指定复杂的调度计划。
Cron 表达式格式
Cron 表达式是由 6 或 7 个字段组成的字符串,字段之间用空格分隔:
秒 分 时 日 月 周 [年]
字段说明
| 位置 | 字段 | 取值范围 | 允许的特殊字符 | |
|---|---|---|---|---|
| 1 | 秒 | 0-59 | , - * / | |
| 2 | 分 | 0-59 | , - * / | |
| 3 | 时 | 0-23 | , - * / | |
| 4 | 日 | 1-31 | , - * ? / L W | |
| 5 | 月 | 1-12 或 JAN-DEC | , - * / | |
| 6 | 周 | 1-7 或 SUN-SAT | , - * ? / L # | |
| 7 | 年 | 1970-2099 或留空 | , - * / |
特殊字符详解
1. 星号 (*)
- 表示匹配该字段的所有值
- 示例:在分钟字段使用
*表示每分钟
2. 问号 (?)
- 仅用于"日"和"周"字段
- 表示不指定值,用于解决这两个字段的冲突
- 示例:
0 0 12 ? * MON表示每周一12点
3. 逗号 (,)
- 指定多个值
- 示例:
0 0,12,18 * * *表示每天0点、12点、18点
4. 连字符 (-)
- 指定范围
- 示例:
0 0 9-17 * * *表示每天9点到17点每小时执行
5. 斜杠 (/)
- 指定增量
- 格式:
开始值/增量 - 示例:
0/15 * * * * *每15秒执行0 0/5 * * * *每5分钟执行
6. L (Last)
- 用于"日"和"周"字段的特殊值
- 示例:
0 0 L * *每月最后一天0 0 * * L每周周六(如果周字段中7表示周六)
7. W (Weekday)
- 用于"日"字段,表示最近的工作日
- 示例:
15 0 20W * *每月20日最近的工作日
8. 井号 (#)
- 用于"周"字段,指定第几周的周几
- 格式:
周几#第几周 - 示例:
0 0 0 ? * 6#3每月第三周的周五
常用示例
基础示例
// 每天中午12点
0 0 12 * * ?
// 每周一上午9点
0 0 9 ? * MON
// 每月1日上午10点15分
0 15 10 1 * ?
// 每年1月1日零点
0 0 0 1 1 ?
复杂示例
// 工作日上午9点到下午5点,每30分钟执行
0 0/30 9-17 ? * MON-FRI
// 每月最后一天上午10点
0 0 10 L * ?
// 每月第三个周五上午10点
0 0 10 ? * 6#3
// 每天8点到18点,每2小时执行
0 0 8-18/2 * * ?
// 每5分钟执行,但从第30秒开始
30 0/5 * * * ?
在不同系统中的使用
1. Spring Framework
@Scheduled(cron = "0 0 9 * * MON-FRI")
public void scheduledTask() {
// 工作日上午9点执行
}
2. Quartz Scheduler
Trigger trigger = TriggerBuilder.newTrigger()
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
.build();
3. Linux Crontab
# <font size=5 color=black ><b>每天凌晨2点执行备份脚本</b></font>
0 2 * * * /home/user/backup.sh
4. 数据库作业(如 PostgreSQL)
SELECT cron.schedule('每天清理', '0 3 * * *', 'DELETE FROM logs WHERE created_at < NOW() - INTERVAL ''30 days''');
注意事项
1. 时区考虑
// 在Quartz中指定时区
CronScheduleBuilder.cronSchedule("0 0 12 * * ?")
.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
2. 字段冲突
- "日"和"周"字段不能同时指定具体值
- 必须有一个使用
?
3. 边界情况
- 2月的最后一天处理
- 闰年的特殊处理
- 夏令时调整
4. 验证表达式
try {
new CronExpression("0 0 12 * * ?");
// 表达式有效
} catch (ParseException e) {
// 表达式无效
}
最佳实践
- 明确时区:始终指定时区,避免时区混淆
- 测试验证:使用在线工具验证表达式
- 文档记录:为复杂表达式添加注释说明
- 错误处理:实现适当的错误处理机制
- 监控日志:记录任务执行情况便于调试
在线验证工具
通过掌握 Cron 表达式,你可以灵活地配置各种复杂的调度任务,满足不同的业务需求。
3️⃣ 参考 3
CronTrigger 与 Cron 表达式详解
1. CronTrigger 概述
CronTrigger 是基于日历的作业调度器,使用 Cron 表达式来定义复杂的调度规则。它比 SimpleTrigger 更灵活,可以处理诸如"每周一上午9点"或"每月最后一天午夜"等复杂的时间调度需求。
2. Cron 表达式格式
Cron 表达式由6或7个字段组成,字段之间用空格分隔:
秒 分 时 日 月 周 年(可选)
字段说明
| 位置 | 字段 | 允许值 | 允许的特殊字符 | |
|---|---|---|---|---|
| 1 | 秒 | 0-59 | , - * / | |
| 2 | 分 | 0-59 | , - * / | |
| 3 | 时 | 0-23 | , - * / | |
| 4 | 日 | 1-31 | , - * ? / L W | |
| 5 | 月 | 1-12 或 JAN-DEC | , - * / | |
| 6 | 周 | 1-7 或 SUN-SAT | , - * ? / L # | |
| 7 | 年 | 1970-2099 | , - * / |
3. 特殊字符详解
* 星号
- 表示匹配该字段的所有值
- 示例:在分字段使用
*表示每分钟
? 问号
- 只能用在日和周期字段
- 表示不指定值,用于避免日和周冲突
- 示例:
0 0 12 * * ?每天12点
- 连字符
- 表示范围
- 示例:
10-20在分字段表示10分到20分
, 逗号
- 表示列举多个值
- 示例:
MON,WED,FRI在周字段表示周一、周三、周五
/ 斜杠
- 表示递增序列
- 格式:
开始值/增量 - 示例:
0/15在秒字段表示从0秒开始,每15秒
L 字母
- 表示最后(Last)
- 在日字段:
L表示当月最后一天 - 在周字段:
L表示周六,数字L表示当月最后一个星期几 - 示例:
L在日字段表示最后一天,5L在周字段表示最后一个周四
W 字母
- 表示工作日(Weekday)
- 只能用在日字段
- 示例:
15W表示最接近当月15日的工作日
# 井号
- 表示第几个星期几
- 只能用在周字段
- 格式:
数字#数字 - 示例:
6#3表示第三个周五
4. 常用表达式示例
基础示例
// 每天中午12点触发
0 0 12 * * ?
// 每天上午10:15触发
0 15 10 * * ?
// 周一到周五上午10:15触发
0 15 10 ? * MON-FRI
// 每月15日上午10:15触发
0 15 10 15 * ?
// 每月最后一天上午10:15触发
0 15 10 L * ?
复杂示例
// 每周三中午12点
0 0 12 ? * WED
// 每月的第三个周五上午10:15
0 15 10 ? * 6#3
// 每天从下午2点到2:55,每5分钟触发
0 0/5 14 * * ?
// 每天从下午2点到2:55和下午6点到6:55,每5分钟触发
0 0/5 14,18 * * ?
// 每年三月的周三上午10:15
0 15 10 ? MAR WED
// 工作日上午9点到下午5点,每30分钟
0 0/30 9-17 ? * MON-FRI
5. Spring 中的 CronTrigger 使用
配置示例
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public CronTriggerFactoryBean cronTrigger(JobDetail jobDetail) {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setCronExpression("0 0/5 * * * ?"); // 每5分钟
return factoryBean;
}
}
Spring Boot 注解方式
@Component
public class ScheduledTasks {
// 每5分钟执行一次
@Scheduled(cron = "0 0/5 * * * ?")
public void taskEvery5Minutes() {
// 任务逻辑
}
// 工作日早上9点执行
@Scheduled(cron = "0 0 9 ? * MON-FRI")
public void weekdayMorningTask() {
// 任务逻辑
}
}
6. Quartz 中的 CronTrigger
创建 CronTrigger
// 使用 Quartz API
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
.build();
// 或者直接创建 CronTrigger
CronTrigger cronTrigger = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group1")
.withSchedule(CronScheduleBuilder
.dailyAtHourAndMinute(9, 30)) // 每天9:30
.build();
7. 注意事项
冲突解决
- 当日和周期字段都指定时可能产生冲突
- 建议其中一个字段使用
?
时区考虑
// 设置时区
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")
.inTimeZone(TimeZone.getTimeZone("America/New_York")))
.build();
表达式验证
public boolean isValidCronExpression(String expression) {
return CronExpression.isValidExpression(expression);
}
8. 在线工具推荐
CronTrigger 提供了极其灵活的任务调度能力,通过掌握 Cron 表达式,可以实现几乎任何复杂的时间调度需求。
4️⃣ 参考 4
CronTrigger 与 Cron 表达式详解
什么是 CronTrigger?
CronTrigger 是基于日历的作业调度器,使用 Cron 表达式来定义调度时间。它比 SimpleTrigger 更灵活,可以处理复杂的调度需求,如"每周一上午9点"或"每月最后一天下午5点"。
Cron 表达式格式
基本格式
秒 分 时 日 月 周 年(可选)
各字段说明
| 字段 | 必填 | 允许值 | 允许特殊字符 | |
|---|---|---|---|---|
| 秒 | 是 | 0-59 | , - * / | |
| 分 | 是 | 0-59 | , - * / | |
| 时 | 是 | 0-23 | , - * / | |
| 日 | 是 | 1-31 | , - * ? / L W | |
| 月 | 是 | 1-12 或 JAN-DEC | , - * / | |
| 周 | 是 | 1-7 或 SUN-SAT | , - * ? / L # | |
| 年 | 否 | 1970-2099 | , - * / |
特殊字符详解
1. * - 所有值
- 表示匹配该字段的所有可能值
- 示例:在分字段使用
*表示每分钟
2. ? - 不指定值
- 只能用于"日"和"周"字段
- 表示不关心该字段的值
- 示例:
0 0 12 ? * MON表示每周一中午12点
3. - - 范围
- 表示一个范围
- 示例:
10-20在秒字段表示10秒到20秒
4. , - 并列值
- 指定多个值
- 示例:
MON,WED,FRI在周字段表示周一、周三、周五
5. / - 增量
- 指定起始时间和间隔
- 格式:
开始值/增量 - 示例:在分字段使用
0/15表示从0分开始,每15分钟
6. L - 最后
- 在日字段:表示当月最后一天
- 在周字段:表示周六(7)
- 示例:
L在日字段表示月底
7. W - 工作日
- 只能用于日字段
- 表示最近的工作日
- 示例:
15W表示离当月15号最近的工作日
8. # - 第几个星期几
- 只能用于周字段
- 格式:
星期#序号 - 示例:
6#3表示每月的第三个周五
常用示例
基础示例
// 每天中午12点
0 0 12 * * ?
// 每周一上午9点
0 0 9 ? * MON
// 每月1号上午10点15分
0 15 10 1 * ?
// 每5分钟执行一次
0 0/5 * * * ?
复杂示例
// 工作日上午9点到下午5点,每小时执行
0 0 9-17 ? * MON-FRI
// 每月最后一天晚上11点
0 0 23 L * ?
// 每月的第三个周五上午10点
0 0 10 ? * 6#3
// 每天上午8点到下午4点,每2小时执行
0 0 8-16/2 * * ?
// 1月和6月的每周一和周三上午9点
0 0 9 ? JAN,JUN MON,WED
在代码中的使用
Java Quartz Scheduler
// 创建 CronTrigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?"))
.build();
// 或者使用 CronTrigger 特定属性
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(CronScheduleBuilder
.cronSchedule("0 0/2 8-17 * * ?")
.withMisfireHandlingInstructionFireAndProceed())
.forJob("myJob", "group1")
.build();
Spring Framework
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public Trigger cronTrigger(JobDetail jobDetail) {
return TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity("cronTrigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?"))
.build();
}
}
// 或者使用注解方式
@Component
public class ScheduledTasks {
@Scheduled(cron = "0 0 9-17 * * MON-FRI")
public void businessHoursTask() {
// 工作时间内每小时执行
}
}
注意事项
1. 字段冲突
- "日"和"周"字段不能同时指定具体值
- 必须有一个字段使用
?
2. 时区考虑
// 指定时区
CronScheduleBuilder.cronSchedule("0 0 12 * * ?")
.inTimeZone(TimeZone.getTimeZone("America/New_York"));
3. 错误处理
try {
new CronTrigger("invalid expression");
} catch (ParseException e) {
// 处理表达式解析错误
}
4. 性能考虑
- 避免过于频繁的调度(如每秒)
- 复杂的表达式可能影响调度器性能
验证工具
在线验证
代码验证
public boolean isValidCronExpression(String expression) {
try {
new CronExpression(expression);
return true;
} catch (ParseException e) {
return false;
}
}
Cron 表达式是强大的调度工具,通过合理使用特殊字符和组合,可以满足绝大多数复杂的调度需求。
5️⃣ 参考 5
CronTrigger 与 Cron 表达式详解
1. 什么是 CronTrigger?
CronTrigger 是基于日历的作业调度触发器,使用 Cron 表达式来定义复杂的调度规则。它比 SimpleTrigger 更灵活,可以指定诸如"每周一至周三上午9点到10点之间每5分钟执行一次"这样的复杂调度计划。
2. Cron 表达式格式
基本格式
秒 分 时 日 月 周 年(可选)
标准格式(6位或7位)
* * * * * * *
| | | | | | |
| | | | | | +-- 年(可选字段)1970-2099
| | | | | +---- 周 1-7 或 SUN-SAT
| | | | +------ 月 1-12 或 JAN-DEC
| | | +-------- 日 1-31
| | +---------- 时 0-23
| +------------ 分 0-59
+-------------- 秒 0-59
3. 各字段详解
3.1 秒(Seconds)
- 取值范围:0-59
- 特殊字符:
, - * /
3.2 分(Minutes)
- 取值范围:0-59
- 特殊字符:
, - * /
3.3 时(Hours)
- 取值范围:0-23
- 特殊字符:
, - * /
3.4 日(Day-of-Month)
- 取值范围:1-31
- 特殊字符:
, - * / ? L W
3.5 月(Month)
- 取值范围:1-12 或 JAN-DEC
- 特殊字符:
, - * /
3.6 周(Day-of-Week)
- 取值范围:1-7 或 SUN-SAT(1=周日,7=周六)
- 特殊字符:
, - * / ? L #
3.7 年(Year,可选)
- 取值范围:1970-2099
- 特殊字符:
, - * /
4. 特殊字符详解
* - 所有值 表示匹配该字段的所有可能值
"0 * * * * ?" # <font size=5 color=black ><b>每分钟的0秒执行</b></font>
? - 不指定值 只能用在日和周字段,表示不关心该字段的值
"0 0 12 * * ?" # <font size=5 color=black ><b>每天12点执行,不关心是周几</b></font>
- - 范围 指定一个范围
"0 0 9-17 * * ?" # <font size=5 color=black ><b>每天9点到17点之间每小时执行</b></font>
, - 并列值 指定多个值
"0 0 10,14,16 * * ?" # <font size=5 color=black ><b>每天10点、14点、16点执行</b></font>
/ - 增量 指定起始时间和间隔
"0 0/5 * * * ?" # <font size=5 color=black ><b>从0分开始,每5分钟执行一次</b></font>
L - 最后
- 在日字段:表示当月最后一天
- 在周字段:表示周六(7)
"0 0 0 L * ?" # <font size=5 color=black ><b>每月最后一天午夜执行</b></font>
"0 0 0 ? * L" # <font size=5 color=black ><b>每周六执行</b></font>
W - 工作日 表示最近的工作日
"0 0 0 15W * ?" # <font size=5 color=black ><b>离15号最近的工作日执行</b></font>
# - 第几个 指定月的第几个周几
"0 0 0 ? * 2#3" # <font size=5 color=black ><b>每月的第三个周一执行</b></font>
5. 常用表达式示例
简单示例
"0 0 12 * * ?" # <font size=5 color=black ><b>每天中午12点</b></font>
"0 15 10 * * ?" # <font size=5 color=black ><b>每天上午10:15</b></font>
"0 0/5 14 * * ?" # <font size=5 color=black ><b>下午2点到2:55期间,每5分钟</b></font>
"0 0-5 14 * * ?" # <font size=5 color=black ><b>下午2点到2:05期间,每分钟</b></font>
业务场景示例
# <font size=5 color=black ><b>工作时间内每半小时执行</b></font>
"0 0/30 9-17 * * ?"
# <font size=5 color=black ><b>每周一上午9点</b></font>
"0 0 9 ? * MON"
# <font size=5 color=black ><b>每月1号上午10点</b></font>
"0 0 10 1 * ?"
# <font size=5 color=black ><b>每季度第一天上午8点</b></font>
"0 0 8 1 1,4,7,10 ?"
# <font size=5 color=black ><b>每年1月1日午夜</b></font>
"0 0 0 1 1 ?"
# <font size=5 color=black ><b>周末每2小时</b></font>
"0 0 0/2 ? * SAT,SUN"
6. Spring 中的 CronTrigger 使用
6.1 Spring Task 配置
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Scheduled(cron = "0 0 9 * * MON-FRI")
public void weekdayJob() {
// 工作日9点执行的任务
}
@Scheduled(cron = "0 0 12 * * ?")
public void dailyJob() {
// 每天12点执行的任务
}
}
6.2 Quartz Scheduler 配置
@Configuration
public class QuartzConfig {
@Bean
public JobDetail sampleJobDetail() {
return JobBuilder.newJob(SampleJob.class)
.withIdentity("sampleJob")
.storeDurably()
.build();
}
@Bean
public Trigger sampleJobTrigger() {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
.cronSchedule("0 0/30 8-17 * * ?")
.withMisfireHandlingInstructionFireAndProceed();
return TriggerBuilder.newTrigger()
.forJob(sampleJobDetail())
.withIdentity("sampleTrigger")
.withSchedule(scheduleBuilder)
.build();
}
}
7. 注意事项
7.1 冲突解决 当日和周字段都指定时,会出现"或"的关系:
"0 0 12 1 * 2" # <font size=5 color=black ><b>每月1号或每周一的中午12点都执行</b></font>
7.2 时区考虑
// 指定时区
CronScheduleBuilder.cronSchedule("0 0 12 * * ?")
.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
7.3 错过触发处理策略
// 处理错过触发的情况
.withMisfireHandlingInstructionFireAndProceed() // 立即执行一次并恢复正常调度
.withMisfireHandlingInstructionDoNothing() // 什么都不做
.withMisfireHandlingInstructionIgnoreMisfires() // 所有错过的都立即执行
8. 验证和测试工具
在线验证工具
代码验证
public class CronValidator {
public static boolean isValidCronExpression(String cronExpression) {
try {
new CronExpression(cronExpression);
return true;
} catch (Exception e) {
return false;
}
}
}
CronTrigger 的 Cron 表达式提供了极其灵活和强大的调度能力,可以满足绝大多数复杂的定时任务需求。掌握其语法和特性对于开发可靠的定时任务系统至关重要。
6️⃣ 参考 6
CronTrigger 的 Cron 表达式格式详解
CronTrigger 是基于日历概念的作业调度器,通过 Cron 表达式定义复杂的触发规则。其表达式由 6 或 7 个字段(秒、分、时、日、月、周、年)组成,字段间以空格分隔,支持特殊字符实现灵活调度。
一、Cron 表达式结构 Cron 表达式有两种常见格式:
- 六字段格式(无年字段):
秒 分 时 日 月 周 - 七字段格式(含年字段):
秒 分 时 日 月 周 年
字段顺序与范围:
| 字段 | 允许值 | 特殊字符 |
|---|---|---|
| 秒(秒) | 0~59 | , - * / |
| 分(分) | 0~59 | , - * / |
| 时(时) | 0~23 | , - * / |
| 日(日) | 1~31(需考虑月份天数) | , - * ? / L W |
| 月(月) | 1~12 或 JAN~DEC | , - * / |
| 周(周) | 1~7(1=周日,7=周六)或 SUN~SAT | , - * ? / L # |
| 年(年) | 1970~2099(可选) | , - * / |
二、特殊字符详解
-
*(任意值)- 匹配字段的任意值。
- 示例:
* * * * * ?表示每分钟触发。
-
?(不指定值)- 仅用于 日 和 周 字段,解决两者冲突。
- 示例:
0 0 12 ? * MON表示每周一中午 12 点触发(日字段设为?避免与周冲突)。
-
-(范围)- 定义连续范围。
- 示例:
0 10-12 * * * ?表示每小时的 10 分、11 分、12 分触发。
-
/(增量)- 从起始时间开始,按固定间隔触发。
- 示例:
0 0/15 * * * ?表示每 15 分钟触发一次(0 分、15 分、30 分、45 分)。
-
,(枚举值)- 列出多个不连续值。
- 示例:
0 0 9,12,15 * * ?表示每天 9 点、12 点、15 点触发。
-
L(最后)- 日字段:表示月份最后一天。
- 周字段:表示周的最后一天(周六)。
- 示例:
0 0 12 L * ?表示每月最后一天中午 12 点触发。
-
W(工作日)- 仅用于 日字段,表示离指定日期最近的工作日(周一至周五)。
- 示例:
0 0 9W * * ?表示每月 9 日最近的工作日触发(若 9 日是周末,则调整为前一个工作日)。
-
LW(最后工作日)- 表示月份最后一个工作日(周五)。
- 示例:
0 0 12 LW * ?表示每月最后一个周五中午 12 点触发。
-
#(第 N 个周几)- 仅用于 周字段,表示月份第 N 个指定的周几。
- 示例:
0 0 12 ? * 2#3表示每月第三个周一中午 12 点触发。
三、常用表达式示例
| 表达式 | 含义 |
|---|---|
0 0/20 * * * ? | 每 20 秒触发一次 |
0 0 2 1 * ? | 每月 1 日凌晨 2 点触发 |
0 15 10 ? * MON-FRI | 周一至周五上午 10:15 触发 |
0 15 10 ? * 6L 2002-2006 | 2002~2006 年每月最后一个周五上午 10:15 触发 |
0 0 10,14,16 * * ? | 每天上午 10 点、下午 2 点、4 点触发 |
0 0/30 9-17 * * ? | 朝九晚五期间每半小时触发一次 |
0 0 12 ? * WED | 每周三中午 12 点触发 |
0 15 10 ? * 6#3 | 每月第三个周五上午 10:15 触发 |
四、注意事项
-
字段冲突:
- 日 和 周 字段需配合
?使用,避免冲突。例如:0 0 12 ? * MON(正确),0 0 12 * * MON(错误)。
- 日 和 周 字段需配合
-
L和W的限制:L不能与范围或列表结合使用(如5L-10L无效)。W不会跨月寻找工作日(如31W在 1 月有效,但 2 月可能无效)。
-
年字段可选:
- 若省略年字段,表达式默认每年生效。
-
时区影响:
- CronTrigger 默认使用系统时区,需通过
ZoneId或TimeZone指定其他时区。
- CronTrigger 默认使用系统时区,需通过
7️⃣ 参考 7
CronTrigger (Cron表达式格式) 详解
一、Cron表达式基础
Cron表达式是一种用于配置定时任务执行时间的字符串规则,广泛应用于Elastic-Job、Quartz、Spring定时任务、XXL-Job等调度框架中。
1. Cron表达式格式
Quartz使用6个字段的格式(秒、分钟、小时、日、月、星期):
秒 分钟 小时 日 月 星期
标准Linux Cron使用5个字段的格式(分钟、小时、日、月、星期):
分钟 小时 日 月 星期
注意:Quartz的Cron表达式比标准Linux Cron多了"秒"字段,且"日"和"星期"字段在Quartz中不能同时指定,其中一个必须用
?表示。
二、字段说明
| 字段 | 范围 | 说明 | 示例 |
|---|---|---|---|
| 秒 | 0-59 | 0-59秒 | 0 |
| 分钟 | 0-59 | 0-59分钟 | 0-59 |
| 小时 | 0-23 | 0-23小时 | 0-23 |
| 日 | 1-31 | 1-31号 | 1-31 |
| 月 | 1-12 或 JAN-DEC | 1-12月 | 1-12 |
| 星期 | 1-7 或 SUN-SAT | 1=周日, 7=周六 | MON-FRI |
| 年 | (可选) | 2023-2025 | 2023-2025 |
三、特殊符号详解
1. 星号(*) - 任意值
- 表示该字段的任意值
- 示例:
*表示所有可能值
2. 问号(?) - 不指定
- 仅用于日和星期字段,表示不指定具体值
- 在Quartz中,日和星期字段不能同时指定,必须用
?表示其中一个不指定 - 示例:
?表示不指定日或星期
3. 逗号(,) - 列表
- 用于列出多个值
- 示例:
1,3,5表示1、3、5
4. 连字符(-) - 范围
- 用于表示范围
- 示例:
9-17表示9到17
5. 斜杠(/) - 步长
- 用于表示间隔
- 示例:
0/5表示从0开始,每5个单位执行一次 - 示例:
*/5表示每5个单位执行一次
6. L - 最后
- 表示最后一天或最后星期几
- 示例:
L表示月的最后一天 - 示例:
6L表示本月最后一个星期五
7. W - 工作日
- 表示离指定日期最近的工作日
- 示例:
15W表示离15号最近的工作日
8. # - 第几个星期几
- 表示本月第几个星期几
- 示例:
2#1表示本月第一个周一 - 示例:
6#3表示本月第三个星期五
四、Quartz中Cron表达式的特殊规则
1. 日和星期字段不能同时指定
- 在Quartz中,日和星期字段只能指定一个,另一个必须用
?表示 - 合法示例:
0 0 12 15 * ?:每月15号中午12点执行0 0 12 ? * MON:每周一中午12点执行
- 非法示例:
0 0 12 15 * MON:同时指定了日和星期,会报错
2. 常见的Quartz Cron表达式示例
| 表达式 | 含义 |
|---|---|
0 * * * * ? | 每分钟执行一次 |
0 0/5 * * * ? | 每5分钟执行一次 |
0 0 0 * * ? | 每天0点执行 |
0 0 12 * * ? | 每天中午12点执行 |
0 0 9-17 * * ? | 每天9点到17点,每小时执行一次 |
0 0 9 ? * MON-FRI | 周一到周五上午9点执行 |
0 0 0 1 * ? | 每月1号0点执行 |
0 0 23 L * ? | 每月最后一天23点执行 |
0 0 10 ? * 6L | 每月最后一个星期五10点执行 |
0 0 10 ? * 2#1 | 每月第一个星期二10点执行 |
五、Cron表达式使用技巧
1. 周期性任务
- 使用
/表达式表示周期,如0/10 * * * * ?表示每10秒执行一次
2. 复杂时间场景
- 结合
L、W、#处理复杂时间场景 - 示例:
0 0 10 ? * 6L表示每月最后一个星期五10点执行
3. 避免常见错误
- 确保日和星期字段不同时指定
- 注意Quartz和标准Linux Cron的格式差异
- 避免使用
0作为秒字段,因为0表示第0秒,实际是"整秒"执行
六、在线工具
推荐使用以下在线工具验证Cron表达式:
七、示例:当前时间2025-09-30 07:25:30的Cron表达式
-
每5分钟执行一次:
0 0/5 * * * ?- 从07:25开始,下一次执行时间为07:30:00
-
每天上午9点执行:
0 0 9 * * ?- 今天执行时间为09:00:00
-
每周一到周五上午9点执行:
0 0 9 ? * MON-FRI- 今天是周二,执行时间为09:00:00
-
每月1号上午10点执行:
0 0 10 1 * ?- 下次执行时间为2025-10-01 10:00:00
八、注意事项
-
Cron表达式的精度:
- 标准Cron表达式最小单位为分钟
- Quartz支持秒级,但不建议用于高频任务(如每2秒执行一次)
-
时区问题:
- Cron表达式默认使用系统时区
- 在分布式系统中,需注意时区一致性
-
表达式验证:
- 在生产环境中使用前,务必使用在线工具验证表达式
-
表达式长度:
- 7个字段的表达式(包含年)可以指定年份范围,但通常不需要
九、Cron表达式与Spring Task对比
| 特性 | Cron表达式 | Spring @Scheduled |
|---|---|---|
| 格式 | 6字段(Quartz)或5字段(Linux) | 5字段(分钟、小时、日、月、星期) |
| 优点 | 灵活、强大 | 简单、与Spring集成 |
| 缺点 | 需要学习 | 功能有限 |
| 适用场景 | 复杂调度 | 简单调度 |
总结
Cron表达式是Quartz框架中用于定义定时任务执行时间的核心机制。理解其字段含义和特殊符号的用法,是正确配置定时任务的关键。在Quartz中,需特别注意日和星期字段不能同时指定的限制,以及?的特殊用法。通过合理使用Cron表达式,可以轻松实现各种复杂的定时任务调度需求。
希望这份详解能帮助您更好地理解和使用CronTrigger和Cron表达式!
8️⃣ 参考 8
Cron表达式是CronTrigger的核心,用于定义任务的执行时间规则。它由7个字段组成(其中最后一个字段可选),格式严格且具有丰富的语法规则。下面详细解析其格式、字段含义、特殊字符及使用示例:
一、基本格式
Cron表达式的标准格式为:
[秒] [分] [时] [日] [月] [周] [年(可选)]
- 字段顺序固定,不可颠倒
- 各字段用空格分隔
- 年字段可省略(大多数场景不需要指定)
二、各字段详解 每个字段都有明确的取值范围和含义,如下表:
| 字段 | 取值范围 | 允许的特殊字符 | 含义说明 |
|---|---|---|---|
| 秒 | 0-59 | * , - / | 一分钟内的第n秒 |
| 分 | 0-59 | * , - / | 一小时内的第n分 |
| 时 | 0-23 | * , - / | 一天内的第n时(24小时制) |
| 日 | 1-31 | * , - / L W ? | 一个月内的第n天 |
| 月 | 1-12 或 JAN-DEC | * , - / | 一年内的第n月(1=1月) |
| 周 | 1-7 或 SUN-SAT | * , - / L # ? | 一周内的第n天(1=周日,7=周六) |
| 年 | 1970-2099 | * , - / | 可选字段,不指定则表示所有年 |
三、特殊字符详解 特殊字符用于灵活定义时间规则,是Cron表达式的核心能力:
-
*(星号)
表示“所有可能的值”,即该字段的每一个值都匹配。
示例:*在“分”字段表示“每分钟”。 -
?(问号)
仅用于“日”和“周”字段,表示“不指定值”,用于避免两个字段的冲突(因为“日”和“周”都表示日期,不能同时精确指定)。
示例:若指定“日=5”,则“周”必须为?;若指定“周=2”(周一),则“日”必须为?。 -
-(减号)
表示范围,定义一个连续的区间。
示例:10-15在“分”字段表示“10分到15分之间的每一分钟”。 -
/(斜杠)
表示“递增”,格式为[起始值]/[步长],即从起始值开始,每隔步长执行一次。
示例:0/30在“秒”字段表示“从0秒开始,每30秒一次”;5/10在“分”字段表示“5分、15分、25分...执行”。 -
,(逗号)
表示列表,指定多个离散的值。
示例:MON,WED,FRI在“周”字段表示“周一、周三、周五”。 -
L(Last,最后)- 在“日”字段:表示当月最后一天(如1月31日、2月28日/29日)。
- 在“周”字段:表示“最后一个星期几”,如
6L表示当月最后一个周五(6=周五)。
示例:L在“日”字段表示“当月最后一天”;FRIL(等价于6L)表示“当月最后一个周五”。
-
W(Weekday,工作日)
仅用于“日”字段,表示“最近的工作日(周一至周五)”。
示例:15W表示“15日最近的工作日”,若15日是周六,则匹配14日(周五);若15日是周日,则匹配16日(周一)。 -
#(序号)
仅用于“周”字段,格式为[周几]#[序号],表示“当月第n个星期几”。
示例:2#3表示“当月第3个周一”(2=周一);6#1表示“当月第1个周五”(6=周五)。
四、常用示例 以下是实际开发中常见的Cron表达式及含义:
| Cron表达式 | 含义说明 |
|---|---|
0 0 12 * * ? | 每天中午12点执行 |
0 0 8,18 * * ? | 每天早上8点和晚上6点执行 |
0 0/30 9-17 * * ? | 每天9点到17点之间,每30分钟执行一次 |
0 0 1 * * MON-FRI | 工作日(周一至周五)凌晨1点执行 |
0 0 1 1 * ? | 每月1日凌晨1点执行 |
0 0 12 ? * 6L | 当月最后一个周五中午12点执行 |
0 0 12 15W * ? | 每月15日最近的工作日中午12点执行 |
0 0 12 ? * 2#3 | 当月第3个周一中午12点执行 |
0/10 * * * * ? | 每10秒执行一次(常用于测试) |
五、注意事项
- “日”和“周”的冲突:两者不能同时指定具体值(需用
?避免冲突),例如0 0 0 5 * 2是无效的,应改为0 0 0 5 * ?(指定5日,不限制周)或0 0 0 ? * 2(指定周一,不限制日)。 - 周字段的编号:Quartz中“周”字段的编号为1=周日,2=周一,...,7=周六(与部分系统不同,需特别注意)。
- 避免过度复杂:过于复杂的表达式(如
0 1-59/2 1,3,5 * 1-6/2 ?)可读性差,建议拆分任务或通过代码逻辑辅助。 - 测试工具:推荐使用在线Cron表达式生成器(如CronMaker)验证表达式的正确性。
掌握Cron表达式是使用CronTrigger的关键,通过灵活组合字段和特殊字符,可以满足几乎所有定时任务的调度需求。
9️⃣ 参考 9
Cron 表达式是 Quartz 框架中 CronTrigger 的核心,它像一个高度可定制的日历时钟,用字符串指定任务在何时、以何种频率执行。下面这张表帮你快速看懂它的结构。
| 字段顺序 | 字段名 | 允许值范围 | 允许的特殊字符 | 说明与技巧 |
|---|---|---|---|---|
| 1 | 秒(Seconds) | 0-59 | , - * / | - |
| 2 | 分(Minutes) | 0-59 | , - * / | - |
| 3 | 时(Hours) | 0-23 | , - * / | - |
| 4 | 日(Day-of-Month) | 1-31 | , - * ? / L W C | 注意月份的实际天数 |
| 5 | 月(Month) | 1-12 或 JAN-DEC | , - * / | 月份英文缩写不区分大小写 |
| 6 | 周(Day-of-Week) | 1-7 (1=周日) 或 SUN-SAT | , - * ? / L C # | 注意: Quartz 中 1=周日 |
| 7 | 年(Year) | 1970-2099 | , - * / | 可选字段,可留空 |
🧠 特殊字符详解
掌握了结构,我们来破解那些让表达式功能强大的“特殊字符”:
| 特殊字符 | 名称 | 含义与示例 |
|---|---|---|
* | 星号 | 所有值。例如,在分字段表示每分钟。 |
? | 问号 | 不指定值,用于避免日和周字段的冲突。 例如 0 0 0 25 * ? 表示每月25日,不关心周几。 |
- | 横杠 | 范围。例如 10-20 在秒字段表示第10秒到第20秒。 |
, | 逗号 | 并列值。例如 MON,WED,FRI 在周字段表示周一、周三和周五。 |
/ | 斜杠 | 间隔触发。例如 0/15 在秒字段表示从第0秒开始,每15秒。 5/20 在分字段表示从第5分开始,每20分钟(5,25,45分)。 |
L | Last | 最后。 在日字段单独使用L表示当月最后一天。 在周字段,6L 表示当月最后一个周五。 |
W | Weekday | 最近工作日(周一至周五)。 例如在日字段设置 15W,如果15日是周六,则在14日(周五)触发。 注意:W前不能是范围或列表。 |
# | 井号 | 第几个星期几。 例如 6#3 在周字段表示每月第三个周五(6=周五)。 如果该日期不存在(如第五个周五),则不触发。 |
📋 常用表达式示例
光说不练假把式,来看些常见场景的写法:
| 表达式 | 含义 |
|---|---|
0 0/5 * * * ? | 每5分钟执行一次(从0分开始) |
0 0 10,14,16 * * ? | 每天上午10点、下午2点、下午4点各执行一次 |
0 0 12 ? * WED | 每个星期三中午12点执行 |
0 0/30 9-17 * * ? | 朝九晚五(9:00-17:00)工作时间内每半小时执行一次 |
0 15 10 ? * MON-FRI | 周一至周五的上午10:15执行 |
0 0 0 1 * ? | 每月1日凌晨执行 |
0 15 10 L * ? | 每月最后一日上午10:15执行 |
0 15 10 ? * 6L | 每月最后一个星期五上午10:15执行 |
0 15 10 ? * 6#3 | 每月第三个星期五上午10:15执行 |
🚨 重要注意事项
- 字段互斥性:
日(Day-of-Month)和周(Day-of-Week)字段在Cron表达式中是互斥的。 为避免冲突,当其中一个字段设置了具体值(包括*)时,另一个字段必须使用?。 例如,想每月10号触发,不管周几,应写为0 0 0 10 * ?,而不是0 0 0 10 * *。 - Spring 的差异:Spring框架内置的定时任务(如
@Scheduled注解)所使用的Cron表达式通常只支持6个字段(秒 分 时 日 月 周),不支持可选的年字段。 直接使用7字段(带年)的表达式在Spring中可能会报错。 L和W的使用限制:在使用L和W字符时,不要为其指定列表或范围(如1-5L,10,15W),否则可能导致意想不到的结果或解析错误。- 测试与验证:复杂的Cron表达式编写后,最好使用在线工具(如中提到的BeJSON)或Quartz/CronSequenceGenerator进行验证,确保其触发时间符合预期。
💎 总结
理解Cron表达式的关键在于掌握7个字段的顺序与含义、灵活运用特殊字符,并特别注意日和周字段的互斥性。从简单的每分钟执行到复杂的“每月第三个周五”这样的需求,它都能优雅地满足。多写多练,你就能熟练驾驭这个强大的调度工具。
🔟 参考 10
一、什么是Cron表达式?
Cron表达式是一个由 6或7个字段 组成的字符串(某些实现,如Quartz,支持第7个“年”字段),每个字段代表一个时间单位,用空格分隔。它用来配置触发任务的具体时间点或周期。
一个标准的Cron表达式格式如下:
秒 分 时 日 月 周 年(可选)
字段顺序与取值范围:
| 位置 | 字段 | 允许值 | 允许的特殊字符 |
|---|---|---|---|
| 1 | 秒(Seconds) | 0-59 | , - * / |
| 2 | 分(Minutes) | 0-59 | , - * / |
| 3 | 时(Hours) | 0-23 | , - * / |
| 4 | 日(Day-of-Month) | 1-31 | , - * / ? L W C |
| 5 | 月(Month) | 1-12 或 JAN-DEC | , - * / |
| 6 | 周(Day-of-Week) | 1-7 或 SUN-SAT | , - * / ? L C # |
| 7 | 年(Year - 可选) | 1970-2099 | , - * / |
注意:
- 周 的取值:
1代表星期天(SUN),2代表星期一(MON),以此类推,7代表星期六(SAT)。 - “日”和“周”字段互斥:为避免冲突,通常会在其中一个字段设置具体值,另一个字段使用
?(不指定)。
二、特殊字符详解
这些字符是Cron表达式的灵魂,提供了强大的灵活性。
| 字符 | 名称 | 含义与示例 |
|---|---|---|
* | 星号 | 所有值。例如,在“分”字段使用 * 表示“每分钟”。 |
? | 问号 | 不指定值。只能用在“日”和“周”字段,表示“不管它是星期几”或“不管它是几号”。例如,想每月1号触发,不管周几,就用 0 0 0 1 * ?。 |
- | 横杠 | 区间。指定一个范围。例如,在“时”字段使用 10-12 表示“10点,11点,12点”。 |
, | 逗号 | 并列。指定多个值。例如,在“周”字段使用 MON,WED,FRI 表示“周一、周三、周五”。 |
/ | 斜杠 | 步长。指定起始时间和间隔。例如: - 在“秒”字段用 0/15 表示“从第0秒开始,每15秒一次”(0,15,30,45)。- 在“分”字段用 5/20 表示“从第5分钟开始,每20分钟一次”(5,25,45)。 |
L | Last | 最后。只能用在“日”和“周”字段。 - 在“日”字段: L 表示月份的最后一天(31号、30号、28或29号)。- 在“周”字段: L 表示星期六(7或SAT)。数字+L 的组合如 5L 表示“最后一个星期四”。 |
W | Weekday | 最近工作日。只能用在“日”字段。例如 15W 表示“离本月15号最近的那个工作日”(周一至周五)。如果15号是周六,则在14号(周五)触发;如果是周日,则在16号(周一)触发。 |
# | 井号 | 第几个星期几。只能用在“周”字段。格式为 n#m,表示“第m个月的星期n”。例如 6#3 表示“每月的第三个星期五”。 |
三、常用表达式示例
| 表达式 | 含义 |
|---|---|
0 0 12 * * ? | 每天中午12点 触发一次 |
0 15 10 ? * * | 每天上午10:15 触发一次 |
0 15 10 * * ? | 同上,每天上午10:15触发 |
0 15 10 * * ? 2023 | 2023年 每天上午10:15触发 |
0 0/5 14 * * ? | 每天下午2点 开始,每5分钟 触发一次(14:00, 14:05, ..., 14:55) |
0 0/5 14,18 * * ? | 每天下午2点 和 下午6点,每5分钟触发一次 |
0 0-5 14 * * ? | 每天下午2:00 到 2:05,每分钟触发一次 |
0 10,44 14 ? 3 WED | 每年三月的每个星期三 的下午 2:10 和 2:44 触发 |
0 15 10 ? * MON-FRI | 每周一至周五 的上午 10:15 触发 |
0 15 10 15 * ? | 每月15号 的上午 10:15 触发 |
0 15 10 L * ? | 每月最后一天 的上午 10:15 触发 |
0 15 10 ? * 6L | 每月最后一个星期五 的上午 10:15 触发 |
0 15 10 ? * 6#3 | 每月第三个星期五 的上午 10:15 触发 |
四、一个完整的CronTrigger定义(以Quartz为例)
在代码中,你通常会这样定义一个CronTrigger:
// 1. 创建一个JobDetail(要执行的任务)
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 2. 创建一个CronTrigger(触发器)
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(CronScheduleBuilder
// 这里是Cron表达式
.cronSchedule("0 0/30 9-17 ? * MON-FRI")
)
.build();
// 3. 将任务和触发器交给调度器
scheduler.scheduleJob(job, trigger);
解释上面的表达式 0 0/30 9-17 ? * MON-FRI:
- 秒:
0(每分钟的第0秒) - 分:
0/30(从0分开始,每30分钟一次) - 时:
9-17(上午9点到下午5点) - 日:
?(不指定) - 月:
*(每个月) - 周:
MON-FRI(周一到周五)
含义:在每周一到周五的工作日,从早上9点到下午5点,每半小时执行一次任务(在9:00, 9:30, 10:00, ..., 16:30, 17:00触发)。
五、注意事项与最佳实践
- 时区问题:Cron表达式默认使用调度器所在服务器的系统时区。如果你的应用是全球性的,务必显式设置触发器的时区(
inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")))。 - “日”和“周”的冲突:牢记这两个字段的互斥性,善用
?来避免意料之外的调度行为。 - 在线工具:强烈推荐使用在线Cron表达式生成器和验证器来辅助编写和调试,例如 Cron Expression Generator & Explainer - Quartz。
- 测试:在将表达式部署到生产环境前,充分测试其触发时间是否符合预期。
希望这份详细的解析能帮助你彻底掌握Cron表达式!
🤔 参考 11
CronTrigger的Cron表达式格式详细解释
CronTrigger是Quartz调度框架的核心组件,用于在Java应用中执行定时任务。它的Cron表达式是一个强大的时间定义工具,支持6到7个字段的格式(标准Cron只有5个字段),每个字段表示时间元素的一个维度。Cron表达式对特殊字符的大小写不敏感,这使得书写更灵活。接下来,我将逐步解释其格式结构、字段含义、取值范围和特殊字符用法。解释基于Quartz框架的官方定义。
1. 基本格式结构 CronTrigger的表达式由6个必需字段和1个可选字段组成,字段之间用空格分隔。字段顺序固定如下:
- 秒(Seconds):0-59
- 分(Minutes):0-59
- 时(Hours):0-23
- 日(Day of Month):1-31
- 月(Month):1-12或月份缩写(如JAN、DEC)
- 周(Day of Week):1-7或星期缩写(如SUN、SAT),其中1代表星期日(SUN)
- 年(Year):可选,1970-2099(如果省略,默认为所有年份)
完整格式示例:
例如,0 0 5 * * ? 表示每天凌晨5点触发,省略了年字段。
2. 字段详解 下表总结了每个字段的取值规则和常见用法:
| 字段名称 | 取值范围 | 特殊字符支持 | 备注说明 | 示例值及含义(示例:0 0 12 ? * MON-FRI) |
|---|---|---|---|---|
| 秒 | 0-59 | - * / , | 表示分钟内的秒数 | 0:每分钟的0秒触发 |
| 分 | 0-59 | - * / , | 表示小时内的分钟数 | 0:每小时的0分触发 |
| 时 | 0-23 | - * / , | 表示一天中的小时(24小时制) | 12:中午12点触发 |
| 日(月) | 1-31 | - * ? / , L W C | 注意:?用于避免与周字段冲突 | ?:不指定具体日,常用于结合周字段 |
| 月 | 1-12或JAN-DEC缩写 | - * / , | 月份缩写大小写不敏感,如jan或JAN均可 | *:每月都触发 |
| 周 | 1-7或SUN-SAT缩写 | - * ? / , L C # | 1=SUN,7=SAT;?用于避免与日字段冲突 | MON-FRI:周一至周五触发 |
| 年(可选) | 1970-2099 | - * / , | 如果省略,任务会在所有年份执行 | 2025:仅在2025年触发 |
关键点:
- 字段冲突处理:日和周字段不能同时指定具体值,否则会冲突(例如,不能同时指定日期15日和星期五)。因此,通常使用
?占位符在其中一个字段表示“不关心”。 - 字段顺序:必须严格按照上述顺序书写,否则表达式无效。
- 与传统crontab的区别:标准Linux crontab只有5字段(分 时 日 月 周),而Quartz CronTrigger额外增加了秒字段和可选年字段,提供了更精细的控制。
3. 特殊字符解释 Cron表达式支持多种特殊字符实现复杂调度逻辑:
*:匹配所有值。例如,*在分字段表示每分钟触发。?:仅用于日和周字段,表示“不指定值”。常用于解决冲突,例如在日字段用?,周字段用MON表示“每周一触发”。-:定义范围。例如,MON-FRI在周字段表示周一至周五。,:列出多个值。例如,1,15在日字段表示每月1日和15日。/:定义步长。例如,0/15在秒字段表示从0秒开始,每15秒触发一次(即0,15,30,45秒)。L:表示“最后”,只用于日和周字段。例如:- 在日字段:
L表示月末最后一天(如L)。 - 在周字段:
SATL表示最后一个星期六。
- 在日字段:
W:工作日(只用于日字段),表示最近的工作日(周一至周五)。例如,15W表示每月15日,如果15日是周末,则触发最近的工作日(14或16日)。C:日历日(只用于日和周字段),表示基于日历的计算。例如,C在周字段表示“日历中的第一个星期日”。#:指定第几个星期几(只用于周字段)。例如,MON#2表示每月的第二个星期一。
特殊字符对大小写不敏感(如mon与MON等效)。
4. 常见示例 以下是一些实用的表达式示例,帮助您理解格式:
0 0 12 * * ?:每天中午12点触发(省略年和周冲突处理)。0 0/5 8-18 ? * MON-FRI:工作日(周一至周五)的8点到18点,每5分钟触发一次。0 0 0 L * ?:每月最后一天的午夜触发。0 0 10 ? * 6#3:每月的第三个星期五上午10点触发(6=FRI)。0 0 0 1 1 ? 2025:仅在2025年1月1日凌晨触发。
5. 验证工具 书写Cron表达式时,容易出错。建议使用在线生成器验证:
- Cron表达式在线生成器
- Cron表达式校验工具
这些工具可帮助您交互式创建和测试表达式。
CronTrigger的表达式因其灵活性广泛应用于定时任务调度,如备份系统、报表生成和事件提醒。
🤔 参考 12
Cron表达式是用于配置CronTrigger实例的字符串,它基于日历概念来定义任务调度的时间表,功能非常强大。下面为您详细解析其格式和用法。
Cron表达式详解
1. 基本结构与字段含义
Cron表达式是一个字符串,以5或6个空格隔开,分为6或7个域(字段),每个域代表不同的时间单位。
基本格式:秒 分 时 日 月 周 年(其中"年"为可选字段)
下表详细说明了每个字段的取值范围和含义:
| 字段 | 必选 | 允许值 | 允许特殊字符 | 说明 |
|---|---|---|---|---|
| 秒(Seconds) | 是 | 0-59 | , - * / | 分钟内的秒数 |
| 分(Minutes) | 是 | 0-59 | , - * / | 小时内的分钟数 |
| 时(Hours) | 是 | 0-23 | , - * / | 一天中的小时数 |
| 日(Day-of-Month) | 是 | 1-31 | , - * ? / L W C | 月份中的日期 |
| 月(Month) | 是 | 1-12或JAN-DEC | , - * / | 一年中的月份 |
| 周(Day-of-Week) | 是 | 1-7或SUN-SAT | , - * ? / L C # | 一周中的星期几(1=星期日) |
| 年(Year) | 否 | 1970-2099 | , - * / | 年份(可选字段) |
2. 特殊字符详解
Cron表达式使用特殊字符来定义复杂的时间规则:
- 星号(
*):表示匹配该域的所有值。例如,在分钟字段使用*表示每分钟都会触发。 - 问号(
?):只能用在日和周字段,表示"无特定值",用于解决日和周字段的冲突。当其中一个字段指定了值,另一个通常设为?。 - 减号(
-):表示一个范围。例如10-12在小时字段表示10点、11点、12点。 - 逗号(
,):列举多个值。例如在分钟字段使用5,20表示在5分和20分触发。 - 斜杠(
/):指定起始时间和间隔时间。格式为x/y,x表示开始值,y表示间隔。例如在秒字段使用0/15表示从0秒开始,每15秒触发。 - L:表示"最后",用于日和周字段。在日字段中表示当月最后一天;在周字段中表示周六(7)。前面加数字如
6L表示最后一个星期五。 - W:表示最近工作日(周一至周五),只能用于日字段。例如
15W表示离当月15日最近的工作日。 - #:指定每月第几个周几,只能用于周字段。例如
6#3表示每月第三个星期五。
3. 常用表达式示例
下面是一些实用的Cron表达式示例及其含义:
| 表达式 | 含义 |
|---|---|
0 */5 * * * ? | 每5分钟执行一次 |
0 0 12 * * ? | 每天中午12点执行 |
0 15 10 ? * MON-FRI | 周一至周五上午10:15执行 |
0 0 10,14,16 * * ? | 每天上午10点、下午2点、4点各执行一次 |
0 0/30 9-17 * * ? | 朝九晚五工作时间内每半小时执行一次 |
0 0 23 L * ? | 每月最后一天晚上11点执行 |
0 15 10 ? * 6L | 每月最后一个星期五上午10:15执行 |
0 15 10 ? * 6#3 | 每月第三个星期五上午10:15执行 |
0 10,44 14 ? 3 WED | 每年三月的每个星期三下午2:10和2:44执行 |
*/5 * * * * ? | 每5秒执行一次 |
4. 注意事项与最佳实践
-
日与周字段的冲突:日字段和周字段可能会相互影响,通常解决方案是将其中一个字段设为
?。例如,想每月10号触发,不管周几:0 0 0 10 * ?。 -
Spring框架的支持:Spring 3.0以后只支持6个字段的Cron表达式(不含年字段),在使用时需要注意。
-
L字符的限制:使用L参数时,不要指定列表或范围,否则可能导致意外结果。
-
W字符的特性:W字符寻找最近工作日不会跨月。例如,
1W如果1号是周六,则会在3号(周一)触发,不会回溯到上个月。 -
边界情况处理:设置午夜和凌晨1点之间触发时要特别小心,确保表达式按预期工作。
5. 在线工具推荐
为了方便创建和调试Cron表达式,您可以利用以下在线工具:
这些工具提供可视化界面,可以帮助您双向解析和生成Cron表达式。
Cron表达式提供了极其灵活的任务调度能力,通过掌握这些规则和技巧,您可以精确控制任务执行的时间计划。