5 段式 cron 只有 5 个字段写错基本错在三处*/n从哪个值起步、日和周是并集还是交集、2 月 29 日不是每年都有。我把这三处做成了一张 30 天日历然后一个个场景点过去。同样是「工作日跑一次」0 3 * * 1-5未来 30 天跑 20 次0 9-18 * * 1-5就要跑 200 次。0 0 1 * *30 天只跑 1 次0 0 29 2 *从 2027 年 2 月 27 日往后数下一次要等 366 天之后每次间隔 1461 天。这些数字不是背下来的是我在页面上换基准时间一格一格点出来的。在线案例与源码https://atomgit.com/deli007/demo_park/tree/main/codearts-cron-expression-lab成品只有一个 index.html双击就能用不装任何依赖页面自己会跑 12 条自检。想自己看一遍git clone仓库后双击 index.html或者用python -m http.server 8000起个静态服务。一、为什么值得做这题人人会写但很少有人把 30 天跑一遍搜「cron 表达式」出来的大多是一张字段范围表加一个在线计算器。范围表告诉你分钟是 0–59但不会告诉你*/15展开成 0,15,30,45 还是 15,30,45,60。也不会告诉你0 0 1 * 1到底是「每月 1 号并且是周一」还是「每月 1 号或者周一」。我把它做成了一个能点、能换基准时间、还会自己验算的页面。二、准备环境打开码道 Web把需求写成一段话浏览器打开码道 Web 版https://devcloud.cn-north-4.huaweicloud.com/chat?sourcedmzntgwsfsourceaddmzntgwwbwz 登录后在对话框里写需求就能拿到一个能跑的单文件应用。码道有三种使用方式WebUI浏览器对话、TUI终端命令行和桌面 IDEIDE 插件。本文用 WebUI 版演示。需求我写了 7 条事后看最值钱的是第 4 条和第 6 条。第 4 条要求画 30 天日历并统计执行次数第 6 条要求页面自带自检脚本并把结果显示出来。有了这两条页面就不再是一个「下次执行时间」查询框而是一台能自己验算的日历。三、需求原文可以照着复制做一个单文件网页应用 index.html原生 HTMLCSSJS无外链、无 CDN、无构建、可离线打开主题是 cron 表达式可视化实验室。 1. 顶部一个输入框输入 5 段式 cron 表达式分 时 日 月 周旁边给出 8 个常用预设按钮0 3 * * *、0 3 * * 1-5、*/15 * * * *、0 9-18 * * 1-5、0 0 1 * *、30 6 * * 0、0 */2 * * *、0 0 29 2 *。 2. 逐字段解析把输入按 5 段切开每段单独一列显示字段名、取值范围的合法区间、这段展开后的具体取值集合例如 */15 展开成 0,15,30,451-5 展开成 1~50 就是 0非法的一段标红并说明错在哪。 3. 下一次执行给出从基准时间起接下来 10 次的执行时间精确到分钟显示年月日 星期 时分第一行还要显示「距现在多久」精确到分钟。 4. 未来 30 天日历视图按天铺一张月历命中的日期高亮每格标出当天会跑几次旁边统计面板显示「未来 30 天共执行 N 次」「平均每天 M 次」「最密集的一天是哪天、跑几次」「平均间隔」。 5. 基准时间可调提供一个 datetime-local 输入改它之后所有结果按新基准重算这样能把 0 0 29 2 * 这种闰年表达式验出来。再加一个「星期字段 0 和 7 都表示周日」的开关说明。 6. 页面上必须有自检脚本并把每条断言结果显示出来例如 0 3 * * 1-5 未来 30 天执行次数、*/15 * * * * 平均间隔15 分钟、0 0 29 2 * 在 2028-02 有 1 次而 2027-02 有 0 次、星期 0 与 7 等价改动参数后重跑自检。 7. 输入非法参数段数不是 5、写了 99 或者 25 这种越界数字、*/0、1- 这种残缺范围要给明确中文提示保留上一次有效值界面不清空。 完成后打开预览让我直接看到运行效果。四、页面长什么样一张月历加十条下次执行最上面是表达式输入框、8 个常用预设、基准时间输入还有一个「星期字段 0 和 7 都表示周日」的开关。中间一行是五个字段的逐段解析每个字段给出合法区间和展开后的取值集合。最下面是月历和统计面板命中的日期高亮角标 ×N 是当天跑几次。五、实测换个表达式数字全变基准时间统一取 2026-10-17 23:16把 7 个表达式挨个跑了一遍。表达式未来 30 天执行平均每天平均间隔第一条下次执行0 3 * * 1-520 次0.7 次≈1895 分钟1 天 7 小时 35 分2026-10-19 周一 03:000 9-18 * * 1-5200 次6.7 次≈184 分钟3 小时 4 分2026-10-19 周一 09:00*/15 * * * *2880 次96 次≈15 分钟2026-10-17 周六 23:30*/5 * * * *8640 次288 次≈5 分钟2026-10-17 周六 23:200 */2 * * *360 次12 次≈120 分钟2026-10-18 周日 00:000 0 1 * *1 次0 次仅 1 次无法计算2026-11-01 周日 00:000 0 * * 6,010 次0.3 次≈4640 分钟3 天 5 小时 20 分2026-10-18 周日 00:00*/15 * * * *那行最能说明问题30 天 2880 次平均每天 96 次正好是 24 乘 4。0 0 * * 6,0是「周六或周日零点」30 天命中 10 次。它的字段解析显示取值是 0 和 6页面把周六统一排到了周日后面。六、日和周同时受限是并集不是交集这一条我用0 0 1 * 1单独验了一遍语义是「每月 1 号或者每周一」。30 天里它命中 5 次分别是 10-19 周一、10-26 周一、11-01 周日、11-02 周一、11-09 周一。11-01 是 1 号但不是周一11-02 是周一但不是 1 号两天都执行了确实是并集。如果你要的是「每月 1 号并且是周一」5 段式 cron 写不出来只能在脚本里再判断一次日期。七、闰年换个基准日间隔从 1 天变成 1461 天基准拉到 2028-02-28 10:000 0 29 2 *的下一条是 2028 年 2 月 29 日距基准 14 小时。基准换回 2027-02-27同一个表达式的下一条变成 2028-02-29距基准 366 天未来 30 天执行 0 次。再往外是0 0 31 2 *2 月没有 31 号页面直接给了一句「在可预见的未来约 2 年窗口没有命中任何时间点请调整表达式或基准时间。」八、核心那段代码字段展开只用一个正则每个字段都走同一个正则星号、单值、范围、步进、逗号列表都在里面。constmString(p).match(/^(\*|\d)(?:-(\d))?(?:\/(\d))?$/);if(!m)returnfail(片段 ${p} 无法解析支持*、a、a-b、*/n、a-b/n、逗号组合);if(step1)returnfail(片段 ${p} 中的步进值${step}必须 ≥ 1);日和周的关系写在dayHit里两个字段只要有一个受限就按并集判断。functiondayHit(d,E){if(!E.months.has(d.getMonth()1))returnfalse;constdomd.getDate(),dowd.getDay();if(E.domFullE.dowFull)returntrue;if(E.domFull)returnE.dows.has(dow);if(E.dowFull)returnE.doms.has(dom);returnE.doms.has(dom)||E.dows.has(dow);}collectNext按天往后扫命中就展开当天的时分组合凑够 10 条为止外面还挂了一条 40 万天的保险丝。九、验证与踩坑页面加载后跑 12 条断言内置参数下 12/12 通过。前 7 条盯字段展开、平均间隔、闰年和周日等价后 5 条专门验非法输入。这里有一条我自己踩到的坑。自检里「拒绝非法输入 · 1-」那条是绿的但它绿得不对。1-只有一段被段数校验先拦下了报的是「表达式只有 1 段需要恰好 5 段」。真正的残缺范围提示要到字段内部才看得到我补测了一次0 1- * * *页面才给出「片段 “1-” 无法解析支持、a、a-b、/n、a-b/n、逗号组合」。断言绿了不等于断言测到了你想测的东西这一条我记下来了。失败路径我也点了一遍把分钟字段写成*/0。页面给的原话是「片段 “*/0” 中的步进值 0 必须 ≥ 1」。结果区不白屏橙色提示写着「当前表达式无效以下保留最近一次有效结果修正表达式后会自动更新。」另外三种非法输入的原文我也抄下来了。99 * * * *给出的是「片段 “99” 起始值 99 超出合法区间 0–59」0 3 * *给出的是「表达式只有 4 段需要恰好 5 段分 时 日 月 周。例0 3 * * 1-5」* * * * * *给出的是「表达式有 6 段需要恰好 5 段分 时 日 月 周请删除多余段」十、实测数据汇总项目实测值页面自检12 / 12 通过单文件体积26858 个字符621 行外部依赖1 个 script 标签0 个 link 标签资源请求0 条性能接口里资源列表是空的*/15 * * * *平均间隔≈15 分钟0 0 29 2 *相邻两次间隔1461 天0 0 */5 * *日字段展开1,6,11,16,21,26,31「资源请求 0 条」是用浏览器性能接口复核的打开页面到把十来个表达式点完资源列表一直是空数组。十一、本地复现双击 index.html 就能用不需要装任何依赖。想走静态服务python -m http.server 8000然后访问 http://localhost:8000 。想看它有没有偷偷联网按 F12 打开网络面板再切几个表达式列表里不会多出请求。十二、说点不足只支持 5 段式没有秒字段和年份字段Quartz 的L、W、#这些扩展一个都没做。所以「每月最后一个工作日」这类写法这个页面写不出来。时区全按浏览器本地时间算没有夏令时处理也没有单独的时区选择。页面在北京打开就算北京时间放到服务器上看差 8 小时。*/n一律从字段最小值起步日字段写*/5展开成 1,6,11,16,21,26,31不是 5,10,15。窗口是写死的 30 天最近 10 次也是写死的没有做成可调。页面只做预测不管执行。任务跑失败会不会重试、机器关机期间错过的任务要不要补这些真正运维时会遇到的问题它一概不回答。直接下载试玩这个 Demo 已经完整开源源代码、本文档和全部截图都在公开仓库里可以直接下载来玩Demo Park 仓库https://atomgit.com/deli007/demo_park本案例目录https://atomgit.com/deli007/demo_park/tree/main/codearts-cron-expression-lab打开上面的链接进入 codearts-cron-expression-lab 文件夹把 index.html 下载到本地用浏览器打开即可运行。十三、用码道做这个页面的体会第一条是需求里把期望值写死。我把「*/15展开 0,15,30,45」「周日 0 和 7 等价」直接写进需求交回来的页面就自带这些断言。第二条是断言尽量写关系式。0 3 * * 1-5那次我给的是 18~24 次的区间因为结果随基准日是周几浮动写死一个常量以后一改参数就会假红。第三条是让页面把统计也做出来。只给一个「下次执行时间」查询框文章里就没有可对比的数字加上日历和次数统计之后才有上面那张表。第四条是失败路径单独交代。我在需求里写了非法输入要给中文提示并保留上一次有效值交回来的就是标红加橙色提示结果区不清空。第五条是边界要自己验。2 月 29 日那段我拿了 2028 和 2027 两个基准日各跑一遍才敢把 366 天和 1461 天写进来。第六条是自检全绿不等于页面全对。前面那条「1-」就是例子函数的断言绿了真正拦下它的却是段数校验。接下来我打算把时区和秒级字段补上再看看能不能把「每月最后一个工作日」这类 Quartz 写法也加进去。
阅读完成 · 觉得有帮助?