Search code examples
javascriptnode.jsdatetimeutc

Getting date range based on date and hour


I am trying to get individual dates ("2022-10-10") and hours ("2022-10-10T09") between an interval in UTC. I could get the individual dates by the following -

function getDatesInRange(startDate, endDate) {
    const date = new Date(startDate.getTime());

    const dates = [];

    while (date <= endDate) {
        const day = new Date(date).toISOString().split(':')[0].split('T')[0];
        dates.push(day);

        date.setDate(date.getDate() + 1);
    }
    return dates;
}
console.log(getDatesInRange(new Date('2022-10-10T20:50:59.938Z'), new Date('2022-10-15T23:50:59.938Z')));

Hence, the above returns - ["2022-10-10", "2022-10-11", "2022-10-12", "2022-10-13", "2022-10-14", "2022-10-15"]

I also want to return the hours of the start and end date and the rest should be dates. So i want to get in return - ["2022-10-10T20", "2022-10-10T21", "2022-10-10T22", "2022-10-10T23" "2022-10-11", "2022-10-12", "2022-10-13", "2022-10-14", "2022-10-15T00", "2022-10-15T01"]

Here is what i have as of now -

function getHoursInRange(startDate, endDate) {
  let startDatePlusOne = new Date(startDate);
  startDatePlusOne.setDate(startDatePlusOne.getDate() + 1);
  
  let endDateMinusOne = new Date(endDate);
  endDateMinusOne.setDate(endDateMinusOne.getDate() - 1);
  
  const date = new Date(startDate.getTime());
  
  console.log("Start date :", date);
  let dates = getDatesInRange(startDatePlusOne, endDateMinusOne);
  console.log("Only days : ", dates);
  
  startDatePlusOne.setHours(0);

    while (date < startDatePlusOne) {
        const day = new Date(date).toISOString().split(':')[0];
        dates.push(day);

        date.setHours(date.getHours() + 1);
    }
    endDateMinusOne.setHours(23);
    const edate = endDateMinusOne.getTime();
    while (edate < endDate) {
        const day = new Date(edate).toISOString().split(':')[0];
        dates.push(day);

        date.setHours(date.getHours() + 1);
    }
  return dates
}

For this use case, i am getting the days back excluding the start and end dates. But for getting each hour of start and end date it gets stuck somehow. Somehow i feel there is a better way to do this. Any ideas ?


Solution

  • You can do it a simpler way by incrementing the timestamp by 30 minutes at a time, and keeping a note of all non-duplicate hour strings and date strings:

    function getDatesInRange(startDate, endDate) {
      let h = new Set(), d = new Set(), t = [];
      for(let i=startDate.getTime(); i<endDate.getTime(); i+=1000*1800) t.push(i);
      [...t, endDate.getTime()].forEach(i=>{
        let s = new Date(i).toISOString();
        [[s.split(':')[0], h], [s.split('T')[0], d]].forEach(([s,r])=>r.add(s));
      });
      let firstDate = [...d.values()][0], lastDate = [...d.values()].pop();
      return d.size===1 ? [...h.values()] : [
        ...[...h.values()].filter(v=>v.startsWith(firstDate)),
        ...[...d.values()].filter(v=>v!==firstDate && v!==lastDate),
        ...[...h.values()].filter(v=>v.startsWith(lastDate))];
    }
    console.log(getDatesInRange(
      new Date('2022-10-10T20:50:59.938Z'), new Date('2022-10-15T23:50:59.938Z')));