I am trying to implement a function groupWeeks(dates)
using reduce
that allows me to group an array of objects { date: '2019-03-11', count: 8 }
by weeks.
The following code works fine. Is there a way to refactor it? It seems to me that my solution is unnecessarily complex. Please ignore Date.prototype.getWeekNumber
and getWeekStart(date)
.
const dates = [
{ date: '2019-02-24', count: 10 },
{ date: '2019-02-25', count: 11 },
{ date: '2019-02-26', count: 12 },
{ date: '2019-03-09', count: 8 },
{ date: '2019-03-10', count: 7 },
{ date: '2019-03-11', count: 6 },
{ date: '2019-04-14', count: 3 },
{ date: '2019-04-15', count: 2 },
{ date: '2019-04-16', count: 4 },
{ date: '2019-04-22', count: 5 }
];
/**
* Returns the week number for this date. dowOffset is the day of week the week
* "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
* the week returned is the ISO 8601 week number.
* @param int dowOffset
* @return int
*/
Date.prototype.getWeek = function(dowOffset) {
/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.epoch-calendar.com */
dowOffset = typeof dowOffset == 'int' ? dowOffset : 0; //default dowOffset to zero
var newYear = new Date(this.getFullYear(), 0, 1);
var day = newYear.getDay() - dowOffset; //the day of week the year begins on
day = day >= 0 ? day : day + 7;
var daynum =
Math.floor(
(this.getTime() -
newYear.getTime() -
(this.getTimezoneOffset() - newYear.getTimezoneOffset()) * 60000) /
86400000
) + 1;
var weeknum;
//if the year starts before the middle of a week
if (day < 4) {
weeknum = Math.floor((daynum + day - 1) / 7) + 1;
if (weeknum > 52) {
nYear = new Date(this.getFullYear() + 1, 0, 1);
nday = nYear.getDay() - dowOffset;
nday = nday >= 0 ? nday : nday + 7;
/*if the next year starts before the middle of
the week, it is week #1 of that year*/
weeknum = nday < 4 ? 1 : 53;
}
} else {
weeknum = Math.floor((daynum + day - 1) / 7);
}
return weeknum;
};
function getWeekStart(date) {
var offset = new Date(date).getDay();
return new Date(new Date(date) - offset * 24 * 60 * 60 * 1000)
.toISOString()
.slice(0, 10);
}
function groupWeeks(dates) {
const groupsByWeekNumber = dates.reduce(function(acc, item) {
const today = new Date(item.date);
const weekNumber = today.getWeek();
// check if the week number exists
if (typeof acc[weekNumber] === 'undefined') {
acc[weekNumber] = [];
}
acc[weekNumber].push(item);
return acc;
}, []);
return groupsByWeekNumber.map(function(group) {
return {
weekStart: getWeekStart(group[0].date),
count: group.reduce(function(acc, item) {
return acc + item.count;
}, 0)
};
});
}
console.log(groupWeeks(dates));