Program Club

PostgreSQL : 두 날짜 사이의 일 / 월 / 년

proclub 2020. 11. 2. 20:07
반응형

PostgreSQL : 두 날짜 사이의 일 / 월 / 년


PostgreSQL에서 SQLServer 기능 datediff 를 구현하는 방법을 찾고 있습니다. 그건,

이 함수는 지정된 startdate와 enddate 사이에 교차하는 지정된 datepart 경계의 개수 (부호있는 정수 값)를 반환합니다.

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

나는 단순히 빼기를 사용하여 'dd'를 할 수 있다는 것을 알고 있지만 다른 두 가지에 대해서는 어떤 생각이 있습니까?


다음과 같이 시도하십시오.

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


간단히 빼십시오.

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

이것은 당신에게 줄 것입니다 :

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

나는 최선의 답을 찾기 위해 시간을 보냈고 나는 그것을 가지고 있다고 생각한다.

이 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'));

.. 두 날짜 사이의 시간이 아니라 날짜 문자열 부분 사이의 문자적인 차이를 얻을 수 있다는 것입니다.

IE :

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

Years(double precision)=-1;

Months(double precision)=-11;

Days(double precision)=-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 */

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

결과 : 6


다음은 출력이 포함 된 완전한 예입니다. psql (10.1, 서버 9.5.10).

30보다 작은 값이 아니라 58을 얻습니다.
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

This question is full of misunderstandings. First lets understand the question fully. The asker wants to get the same result as for when running the MS SQL Server function DATEDIFF ( datepart , startdate , enddate ) where datepart takes dd, mm, or yy.

This function is defined by:

This function returns the count (as a signed integer value) of the specified datepart boundaries crossed between the specified startdate and enddate.

That means how many day boundaries, month boundaries, or year boundaries, are crossed. Not how many days, months, or years it is between them. That's why datediff(yy, '2010-04-01', '2012-03-05') is 2, and not 1. There is less than 2 years between those dates, meaning only 1 whole year has passed, but 2 year boundaries have crossed, from 2010 to 2011, and from 2011 to 2012.

The following are my best attempt at replicating the logic correctly.

-- 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

I would like to expand on Riki_tiki_tavi's answer and get the data out there. I have created a datediff function that does almost everything sql server does. So that way we can take into account any unit.

create function datediff(units character varying, start_t timestamp without time zone, end_t timestamp without time zone) returns integer
language plpgsql
 as
 $$
DECLARE
 diff_interval INTERVAL; 
 diff INT = 0;
 years_diff INT = 0;
BEGIN
 IF units IN ('yy', 'yyyy', 'year', 'mm', 'm', 'month') THEN
   years_diff = DATE_PART('year', end_t) - DATE_PART('year', start_t);

   IF units IN ('yy', 'yyyy', 'year') THEN
     -- SQL Server does not count full years passed (only difference between year parts)
     RETURN years_diff;
   ELSE
     -- If end month is less than start month it will subtracted
     RETURN years_diff * 12 + (DATE_PART('month', end_t) - DATE_PART('month', start_t)); 
   END IF;
 END IF;

 -- Minus operator returns interval 'DDD days HH:MI:SS'  
 diff_interval = end_t - start_t;

 diff = diff + DATE_PART('day', diff_interval);

 IF units IN ('wk', 'ww', 'week') THEN
   diff = diff/7;
   RETURN diff;
 END IF;

 IF units IN ('dd', 'd', 'day') THEN
   RETURN diff;
 END IF;

 diff = diff * 24 + DATE_PART('hour', diff_interval); 

 IF units IN ('hh', 'hour') THEN
    RETURN diff;
 END IF;

 diff = diff * 60 + DATE_PART('minute', diff_interval);

 IF units IN ('mi', 'n', 'minute') THEN
    RETURN diff;
 END IF;

 diff = diff * 60 + DATE_PART('second', diff_interval);

 RETURN diff;
END;
$$;

참고URL : https://stackoverflow.com/questions/17833176/postgresql-days-months-years-between-two-dates

반응형