How to calculate how many weeks a given month has with Javascript?

Asked

Viewed 22,410 times

3

I’m creating a calendar "in hand".

I know you will say that there are several libs that already assemble the whole calendar, only in my project can not have external libs beyond Angularjs 1.5.8, I can not use any lib that does it automatically for me.

Below is the code I tried to make:

var data = new Date();
var dias = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
verificaBissexto(dias);
var num_semanas = Math.floor((dias[mes] + data.getDay()) / 7);

I have this variable dias keeping the number of days of each month.

If I divide by 7 the month of February of this year is 3 weeks, which is not real. I have a function that checks if the year is leap, if the year is leap it changes the values by dias = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], still gives problem.

I tried to make the division by 5, the month of February 2019 gets good only that mess the February 2020.

This variable mes that is indicating the index of the array is being passed by parameter.

1 answer

3


Taking into account that a week has 7 days and 4 weeks is 28 days, so every month has 4 weeks, plus a certain number X of days, where "X" may be zero (for February), 1 (for February in leap years), 2 (for months with 30 days), or 3 (for months with 31 days).

All right, technically a month with 31 days has 4,428571428571428... weeks, but how are you rounding down with Math.floor, then every month should have 4 weeks. Theoretically there is nothing to calculate...

Even if it was to calculate, I didn’t understand why add up the value of data.getDay(), since according to the documentation this method returns a value of 0 to 6 (0 for Sunday, 1 for Monday, etc). And you are using the current date (new Date()), ie, every day you run this code, will have a different result.


How you want to build a calendar, probably the goal is to know how many lines will be needed to display the month. And this depends on more factors than simply the number of weeks.

Most calendars - at least in Brazil - use Sunday as the first day of the week, but there are calendars that put the Monday at first, and I’ve seen libraries on it was possible to choose any day of the week as the first day. But let’s assume it’s Sunday, to simplify.

In this case, the January 2016 calendar would occupy 6 lines (even if the month does not have 6 weeks):

    Janeiro 2016      
Do Se Te Qu Qu Se Sá  
                1  2  <-- primeira linha
 3  4  5  6  7  8  9  <-- segunda linha  
10 11 12 13 14 15 16  <-- terceira linha  
17 18 19 20 21 22 23  <-- quarta linha  
24 25 26 27 28 29 30  <-- quinta linha  
31                    <-- sexta linha

All because the month starts on a Friday, and that makes the 31st stand alone on the sixth line. There are calendars, especially printed ones, that usually put "24/31" in the same space, but in calendars online I have noticed that most displays in 6 lines same.

Already February 2015 would occupy only 4 lines:

   Fevereiro 2015     
Do Se Te Qu Qu Se Sá  
 1  2  3  4  5  6  7  <-- primeira linha  
 8  9 10 11 12 13 14  <-- segunda linha  
15 16 17 18 19 20 21  <-- terceira linha  
22 23 24 25 26 27 28  <-- quarta linha  

In this case, the number of lines is equal to the amount of weeks (four). But in February 2017, even with the month having 28 days (and therefore the same amount of weeks), the calendar needs 5 lines:

   Fevereiro 2017     
Do Se Te Qu Qu Se Sá  
          1  2  3  4  <-- primeira linha  
 5  6  7  8  9 10 11  <-- segunda linha  
12 13 14 15 16 17 18  <-- terceira linha  
19 20 21 22 23 24 25  <-- quarta linha  
26 27 28              <-- quinta linha  

So I think you actually don’t want the amount of weeks, since every month have between 4 and 4.4 weeks, which rounding down, will always be 4.

What you are probably looking for is the amount of lines that will be needed in the calendar to show every day of a given month. So let’s see how to calculate this, considering that the first day of the week is Sunday.

The only case where only 4 lines are needed is when the month has 28 days (February in non-leap years) and the first day of the month is Sunday (as already seen in the example above, with February 2015).

To verify this, simply create a date on the 1st of the said month, check if it is February, if it is leap year (to know if it has 28 or 29 days) and if the day is Sunday:

// https://pt.wikipedia.org/wiki/Ano_bissexto#Calend%C3%A1rio_Gregoriano
// ano bissexto é divisível por 4
// mas se for múltiplo de 100, só é bissexto se for divisível por 400
function bissexto(ano) {
    return ! ((ano % 4) || (!(ano % 100) && (ano % 400)));
}

data.setDate(1); // mudar para dia 1
data.setMonth(mes);
data.setFullYear(ano);
if (data.getDay() == 0 && ! bissexto(data.getFullYear())) {
    // é domingo e ano não é bissexto, vai precisar de 4 linhas no calendário
}

Remembering that the value passed to setMonth should be between 0 and 11 (0 for January, 1 for February, etc).

If the month has more than 28 days, then you will always need at least 5 lines. But we can only see the cases where you need 6, as they are fewer and it is easier to check.

If the month has 30 days, the sixth line will only be required if the first day is a Saturday, as in June 2019:

     Junho 2019       
Do Se Te Qu Qu Se Sá  
                   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                   

Note that if day 1 is any day of the week other than Saturday, day 30 will be on the fifth line. That is, if the month has 30 days (and you already know how to verify it, so I will not repeat the code), just check if the value of data.getDay() is 6 (Saturday). If it is 6 lines will be needed, otherwise only 5 will suffice.

Already if the month has 31 days, the sixth line will only be required if the day 1 is Friday or Saturday (ie if getDay() returns 5 or 6). We have already seen an example above, with January 2016.

And when the month has 29 days, you will never need 6 lines. See, for example, February 2020:

   Fevereiro 2020     
Do Se Te Qu Qu Se Sá  
                   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  

No matter what day of the week the month starts, you’ll always need 5 lines to display the month.

In short, for a calendar where the first day of the week is Sunday:

  • month with 28 days:
    • if first day of the month is Sunday, 4 lines
    • else, 5 lines
  • month with 30 days:
    • if first day of the month is Saturday, 6 lines
    • else, 5 lines
  • month with 31 days:
    • if first day of the month is Friday or Saturday, 6 lines
    • else, 5 lines
  • all other cases, 5 lines

As it is not clear how you are assembling the calendar (it is probably a table, but anyway, I won’t try to guess), I won’t suggest any additional code.

  • thank you, help yes, I will post the result here when he is ready, thank you very much for dedicating your time to help me.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.