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
.