Подтвердить что ты не робот

PostgreSQL: дни/месяцы/годы между двумя датами

Я ищу способ реализовать функцию Datediff SQLServer-функции в PostgreSQL. То есть,

Эта функция возвращает количество (в виде целочисленного значения со знаком) указанных границ даты, пересекаемых между указанной начальной датой и конечной датой.

datediff(dd, '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval
datediff(mm, '2010-04-01', '2012-03-05') = 23  // 23 changes of month
datediff(yy, '2010-04-01', '2012-03-05') = 2   // 2 changes of year

Я знаю, что мог бы сделать "дд", просто используя вычитание, но есть какие-нибудь идеи о двух других?

4b9b3361

Ответ 1

Попробуйте что-то вроде:

select age('2010-04-01', '2012-03-05'),
       date_part('year',age('2010-04-01', '2012-03-05')),
       date_part('month',age('2010-04-01', '2012-03-05')),
       date_part('day',age('2010-04-01', '2012-03-05'));

Эти функции дадут вам полные годы, месяц, дни... между двумя датами. Для количества изменений даты - нам ссылка, предоставленная revoua: http://www.sqlines.com/postgresql/how-to/datediff

Ответ 2

просто вычтите их:

select '2015-01-12'::date - '2015-01-01'::date;

Это даст вам:

?column? 
----------
   11

Ответ 3

Я потратил некоторое время на поиски лучшего ответа, и я думаю, что он у меня есть.

Этот sql даст вам количество дней между двумя датами как integer:

SELECT
    (EXTRACT(epoch from age('2017-6-15', now())) / 86400)::int

.. который при запуске сегодня (2017-3-28) предоставляет мне:

?column?
------------
77

Заблуждение относительно принятого ответа:

select age('2010-04-01', '2012-03-05'),
   date_part('year',age('2010-04-01', '2012-03-05')),
   date_part('month',age('2010-04-01', '2012-03-05')),
   date_part('day',age('2010-04-01', '2012-03-05'));

.. заключается в том, что вы получите буквальную разницу между частями строк даты, а не количеством времени между двумя датами.

I.E:

Age(interval)=-1 years -11 mons -4 days;

Years(double precision)=-1;

Months(double precision)=-11;

Days(double precision)=-4;

Ответ 4

Почти та же функция, как вам нужно ( на основе atiruz ответа, сокращенный вариант UDF из здесь)

CREATE OR REPLACE FUNCTION datediff(type VARCHAR, date_from DATE, date_to DATE) RETURNS INTEGER LANGUAGE plpgsql
AS
$$
DECLARE age INTERVAL;
BEGIN
    CASE type
        WHEN 'year' THEN
            RETURN date_part('year', date_to) - date_part('year', date_from);
        WHEN 'month' THEN
            age := age(date_to, date_from);
            RETURN date_part('year', age) * 12 + date_part('month', age);
        ELSE
            RETURN (date_to - date_from)::int;
    END CASE;
END;
$$;

Использование:

/* Get months count between two dates */
SELECT datediff('month', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 10 */

/* Get years count between two dates */
SELECT datediff('year', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 1 */

/* Get days count between two dates */
SELECT datediff('day', '2015-02-14'::date, '2016-01-03'::date);
/* Result: 323 */

/* Get months count between specified and current date */
SELECT datediff('month', '2015-02-14'::date, NOW()::date);
/* Result: 47 */

Ответ 5

SELECT date_part ('year', f) * 12
     + date_part ('month', f)
FROM age ('2015-06-12'::DATE, '2014-12-01'::DATE) f

Результат: 6

Ответ 6

Вот полный пример с выводом. psql (10.1, сервер 9.5.10).

Вы получаете 58, а не какое-то значение меньше 30.
Удаление функции age(), решило проблему, о которой упоминалось в предыдущем посте.

drop table t;
create table t(
    d1 date
);

insert into t values(current_date - interval '58 day');

select d1
, current_timestamp - d1::timestamp date_diff
, date_part('day', current_timestamp - d1::timestamp)
from t;

     d1     |        date_diff        | date_part
------------+-------------------------+-----------
 2018-05-21 | 58 days 21:41:07.992731 |        58

Ответ 7

Этот вопрос полон недоразумений. Сначала давайте полностью поймем вопрос. Запрашивающий хочет получить тот же результат, что и при запуске функции MS SQL Server DATEDIFF ( datepart, startdate, enddate ) где datepart принимает dd, mm или yy.

Эта функция определяется:

Эта функция возвращает количество (в виде целочисленного значения со знаком) указанных границ даты, пересекаемых между указанной начальной датой и конечной датой.

Это означает, что границы дня, месяца или года пересекаются. Не сколько дней, месяцев или лет между ними. Вот почему datediff(yy, '2010-04-01', '2012-03-05') равен 2, а не 1. Между этими датами меньше 2 лет, то есть прошел всего 1 год, а 2 года Границы пересеклись с 2010 по 2011 год и с 2011 по 2012 год.

Ниже приведены мои лучшие попытки правильно воспроизвести логику.

-- datediff(dd', '2010-04-01', '2012-03-05') = 704 // 704 changes of day in this interval
select ('2012-03-05'::date - '2010-04-01'::date );
-- 704 changes of day

-- datediff(mm, '2010-04-01', '2012-03-05') = 23  // 23 changes of month
select (date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date)) * 12 + date_part('month', '2012-03-05'::date) - date_part('month', '2010-04-01'::date)
-- 23 changes of month

-- datediff(yy, '2010-04-01', '2012-03-05') = 2   // 2 changes of year
select date_part('year', '2012-03-05'::date) - date_part('year', '2010-04-01'::date);
-- 2 changes of year