Moment.js how to get week of month? (google calendar style)

I am using Moment.js and it is great. The problem I have now is that I can’t figure out how to get the week of the month a certain date is. I can only find “week of year” in the Moment js docs. For example, if I choose today’s date (2/12/2014), I would like to know that this date is in the second week of this month of february and consequently, it is the second wednesday of the month. Any ideas?

EDIT:
I guess some clarification is necessary. What I need most is the nth number of a certain day in a month. For example, (from the comments) Feb 1, 2014 would be the first Saturday of the month. Feb 3, 2014 would be the first Monday of the month even though it is “technically” the second week of the month. Basically, exactly how google calendar’s repeat function classifies days.

It seems that moment.js does not have the method that implements the functionality that you are looking for.
However, you can find the nth number of a certain day of the week in a month is using the Math.ceil of the date / 7
For example:

var firstFeb2014 = moment("2014-02-01"); //saturday
var day = firstFeb2014.day(); //6 = saturday
var nthOfMoth = Math.ceil(firstFeb2014.date() / 7); //1

var eightFeb2014 = moment("2014-02-08"); //saturday, the next one
console.log( Math.ceil(eightFeb2014.date() / 7) ); //prints 2, as expected

It looks like this is the number you are looking for, as demonstrated by the following test

function test(mJsDate){
   var str = mJsDate.toLocaleString().substring(0, 3) +
             " number " + Math.ceil(mJsDate.date() / 7) +
             " of the month";
   return str;
}

for(var i = 1; i <= 31; i++) {
   var dayStr = "2014-01-"+ i;
   console.log(dayStr + " " + test(moment(dayStr)) );
}

//examples from the console:
//2014-01-8 Wed number 2 of the month
//2014-01-13 Mon number 2 of the month
//2014-01-20 Mon number 3 of the month
//2014-01-27 Mon number 4 of the month
//2014-01-29 Wed number 5 of the month

When calculating the week of the month based on a given date, you have to take the offset into account. Not all months start on the first day of the week.

Read More:   Simplest way to detect a pinch

If you want to take this offset into account, you can use something something like the following if you are using moment.

function weekOfMonth (input = moment()) {
  const firstDayOfMonth = input.clone().startOf('month');
  const firstDayOfWeek = firstDayOfMonth.clone().startOf('week');

  const offset = firstDayOfMonth.diff(firstDayOfWeek, 'days');

  return Math.ceil((input.date() + offset) / 7);
}

Simple using moment.js

function week_of_month(date) {

        prefixes = [1,2,3,4,5];

    return prefixes[0 | moment(date).date() / 7] 

}

This library adds the function moment.weekMonth()
https://github.com/c-trimm/moment-recur

I made some modifications based on feedback.

let weeks = moment().weeks() - moment().startOf('month').weeks() + 1;
weeks = (weeks + 52) % 52;

On days passing through the next year, the week value will be negative so I had to add 52.

What about something like:

weekOfCurrentMonth = (moment().week() - (moment().month()*4));

This takes the current week of the year, and subtracts it by the 4 times the number of previous months. Which should give you the week of the current month

I think the answer to this question will be helpful, even though it doesn’t use moment.js as requested:

Get week of the month

function countWeekdayOccurrencesInMonth(date) {

    var m = moment(date),
            weekDay = m.day(),
            yearDay = m.dayOfYear(),
            count = 0;

    m.startOf('month');
    while (m.dayOfYear() <= yearDay) { 
        if (m.day() == weekDay) {
            count++; 
        }
        m.add('days', 1); 
    }

    return count;
}

There is a problem with @Daniel Earwicker answer.
I was using his function in my application and the while loop was infinite because of the following situation:

I was trying to figure out which week of december (2016) was the day 31.
the first day of december was day 336 of the year. The last day of december was day 366 of the year.

Read More:   How to reduce stack trace when throwing error (point to call site)

Problem here: When it was day 366 (31 of december, last day of the year) the code added another day to this date. But with another day added it would be day 1 of january of 2017. Therefore the loop never ended.

 while (m.dayOfYear() <= yearDay) { 

    if (m.day() == weekDay) {
        count++; 
    }
    m.add('days', 1); 
}

I added the following lines to the code so the problem would be fixed:

function countWeekdayOccurrencesInMonth(date) {

  var m = moment(date),
        weekDay = m.day(),
        yearDay = m.dayOfYear(),
        year = m.year(),
        count = 0;

 m.startOf('month');

 while (m.dayOfYear() <= yearDay && m.year() == year) {
    if (m.day() == weekDay) {
        count++;
    }
    m.add('days', 1);
 }

 return count;
}

It verifies if it is still in the same year of the date being veryfied

Here’s Robin Malfait‘s solution implemented with the lightweight library date-fns

import {
    differenceInDays,
    startOfMonth,
    startOfWeek,
    getDate
} from 'date-fns'

const weekOfMonth = function (date) {
    const firstDayOfMonth = startOfMonth(date)
    const firstDayOfWeek = startOfWeek(firstDayOfMonth)
    const offset = differenceInDays(firstDayOfMonth, firstDayOfWeek)
    return Math.ceil((getDate(date) + offset) / 7)
}

export default weekOfMonth

I’d do the following:

let todaysDate = moment(moment.now());
let endOfLastMonth = moment(get(this, 'todaysDate')).startOf('month').subtract(1, 'week');

let weekOfMonth = todaysDate.diff(endOfLastMonth, 'weeks');

That gets todaysDate and the endOfLastMonth and then uses Moment’s built-in diff() method to compute the current month’s week number.

It’s not built-in, but basically you can subtract the week number of the start of the month from the week number of the date in question.

function weekOfMonth(m) {
  return m.week() - moment(m).startOf('month').week() + 1;
}

Credit goes to code by original author, give him a star if it helped you.

How about this?

const moment = require("moment");

// Generate Week Number of The Month From Moment Date
function getWeekOfMonth(input = moment()) {
    let dayOfInput = input.clone().day(); // Saunday is 0 and Saturday is 6
    let diffToNextWeek = 7 - dayOfInput;
    let nextWeekStartDate = input.date() + diffToNextWeek;
    return Math.ceil((nextWeekStartDate) / 7);
}


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts