ewig
ewig

Reputation: 17

Is there a easy way to get week number array by month and year?

I try to get week numbers of year in specific month and year with javascript.

function getWeekNumbers(month, year) {
  var first, last, weeks = [];

  if (month < 10)
    month = "0" + month;

  var date = "01." + month + "." + year;
  first = moment(date, 'dd.MM.yyyy').startOf('month').week();
  last = moment(date, 'dd.MM.yyyy').endOf('month').week();

  for (i = first; i < last; i++) {
    weeks.push(i);
  }

  return weeks;
}

var result = getWeekNumbers(3, 2021);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script>

I need the result like; [9,10,11,12,13]

But the code is not work properly.

It will also cause problems in the 12th month.

Upvotes: 0

Views: 1333

Answers (2)

Brandon McConnell
Brandon McConnell

Reputation: 6119

Would this satisfy what you're looking for? I used some array chunking and date functions to break the dates of any given month into their respective weeks:

const getWeeks = (month, year) => Array(new Date(year, month, 0).getDate()).fill(0).map((_,i) => new Date(year, month-1, i+1)).map((d,i,a) => !i && d.getDay() ? [Array(d.getDay()).fill(null), d.getDate()] : d.getDate() === a.length && d.getDay() < 6 ? [d.getDate(), Array(6-d.getDay()).fill(null)] : d.getDate()).flat(2).map((d,i,a) => a.length ? a.splice(0,7) : null).filter(w => w);

// February 2021

getWeeks(2, 2021); // -> returns array below ↓↓↓

[
    [null,    1,    2,    3,    4,    5,    6],
    [   7,    8,    9,   10,   11,   12,   13],
    [  14,   15,   16,   17,   18,   19,   20],
    [  21,   22,   23,   24,   25,   26,   27],
    [  28, null, null, null, null, null, null]
]

If you'd prefer not have the null placeholders, but just have shorter arrays when a week has fewer days, we can achieve this using an additional filter. We can even include an optional parameter for this value, that when left empty (or set to undefined) will yield the trimmed arrays:

const getWeeks = (month, year, nullVal) => Array(new Date(year, month, 0).getDate()).fill(0).map((_,i) => new Date(year, month-1, i+1)).map((d,i,a) => !i && d.getDay() ? [Array(d.getDay()).fill(nullVal), d.getDate()] : d.getDate() === a.length && d.getDay() < 6 ? [d.getDate(), Array(6-d.getDay()).fill(nullVal)] : d.getDate()).flat(2).map((d,i,a) => a.length ? a.splice(0,7) : null).filter(w => w).map(w => nullVal !== undefined ? w : w.filter(d => d));

// December 2021

getWeeks(12, 2021); // -> bullish value blank :: trimming weeks, returns array below ↓↓↓

[
    [             1,  2,  3,  4],
    [ 5,  6,  7,  8,  9, 10, 11],
    [12, 13, 14, 15, 16, 17, 18],
    [19, 20, 21, 22, 23, 24, 25],
    [26, 27, 28, 29, 30, 31    ]
]

getWeeks(12, 2021, 0); // -> using 0 as nullish value, returns array below ↓↓↓

[
    [ 0,  0,  0,  1,  2,  3,  4],
    [ 5,  6,  7,  8,  9, 10, 11],
    [12, 13, 14, 15, 16, 17, 18],
    [19, 20, 21, 22, 23, 24, 25],
    [26, 27, 28, 29, 30, 31,  0]
]

You can also use this function to get the number of weeks in a month or the dates in a particular week by the week's index value:

// Get number of weeks in month
getWeeks(12, 2021).length // -> 5

// Get dates in a week by index value
getWeeks(5, 2021)[2] // -> [9, 10, 11, 12, 13, 14, 15]

Upvotes: 0

simon
simon

Reputation: 1105

Your solution is very close, I made some small tweaks to my own liking but you can change that back if you want.

First of all, I recommend using isoWeek instead of week, isoWeek conforms to week numbering according to ISO 8601 (https://momentjs.com/docs/#/get-set/iso-week/).

Your other error lies in not including last as part of the for loop, in this case you want to include it unlike normally where you just loop to the end of a list. Thus <= is what you need in the for-loop.

function getWeekNumbers(month,year) {
    var first, last, weeks=[];
    
    first = moment().month(month - 1).year(year).startOf('month').isoWeek();
    last = moment().month(month - 1).year(year).endOf('month').isoWeek();
    
      
    for(var i = first; i <= last; i++){
      weeks.push(i);
    }
    
    return weeks;
}

Upvotes: 1

Related Questions