0

I would like to group a simple date array by week and month (in an array). I know there are many examples, and the question has been asked many times, but I cannot find an example on a very simple date format, and not a date-time stamp.

My date data array looks like this:

"timeline_data": [
  "2016-12-20",
  "2016-12-21",
  "2016-12-22",
  "2016-12-23",
  "2016-12-24",
  "2016-12-25",
  "2016-12-26",
  "2016-12-27",
  "2016-12-28",
  "2016-12-29",
  "2016-12-30",
  "2016-12-31",
  "2017-01-01",
  "2017-01-02",
  "2017-01-03",
  "2017-01-04",
  "2017-01-05",
  "2017-01-06",
  "2017-01-07",
  "2017-01-08",
  "2017-01-09",
  "2017-01-10"
]

This is what is getting me: I am not sure whether there is an easy way of looping through this array, and simple pushing the items into new arrays, or whether the date will have to be modified, and the "-" removed with something like:

var date="2016-12-20";
var newDate = date.replace(/-/g, "");

And then obviously, the "-" will have to be replaced.

I hope there is a simpler way.

benomatis
  • 5,536
  • 7
  • 36
  • 59
onmyway
  • 1,435
  • 3
  • 29
  • 53
  • What is the expected output structure? – Sandeep Nayak Jan 11 '17 at 06:31
  • An array of dates grouped by week and the same for an array of dates grouped by month. So it would probably be an array of arrays. – onmyway Jan 11 '17 at 06:38
  • You likely need to determine the week of the year that each date belongs to (see [*Get week of year in JavaScript like in PHP*](http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php/6117889#6117889)), then group by that. Be careful parsing the date strings, "2016-12-20" will be parsed as UTC so may be out by 1 day depending on your time zone. Use a library. – RobG Jan 11 '17 at 06:48
  • The weeks can be grouped in simple arrays of seven days (array of arrays). No funny stuff. it is only the months one would have to calculate the days of the exact month, and then group in array of the specific month. – onmyway Jan 11 '17 at 07:10

1 Answers1

3

I'd do something like the following, hopefully the comments are sufficient. There may be a funkier way to go about it, but this way is fairly clear to me:

/* Helper to get the ISO week number of a date
** @param {Date} date to get week of
** @returns {Array} [year, weekNumber]
*/
function getWeekNumber(d) {
  d = new Date(+d);
  d.setHours(0,0,0,0);
  d.setDate(d.getDate() + 4 - (d.getDay()||7));
  var yearStart = new Date(d.getFullYear(),0,1);
  var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
  return [d.getFullYear(), weekNo];
}

/* Parse ISO 8601 format date string to local date
** @param {string} s - string to parse like 2016-12-15
** @returns {Date}
*/
function parseISOLocal(s) {
  var b = s.split(/\D/);
  return new Date(b[0],b[1]-1,b[2]);
}

var data = [ "2016-12-20", "2016-12-21", "2016-12-22", "2016-12-23", "2016-12-24", "2016-12-25", "2016-12-26", "2016-12-27", "2016-12-28", "2016-12-29", "2016-12-30", "2016-12-31", "2017-01-01", "2017-01-02", "2017-01-03", "2017-01-04", "2017-01-05", "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"];

// Prepend year and week number to dates, e.g. "201651:2016-12-20", then sort
var arr = data.map(function(s){
  var week = getWeekNumber(parseISOLocal(s));
  return week[0] + ('0' + week[1]).slice(-2) + ':' + s;
}).sort();

// Group in arrays by week in an object
var groupedObj = arr.reduce(function (result, value) {
  var b = value.split(':');
  if (!result[b[0]]) result[b[0]] = [];
  result[b[0]].push(b[1]);
  return result;
},{});

// Grab arrays in order of week number. Sort keys to maintain order
var groupedArray = Object.keys(groupedObj).sort().map(key=>groupedObj[key]);

// Final set of grouped dates
console.log(groupedArray.join('\n\n'))

The getWeekNumber function is borrowed from here.

Community
  • 1
  • 1
RobG
  • 142,382
  • 31
  • 172
  • 209
  • Thank you for the great answer! This is a great start. Any suggestions on grouping by month? Perhaps using something from this post: http://stackoverflow.com/questions/1184334/get-number-days-in-a-specified-month-using-javascript – onmyway Jan 11 '17 at 07:16
  • 1
    @onmyway—grouping by month just requires a slight change to the *reduce* function to get the right value to group on. You'll need to include the year to avoid duplicates. – RobG Jan 11 '17 at 07:19