obi-jam fix beginner 5 minutes

Natural Language Date Parsing: The Same-Day Weekday Bug

Off-by-one errors are annoying. Off-by-one-week errors are worse — because nobody notices until the reminder doesn't fire.

The Problem

@Obi has a reminder parser that accepts natural language input like ~wed 10pm to schedule tasks in Vikunja. On a Wednesday, the command ~wed 10pm was scheduling the reminder for the following Wednesday — seven days later — instead of today at 10pm.

Why This Happens

The standard day-of-week calculation looks like this:

// Before — buggy
const dayMap = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 };
const targetDay = dayMap[dayInput.toLowerCase()];
const today = new Date().getDay();

let daysAhead = targetDay - today;
if (daysAhead <= 0) daysAhead += 7;  // BUG: <= 0 treats today as "past"

const reminderDate = new Date();
reminderDate.setDate(reminderDate.getDate() + daysAhead);

When targetDay equals today, daysAhead is 0. The check <= 0 catches it and adds 7, pushing the date to next week.

This is a common pattern in any system that parses weekday references — “next Monday,” “this Friday,” reminder schedulers, cron-like natural language parsers. The <= 0 guard is intended to prevent scheduling in the past, but it’s too aggressive.

The Fix

Change <= 0 to < 0, then add a second check for same-day-but-time-passed:

// After — correct
const dayMap = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 };
const targetDay = dayMap[dayInput.toLowerCase()];
const today = new Date().getDay();

let daysAhead = targetDay - today;
if (daysAhead < 0) daysAhead += 7;  // Only wrap if target day is earlier in the week

// Same day, but time already passed — advance to next week
if (daysAhead === 0) {
  const now = new Date();
  const targetTime = new Date();
  targetTime.setHours(parsedHour, parsedMinute, 0, 0);
  if (now > targetTime) {
    daysAhead = 7;
  }
}

const reminderDate = new Date();
reminderDate.setDate(reminderDate.getDate() + daysAhead);
reminderDate.setHours(parsedHour, parsedMinute, 0, 0);

The logic now handles three cases:

  1. Target day is later this weekdaysAhead is positive, no adjustment
  2. Target day is today, time hasn’t passeddaysAhead is 0, schedule for today
  3. Target day is today, time already passeddaysAhead becomes 7, schedule for next week

Key Takeaway

Any time you’re parsing weekday references into dates, the same-day case needs its own branch. The <= 0 to < 0 change is one character, but the difference is a week. Test your date parser on the current day of the week — it’s the case most developers forget.

FAQ

Why does my day-of-week date parser skip today?

The standard pattern for calculating days ahead — if (daysAhead <= 0) daysAhead += 7 — treats 'today' the same as 'already passed.' When the current day matches the target weekday, daysAhead is 0, which triggers the +7 and schedules for next week. Change <= 0 to < 0 to allow same-day scheduling, then add a separate check for whether the time has already passed today.

How should I handle 'next Monday' vs 'this Monday' in a date parser?

If the target weekday matches today and the requested time hasn't passed, schedule for today. If the time has passed, advance to next week. This matches how humans think about it — 'Monday 10pm' said on Monday at 2pm means today at 10pm, not next Monday.