0

I'm facing difficulty handling monthly recurring meetings in my application. The requirement is for these meetings to consistently fall on the same day of the week within the same week of the month, regardless of the specific date.

For example, if the initial meeting is on the 4th of June, and it happens to be on a Monday, the subsequent meetings should always fall on a Monday within the same week of the month (second weeks of the month), even if the specific date changes (e.g., the 5th of July).

I have implemented a solution in Node.js using an API endpoint that fetches meeting data from a CSV file. The endpoint receives the room and date parameters and checks for availability based on the recurring meetings stored in the CSV file.

// API endpoint to retrieve the CSV data (Fetching recurring meetings)
app.get('/api/checkAvailability', (req, res) => {
  const { room, date } = req.query;

  const results = [];

  fs.createReadStream('3meetings.csv')
    .pipe(csv())
    .on('data', (data) => results.push(data))
    .on('end', () => {
      const occupiedSlots = results.filter((meeting) => {
        if (meeting.room === room && meeting.date <= date) {
          const interval = meeting.interval.toUpperCase();

          // Calculate the number of days between the meeting date and the provided date
          const daysDiff = Math.floor(
            (new Date(date) - new Date(meeting.date)) / (1000 * 60 * 60 * 24)
          );

          if (interval === 'D') {
            // For daily intervals, check if the days difference is divisible by 1
            if (daysDiff % 1 === 0) {
              return true; // Occupied slot for the provided date and daily interval
            }
          } else if (interval === 'W') {
            // For weekly intervals, check if the days difference is divisible by 7
            if (daysDiff % 7 === 0) {
              return true; // Occupied slot for the provided date and weekly interval
            }
          } else if (interval === 'W2') {
            // For weekly intervals with 1 week gap, check if the days difference is divisible by 14
            if (daysDiff % 14 == 0) {
              return true;
            }
          }
        }
        return false;
      });

      if (occupiedSlots.length > 0) {
        res.json({ isAvailable: false, occupiedSlots });
      } else {
        res.json({ isAvailable: true });
      }
    });
});

The existing code handles daily (D), weekly (W), and biweekly (W2) recurring intervals. However, it does not account for the monthly intervals as described above.

Could you please provide guidance on modifying the code to support monthly recurring meetings that consistently fall on the same day of the week within the same week of the month?

traizooo
  • 144
  • 14
  • 1
    For that, you should first of all be clear about what the "same week" is. You mean if the first meeting was on the second Thursday of a month all subsequent meetings have also to be on the second Thursday of the following months? What if the first meeting is on the fifth Monday of a month, but not all months have five Mondays? – derpirscher Jun 27 '23 at 06:34
  • To be clear, i have all monthly recurring meetings in the first or second wednesdays of the month only, so it won't be a case i guess – traizooo Jun 27 '23 at 06:38
  • Your comment contradicts your question where you as an example provided a meeting on the 27th of June, which is obviously never the *first* or *second* wednesday (or any other weekday) of a month ... – derpirscher Jun 27 '23 at 08:51
  • but that was example... – traizooo Jun 27 '23 at 08:52
  • Well, then make an example which acutally describes your needs and not one that can never happen ... – derpirscher Jun 27 '23 at 08:53
  • Will your meeting on Monday in the fourth week of every month still happen on that date if it’s December 25? If not, your code needs further complication. – Mike Scott Jun 27 '23 at 09:24
  • BTW: You can simplify code like `if (someCondition) { return true;}` to just `return someCondition;` and `daysDiff % 1 === 0` will *always* be true ... – derpirscher Jun 27 '23 at 12:19

2 Answers2

1

You can add a recurrence interval of 'M' to signify these monthly meetings.

I've created getDayOfWeek() and getWeekOfMonth() functions, using the answer here to create the getWeekOfMonth value.

If the week of the month and the day of the week are equal for a room, an occupied status will be returned.

I'd suggest adding some unit tests to the getOccupiedSlots() to ensure it's returning the expected result for a given set of inputs.

