날짜 시간 데이터 타입

날짜 시간 데이터 타입 (Date-time data types)

시계열 데이터 관리를 위한 ClickHouse의 날짜/시간 데이터 타입과 타임존 처리, 변환 함수를 살펴봐요.

출처: 문서

본문

효과적인 시계열 데이터 관리를 위해서는 포괄적인 날짜와 시간 타입 세트가 필요하며 ClickHouse는 정확히 그것을 제공해요. 나노초 정확도의 고정밀 타임스탬프까지, 컴팩트한 날짜 표현부터 이러한 타입들은 서로 다른 시계열 애플리케이션의 저장 효율과 실용적 요구 사항의 균형을 맞추도록 설계되었어요. 과거 금융 데이터든 IoT 센서 판독값이든 미래 날짜 이벤트든, ClickHouse의 날짜와 시간 타입은 다양한 시간 데이터 시나리오를 처리하는 데 필요한 유연성을 제공해요. 지원되는 타입의 범위를 통해 스토리지 공간과 쿼리 성능을 모두 최적화하면서 사용 사례가 요구하는 정밀도를 유지할 수 있어요.

  • Date 타입은 대부분의 경우 충분해요. 이 타입은 날짜 저장에 2바이트가 필요하고 범위가 [1970-01-01, 2149-06-06]로 제한돼요.
  • Date32는 더 넓은 날짜 범위를 다뤄요. 날짜 저장에 4바이트가 필요하고 범위가 [0000-01-01, 9999-12-31]로 제한돼요.
  • DateTime은 초 단위 정밀도로 날짜-시간 값을 저장하며 범위가 [1970-01-01 00:00:00, 2106-02-07 06:28:15]예요. 값당 4바이트가 필요해요.
  • 더 많은 정밀도가 필요한 경우 DateTime64를 사용할 수 있어요. 최대 나노초까지 정밀도로 시간을 저장할 수 있으며 범위가 [1900-01-01 00:00:00, 2299-12-31 23:59:59.99999999]예요. 값당 8바이트가 필요해요.

다양한 날짜 타입을 저장하는 테이블을 만들어 볼게요:

CREATE TABLE dates
(
    `date` Date,
    `wider_date` Date32,
    `datetime` DateTime,
    `precise_datetime` DateTime64(3),
    `very_precise_datetime` DateTime64(9)
)
ENGINE = MergeTree
ORDER BY tuple();

now() 함수로 현재 시간을 반환하고 now64()로 첫 번째 인자를 통해 지정된 정밀도로 가져올 수 있어요.

INSERT INTO dates
SELECT now(),
       now()::Date32 + toIntervalYear(100),
       now(),
       now64(3),
       now64(9) + toIntervalYear(200);

이러면 컬럼 타입에 따라 컬럼에 시간이 채워져요:

SELECT * FROM dates
FORMAT Vertical;
Row 1:
──────
date:                  2025-03-12
wider_date:            2125-03-12
datetime:              2025-03-12 11:39:07
precise_datetime:      2025-03-12 11:39:07.196
very_precise_datetime: 2025-03-12 11:39:07.196724000

Time 및 Time64 타입

날짜 컴포넌트 없이 하루 중 시간 값만 저장해야 하는 시나리오에는 ClickHouse가 25.6 버전에서 도입된 TimeTime64 타입을 제공해요. 이 타입들은 반복 스케줄, 일일 패턴, 또는 날짜와 시간 컴포넌트를 분리하는 것이 합리적인 상황을 나타내는 데 유용해요.

TimeTime64를 사용하려면 설정을 활성화해야 해요: SET enable_time_time64_type = 1;이 타입들은 25.6 버전에서 도입되었어요.

Time 타입은 초 단위 정밀도로 시간, 분, 초를 저장해요. 내부적으로 부호 있는 32비트 정수로 저장되며 [-999:59:59, 999:59:59] 범위를 지원해서 24시간을 초과하는 값도 허용해요. 이는 경과 시간을 추적하거나 단일 하루를 벗어나는 값이 나오는 산술 연산을 수행할 때 유용할 수 있어요. 초 미만 정밀도가 필요하면 Time64는 부호 있는 Decimal64 값으로 구성 가능한 소수 자릿수와 함께 시간을 저장해요. 자릿수 수를 정의하는 정밀도 매개변수(0-9)를 받아요. 일반적인 정밀도 값은 3(밀리초), 6(마이크로초), 9(나노초)예요. TimeTime64 모두 타임존을 지원하지 않아요 — 지역 컨텍스트 없는 순수한 하루 중 시간 값을 나타내요. 시간 컬럼이 있는 테이블을 만들어 볼게요:

SET enable_time_time64_type = 1;

CREATE TABLE time_examples
(
    `event_id` UInt8,
    `basic_time` Time,
    `precise_time` Time64(3)
)
ENGINE = MergeTree
ORDER BY event_id;

문자열 리터럴이나 숫자 값으로 시간 값을 삽입할 수 있어요. Time의 경우 숫자 값은 00:00:00 이후의 초로 해석돼요. Time64의 경우 숫자 값은 00:00:00 이후의 초로 해석되며 소수 부분은 컬럼의 정밀도에 따라 해석돼요:

