
本文详解如何在 spring 中编写合规的 cron 表达式,实现工作日(周一至周五)9:00–17:00 每30分钟触发一次定时任务,且严格避免 17:30 的误触发。
本文详解如何在 spring 中编写合规的 cron 表达式,实现工作日(周一至周五)9:00–17:00 每30分钟触发一次定时任务,且严格避免 17:30 的误触发。
在 Spring 的 @Scheduled 注解中,Cron 表达式遵循 6 或 7 位扩展格式(秒、分、时、日、月、周、年),其中最常用的是 6 位格式:<秒> <分> <时> <日> <月> <周>。需特别注意:Spring 默认使用的是 Quartz 风格 Cron(非 Unix/Linux crontab),其「周字段」支持 MON-FRI、1-5 等写法,且 小时范围是 0–23(24 小时制),而关键限制在于——0/30 这类步长表达式会在指定范围内“从起点开始,按步长累加”,不自动截断到区间终点。
例如原始表达式:
@Scheduled(cron = "0 0/30 9-17 * * MON-FRI")
看似意图是“9点到17点之间每30分钟”,但实际解析逻辑为:
✅ 小时取值为 9,10,11,12,13,14,15,16,17;
✅ 对每个匹配的小时(如 17),再匹配分钟 0/30 → 即 0,30;
❌ 因此 17:30 会被合法触发——这正是问题根源。
✅ 正确解法是显式拆分小时段,将 17 单独列出,并仅允许其对应 0 分(即 17:00),而 9–16 小时则保留 0/30(覆盖 :00 和 :30):
@Scheduled(cron = "0 0/30 9-16,17 * * MON-FRI")
该表达式等价于:
- 9-16 小时内:每小时的 0 分和 30 分(即 9:00、9:30、…、16:00、16:30);
- 17 小时内:仅 0 分(即 17:00);
- 周一至周五执行,完全满足需求。
⚠️ 注意事项:
- Spring 5.3+ 及主流 Spring Boot 版本(2.6+ / 3.x)均完整支持 9-16,17 这种逗号分隔的小时写法,无需额外配置;
- 切勿写作 0 0,30 9-17 * * MON-FRI —— 这会遗漏 10:00、11:30 等中间时间点,变成“每天只运行 2×9=18 次”,而非预期的“每30分钟一次”(共 17 次/天:9:00→17:00 共 17 个半点);
- 若需更高可读性,也可用 0 0,30 9,10,11,12,13,14,15,16,17 * * MON-FRI,但冗长且易出错,不推荐;
- 建议在单元测试中结合 TaskScheduler 或使用 spring-boot-starter-quartz 的测试工具验证触发时间点。
总结:Spring Cron 的步长语法(x/y)不具备智能边界裁剪能力,必须通过显式枚举或区间组合来精确控制终止时刻。牢记“9-16,17 是安全模式,9-17 + 0/30 是陷阱模式”,即可稳健实现工作日定时调度。

















