From 31938bace7ace0485b2bc22fd200a58216b3213c Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 15 Jan 2026 09:22:13 -0500 Subject: [PATCH 1/2] fix: Meeting scheduling timezone comparison bug When Claude provides a datetime like "2026-01-15T09:15:00" without timezone info, JavaScript's Date parses it as server local time (UTC). This caused Addie to incorrectly reject meeting times as "already passed" when users specified times in their local timezone. The fix compares times within the specified timezone context by: 1. Getting current time formatted in the target timezone 2. Comparing ISO strings directly (lexicographically sortable) This ensures "9:15 AM ET" is compared against "current time in ET", not UTC. Co-Authored-By: Claude Opus 4.5 --- server/src/addie/mcp/meeting-tools.ts | 34 ++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/server/src/addie/mcp/meeting-tools.ts b/server/src/addie/mcp/meeting-tools.ts index 3bb7503d1a..f32fc22eeb 100644 --- a/server/src/addie/mcp/meeting-tools.ts +++ b/server/src/addie/mcp/meeting-tools.ts @@ -71,6 +71,33 @@ function formatTime(date: Date, timezone = 'America/New_York'): string { }); } +/** + * Get the current time as an ISO string in a specific timezone (for comparison). + * Returns format like "2026-01-15T09:30:00" + */ +function getNowInTimezone(timezone: string): string { + // 'sv-SE' locale gives us ISO-like format: "2026-01-15 09:30:00" + return new Date().toLocaleString('sv-SE', { timeZone: timezone }).replace(' ', 'T'); +} + +/** + * Check if a datetime string (without timezone) represents a future time + * in the specified timezone. + */ +function isFutureTimeInTimezone(isoString: string, timezone: string): boolean { + // If the string has timezone info, convert to the target timezone for comparison + if (/Z|[+-]\d{2}:\d{2}$/.test(isoString)) { + const date = new Date(isoString); + const dateInTz = date.toLocaleString('sv-SE', { timeZone: timezone }).replace(' ', 'T'); + return dateInTz > getNowInTimezone(timezone); + } + + // No timezone info - treat the string as already being in the target timezone + // Just compare strings directly (ISO format is lexicographically sortable) + const normalizedInput = isoString.substring(0, 19); // Take just "YYYY-MM-DDTHH:MM:SS" + return normalizedInput > getNowInTimezone(timezone); +} + /** * Format recurrence rule for display */ @@ -440,9 +467,10 @@ export function createMeetingToolHandlers( return `❌ Invalid start time format. Please use ISO 8601 format (e.g., "2026-01-15T14:00:00").`; } - // Check if meeting is in the future - if (startTime <= new Date()) { - return `❌ Meeting time must be in the future.`; + // Check if meeting is in the future (comparing in the specified timezone) + if (!isFutureTimeInTimezone(startTimeStr, timezone)) { + const nowInTz = getNowInTimezone(timezone); + return `❌ Meeting time must be in the future. Current time in ${timezone}: ${formatTime(new Date(), timezone)}`; } const durationMinutes = (input.duration_minutes as number) || 60; From 8f6da2ee9f65c7abf06d04b509e0fb71218a7530 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 15 Jan 2026 09:22:39 -0500 Subject: [PATCH 2/2] chore: Add changeset for timezone fix --- .changeset/timezone-meeting-fix.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/timezone-meeting-fix.md diff --git a/.changeset/timezone-meeting-fix.md b/.changeset/timezone-meeting-fix.md new file mode 100644 index 0000000000..e9ce99d6fd --- /dev/null +++ b/.changeset/timezone-meeting-fix.md @@ -0,0 +1,8 @@ +--- +--- + +fix: Meeting scheduling timezone comparison bug + +Fixed Addie incorrectly rejecting meeting times as "already passed" when users +specified times in their local timezone. The datetime comparison now correctly +interprets times in the specified timezone context.