diff --git a/frontend/src/helpers/time/parseDate.ts b/frontend/src/helpers/time/parseDate.ts index caf0f885d..102ec089c 100644 --- a/frontend/src/helpers/time/parseDate.ts +++ b/frontend/src/helpers/time/parseDate.ts @@ -15,23 +15,29 @@ interface dateFoundResult { const monthsRegexGroup = '(january|february|march|april|june|july|august|september|october|november|december|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)' /** - * Tries matching a date regex against text, but only at the start or end of the string. - * This prevents false positives like "The 9/11 Report" where the date-like pattern - * appears in the middle of the text. + * Matches a date regex against text, rejecting matches that appear in the middle + * of text with non-date content on both sides. This prevents false positives like + * "The 9/11 Report" while still allowing "meeting 9/11 at 10:00". * - * The pattern is tested in two passes: first anchored to the start, then anchored to the end. + * Matches at the start or end of text are always accepted. Middle matches are + * only accepted when followed by a time expression (at/@ prefix). */ function matchDateAtBoundary(text: string, pattern: string): RegExpExecArray | null { - // Pass 1: try matching at the start of the text - const startRegex = new RegExp(`^${pattern}($| )`, 'gi') - const startResult = startRegex.exec(text) - if (startResult !== null) { - return startResult - } + const regex = new RegExp(`(^| )${pattern}($| )`, 'gi') + const result = regex.exec(text) + if (result === null) return null - // Pass 2: try matching at the end of the text - const endRegex = new RegExp(`(^| )${pattern}$`, 'gi') - return endRegex.exec(text) + const matchEnd = result.index + result[0].length + const isAtStart = result.index === 0 + const isAtEnd = matchEnd >= text.length + + if (isAtStart || isAtEnd) return result + + // Allow middle-of-text matches when followed by a time expression + const afterMatch = text.substring(matchEnd) + if (/^(at |@ )/i.test(afterMatch)) return result + + return null } function matchesDateExpr(text: string, dateExpr: string): boolean { diff --git a/frontend/src/modules/parseTaskText.test.ts b/frontend/src/modules/parseTaskText.test.ts index 2a05d743c..7147f71b2 100644 --- a/frontend/src/modules/parseTaskText.test.ts +++ b/frontend/src/modules/parseTaskText.test.ts @@ -392,6 +392,8 @@ describe('Parse Task Text', () => { const boundaryTests = [ {input: '9/11 meeting', dateStr: '2021-9-11', text: 'meeting'}, {input: 'meeting 9/11', dateStr: '2021-9-11', text: 'meeting'}, + {input: 'meeting 9/11 at 10:00', dateStr: '2021-9-11', text: 'meeting'}, + {input: 'meeting 9/11 @ 15:00', dateStr: '2021-9-11', text: 'meeting'}, {input: '2021-06-24 Lorem Ipsum', dateStr: '2021-6-24', text: 'Lorem Ipsum'}, {input: 'Lorem Ipsum 06/26/2021', dateStr: '2021-6-26', text: 'Lorem Ipsum'}, {input: '01.02 Lorem Ipsum', dateStr: '2022-2-1', text: 'Lorem Ipsum'},