INSERT INTO time_examples VALUES
    (1, '14:30:25', '14:30:25.123'),
    (2, 52225, 52225.456),
    (3, '26:11:10', '26:11:10.789');  -- Values normalize beyond 24 hours
SELECT * FROM time_examples ORDER BY event_id;
┌─event_id─┬─basic_time─┬─precise_time─┐
│        1 │ 14:30:25   │ 14:30:25.123 │
│        2 │ 14:30:25   │ 14:30:25.456 │
│        3 │ 26:11:10   │ 26:11:10.789 │
└──────────┴────────────┴──────────────┘

시간 값은 자연스럽게 필터링할 수 있어요:

SELECT * FROM time_examples WHERE basic_time = '14:30:25';

타임존 (Timezones)

많은 사용 사례에서 타임존도 저장해야 해요. DateTime 또는 DateTime64 타입의 마지막 인자로 타임존을 설정할 수 있어요:

CREATE TABLE dtz
(
    `id` Int8,
    `dt_1` DateTime('Europe/Berlin'),
    `dt_2` DateTime,
    `dt64_1` DateTime64(9, 'Europe/Berlin'),
    `dt64_2` DateTime64(9)
)
ENGINE = MergeTree
ORDER BY id;

DDL에서 타임존을 정의했으므로 이제 다른 타임존을 사용해 시간을 삽입할 수 있어요:

INSERT INTO dtz
SELECT 1,
       toDateTime('2022-12-12 12:13:14', 'America/New_York'),
       toDateTime('2022-12-12 12:13:14', 'America/New_York'),
       toDateTime64('2022-12-12 12:13:14.123456789', 9, 'America/New_York'),
       toDateTime64('2022-12-12 12:13:14.123456789', 9, 'America/New_York')
UNION ALL
SELECT 2,
       toDateTime('2022-12-12 12:13:15'),
       toDateTime('2022-12-12 12:13:15'),
       toDateTime64('2022-12-12 12:13:15.123456789', 9),
       toDateTime64('2022-12-12 12:13:15.123456789', 9);

이제 테이블에 무엇이 있는지 살펴볼게요:

SELECT dt_1, dt64_1, dt_2, dt64_2
FROM dtz
FORMAT Vertical;
Row 1:
──────
dt_1:   2022-12-12 18:13:14
dt64_1: 2022-12-12 18:13:14.123456789
dt_2:   2022-12-12 17:13:14
dt64_2: 2022-12-12 17:13:14.123456789

Row 2:
──────
dt_1:   2022-12-12 13:13:15
dt64_1: 2022-12-12 13:13:15.123456789
dt_2:   2022-12-12 12:13:15
dt64_2: 2022-12-12 12:13:15.123456789

첫 번째 행에서는 모든 값을 America/New_York 타임존으로 삽입했어요.

  • dt_1dt64_1은 쿼리 시점에 Europe/Berlin으로 자동 변환돼요.
  • dt_2dt64_2는 타임존이 지정되지 않아 이 경우 Europe/London인 서버의 로컬 타임존을 사용해요.

두 번째 행에서는 타임존 없이 모든 값을 삽입했으므로 서버의 로컬 타임존이 사용됐어요. 첫 번째 행과 마찬가지로 dt_1dt64_1Europe/Berlin으로 변환되고, dt_2dt64_2는 서버의 로컬 타임존을 사용해요.

날짜 시간 함수

ClickHouse는 서로 다른 데이터 타입 사이를 변환하게 해주는 함수 집합도 제공해요. 예를 들어 toDate를 사용해 DateTime 값을 Date 타입으로 변환할 수 있어요:

SELECT
    now() AS current_time,
    toTypeName(current_time),
    toDate(current_time) AS date_only,
    toTypeName(date_only)
FORMAT Vertical;
Row 1:
──────
current_time:             2025-03-12 12:32:54
toTypeName(current_time): DateTime
date_only:                2025-03-12
toTypeName(date_only):    Date

toDateTime64를 사용해 DateTimeDateTime64로 변환할 수 있어요:

SELECT
    now() AS current_time,
    toTypeName(current_time),
    toDateTime64(current_time, 3) AS date_only,
    toTypeName(date_only)
FORMAT Vertical;
Row 1:
──────
current_time:             2025-03-12 12:35:01
toTypeName(current_time): DateTime
date_only:                2025-03-12 12:35:01.000
toTypeName(date_only):    DateTime64(3)

그리고 toDateTime를 사용해 DateDateTime64에서 다시 DateTime으로 갈 수 있어요:

SELECT
    now64() AS current_time,
    toTypeName(current_time),
    toDateTime(current_time) AS date_time1,
    toTypeName(date_time1),
    today() AS current_date,
    toTypeName(current_date),
    toDateTime(current_date) AS date_time2,
    toTypeName(date_time2)
FORMAT Vertical;
Row 1:
──────
current_time:             2025-03-12 12:41:00.598
toTypeName(current_time): DateTime64(3)
date_time1:               2025-03-12 12:41:00
toTypeName(date_time1):   DateTime
current_date:             2025-03-12
toTypeName(current_date): Date
date_time2:               2025-03-12 00:00:00
toTypeName(date_time2):   DateTime

더 알아보기 (Learn more)