# Somar meses e calcular idade sem erro: o problema do dia 31

> Somar 1 mês a 31 de janeiro não tem resposta óbvia: fevereiro não tem dia 31. O Excel, o relativedelta do Python e a maioria das bibliotecas usam o último dia do mês (28 ou 29 de fevereiro), enquanto o Date do JavaScript e o DateTime do PHP "transbordam" para 3 de março. Este guia mostra a regra, o código que soma meses do mesmo jeito em JavaScript, Python e PHP, e como calcular a idade sem os erros de dividir dias por 365.

- Endereço oficial: https://pradev.com.br/guias/somar-meses-e-calcular-idade-sem-erro
- Tipo: Guia
- Publicado em: 2026-10-01
- Atualizado em: 2026-10-01
- Autor: Leonardo Gaertner (https://pradev.com.br/sobre)
- Ferramentas: [Somar Dias em Datas](https://pradev.com.br/somar-dias-em-datas), [Calcular Idade](https://pradev.com.br/calcular-idade), [Diferença entre Datas](https://pradev.com.br/diferenca-entre-datas)

## O problema: meses têm tamanhos diferentes

Somar dias é simples: cada dia tem o mesmo tamanho. Somar meses não, porque eles têm de 28 a 31 dias. Para a maioria das datas, somar 1 mês mantém o dia: 15 de março mais 1 mês é 15 de abril. O problema aparece nos dias 29, 30 e 31, quando o mês de destino é mais curto.

- Excel (`DATAM`), Python (`relativedelta`), date-fns e Java (`plusMonths`): 31/01 + 1 mês = 28/02 (ou 29/02 em ano bissexto). O dia é limitado ao último do mês.
- JavaScript (`setMonth`) e PHP (`modify("+1 month")`): 31/01 + 1 mês = 03/03. O dia 31 de fevereiro "transborda" para março.
- Código Civil, art. 132: um prazo em meses vence no dia de igual número; se ele não existir, no dia seguinte, 1º de março.

Nenhuma é errada em si, mas misturar regras entre o sistema e a planilha gera cobranças em datas diferentes. Escolha uma e use a mesma em todo lugar. A calculadora de [somar dias a uma data](https://pradev.com.br/somar-dias-em-datas) usa a do último dia do mês.

## Somando meses com o último dia do mês

A conta mais segura trabalha com a data como texto `AAAA-MM-DD`, sem hora e sem fuso: transforma ano e mês em um total de meses, soma, volta para ano e mês e limita o dia ao último do mês de destino.

```javascript
// Soma meses a uma data AAAA-MM-DD. Se o dia não existe no mês final, usa o último dia dele:
// 31/01 + 1 mês = 28/02 (ou 29/02 em ano bissexto). É a regra do Excel (DATAM) e do relativedelta.
function somarMeses(data, meses) {
  const [a, m, d] = data.split('-').map(Number);
  const total = a * 12 + (m - 1) + meses;
  const ano = Math.floor(total / 12);
  const mes = (total % 12) + 1;
  const ultimoDia = new Date(Date.UTC(ano, mes, 0)).getUTCDate(); // dia 0 do mês seguinte
  const dia = Math.min(d, ultimoDia);
  return `${String(ano).padStart(4, '0')}-${String(mes).padStart(2, '0')}-${String(dia).padStart(2, '0')}`;
}

console.log(somarMeses('2026-01-31', 1)); // 2026-02-28
console.log(somarMeses('2024-01-31', 1)); // 2024-02-29
console.log(somarMeses('2026-03-31', -1)); // 2026-02-28
```

_JavaScript. Sem setMonth, que transborda o dia._

```python
import calendar
from datetime import date


def somar_meses(d: date, meses: int) -> date:
    """Soma meses mantendo o dia; se ele não existe no mês final, usa o último dia do mês."""
    total = d.year * 12 + (d.month - 1) + meses
    ano, mes = divmod(total, 12)
    mes += 1
    ultimo = calendar.monthrange(ano, mes)[1]
    return date(ano, mes, min(d.day, ultimo))


print(somar_meses(date(2026, 1, 31), 1))  # 2026-02-28
print(somar_meses(date(2024, 1, 31), 1))  # 2024-02-29
# Com a biblioteca dateutil, o mesmo resultado: date(2026, 1, 31) + relativedelta(months=1)
```

_Python_

```php
<?php
// Soma meses mantendo o dia; se ele não existe no mês final, usa o último dia do mês.
// Cuidado: (new DateTime('2026-01-31'))->modify('+1 month') dá 2026-03-03, porque o PHP "transborda" o dia.
function somarMeses(string $data, int $meses): string
{
    [$a, $m, $d] = array_map('intval', explode('-', $data));
    $total = $a * 12 + ($m - 1) + $meses;
    $ano = intdiv($total, 12);
    $mes = $total % 12 + 1;
    $ultimo = (int) date('t', mktime(0, 0, 0, $mes, 1, $ano)); // dias do mês
    return sprintf('%04d-%02d-%02d', $ano, $mes, min($d, $ultimo));
}

echo somarMeses('2026-01-31', 1), PHP_EOL; // 2026-02-28
echo (new DateTime('2026-01-31'))->modify('+1 month')->format('Y-m-d'), PHP_EOL; // 2026-03-03
```

_PHP. A segunda linha mostra o transbordo do modify do PHP._

## Calculando a idade

O erro mais comum é dividir os dias vividos por 365, ou por 365,25. As duas contas erram perto do aniversário, porque a quantidade de anos bissextos no período varia. A forma certa é subtrair os anos e tirar 1 se o aniversário daquele ano ainda não chegou:

```javascript
// Idade em anos completos na data de referência (padrão: hoje), com datas no formato AAAA-MM-DD.
function calcularIdade(nascimento, referencia = new Date().toISOString().slice(0, 10)) {
  const [an, mn, dn] = nascimento.split('-').map(Number);
  const [ar, mr, dr] = referencia.split('-').map(Number);
  let idade = ar - an;
  // Ainda não fez aniversário neste ano? Tira 1.
  // Nesta conta, quem nasceu em 29/02 faz aniversário em 1º/03 nos anos não bissextos.
  if (mr < mn || (mr === mn && dr < dn)) idade--;
  return idade;
}

console.log(calcularIdade('1990-10-02', '2026-10-01')); // 35
console.log(calcularIdade('1990-10-02', '2026-10-02')); // 36
```

_JavaScript_

```python
from datetime import date


def calcular_idade(nascimento: date, referencia: date | None = None) -> int:
    """Idade em anos completos na data de referência (padrão: hoje)."""
    referencia = referencia or date.today()
    # Ainda não fez aniversário neste ano? A comparação de tuplas resolve: (mês, dia).
    # Nesta conta, quem nasceu em 29/02 faz aniversário em 1º/03 nos anos não bissextos.
    ainda_nao = (referencia.month, referencia.day) < (nascimento.month, nascimento.day)
    return referencia.year - nascimento.year - ainda_nao


print(calcular_idade(date(1990, 10, 2), date(2026, 10, 1)))  # 35
print(calcular_idade(date(1990, 10, 2), date(2026, 10, 2)))  # 36
```

_Python_

Para a idade exata em anos, meses e dias, use a [calculadora de idade](https://pradev.com.br/calcular-idade), e para a distância entre duas datas quaisquer, a de [diferença entre datas](https://pradev.com.br/diferenca-entre-datas). As duas contam meses de calendário, com a mesma regra do último dia do mês.

## Quem nasceu em 29 de fevereiro

Nos anos não bissextos, o aniversário de quem nasceu em 29 de fevereiro cai em 28 de fevereiro ou em 1º de março, conforme a regra. O código de idade acima, que compara mês e dia, faz a idade mudar em 1º de março, o que coincide com a leitura do Código Civil. Bibliotecas que somam anos com o último dia do mês, como o relativedelta, mudam em 28 de fevereiro. Se a data importa para um direito, como a maioridade, documente qual regra o sistema usa.

## Perguntas frequentes

### Quanto é 31 de janeiro mais 1 mês?

Depende da regra. No Excel e no Python com relativedelta, 28 de fevereiro (ou 29 em ano bissexto). No JavaScript com setMonth e no PHP com modify, 3 de março. Pelo Código Civil, para prazos, 1º de março.

### Somar 30 dias é o mesmo que somar 1 mês?

Não. Trinta dias a partir de 1º de fevereiro de 2026 dão 3 de março, e 1 mês dá 1º de março. Contratos costumam dizer qual das duas formas vale.

### Por que não usar a diferença em milissegundos para calcular a idade?

Porque dividir o tempo por um ano médio erra no dia do aniversário e perto dele, e o horário de verão pode tirar ou pôr uma hora na conta. Compare ano, mês e dia, como no código do guia.

## Fontes

- [Código Civil, art. 132: contagem de prazos em dias, meses e anos](https://www.planalto.gov.br/ccivil_03/leis/2002/l10406compilada.htm)
- [Documentação do Python: dateutil.relativedelta](https://dateutil.readthedocs.io/en/stable/relativedelta.html)

## Guias relacionados

- [Datas e fuso horário em JavaScript: por que sua data muda de dia](https://pradev.com.br/guias/datas-e-fuso-horario-em-javascript): Por que new Date("2026-01-15") vira dia 14 no Brasil, como mostrar datas no horário de Brasília e como evitar erros de fuso em JavaScript, Python e PHP.
- [Como calcular dias úteis com os feriados nacionais](https://pradev.com.br/guias/como-calcular-dias-uteis-com-feriados): Como calcular dias úteis e prazos com os feriados nacionais do Brasil, incluindo Sexta-feira Santa pela Páscoa e Consciência Negra, em JavaScript, Python e PHP.
