skip to Main Content

I have an availabilities collection. Inside this collection could be a few entries that are date based for example:

{
  "_id": "64b03ed794d87927a3066e13",
  "startDateTime": "2023-07-07T18:00:00.000Z",
  "endDateTime": "2023-07-12T15:00:00.000Z",
  "availabilityType": "blackout"
}
{
  "_id": "64b03eb094d87927a3066ddb",
  "startDateTime": "2023-07-03T18:00:00.000Z",
  "endDateTime": "2023-07-06T15:00:00.000Z",
  "availabilityType": "blackout"
}

I am trying to figure out the best way to create an array of dates for the month and if there is an “availability” for some of the days, then return that within the date array. I thought about creating an array of days using javascript but then I’d have to iterate for each day to see there are any availabilities on the day; this seems very inefficient.

Ideally what I am looking to build is something similar to the following:

[
  {
    "date": "2023-07-01",
    "availabilityType": "available"
  },
  {
    "date": "2023-07-02",
    "availabilityType": "available"
  },
  {
    "date": "2023-07-03",
    "availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
  },
  {
    "date": "2023-07-04",
    "availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
  },
  {
    "date": "2023-07-05",
    "availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
  },
  {
    "date": "2023-07-06",
    "availabilityType": "booked" // because there was an availability entry in the collection that is marked as booked
  },
  ... etc up to July 31
]

Any suggestions on how this might be done?

3

Answers


  1. One approach is to pre-generate an array for the month with a default status of "available" for all days, then loop through the availabilities and update the relevant entries in your array. for example, Firstly, generate the array for the month:

    const getMonth = (year, month) => {
        const start = new Date(year, month, 1);
        const end = new Date(year, month + 1, 1);
        const days = [];
        
        for(let day = start; day < end; day.setDate(day.getDate() + 1)) {
            days.push({
                date: day.toISOString().slice(0, 10),
                availabilityType: 'available',
            });
        }
        
        return days;
    };
    
    const monthData = getMonth(2023, 6); // for July 2023 (month is 0-indexed)
    

    Then, update the availability data with the array data:

    const availabilities = [
        { startDateTime: "2023-07-07T18:00:00.000Z", endDateTime: "2023-07-12T15:00:00.000Z", availabilityType: "blackout" },
        { startDateTime: "2023-07-03T18:00:00.000Z", endDateTime: "2023-07-06T15:00:00.000Z", availabilityType: "blackout" }
    ];
    
    for (let av of availabilities) {
        const startDay = new Date(av.startDateTime).getDate();
        const endDay = new Date(av.endDateTime).getDate();
        
        for (let i = startDay - 1; i < endDay; i++) {
            monthData[i].availabilityType = av.availabilityType;
        }
    }
    

    This assumes that availabilities is sorted in ascending order and does not contain overlapping intervals. If these assumptions are not true, you may need to sort availabilities first and add additional checks in the second loop.

    Login or Signup to reply.
  2. Here is another take on it:

    const bookings=[{ "_id": "64b03ed794d87927a3066e13", "startDateTime": "2023-07-07T18:00:00.000Z",
      "endDateTime": "2023-07-12T15:00:00.000Z", "availabilityType": "blackout"},
     {"_id": "64b03eb094d87927a3066ddb", "startDateTime": "2023-07-03T18:00:00.000Z",
      "endDateTime": "2023-07-06T15:00:00.000Z", "availabilityType": "blackout" }];
    
     const monthCal={}; // set up the calendar for one month: July 2023   
     for (let d=1, m=6, y=2023, ld=new Date(y,m+1,0).getDate(); // set to 00:00h the following day
          d <= ld; d++ ) monthCal[`${y}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`]=false;
          
    bookings.forEach(b=>{
     // define the cut-off date ld as "00:00h", the day after endDateTime:
     const ld=new Date(b.endDateTime); ld.setDate(ld.getDate()+1); ld.setHours(0);
     for (let d=new Date(b.startDateTime); d < ld; d.setDate(d.getDate()+1)) 
      monthCal[d.toISOString().slice(0,10)]=true;
    });
    
    console.log(monthCal)
    
    // or if you want the original output format:
    
    console.log(Object.entries(monthCal).map(([date,v])=>({date,availabilityType:v?"booked":"available"})));

    As the monthCal object allows the dates to be found directly, without using in inner loop, this might be slightly more efficient then scanning through an array of objects.

    Login or Signup to reply.
  3. You can simply achieve this by defining a startDate and an endDate to represent the range of dates for the month you want to get the details. For demo purpose, I am using July month range.

    const startDate = new Date("2023-07-01");
    const endDate = new Date("2023-07-31");
    

    Then, we will iterate over each date using a for loop, starting from the startDate and incrementing by one day until the endDate.

    Within the loop, we check if the current date falls within the startDateTime and endDateTime range of any object in the array with the availabilityType blackout. If it does, the isBooked variable is set to true, indicating that the date is booked. Otherwise, isBooked remains false, indicating that the date is available.

    Finally, we push an object to the allDates array for each date, setting the date property to the formatted date string and the available property to either booked or available based on the isBooked value.

    Live Demo :

    const array = [
      {
        "_id": "64b03ed794d87927a3066e13",
        "startDateTime": "2023-07-07T18:00:00.000Z",
        "endDateTime": "2023-07-12T15:00:00.000Z",
        "availabilityType": "blackout"
      },
      {
        "_id": "64b03eb094d87927a3066ddb",
        "startDateTime": "2023-07-03T18:00:00.000Z",
        "endDateTime": "2023-07-06T15:00:00.000Z",
        "availabilityType": "blackout"
      }
    ];
    
    const startDate = new Date("2023-07-01");
    const endDate = new Date("2023-07-31");
    
    const allDates = [];
    for (let date = startDate; date <= endDate; date.setDate(date.getDate() + 1)) {
      const dateString = date.toISOString().split('T')[0];
      const isBooked = array.some(item => {
        const startDateTime = new Date(item.startDateTime);
        const endDateTime = new Date(item.endDateTime);
        return dateString >= startDateTime.toISOString().split('T')[0] && dateString <= endDateTime.toISOString().split('T')[0] && item.availabilityType === "blackout";
      });
      allDates.push({ date: dateString, available: isBooked ? "booked" : "available" });
    }
    
    console.log(allDates);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search