// Using function from https://stackoverflow.com/questions/3280323/get-week-of-the-month
function getWeekOfMonth(date) {
  date = new Date(date)
  const firstWeekday = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
  const offsetDate = date.getDate() + firstWeekday - 1;
  return Math.floor(offsetDate / 7);
}

function getDayOfWeek(date) {
  return new Date(date).getDay();
}

function weekOfMonthEqual(date1, date2) {
  return getWeekOfMonth(date1) === getWeekOfMonth(date2);
}

function dayOfWeekEqual(date1, date2) {
  return getDayOfWeek(date1) === getDayOfWeek(date2);
}

function getOccupiedSlots(results, room, date) { 
  return results.filter((meeting) => {
    if (meeting.room === room && meeting.date <= date) {
      const interval = meeting.interval.toUpperCase();
  
      // Calculate the number of days between the meeting date and the provided date
      const daysDiff = Math.floor(
        (new Date(date) - new Date(meeting.date)) / (1000 * 60 * 60 * 24)
      );
  
      if (interval === 'D') {
        // For daily intervals, check if the days difference is divisible by 1
        if (daysDiff % 1 === 0) {
          return true; // Occupied slot for the provided date and daily interval
        }
      } else if (interval === 'W') {
        // For weekly intervals, check if the days difference is divisible by 7
        if (daysDiff % 7 === 0) {
          return true; // Occupied slot for the provided date and weekly interval
        }
      } else if (interval === 'W2') {
        // For weekly intervals with 1 week gap, check if the days difference is divisible by 14
        if (daysDiff % 14 == 0) {
          return true;
        }
      } else if (interval === 'M') {
        // For monthly intervals check if week of month and day of week are equal
        if (weekOfMonthEqual(date, meeting.date) && dayOfWeekEqual(date, meeting.date)) {
          return true;
        }
      }
    }
    return false;
  });
}

// API endpoint to retrieve the CSV data (Fetching recurring meetings)
app.get('/api/checkAvailability', (req, res) => {
  const { room, date } = req.query;

  const results = [];

  fs.createReadStream('3meetings.csv')
    .pipe(csv())
    .on('data', (data) => results.push(data))
    .on('end', () => {
      const occupiedSlots = getOccupiedSlots(results, room, date);
      if (occupiedSlots.length > 0) {
        res.json({ isAvailable: false, occupiedSlots });
      } else {
        res.json({ isAvailable: true });
      }
    });
});
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • 1
    `getWeekOfMonth(new Date(2023,5,9))` returns 1, eventhough the 9th of June is the second Friday of June 2023 ... Yes, I know, strictly speeking the first week of June 2023 starts on 5th of June. But as I understand it, the question is about the *nth* occurence of a specific weekday in a month. – derpirscher Jun 27 '23 at 09:13
  • @derpirscher it should return a 0-based result, e.g. first week is 0, second week is 1. – Terry Lennox Jun 27 '23 at 09:18
  • 1
    Alright, but still as I understand it (but I admit I might be wrong, OP should clarify), it's not about the week number but about the *nth* occurence of that weekday within the month. Ie in my opinion `getWeekOfMonth(new Date(2023,5,7))` and `getWeekOfMonth(new Date(2023,5,8))` should return different results, because June 7th is the first Wednesday, but June 8th is the second Thursday of June 2023 ... – derpirscher Jun 27 '23 at 09:27
1

A simple possibility to calculate which occurence of a weekday a specific date is, is to just count how often you can go a week into the past before you reach a different month.

//This gives a result like "2023-06-27 is the 4th Wednesday of the month"
function weekCount(d) {
  let c = 0, month = d.getMonth();
  while (month == d.getMonth()) {
    c++;
    d = new Date(d.getTime() - 604800000);
  }
  return c;
}

Then use the result of this function to check, if the date in question and the meeting.date share the same weekday and the same weekcount

else if (interval === 'M') {
  let d = new Date(date), md = new Date(meeting.date);
  return d.getDay() === md.getDay() && //dates must be same weekday
         weekCount(d) === weekCount(md);  //and same weekCount
}
derpirscher
  • 14,418
  • 3
  • 18
  • 35