Количество месяцев с двойной точностью между датами postgres

Можно ли рассчитать количество месяцев между двумя датами как двойную точность вместо целого числа? Например, разница между 2016-05-04 и 2015-03-21 будет составлять что-то вроде 13.42 или 13.43 месяцев?


person Pedro Carvalho    schedule 14.06.2016    source источник
comment
0,42 или 0,43 какого месяца?   -  person Gilbert Le Blanc    schedule 14.06.2016
comment
Мне все равно, это может быть 13 дней из 30, или 31, или 29, или 28. Пока это целое число месяцев + приблизительная доля количества, примерно равного месяцу, я доволен.   -  person Pedro Carvalho    schedule 14.06.2016


Ответы (2)


Есть много способов вычислить что-то подобное, и вы получите разные результаты в зависимости от правил, которые вы используете для вычисления.

Следующий способ дает вам число 12-х годов в течение заданного периода между двумя датами:

select (date'2016-05-04' - date'2015-03-21') / 365.0 * 12

Вышеуказанные результаты в 13.48.

Следующий способ дает, возможно, более точное число (13,47), хотя и намного сложнее, и дает минимальную разницу:

select extract('years' from age) * 12 + extract('months' from age) + extract('days' from age) / 30
from (select age('2016-05-04'::timestamp, '2015-03-21'::timestamp)) a
person Ezequiel Tolnay    schedule 16.06.2016

Для тех, кого интересует точный расчет, я написал следующую функцию для вычисления разницы между двумя датами в месяцах, включая дробную часть:

CREATE FUNCTION
  MONTH_FRACTION(
      from_date DATE
    , to_date DATE
  )

  RETURNS REAL

  AS
    $$
      WITH
          aux_1 AS (  -- Auxiliary table
            SELECT
                AGE(to_date, from_date) AS duration
          )

        , aux_2 AS (  -- Auxiliary table
            SELECT
                (from_date + DATE_TRUNC('MONTH', duration))::DATE AS to_date_floor
              , (from_date + DATE_TRUNC('MONTH', duration + INTERVAL '1 MONTH'))::DATE AS to_date_ceil
            FROM
              aux_1
          )

      SELECT
        CASE WHEN
          to_date >= from_date
        THEN
          (12 * EXTRACT(YEAR FROM duration) + EXTRACT(MONTH FROM duration) + (to_date - to_date_floor)::REAL / (to_date_ceil - to_date_floor)::REAL)::REAL
        ELSE
          NULL
        END

      FROM
        aux_1, aux_2
    $$

  LANGUAGE SQL
  IMMUTABLE
  RETURNS NULL ON NULL INPUT;
person Mikoláš Volek    schedule 30.07.2018