From 6cdfd346fafa1ed15ab695a1b044d703cd88139e Mon Sep 17 00:00:00 2001 From: Charlie Tonneslan Date: Sun, 17 May 2026 14:06:34 -0400 Subject: [PATCH 1/2] tau-bot: skip times the author marked as local "10:51 local time" means whatever the reader's clock says, not the author's, so converting it to their timezone is misleading. Add "local" / "local time" to the matcher and drop those matches up front so Tau-bot stays quiet. Closes #533. Signed-off-by: Charlie Tonneslan --- src/scripts/timezone.js | 11 +++++++++-- src/scripts/timezone.test.js | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/scripts/timezone.js b/src/scripts/timezone.js index 6f19d315..22562bd5 100644 --- a/src/scripts/timezone.js +++ b/src/scripts/timezone.js @@ -31,7 +31,12 @@ const TIMEZONES = { }; const matcher = - /(\d{1,2}:\d{2}\s?(am|pm)?)\s?(((ak|a|c|e|m|p)(s|d)?t)|:(eastern|central|mountain|pacific)-time-zone:)?/i; + /(\d{1,2}:\d{2}\s?(am|pm)?)\s?(local(?:\s+time)?|((ak|a|c|e|m|p)(s|d)?t)|:(eastern|central|mountain|pacific)-time-zone:)?/i; + +// "local time" means whatever the reader's clock says, not the author's, so +// there's nothing to convert. Mark those matches so we drop them up front. +const isLocalTimeMatch = (timezone) => + typeof timezone === "string" && /^local/i.test(timezone); module.exports = (app) => { helpMessage.registerNonInteractive( @@ -56,7 +61,9 @@ module.exports = (app) => { let m = null; let ampm = null; - const matches = [...text.matchAll(RegExp(matcher, "gi"))]; + const matches = [...text.matchAll(RegExp(matcher, "gi"))].filter( + ([, , , timezone]) => !isLocalTimeMatch(timezone), + ); // If there aren't any matches, that can be because this was crossposted. // We don't want to have the bot respond to those because the authorship of diff --git a/src/scripts/timezone.test.js b/src/scripts/timezone.test.js index e1439c98..0351b23d 100644 --- a/src/scripts/timezone.test.js +++ b/src/scripts/timezone.test.js @@ -78,7 +78,7 @@ describe("Handy Tau-bot timezone conversions", () => { timezone(app); expect(app.message).toHaveBeenCalledWith( - /(\d{1,2}:\d{2}\s?(am|pm)?)\s?(((ak|a|c|e|m|p)(s|d)?t)|:(eastern|central|mountain|pacific)-time-zone:)?/i, + /(\d{1,2}:\d{2}\s?(am|pm)?)\s?(local(?:\s+time)?|((ak|a|c|e|m|p)(s|d)?t)|:(eastern|central|mountain|pacific)-time-zone:)?/i, expect.any(Function), ); }); @@ -242,6 +242,19 @@ describe("Handy Tau-bot timezone conversions", () => { expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); }); + it("does not respond when the author marks the time as local", async () => { + // "local time" / "local" mean "whatever the reader's clock says", so + // there's nothing to translate. Tracked at #533. + for (const text of [ + "Is 10:51 local time too early for more pizza talk?", + "meeting at 9:00 local", + ]) { + message.event.text = text; + await handler(message); + expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); + } + }); + it("correctly converts 24 hour time", async () => { message.event.text = "23:42 mst"; await handler(message); From cea3d21842339391c985631b75c1654416eef039 Mon Sep 17 00:00:00 2001 From: Charlie Tonneslan Date: Mon, 18 May 2026 12:15:13 -0400 Subject: [PATCH 2/2] tau-bot: split local-time test into two cases Signed-off-by: Charlie Tonneslan --- src/scripts/timezone.test.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/scripts/timezone.test.js b/src/scripts/timezone.test.js index 0351b23d..66c82bb0 100644 --- a/src/scripts/timezone.test.js +++ b/src/scripts/timezone.test.js @@ -242,17 +242,18 @@ describe("Handy Tau-bot timezone conversions", () => { expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); }); - it("does not respond when the author marks the time as local", async () => { - // "local time" / "local" mean "whatever the reader's clock says", so - // there's nothing to translate. Tracked at #533. - for (const text of [ - "Is 10:51 local time too early for more pizza talk?", - "meeting at 9:00 local", - ]) { - message.event.text = text; - await handler(message); - expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); - } + it('does not respond when the time is followed by "local time"', async () => { + message.event.text = "Is 10:51 local time too early for more pizza talk?"; + await handler(message); + + expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); + }); + + it('does not respond when the time is followed by "local"', async () => { + message.event.text = "meeting at 9:00 local"; + await handler(message); + + expect(slack.postEphemeralMessage).not.toHaveBeenCalled(); }); it("correctly converts 24 hour time", async () => {