Javascript – Último dia do mês

by Luiz Paulo | novembro 14, 2008 | 15 Comments »

Essa semana, eu precisei de uma solução em Javascript para encontrar o "último dia do mês" ou "quantidade de dias do mês" como preferir. Consultei o Google e encontrei algumas soluções, algumas delas mais simples e outras bem criativas.

Achei o assunto interessante e resolvi divulgar aqui para quem precisar utilizar.

Primeiro vou postar as soluções sérias para o pessoal que está pesquisando e precisa utilizar em seu código

Soluções simples

Exemplo longo (função):

function daysInMonth(month,year) {
	var m = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	if (month != 2) return m[month - 1];
	if (year % 4 != 0) return m[1];
	if (year % 100 == 0 && year%400 != 0) return m[1];
 
	return m[1] + 1;
}

Exemplo curto (função):
Aqui está a grande sacada do javaScript, que interpreta o 0(zero) como "o dia antes do dia primeiro" que obviamente é o último dia do mês anterior.

function daysInMonth(month,year) {
	var dd = new Date(year, month, 0);
	return dd.getDate();
}

Exemplo curto (inline):

var lastDay = (new Date(year, month, 0)).getDate();

Soluções criativas

Não se assustem, mas as soluções citadas abaixo funcionam!

Solução utilizando Switch:

function getLastDayOfMonth(month,year)
{
	var day;
 
	switch(month)
	{
		case 1 :
		case 3 :
		case 5 :
		case 7 :
		case 8 :
		case 10:
		case 12:
			day = 31;
			break;
		case 4 :
		case 6 :
		case 9 :
		case 11:
		   	day = 30;
			break;
		case 2 :
			if( ( (year % 4 == 0) && ( year % 100 != 0) ) || (year % 400 == 0) )
				day = 29;
			else
				day = 28;
			break;
 
	}
	return day;
}

Essa é legal

function anoBissexto(anoCompleto) 
{
	if(!(anoCompleto%4) && (anoCompleto%100 || !(anoCompleto%400))) return true;
	return false;
}
function diasNoMes(mes,ano)
{
	var var_type=typeof mes;
	if(var_type != "number" && var_type != "string") return false;
	if(var_type == "number" && (mes > 11 || mes < 0) && !isInt(mes)) return false;
	var eng_args_allowed = "january-february-march-april-may-june-july-august-september-october-november-december";
	var bra_args_allowed = "janeiro-fevereiro-marçomarco-abril-maio-junho-julho-agosto-setembro-outubro-novembro-dezembro";
	var vet_eng_args_allowed = eng_args_allowed.split("-");
	var vet_bra_args_allowed = bra_args_allowed.split("-");
	var datahj = new Date();
	var anohj = datahj.getFullYear();
	var dias = [31,anoBissexto(ano)?29:28,31,30,31,30,31,31,30,31,30,31];
 
	if(var_type == "string")
	{
		indice_eng = keyPosMatch(vet_eng_args_allowed,mes);
		indice_bra = keyPosMatch(vet_bra_args_allowed,mes);
		if(indice_eng>=0) return dias[indice_eng];
		if(indice_bra>=0) return dias[indice_bra];
		return false;
	}
	else return dias[mes];
}

Façam bom proveito!

Categorias: Desenvolvimento web, JavaScript, Linguagens
Tags: , , , , ,

