[BUG]: Weekly and monthly scheduled jobs run a day early or late when the local time is on a different UTC date

当 AnythingLLM 的周/月定时任务的本地时间在 UTC 中落在不同日期时,任务会提前或延后一天运行;优先排查计划任务是否以 UTC cron 存储、但前端只转换了时/分而保留了本地星期与日期。

快速结论:当 AnythingLLM 的周/月定时任务的本地时间在 UTC 中落在不同日期时,任务会提前或延后一天运行;优先排查计划任务是否以 UTC cron 存储、但前端只转换了时/分而保留了本地星期与日期。

适用环境:AnythingLLM 本地开发(Local development);master 分支,Issue 中确认的提交为 fab41657 与 fb299da0;依赖 @breejs/later 4.2.0、moment 2.30.1;复现脚本使用 Node v24.21.0;时区示例包含 America/New_York、Asia/Tokyo、Australia/Sydney。LLM 提供商与模型任意,与运行日期无关;Embedder 不适用。

最快修复方案:暂无确认的一步修复方案。Issue 中验证有效的修复方向是:cron 保存用户的本地字段(完全不做小时偏移),并在任务上增加 IANA timezone 列,在计算下次运行时按该时区解析;使用 Intl.DateTimeFormat 获取候选运行时刻的偏移,而不需要在保存时计算偏移,也无需引入新依赖。

注意事项:如果只做“星期几/月内日期”平移而不保存时区,任务仍会在 DST 切换后偏移一小时;Issue 中已指出 0 1 * * 1 在 2026-11-01 美国 DST 结束后会变为本地 20:00 运行。因此仅平移日期的补丁是不完整的。

问题场景

用户在 AnythingLLM 的 Settings > Scheduled Jobs 中创建每周或每月的定时任务,本地时间恰好落在与 UTC 不同的日期上时触发问题。例如在 America/New_York 时区设置“周一 21:00”,实际在下周日 21:00 运行;在 Asia/Tokyo 设置“周一 08:00”,实际在周二运行;月任务设置为某月 15 日 20:00,在纽约会提前到 14 日运行。任务列表和编辑表单仍显示周一(或 15 日),只有 Next Run 列显示真实运行日。Agent 的 create-scheduled-job 工具也存在同样缺口。

报错原文

[BUG]: Weekly and monthly scheduled jobs run a day early or late when the local time is on a different UTC date

America/New_York  weekly Mon 21:00      saved "0 1 * * 1"     next run Sun 4 Oct 21:00    edit form: Mon
America/New_York  monthly day 15 20:00  saved "0 0 15 * *"    next run Wed 14 Oct 20:00   edit form: day 15
Asia/Tokyo        weekly Mon 08:00      saved "0 23 * * 1"    next run Tue 6 Oct 08:00    edit form: Mon
agent tool, Australia/Sydney "0 9 * * 1-5" -> "0 23 * * 1-5", next runs Tue, Wed, Thu, Fri, Sat

原因分析

最可能的原因是任务以 UTC cron 形式保存,服务端使用 later.date.UTC()(server/models/scheduledJob.js)在 UTC 下评估执行时间;而前端日程构建器 frontend/src/pages/GeneralSettings/ScheduledJobs/utils/cron.js 中的 localTimeToUTC 与 utcTimeToLocal 只把小时和分钟转换为 UTC,保留了本地的星期与月内日期,导致保存的 cron 与用户意图不一致。Agent 的 server/utils/agents/aibitat/plugins/create-scheduled-job/cronUtils.js 中的 convertCronLocalToUtc 存在同样缺口。

Issue 中还确认了第二个缺陷:保存的 UTC cron 被冻结在保存当天的 UTC 偏移上。由于 localTimeToUTC 通过 moment()(即“今天”)推导偏移,0 1 * * 1 实际编码的是“21:00 EDT”;2026-11-01 美国 DST 结束后,同一条记录会在本地 20:00 触发。对于“Monday 21:00 America/New_York”,并不存在一个正确的 5 字段 UTC cron,必须存储时区并在评估时应用。

此外,buildCronFromBuilderState 与 parseCronToBuilderState 省略了同样的转换,使得构建/解析往返测试为恒等,单测通过但任务实际在错误日期运行,这也是编辑表单仍显示周一的原因。

环境排查

  • 确认 AnythingLLM 运行方式:Issue 中为 Local development。
  • 确认分支/提交:Issue 中验证过 master fab41657 与 fb299da0。
  • 确认依赖版本:@breejs/later 4.2.0、moment 2.30.1。
  • 确认 Node 版本:复现脚本使用 Node v24.21.0。
  • 确认本机时区:如 America/New_York、Asia/Tokyo、Australia/Sydney,并留意是否接近 DST 切换日期。
  • 确认触发路径:UI 的 Scheduled Jobs 构建器,或 Agent 的 create-scheduled-job 工具。

解决步骤

  1. 先按 Issue 复现步骤确认现象:将电脑时区设为 America/New_York,打开 Settings > Scheduled Jobs 新建任务,填写 Name 与 Prompt,选择 weekly,只勾选 Monday,设置 21:00 并保存,保持启用。
  2. 观察 Next Run 列是否显示为周日;如果显示周日,说明已命中该缺陷。
  3. 检查任务保存的 cron 与编辑表单显示是否不一致:编辑表单可能仍显示 Mon 与 21:00,而保存的 cron 为 0 1 * * 1。
  4. 排查 Agent 路径:检查 server/utils/agents/aibitat/plugins/create-scheduled-job/cronUtils.js 的 convertCronLocalToUtc 是否同样只转换小时/分钟。
  5. 可优先尝试 Issue 中验证有效的修复方向:cron 保存用户的本地字段(不做小时偏移),并在任务上增加 IANA timezone 列,在计算下次运行时按该时区解析。
  6. 实现时使用 Intl.DateTimeFormat 获取候选运行时刻的时区偏移,避免在保存时用 moment() 推导偏移;Issue 中给出了 tzParts 辅助函数的示例实现。
  7. 如果暂时无法引入 timezone 列,至少不要只平移星期/日期,否则 DST 切换后仍会偏移一小时。

验证方法

用 Issue 相同的复现与计算方式验证:以 America/New_York 创建“weekly Mon 21:00”,确认 Next Run 为周一 21:00 本地时间;再检查 DST 结束后(如 2026-11-01 之后)仍为本地 21:00,而不是 20:00。对月任务验证“day 15 20:00”在 10 月与 11 月均落在 15 日 20:00。对 Agent 工具验证 Australia/Sydney 的 0 9 * * 1-5 应只在周一至周五运行,而不是周二至周六。

参考来源

Mintplex-Labs/anything-llm #6555

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 26902

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注