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

14

25

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.

Reyreyes answered 12/2, 2014 at 19:41 Comment(2)
How do you want to define the behaviour? 1 February 2014 was a Saturday. Was 3 February in the first week of the month, or the second?Chalybeate
For 1 Feb 2014, I would consider that the first saturday of the month. For 3 Feb 2014, I would consider that the first monday of the month. Basically, exactly how google calendar classifies it.Reyreyes
A
41

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
Anility answered 12/2, 2014 at 20:34 Comment(6)
What is x.date() ?Fearless
The date method returns the day of the month.Anility
@Fearless x should really be any momentjs object, in this example it should have been firstFeb2014, I edited the answer to clear up this confusion.Sherylsheryle
Does not work for July 30, 2018. July 2018 spans over 6 weeks. The above solution returns 5 for this date.Timofei
@Timofei Looking at a calendar, it appears July 2018 is in fact 5 weeks long. Am I missing something?Summer
Why not moment(yourDate).weeks() ?Michaelamichaele
H
25

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.

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);
}
Hearty answered 26/9, 2017 at 14:10 Comment(1)
Whilst this doesn't solve the OPs problem, it solves mine - I needed to find the week of the month as you would look at a calendar, i.e Monday -> Sunday, where the first 'week' could include days from the previous month, thanksGlottalized
C
6

Simple using moment.js

function week_of_month(date) {

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

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

}
Clod answered 16/10, 2014 at 5:47 Comment(1)
Why not use date.getDate() instead of moment(date).date(), moreso 2017-07-27 returns a wrong weekLampkin
W
4

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.

Woolcott answered 9/8, 2019 at 5:12 Comment(2)
what's difference between moment().add(0, 'month').startOf('month').weeks() & moment().startOf('month').weeks(), is there any situation when both returns different valuesUitlander
For 2021-12-31, It return -47 as week numberEugenaeugene
S
3

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

Solve answered 27/1, 2017 at 21:17 Comment(0)
I
1

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

Isoleucine answered 12/2, 2014 at 19:46 Comment(2)
I've thought about something along those lines, but the problem is that not every month has 4 weeks. For example, last month, January 2014, had "technically" 5 weeks.Reyreyes
@Reyreyes unless you only count whole weeks in which case it had 3! Unfortunately you have to pick a definition according to which each week will "belong" to a specific month, and there is no single agreed correct way to do this.Zebada
C
1

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

Chalybeate answered 12/2, 2014 at 20:9 Comment(0)
Z
1
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;
}
Zebada answered 12/2, 2014 at 20:28 Comment(1)
Both your answer and Giovanni's work exactly the way I need. thanks!Reyreyes
H
1

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.

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

Henandchickens answered 21/12, 2016 at 18:14 Comment(0)
K
1

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
Kerrison answered 19/3, 2019 at 15:46 Comment(0)
C
1

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.

Castoff answered 19/7, 2019 at 22:50 Comment(0)
P
0

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.

Proclitic answered 20/1, 2021 at 9:31 Comment(0)
P
0

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);
}
Paraguay answered 27/7, 2022 at 8:30 Comment(0)
B
0

Simple code, but has been working for me.

const weekOfTheMonth = (myMomentDate) => {
    const startDay = moment(myMomentDate).startOf('week');
    const day = parseInt(startDay.format('DD'),10);
    if(day > 28){
      return 5;
    }

    if((day > 21) && (day <= 28) ){
      return 4;
    }

    if((day > 14) && (day <= 21) ){
      return 3;
    }

    if((day > 7) && (day <= 14) ){
      return 2;
    }

    return 1;
  }
Boehike answered 23/1, 2023 at 21:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.