Interval 타입

Interval 타입 (Interval Type)

INTERVAL은 시간의 기간(period)을 나타내며, DATE, TIMESTAMP, TIMESTAMPTZ, TIME 값에 더하거나 뺄 수 있어요.

출처: 문서

본문

Name Description
INTERVAL 시간의 기간

INTERVAL은 단위(unit)와 함께 수량을 제공하면 만들 수 있어요. 월(months), 일(days), *마이크로초(microseconds)*가 아닌 단위는 이 세 가지 기준 단위 중 더 작은 단위로 변환된 동일한 수량으로 변환돼요.

SELECT
    INTERVAL 1 YEAR, -- 단일 단위: YEAR 키워드 사용; 12개월로 저장됨
    INTERVAL (random() * 10) YEAR, -- 가변 수량에는 괄호가 필요함;
                                   -- 정수 개월 수로 저장됨
    INTERVAL '1 month 1 day', -- 여러 단위에는 문자열 타입 필요; (1 month, 1 day)로 저장됨
    '16 months'::INTERVAL, -- 문자열 캐스트 지원; 16개월로 저장됨
    '48:00:00'::INTERVAL, -- HH::MM::SS 문자열 지원; (48 * 60 * 60 * 1e6 마이크로초)로 저장됨
;

경고: 단위 키워드와 함께 사용할 때 소수 값은 정수로 잘려요(단위가 SECONDSMILLISECONDS인 경우 제외).

SELECT INTERVAL '1.5' YEARS;
-- 12개월 반환; `to_years(CAST(trunc(1.5) AS INTEGER))`와 동일

더 정밀하게 하려면 문자열에 단위를 포함하거나 더 세분화된 단위를 사용해요. 예: INTERVAL '1.5 years' 또는 INTERVAL 18 MONTHS.

세 개의 독립적인 기준 단위가 필요한 이유는, 한 달이 고정된 일수에 대응하지 않고(2월은 3월보다 날이 적음), 하루가 고정된 마이크로초 수에 대응하지 않기 때문이에요(일광 절약 시간 때문에 하루가 25시간 또는 23시간이 될 수 있음). 구성 요소로 나뉘는 덕분에 INTERVAL 클래스는 특정 시간 단위를 날짜에 더하거나 빼는 데 적합해요. 예를 들어 다음 SQL 쿼리로 매월 1일을 담은 테이블을 만들 수 있어요.

SELECT DATE '2000-01-01' + INTERVAL (i) MONTH
FROM range(12) t(i);

INTERVALdatepart 함수로 분해될 때, months 구성 요소는 추가로 연과 월로 분할되고 microseconds 구성 요소는 시, 분, 마이크로초로 분할돼요. days 구성 요소는 추가 단위로 분할되지 않아요. 이를 보여주기 위해 다음 쿼리는 세 기준 단위의 임의 수량을 합해 period라는 INTERVAL을 생성해요. 그런 다음 period에서 앞서 언급한 여섯 부분을 추출해 다시 합치고, 결과가 항상 원래 period와 같음을 확인해요.

SELECT
    period = list_reduce(
        [INTERVAL (datepart(part, period) || part) FOR part IN
             ['year', 'month', 'day', 'hour', 'minute', 'microsecond']
        ],
        (i1, i2) -> i1 + i2
    ) -- 항상 true
FROM (
    VALUES (
        INTERVAL (random() * 123_456_789_123) MICROSECONDS
        + INTERVAL (random() * 12_345) DAYS
        + INTERVAL (random() * 12_345) MONTHS
    )
) _(period);

경고: microseconds 구성 요소는 시, 분, 초(seconds), 마이크로초가 아니라 시, 분, 마이크로초로만 분할돼요.

다음 표는 datepart가 세 기준 단위의 함수로 이 부분들을 어떻게 추출하는지 공식으로 설명해요.

