Home > other >  Count dates within date intervals
Count dates within date intervals

Time:03-13

I've an array abc containing date and time. I need to convert it into time slots of 1 day with limits determined by startDate and endDate with 'x' containing time slots and 'y' containing count of occurrence in those time slots. How can I get the count of occurrences in abc as per the interval and map it correctly it as per the date intervals?

const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];
const startDate = '2021-07-05'; 
const endDate = '2021-11-05';
const res = [{x: '2021-07-05 - 2021-08-05' , y: '1' },{x: '2021-08-05 - 2021-09-05' , y: '2' }, {x: '2021-09-05 - 2021-10-05' , y: '1' },{x: '2021-10-05 - 2021-11-05' , y: '0' }];
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

CodePudding user response:

This may be one possible solution to achieve the desired objective:

Code Snippet

Please look at countWithinLimits method which houses the significant portions of the solution.

const data = [
  '2021-07-05T00:53:44.953Z', '2021-07-04T00:53:44.953Z', 
  '2021-07-14T00:53:44.953Z', '2021-07-12T00:53:44.953Z', 
  '2021-07-06T00:53:44.953Z', '2021-07-05T00:53:44.953Z', 
  '2021-07-07T00:53:44.953Z', '2021-07-11T00:53:44.953Z', 
  '2021-07-08T00:53:44.953Z', '2021-07-10T00:53:44.953Z', 
  '2021-07-09T00:53:44.953Z', '2021-07-07T00:53:44.953Z', 
  '2021-07-10T00:53:44.953Z', '2021-07-05T00:53:44.953Z', 
  '2021-07-11T00:53:44.953Z', '2021-07-07T00:53:44.953Z', 
];
const startDate = '2021-07-05';
const endDate = '2021-07-11';

// expected result structure for reference
const expectedResult = [
  {x: '2021-07-05 - 2021-07-06', y: '1' },
  {x: '2021-07-06 - 2021-07-07', y: '2' },
  {x: '2021-07-07 - 2021-07-08', y: '1' },
  {x: '2021-07-08 - 2021-07-09', y: '0' }
];

const countWithinLimits = (st, en, arr = data) => {

  // helper function to add 'i' days to given 'dt'
  const addDays = (dt, i) => {
    const nx = new Date(dt);
    return (
        (
        new Date(nx.setDate(nx.getDate()   i))
        ).toISOString().split('T')[0]
    );
  };
  
  // transform 'dt' into look like 'x' in the expected result
  const transformToKey = dt => (`${dt} - ${addDays(dt, 1)}`);
  
  // set constants for start and end dates
  const stDate = new Date(st), enDate = new Date(en);
  
  // first determine the number of slots
  // (each will be 1-day duration, from st till en)
  const numDays = (
    Math.ceil(
      Math.abs(enDate - stDate) / (1000 * 60 * 60 * 24)
    )
  );
  
  // next, obtain an array with the slots
  // something like this: ['2021-07-05 - 2021-07-06', ....]
  const slots = (
    [...Array(numDays).keys()]
    .map(i => addDays(st, i))
    .map(d => transformToKey(d))
  );
  
  // generate an object with props as the slots and values as zeroes
  // like this: { '2021-07-05 - 2021-07-06': 0, ....}
  const slotObj = slots.reduce(
    (fin, itm) => ({...fin, [itm]: 0}),
    {}
  );
  
  // iterate through the data (arr)
  // find the slot in which a given date fits
  // and add 1 to the counter, if the slot is found in slotObj
  // do not count the date if it doesn't match any slots
  const countPerSlot = arr.reduce(
    (fin, itm) => ({
        ...fin,
      ...(
        [transformToKey(itm.split('T')[0])] in fin
        ? {
            [transformToKey(itm.split('T')[0])]: (
            fin[transformToKey(itm.split('T')[0])]   1
          )
        }
        : {}
      )
    }),
    {...slotObj}
  );
  
  // finally, transform the countPerSlot object 
  // into the expected result array
  return (
    Object.entries(countPerSlot)
    .map(
      ([k, v]) => ({ x: k, y: v})
    )
  );
};

console.log(countWithinLimits(startDate, endDate));

Explanation

While there are comments in-line in the above code-snippet, should there be any specific point that requires a more detailed explanation, 'comments' below may be used to notify and this answer may be updated with more details.

The big-picture idea is this:

  • split the solution into different smaller-parts
  • first, generate the time-slots (of length 1 day)
  • next, create an object where the props is the period (like 2021-07-05 - 2021-07-06)
  • now, iterate through the data and increment a counter corresponding to the prop where the date fits
  • and finally, transform the object into an array that matches the expected result ([ {x : '2021-07-05 - 2021-07-06', y: '2' }, .... ])

CodePudding user response:

As per my understanding, I created a simple working demo as per the start and end date you provided in the question :

const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];

const startDate = '2021-07-05'; 
const endDate = '2021-11-05';

function countDates(inputArray, startDate, endDate) {
    let count = 0;
  const dateArray = abc.map((item) => new Date(item.split("T")[0]).getTime());

  dateArray.forEach((dayTime) => {
    if(dayTime >= new Date(startDate).getTime() && dayTime <= new Date(endDate).getTime()) {
      count   ;
    }
  });
  
  return [{x: `${startDate} - ${endDate}`, y: count}];
}

console.log(countDates(abc, startDate, endDate));

Note : I am assuming you have to fetch a range once at a time between startDate and endDate.

  • Related