15 Comentários

  1. avatar Rodrigo Cacilhas novembro 16th, 2008 at 12:02

    Eu acho simplesmente incrível a capacidade que as pessoas têm de complicar o que é simples. =)

    Muito bom artigo!

    []'s
    Cacilhas

  2. avatar Zappala novembro 17th, 2008 at 11:11

    É verdade, a mente humana é muito criativa... Muito bom o post LP!

    Estava eu pensando, será que isso rola em Java?

    Então temos:
    >> System.out.println(new SimpleDateFormat("dd").format(new Date(2008,2,0)));

    ou ainda uma mais fácil:
    >> System.out.println(new GregorianCalendar(2008,2,0).get(Calendar.DAY_OF_MONTH));

    Infelizmente a versão intuitiva não funciona e já é 'deprecated' a muito tempo...
    >> System.out.println(new Date(2008,2,0).getDay()); //Não funciona!

    Valeu,
    Zappala.

  3. avatar admin novembro 17th, 2008 at 13:29

    Boooa Zappala, ótimo exemplo!

    Falando em código compacto, nesse caso, JAVA não fica atrás.

    Agora, como se faz isso em C, Ruby, Pyton, Lua, etc?

    Você sabe alguma solução compacta para alguma dessas liguagens? Posta pra gente conhecer :)

    []'s

  4. avatar Rodrigo Cacilhas novembro 17th, 2008 at 15:00

    Em Python temos a função monthrange() do módulo calendar:

    last_day = calendar.monthrange(year, month)[1]

    Em Lua é preciso usar o módulo os para calcular. Então podemos criar uma função para calcular isso:

    function lastday(year, month)
        month = month + 1
        if month == 13 then
            month = 1
            year = year + 1
        end
        return 0 + os.date(
            "%d",
            os.time {
                year = year
                month = month
                day = 1
            } - 86400
        )
    end

    Em C++, a Boost oferece a função end_of_month() no cabeçalho:

    date_time/gregorian/greg_date.hpp

    Em Objective-C deve haver alguma forma mais simples, mas uma forma é usando a classe NSDate.

    Criei uma função para resolver isso:

    int lastday(int year, int month) {
        id date = [NSDate
            dateWithString: [NSString
                stringWithFormat: @"%d-%d-01 00:00:00 +000", year, month
            ]
        ];
    
        [date addTimeInterval: -86400.];
    
        id day = [date
            descriptionWithCalendarFormat: @"%d"
            timeZone: [NSTimeZone timeZoneWithName: @"GMT+0"]
            locale: nil
        ];
    
        return [day intValue];
    }

    Em C e em Ruby vou ficar devendo.

    []'s
    Cacilhas, La Batalema

  5. avatar Valdinei dos Santos novembro 17th, 2008 at 15:22

    Ai Luiz em rails como se trabalha com data:

    d = Date.new(2008,11)
    d.end_of_month
    => Sun, 30 Nov 2008
    

    Ja me deu Dia mes Ano :)

    #Agora convertido em string
    d.to_s
    => "2008-11-01"
    

    Agora mais umas brincadeirinhas :)

     d.tomorrow
    => Sun, 02 Nov 2008
    
    #Que Dia foi ontem mesmo?
    d.yesterday
    => Fri, 31 Oct 2008
    
    #Agora em UnixTime
    d.end_of_day.to_i
    1225591199
    

    Tem umas paradas que acho muito maneiras tipo

    >> now = DateTime.new(2008,11,17)
    => Mon, 17 Nov 2008 00:00:00 +0000
    
    #Adicionando 5 minutos
    >> now + 5.minutes
    => Mon, 17 Nov 2008 00:05:00 +0000
    
    #Adicionando 3 dias
    >> now + 3.days
    => Thu, 20 Nov 2008 00:00:00 +0000
    
    #Que tal mais uma semana
    >> now + 1.week
    => Mon, 24 Nov 2008 00:00:00 +0000
    
    #Tudo Bem vamos tentar com mais 10 anos 
    
    >> now + 10.years
    => Sat, 17 Nov 2018 00:00:00 +0000
    

    Tem muitas coisas prontas mas tudo isso em Rails em Ruby não parei para ver como é não, mas não deve ser dificil. Ruim de trabalhar com data é no Python, eu não gosto como ele trabalha acho complicado.

    Cada linguagem e FrameWork tem suas vantagens e suas desvantagens as vezes vale dar uma olhada no codigo de outra linguagem e adpatar. (marreta)

    Abraços

  6. avatar Rodrigo Cacilhas novembro 17th, 2008 at 15:27

    Ah! Esqueci de Smalltalk!

    A ideia aqui é similar à de Lua: primeiro agente pega o primeiro dia do próximo mês (m é o mês, y é o ano):

    m := m + 1.
    (m = 13) ifTrue: [
        m := 1.
        y := y + 1.
    ].

    Então calcula a data e volta um dia:

    aux := Date year: y month: m day: 1.
    aux := aux addDays: -1.

    O último dia do mês desejado então pode ser obtido com:

    last_day := aux dayOfMonth.

    []'s
    Cacilhas, La Batalema

  7. avatar admin novembro 17th, 2008 at 15:44

    Muito bom!

    @valdineisantos Boas respostas :) Gostei da forma com que o Ruby trara data. Bem simples essas propriedades de número "3.day | 3.month".

    @cacilhas Cara você é foda! Pessoal postando suas humildes opiniões e vc vem com SmallTalk.
    "Só para tirar onda, heheheh"

    []'s

  8. avatar Rodrigo Cacilhas novembro 17th, 2008 at 16:26

    O que acho complicado de se lidar em Python com data é ter muitos módulos para essa finalidade.

    Módulos diferentes fazendo coisas diferentes e também coisas iguais.

    Mas no mais, não vejo complicação. Talvez não seja tão simples quanto Ruby, mas a implementação interna é mais bem acabada.

    Deixe-me reproduzir os exemplos de Ruby em Python:

    Primeiro importe o seguinte:

    from datetime import *
    import calendar

    Último dia do mês:

    d = date(
        2008, 11, calendar.monthrange(2008, 11)[1]
    )

    Convertido em string:

    d.strftime("%F")

    Amanhã:

    date.today() + timedelta(days=1)

    Ontem:

    date.today() - timedelta(days=1)

    Para o formato Unix realmente não sei como converter um date, porque estou enferrujado em Python. Vou substituir pelo formato C, depois quando eu encontrar como converter para o formato Unix eu comento aqui:

    d.timetuple()

    Para as brincadeira com data, é preciso um datetime:

    now = datetime.now()
    
    # Adicionando cinco minutos
    print now + timedelta(minutes=5)
    
    # Adicionando três dias
    print now + timedelta(days=3)
    
    # Adicionando uma semana
    # infelizmente timedelta não suporta anos
    print now + timedelta(days=3652)

    Ou seja, apesar das diferenças, lidar com data em Python não é tão complicado quanto parece à primeira vista.

    Para terminar, o L.P. achou que ficou confuso em Smalltalk, então vou escrever aqui tudo em uma tacada só:

    lastDayOfMonth: m year: y
        | aux |
    
        m := m + 1.
        (m = 13) ifTrue: [
            m := 1.
            y := y + 1.
        ].
    
        aux := Date year: y month: m day: 1.
        aux := aux addDays: -1.
    
        ↑ aux dayOfMonth
    !!

    []'s
    Cacilhas, La Batalema

  9. avatar Valdinei dos Santos novembro 17th, 2008 at 16:44

    Muito bom os exemplos @cacilhas tive que fazer a adição de dias em datas com python usei o timedelta e funcionou perfeitamente (embora eu continue não gostando).

    Cada linguagem com suas bizarrices. Achei os exemplos maneiros e bem instrutivos, pode contar que terá muitos acessos quando o google indexar pois data geralmente é uma questão muito procurada e com esse vasto numero de exemplo o visitantes vão chegar ao montes :)

    Vou tentar fazer em Shell Script para praticar.

    Alguém poderia fazer em Windows linha de comando, VB, ASP.NET e afins (post infinito a vista).

  10. avatar Rodrigo Cacilhas novembro 18th, 2008 at 9:08

    Duas coisinhas:

    1) Acho que errei no Smalltalk: não lembro bem, mas acho que !! é usado para encerrar classe. Para encerrar método então é !.

    2) Faltou Common Lisp!

    (defun last-day-of-month (y m)
      (setq m (+ m 1))
      (when (= m 13)
        (setq m 1)
        (setq y (+ y 1)))
      (let (
          (*sec* 0)
          (*min* 0)
          (*hour* 0)
          (*day* 0)
          (*month* 0)
          (*year* 0)
          (*date-of-week* 0)
          (*dst-p* 0)
          (*tz* 0)
        )
        (multiple-value-bind
          (*sec* *min* *hour* *day* *month* *year* *date-of-week* *dst-p* *tz*)
          (decode-universal-time
            (-
              (encode-universal-time 0 0 0 1 m y)
              86400))
          *day*)))

    []'s
    Cacilhas, La Batalema

  11. avatar Rodrigo Cacilhas novembro 18th, 2008 at 9:32

    Na verdade é possível fazer sem o form let:

    (defun last-day-of-month (y m)
      (setq m (+ m 1))
      (when (= m 13)
        (setq m 1)
        (setq y (+ y 1)))
      (multiple-value-bind
        (*sec* *min* *hour* *day* *month* *year* *date-of-week* *dst-p* *tz*)
        (decode-universal-time
          (-
            (encode-universal-time 0 0 0 1 m y)
            86400))
        *day*))

    O form multiple-value-bind já resolve o que o let pretendia.

    Nisso que dá ficar enferrujado!

    []'s
    Cacilhas. La Batalema

  12. avatar guilherme gualberto dezembro 2nd, 2008 at 8:28

    em fortran possuem algumas funcoes Intrinsicas
    program Hora_e_data
    interger ,parameter:: n = 3
    interger :: data(n),horaSys(n)
    call idate(data)
    ! data(1)=dia, data(2)=mes data(3)=ano
    call itime(horaSys)
    ! horaSys(1)=hora, horaSys(2)=minute,horaSys(3)=second
    write(*,'('Date ', i2.2, '/', i2.2, '/', i4.4, '; time ',i2.2, ':', i2.2, ':', i2.2)')data(2), data(1), data(3), now
    endprogram

  13. avatar Rafael Henter dezembro 2nd, 2008 at 22:21

    Ola amigos!

    @Valdinei, você falou sobre algumas linguagens para MS. Tanto o ASP.NET quanto o VB usam os recursos de data direto do sistema, e caso você saber de alguma data é feito com calculo. Da uma olhada em um codigo para calcular quando será o proximo carnaval.

    ###############
    Public Function pascoa(pano As String)

    Dim x As Integer, y As Integer, a As Integer, b As Integer, c As Integer, d As Integer, e As Integer, dia As Integer
    Dim mes As String

    mes = vazio
    dia = 0
    ano = Val(pano)
    x = 24
    y = 5
    a = ano Mod 19
    b = ano Mod 4
    c = ano Mod 7
    d = (19 * a + x) Mod 30
    e = (2 * b + 4 * c + 6 * d + y) Mod 7

    If (d + e) > 9 Then
    dia = (d + e - 9)
    mes = "04"
    Else
    dia = (d + e + 22)
    mes = "03"
    End If

    pascoa = Format(CDate(LTrim(Str(dia)) & "/" & mes & "/" & LTrim(pano)), "dd/mm/yyyy")

    End Function

    Bom neste exemplo ja da para ver que VB assusta tanto quanto Smalltalk

  14. avatar Rafael Henter dezembro 3rd, 2008 at 7:42

    Esqueci de colocar o restante do codigo para calcular o carnaval

    Public Function carnaval(pano As String)

    Dim x As Integer, y As Integer, a As Integer, b As Integer, c As Integer, d As Integer, e As Integer, dia As Integer
    Dim mes As String
    Dim vpascoa As Date

    mes = vazio
    dia = 0
    ano = Val(pano)
    x = 24
    y = 5
    a = ano Mod 19
    b = ano Mod 4
    c = ano Mod 7
    d = (19 * a + x) Mod 30
    e = (2 * b + 4 * c + 6 * d + y) Mod 7

    If (d + e) > 9 Then
    dia = (d + e - 9)
    mes = "04"
    Else
    dia = (d + e + 22)
    mes = "03"
    End If

    vpascoa = Format(CDate(LTrim(Str(dia)) & "/" & mes & "/" & LTrim(pano)), "dd/mm/yyyy")
    carnaval = Format(CDate(vpascoa) - 47, "dd/mm/yyyy")

    End Function

  15. avatar Fábio Caldas dezembro 23rd, 2008 at 10:39

    Bem em C# as coisas são bem simples

    int year = 2008;
    int month = 09;
    int daysInMonth = DateTime.DaysInMonth(year,month);

    Pronto assim a variável 'daysInMonth' vai retornar a quantidade de dias de um determinado mês em um determinado assim.

    Mas para quem é curioso como eu, segue o Disassemble dessa função:

    public static int DaysInMonth(int year, int month)
            {
                bool isLeapYear = false;
                int[] DaysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
                int[] DaysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
     
                if ((month  12))
                    throw new ArgumentOutOfRangeException("month", "ArgumentOutOfRange_Month");
     
                if ((year  0x270f))
                    throw new ArgumentOutOfRangeException("year", "ArgumentOutOfRange_Year");
     
                if ((year % 4) != 0)
                    isLeapYear = false;
                if ((year % 100) == 0)
                    isLeapYear =((year % 400) == 0);
                isLeapYear = true;
     
                int[] numArray = (isLeapYear) ? DaysToMonth366 : DaysToMonth365;
                return (numArray[month] - numArray[month - 1]);
            }

Deixe um comentário


 

Sobre

Foto Luiz Paulo

Sou desenvolvedor web desde 2000, atuei em grandes projetos web2.0. Atualmente trabalho na Automatos junto equipe de site desenvolvendo projetos web2.0 e utilizando como server-side a linguagem java.

Para saber mais sobre mim, acesse Meus Links ›


Valid XHTML 1.0 Strict Valid CSS!

Luiz Paulo | tecnologia web