Part Formula
year #months // 12
month #months % 12
day #days
hour #microseconds // (60 * 60 * 1_000_000)
minute (#microseconds // (60 * 1_000_000)) % 60
microsecond #microseconds % (60 * 1_000_000)

추가로 datepartINTERVAL에서 세기(century), 십 년(decade), 분기(quarter), 초(second), 밀리초(millisecond)를 추출하는 데에도 사용할 수 있어요. 그러나 이 부분들은 원래 INTERVAL을 다시 조립할 때는 필요하지 않아요. 사실 이전 쿼리가 이 추가 부분 중 하나라도 추출한다면, 추출된 부분의 합은 일반적으로 원래 period보다 커져요.

Part Formula
century datepart('year', interval) // 100
decade datepart('year', interval) // 10
quarter datepart('month', interval) // 3 + 1
second datepart('microsecond', interval) // 1_000_000
millisecond datepart('microsecond', interval) // 1_000

모든 단위는 0-기반 인덱싱을 사용하지만, 분기(quarter)만 1-기반 인덱싱을 사용해요.

예를 들어:

SELECT
    datepart('decade', INTERVAL 12 YEARS), -- 1 반환
    datepart('year', INTERVAL 12 YEARS), -- 12 반환
    datepart('second', INTERVAL 1_234 MILLISECONDS), -- 1 반환
    datepart('microsecond', INTERVAL 1_234 MILLISECONDS), -- 1_234_000 반환
;

타임스탬프, 날짜, Interval 간의 산술 (Arithmetic with Timestamps, Dates and Intervals)

INTERVAL+- 연산자를 사용해 TIMESTAMP, TIMESTAMPTZ, DATE, TIME에 더하거나 뺄 수 있어요.

SELECT
    DATE '2000-01-01' + INTERVAL 1 YEAR,
    TIMESTAMP '2000-01-01 01:33:30' - INTERVAL '1 month 13 hours',
    TIME '02:00:00' - INTERVAL '3 days 23 hours', -- 감싸짐; TIME '03:00:00'과 동일
;

INTERVALDATE에 더하면 INTERVAL에 마이크로초 구성 요소가 없어도 TIMESTAMP가 반환돼요. 결과는 INTERVAL을 더하기 전에 DATETIMESTAMP로 캐스트한(시간 구성 요소를 00:00:00으로 설정) 것과 같아요.

반대로 두 TIMESTAMP 또는 두 TIMESTAMPTZ를 서로 빼면 days와 microseconds 구성 요소만 가진, 타임스탬프 간의 차이를 설명하는 INTERVAL이 생성돼요. 예를 들어:

SELECT
    TIMESTAMP '2000-02-06 12:00:00' - TIMESTAMP '2000-01-01 11:00:00', -- 36 days 1 hour
    TIMESTAMP '2000-02-01' + (TIMESTAMP '2000-02-01' - TIMESTAMP '2000-01-01'), -- '2000-03-03', NOT '2000-03-01'
;

DATE를 서로 빼면 INTERVAL이 아니라 주어진 날짜 간의 일수를 정수 값으로 반환해요.

경고: 두 TIMESTAMPINTERVAL 차이에서 부분을 추출하는 것은 해당 단위에 대한 두 TIMESTAMP 사이의 파티션 경계 수를 계산하는 것과 동일하지 않아요. 후자는 datediff 함수가 계산해요.

SELECT
    datediff('day', TIMESTAMP '2020-01-01 01:00:00', TIMESTAMP '2020-01-02 00:00:00'), -- 1
    datepart('day', TIMESTAMP '2020-01-02 00:00:00' - TIMESTAMP '2020-01-01 01:00:00'), -- 0
;

동등성과 비교 (Equality and Comparison)

동등성과 정렬 비교만을 위해, INTERVAL의 총 마이크로초 수는 days 기준 단위를 24 * 60 * 60 * 1e6 마이크로초로, months 기준 단위를 30일(30 * 24 * 60 * 60 * 1e6 마이크로초)로 변환해 계산해요.

그 결과 기능적으로 다르더라도 INTERVAL이 동등하게 비교될 수 있고, INTERVAL을 날짜나 타임스탬프에 더할 때 정렬 순서가 항상 보존되지는 않아요.

예를 들어:

  • INTERVAL 30 DAYS = INTERVAL 1 MONTH
  • 하지만 DATE '2020-01-01' + INTERVAL 30 DAYS != DATE '2020-01-01' + INTERVAL 1 MONTH

그리고

  • INTERVAL '30 days 12 hours' > INTERVAL 1 MONTH
  • 하지만 DATE '2020-01-01' + INTERVAL '30 days 12 hours' < DATE '2020-01-01' + INTERVAL 1 MONTH

함수 (Functions)

INTERVAL과 함께 사용할 수 있는 date part 목록은 Date Part Functions 페이지에서 확인해요.

interval을 조작하는 함수는 Interval Operators 페이지에서 확인해요.

더 알아보기 (Learn more)