diff --git a/CHANGELOG.md b/CHANGELOG.md index 346e71fcb..2a16c7ced 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,12 @@ on a still screen, for an action that never happened. three — but the Bot was still offered the tools, so it reached for one, was refused, and spent the turn saying so. The tools a switch turns off are now withheld from the Bot in the first place. +### A repeated minute in a routine's schedule is described once + +A schedule like `0,30,0 9 * * *` fires at 09:00 and 09:30, but the routines page and the model were +told "Every day at 09:00, 09:00 and 09:30". Repeated minutes are now said once, as repeated weekdays +already were. + ### An app you have not connected is offered where you are reading A Bot asked to use an app whose account the person had not connected answered with the name of a diff --git a/server/src/routines/schedule.ts b/server/src/routines/schedule.ts index 7fae13c7c..dfa117359 100644 --- a/server/src/routines/schedule.ts +++ b/server/src/routines/schedule.ts @@ -298,7 +298,9 @@ export function describeCron(cron: string): string { .split(",") .map((part) => parsePlainInt(part, 0, 59)); if (minutes.every((value): value is number => value !== null)) { - const times = [...minutes] + // De-duplicated like `weekdays`: cron fires once for `0,0`, so it must not read as + // "09:00 and 09:00". + const times = [...new Set(minutes)] .sort((a, b) => a - b) .map((value) => `${pad2(hour)}:${pad2(value)}`); return `Every day at ${joinWords(times)}`; diff --git a/server/tests/routine-schedule.test.ts b/server/tests/routine-schedule.test.ts index 8f42bdf2b..6b84d10fb 100644 --- a/server/tests/routine-schedule.test.ts +++ b/server/tests/routine-schedule.test.ts @@ -182,6 +182,12 @@ describe("describeCron", () => { expect(describeCron("0,30 9 * * *")).toBe("Every day at 09:00 and 09:30"); }); + // cron fires once per distinct minute, so a repeated minute must not be described twice. + test("a repeated minute in the list is described once", () => { + expect(describeCron("0,30,0 9 * * *")).toBe("Every day at 09:00 and 09:30"); + expect(describeCron("15,15 9 * * *")).toBe("Every day at 09:15"); + }); + test("falls through to the raw expression when it is stranger than words", () => { expect(describeCron("*/7 3,4 * * *")).toBe("*/7 3,4 * * *"); });