Categorias:

Funções de data e hora

MONTHS_BETWEEN

Retorna o número de meses entre dois valores DATE ou TIMESTAMP.

Por exemplo, MONTHS_BETWEEN('2020-02-01'::DATE, '2020-01-01'::DATE) retorna 1.0.

Consulte também:

DATEDIFF

Sintaxe

MONTHS_BETWEEN( <date_expr1> , <date_expr2> )
Copy

Argumentos

date_expr1

A data da qual é feita a subtração.

date_expr2

A data a ser subtraída.

Retornos

FLOAT representando o número de meses entre as duas datas.

O número é calculado conforme descrito abaixo:

  • A porção inteira do FLOAT é calculada usando as partes do ano e do mês dos valores de entrada.

  • Na maioria das situações, a parte fracionada é calculada usando as partes do dia e da hora dos valores de entrada. (Ao calcular a fração de um mês, a função considera cada mês como 31 dias de duração).

    No entanto, há duas exceções:

    • Se os dias do mês forem os mesmos (por exemplo, 28 de fevereiro e 28 de março), a parte fracionada será zero, mesmo que um ou ambos os valores de entrada sejam carimbos de data/hora e as horas sejam diferentes.

    • Se os dias do mês forem ambos o último dia do mês (por exemplo, fevereiro 28 e março 31), a parte fracionada será zero, mesmo que os dias do mês não sejam os mesmos.

    Por exemplo, a função considera cada um dos seguintes pares de carimbo de data/hora/datas com um intervalo exato de 1,0 mês:

    Carimbo de data/hora 1

    Carimbo de data/hora 2

    Notas

    2019-03-01 02:00:00

    2019-02-01 13:00:00

    O mesmo dia de cada mês.

    2019-03-28

    2019-02-28

    O mesmo dia de cada mês.

    2019-03-31

    2019-02-28

    Último dia de cada mês.

    2019-03-31 01:00:00

    2019-02-28 13:00:00

    Último dia de cada mês.

Notas de uso

  • Se a data (ou carimbo de data/hora) d1 representar um ponto no tempo anterior a d2, então MONTHS_BETWEEN(d1, d2) retornará um valor negativo; caso contrário, retornará um valor positivo. De modo mais geral, a troca das entradas reverte o sinal: MONTHS_BETWEEN(d1, d2) = -MONTHS_BETWEEN(d2, d1).

  • Você pode usar um valor DATE para um parâmetro de entrada e um TIMESTAMP para o outro.

  • Se você usar um ou mais valores TIMESTAMP, mas não quiser diferenças fracionais baseadas na hora do dia, então converta suas expressões TIMESTAMP em DATE.

  • Se você quiser apenas valores inteiros, você poderá truncar, arredondar ou converter o valor. Por exemplo:

    SELECT
        ROUND(MONTHS_BETWEEN('2019-03-31 12:00:00'::TIMESTAMP,
                             '2019-02-28 00:00:00'::TIMESTAMP)) AS MonthsBetween1;
    +----------------+
    | MONTHSBETWEEN1 |
    |----------------|
    |              1 |
    +----------------+
    
    Copy
  • Se alguma entrada for NULL, o resultado será NULL.

Exemplos

Este exemplo mostra diferenças em meses inteiros. O primeiro par de datas tem o mesmo dia do mês (15). O segundo par de datas são os dois últimos dias em seus respectivos meses (28 de fevereiro e 31 de março).

SELECT
    MONTHS_BETWEEN('2019-03-15'::DATE,
                   '2019-02-15'::DATE) AS MonthsBetween1,
    MONTHS_BETWEEN('2019-03-31'::DATE,
                   '2019-02-28'::DATE) AS MonthsBetween2;
+----------------+----------------+
| MONTHSBETWEEN1 | MONTHSBETWEEN2 |
|----------------+----------------|
|       1.000000 |       1.000000 |
+----------------+----------------+
Copy

O próximo exemplo mostra diferenças nos meses fracionários.

  • Para a primeira coluna, a função é aprovada em duas datas.

  • Para a segunda coluna, dois carimbos de data/hora são passados na função que representam as mesmas duas datas que foram usadas para a primeira coluna, mas com horas diferentes. A diferença na segunda coluna é maior do que na primeira devido às diferenças na hora.

  • Para a terceira coluna, dois carimbos de data/hora são passados na função que representam o mesmo dia de seus respectivos meses. Isto faz com que a função ignore quaisquer diferenças de hora entre os carimbos de data/hora, de modo que a parte fracionária seja 0.

SELECT
    MONTHS_BETWEEN('2019-03-01'::DATE,
                   '2019-02-15'::DATE) AS MonthsBetween1,
    MONTHS_BETWEEN('2019-03-01 02:00:00'::TIMESTAMP,
                   '2019-02-15 01:00:00'::TIMESTAMP) AS MonthsBetween2,
    MONTHS_BETWEEN('2019-02-15 02:00:00'::TIMESTAMP,
                   '2019-02-15 01:00:00'::TIMESTAMP) AS MonthsBetween3
    ;
+----------------+----------------+----------------+
| MONTHSBETWEEN1 | MONTHSBETWEEN2 | MONTHSBETWEEN3 |
|----------------+----------------+----------------|
|       0.548387 |       0.549731 |       0.000000 |
+----------------+----------------+----------------+
Copy

O fato de a função retornar um número inteiro de meses tanto quando os dias do mês são os mesmos (por exemplo, 28 de fevereiro e 28 de março) e quando os dias do mês são o último dia do mês (por exemplo, 28 de fevereiro e 31 de março) pode levar a um comportamento não intuitivo; especificamente, o aumento da primeira data no par nem sempre aumenta o valor de saída. Neste exemplo, como a primeira data aumenta de 28 de março para 30 de março, e depois para 31 de março, a diferença aumenta de 1,0 para um número maior e depois diminui de volta para 1,0.

  • Para a primeira coluna, as datas de entrada representam o mesmo dia em meses diferentes, portanto a função retorna 0 para a parte fracionária do resultado.

  • Para a segunda coluna, as datas de entrada representam dias diferentes em meses diferentes (e não são ambos o último dia do mês), então a função calcula a parte fracionária do resultado.

  • Para a terceira coluna, as datas de entrada representam os últimos dias em cada um de dois meses diferentes, portanto a função retorna novamente 0 para a parte fracionária do resultado.

SELECT
    MONTHS_BETWEEN('2019-03-28'::DATE,
                   '2019-02-28'::DATE) AS MonthsBetween1,
    MONTHS_BETWEEN('2019-03-30'::DATE,
                   '2019-02-28'::DATE) AS MonthsBetween2,
    MONTHS_BETWEEN('2019-03-31'::DATE,
                   '2019-02-28'::DATE) AS MonthsBetween3
    ;
+----------------+----------------+----------------+
| MONTHSBETWEEN1 | MONTHSBETWEEN2 | MONTHSBETWEEN3 |
|----------------+----------------+----------------|
|       1.000000 |       1.064516 |       1.000000 |
+----------------+----------------+----------------+
Copy

Este exemplo mostra que a inversão da ordem dos parâmetros inverte o sinal do resultado:

SELECT
    MONTHS_BETWEEN('2019-03-01'::DATE,
                   '2019-02-01'::DATE) AS MonthsBetween1,
    MONTHS_BETWEEN('2019-02-01'::DATE,
                   '2019-03-01'::DATE) AS MonthsBetween2
    ;
+----------------+----------------+
| MONTHSBETWEEN1 | MONTHSBETWEEN2 |
|----------------+----------------|
|       1.000000 |      -1.000000 |
+----------------+----------------+
Copy