cup_of
cup_of

Reputation: 6687

get the number of weeks (rows) in a month from moment.js

I'd like to get the number of calendar rows (weeks) in any month using momentjs

For example:

This would be 5

enter image description here

and this would be 6

enter image description here

Heres what I have to work with:

I have the month, start of month, and end of month as a moment items

const month; // (month moment obj)
const start = moment(month).startOf('month');
const end = moment(month).endOf('month');

Heres what I've tried so far (with no luck)

const weeks = end.diff(start, 'week'); // always gives 4
const weeks = moment.duration(end - start).weeks() + 1; // always gives 5

I really would prefer to use Moment.js for simplicity and accuracy. I've seen some pure JS answers on here but none of them are truly reliable.

Upvotes: 5

Views: 2054

Answers (3)

Probably this is not the best way to do it, but at least it gives the correct answer.

function getWeeksInMonth(date: Moment | null) {
    if (!date) {
        return 0;
    }

    let weeksInMonth = 0;
    const firstMonthDate = date.clone().startOf('month');
    const lastMonthDate = firstMonthDate.clone().endOf('month');
    const currentWeekFirstDate = firstMonthDate.clone().startOf('week');

    while (lastMonthDate.isAfter(currentWeekFirstDate)) {
        weeksInMonth++;
        currentWeekFirstDate.add(1, 'week');
    }

    return weeksInMonth;
}

Upvotes: -1

user3463892
user3463892

Reputation:

You should take in consideration also the offsets.


function weeksOfMonth (input = moment()) {
  const startMonth = input.clone().startOf('month');
  const startWeek = startMonth.clone().startOf('isoWeek');
  const startOffset = startMonth.diff(startWeek, 'days'); 
  
  const endMonth = input.clone().endOf('month');
  const endWeek = endMonth.clone().endOf('isoWeek');
  const endOffset = endWeek.diff(endMonth, 'days'); 

  return Math.ceil((endMonth.diff(startMonth, 'days') + startOffset + endOffset) / 7);
}

Upvotes: 0

jordiburgos
jordiburgos

Reputation: 6302

This is a curious problem. Edited new solution: count the days of the first week (row one), then the next weeks (middle rows), if there are pending days add another row:

Taking into account that week starts on Monday with 'isoWeekDay()'.

As of October 9th 2019:

let now = moment('9/oct/2019');
// First row
let firstWeekDays = 7 - now.startOf('month').isoWeekday() + 1;
let rows = 1
rest = now.daysInMonth() - firstWeekDays;
// Middle rows
let middleRows = Math.floor(rest/7);
rows = rows + middleRows;
rest = rest - (middleRows * 7);
// Last row?
if (rest > 0) {
    rows = rows + 1;
}
console.log(rows); // 5

Upvotes: 3

Related Questions