DateTime 데이터 타입

DateTime 데이터 타입

캘린더 날짜와 하루 중 시각으로 표현할 수 있는 순간(instant)을 저장하는 데이터 타입이에요. 지원 범위는 [1970-01-01 00:00:00, 2106-02-07 06:28:15]이고, 분해능(resolution)은 1초예요.

출처: 문서

본문

캘린더 날짜와 하루 중 시각으로 표현할 수 있는 순간을 저장할 수 있어요.

문법:

DateTime([timezone])

지원 범위는 [1970-01-01 00:00:00, 2106-02-07 06:28:15]이에요. 분해능은 1초예요.

속도 (Speed)

Date 데이터 타입은 대부분의 조건에서 DateTime보다 빨라요. Date 타입은 2바이트 저장 공간이 필요한 반면 DateTime은 4바이트가 필요해요. 그런데 압축 과정에서 DateDateTime의 크기 차이는 더 커져요. 이 확대는 DateTime의 분·초 부분이 압축이 잘 안 되기 때문에 발생해요. DateTime 대신 Date로 필터링·집계하는 것도 더 빨라요.

사용 시 유의점 (Usage Remarks)

시점은 시간대나 일광 절약 시간제와 무관하게 Unix timestamp로 저장돼요. 시간대는 DateTime 타입 값이 텍스트 형식으로 표시되는 방식과, 문자열로 지정된 값('2020-01-01 05:00:01')이 파싱되는 방식에 영향을 줘요. 테이블에는 시간대에 무관한 Unix timestamp가 저장되고, 시간대는 이를 텍스트 형식으로 변환하거나 데이터 가져오기/내보내기 시 다시 되돌리는 데, 또는 값에 대해 캘린더 계산을 할 때(toDate, toHour 함수 등) 사용돼요. 시간대는 테이블 행(또는 결과셋)에 저장되지 않고 컬럼 메타데이터에 저장돼요.

지원되는 시간대 목록은 IANA Time Zone Database에서 찾을 수 있고, SELECT * FROM system.time_zones로도 조회할 수 있어요. 목록은 Wikipedia에서도 볼 수 있어요.

테이블을 만들 때 DateTime 타입 컬럼에 시간대를 명시적으로 설정할 수 있어요. 예: DateTime('UTC'). 시간대를 설정하지 않으면 ClickHouse는 timezone 서버 설정의 값 또는 ClickHouse 서버 시작 시점의 운영체제 설정 값을 사용해요.

clickhouse-client는 데이터 타입을 초기화할 때 시간대를 명시적으로 설정하지 않으면 기본적으로 서버 시간대를 적용해요. 클라이언트 시간대를 사용하려면 --use_client_time_zone 파라미터와 함께 clickhouse-client를 실행해요.

ClickHouse는 date_time_output_format 설정의 값에 따라 값을 출력해요. 기본값은 YYYY-MM-DD hh:mm:ss 텍스트 형식이에요. 또한 formatDateTime 함수로 출력을 바꿀 수 있어요. ClickHouse에 데이터를 넣을 때는 date_time_input_format 설정의 값에 따라 다양한 날짜·시간 문자열 형식을 사용할 수 있어요.

예시 (Examples)

1. DateTime 타입 컬럼이 있는 테이블을 만들고 데이터를 넣는 예시에요.

CREATE TABLE dt
(
    `timestamp` DateTime('Asia/Istanbul'),
    `event_id` UInt8
)
ENGINE = TinyLog;
-- Parse DateTime
-- - from a string,
-- - from a number interpreted as the number of seconds since 1970-01-01 (a fractional part is truncated to whole seconds).
INSERT INTO dt VALUES ('2019-01-01 00:00:00', 1), (1546300800, 2);

SELECT * FROM dt;
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │        1 │
│ 2019-01-01 03:00:00 │        2 │
└─────────────────────┴──────────┘
  • datetime을 숫자로 넣으면 초 단위의 Unix Timestamp(UTC)로 취급돼요. 1546300800은 UTC 기준 '2019-01-01 00:00:00'을 나타내요. 그런데 timestamp 컬럼에 Asia/Istanbul(UTC+3) 시간대가 지정되어 있으므로, 문자열로 출력할 때 값은 '2019-01-01 03:00:00'으로 보여져요. 소수부나 지수부가 있는 숫자도 받아들이며, CAST, toDateTime, Values 형식과 일관되게 초 단위로 잘라요. (26.8 버전 이전에는 JSONValues/Quoted 입력 경로 — 후자는 Quoted 이스케이프 규칙으로 필드를 파싱하는 모든 형식(Values, MySQLDump, Quoted 필드 이스케이프로 구성된 Template/CustomSeparated/Regexp)을 포함 — 에서 그러한 소수·지수 숫자를 스트리밍 파서가 받아들이지 않았어요. 그것을 복원하려면 input_format_read_datetime_number_as_raw_value = 1로 설정해요. Values 형식 자체에서는 그런 리터럴이 SQL 표현식 폴백을 통해 여전히 동작했고(초 수로 읽음), 호환 모드에서도 계속 동작해요. JSONExtractJSON 데이터 타입에서는 소수 값이 Float64로 파싱되므로, 정확히 원문 텍스트를 자르는 행 입력 형식들과 달리 정수 초 경계에 근접한 값이 인접한 초로 반올림될 수 있어요. 탭으로 구분된 형식, CSV 및 기타 이스케이프 텍스트 형식은 이 설정의 적용을 받지 않아요.)

  • datetime을 문자열 값으로 넣으면 컬럼 시간대 기준으로 취급돼요. '2019-01-01 00:00:00'Asia/Istanbul 시간대 기준으로 취급되어 1546290000으로 저장돼요.

2. DateTime 값 필터링

SELECT * FROM dt WHERE timestamp = toDateTime('2019-01-01 00:00:00', 'Asia/Istanbul')
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │        1 │
└─────────────────────┴──────────┘

DateTime 컬럼 값은 WHERE 술어의 문자열 값을 사용해 필터링할 수 있어요. 그 값은 자동으로 DateTime으로 변환돼요.

SELECT * FROM dt WHERE timestamp = '2019-01-01 00:00:00'
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │        1 │
└─────────────────────┴──────────┘

3. DateTime 타입 컬럼의 시간대 얻기

SELECT toDateTime(now(), 'Asia/Istanbul') AS column, toTypeName(column) AS x
┌──────────────column─┬─x─────────────────────────┐
│ 2019-10-16 04:12:04 │ DateTime('Asia/Istanbul') │
└─────────────────────┴───────────────────────────┘

4. 시간대 변환

SELECT
toDateTime(timestamp, 'Europe/London') AS lon_time,
toDateTime(timestamp, 'Asia/Istanbul') AS istanbul_time
FROM dt
┌───────────lon_time──┬───────istanbul_time─┐
│ 2019-01-01 00:00:00 │ 2019-01-01 03:00:00 │
│ 2018-12-31 21:00:00 │ 2019-01-01 00:00:00 │
└─────────────────────┴─────────────────────┘

시간대 변환은 메타데이터만 바꾸므로 연산 비용이 없어요.

시간대 지원 제한 (Limitations on time zones support)

일부 시간대는 완전히 지원되지 않을 수 있어요. 다음과 같은 경우가 있어요.

UTC와의 차이가 15분의 배수가 아니면 시·분 계산이 부정확할 수 있어요. 예를 들어 라이베리아 몬로비아(Monrovia)의 시간대는 1972년 1월 7일 이전에 UTC -0:44:30 오프셋이었어요. 몬로비아 시간대의 과거 시각을 계산한다면 시간 처리 함수가 틀린 결과를 낼 수 있어요. 1972년 1월 7일 이후의 결과는 그럼에도 정확해요.

시간 전환(일광 절약 시간제나 다른 이유로)이 15분의 배수가 아닌 시점에 수행된 경우, 그 특정 날짜에 틀린 결과가 나올 수도 있어요.

단조롭지 않은 캘린더 날짜. 예를 들어 Happy Valley - Goose Bay에서는 2010년 11월 7일 00:01:00(자정 1분 후)에 시간을 한 시간 뒤로 전환했어요. 그래서 11월 6일이 끝난 뒤 사람들은 11월 7일의 1분 전체를 관찰한 다음, 시간이 11월 6일 23:01로 되돌아갔고, 다시 59분 후에 11월 7일이 시작됐어요. ClickHouse는 (아직) 이런 재미를 지원하지 않아요. 이런 날 동안 시간 처리 함수의 결과가 약간 부정확할 수 있어요.

케이시(Casey) 남극 기지에도 2010년에 비슷한 문제가 있었어요. 그들은 3월 5일 02:00에 시간을 세 시간 뒤로 바꿨어요. 남극 기지에서 작업한다면 ClickHouse를 쓰는 걸 두려워하지 마세요. 시간대를 UTC로 설정하거나 부정확함을 감안하면 돼요.

여러 날에 걸친 시간 이동. 일부 태평양 섬들이 시간대 오프셋을 UTC+14에서 UTC-12로 바꿨어요. 별문제는 아니지만, 전환일의 과거 시점에 대해 해당 시간대로 계산하면 약간의 부정확함이 있을 수 있어요.

일광 절약 시간제(DST) 처리 (Handling daylight saving time)

시간대가 있는 ClickHouse의 DateTime 타입은 일광 절약 시간제(DST) 전환 중, 특히 다음 경우에 예상 밖의 동작을 보일 수 있어요.

  • date_time_output_formatsimple로 설정된 경우
  • 시계가 뒤로 움직여("Fall Back") 한 시간이 겹치는 경우
  • 시계가 앞으로 움직여("Spring Forward") 한 시간이 없어지는 경우

기본적으로 ClickHouse는 항상 겹치는 시간의 더 이른 발생을 선택하며, 앞으로 이동 중에는 존재하지 않는 시간을 해석할 수 있어요. 예를 들어 일광 절약 시간제(DST)에서 표준시로 전환되는 다음 경우를 생각해 볼게요.

  • 2023년 10월 29일 02:00:00에 시계가 01:00:00으로 뒤로 움직여요(BST → GMT).
  • 01:00:00 – 01:59:59 시간이 두 번 나타나요(BST에서 한 번, GMT에서 한 번).
  • ClickHouse는 항상 첫 번째 발생(BST)을 선택하므로, 시간 간격을 더할 때 예상 밖의 결과가 생겨요.
SELECT '2023-10-29 01:30:00'::DateTime('Europe/London') AS time, time + toIntervalHour(1) AS one_hour_later

┌────────────────time─┬──────one_hour_later─┐
│ 2023-10-29 01:30:00 │ 2023-10-29 01:30:00 │
└─────────────────────┴─────────────────────┘

마찬가지로 표준시에서 일광 절약 시간제로 전환하는 동안에는 한 시간이 생략된 것처럼 보일 수 있어요. 예를 들어:

  • 2023년 3월 26일 00:59:59에 시계가 02:00:00으로 앞으로 점프해요(GMT → BST).
  • 01:00:0001:59:59 시간이 존재하지 않아요.
SELECT '2023-03-26 01:30:00'::DateTime('Europe/London') AS time, time + toIntervalHour(1) AS one_hour_later

┌────────────────time─┬──────one_hour_later─┐
│ 2023-03-26 00:30:00 │ 2023-03-26 02:30:00 │
└─────────────────────┴─────────────────────┘

이 경우 ClickHouse는 존재하지 않는 시간 2023-03-26 01:30:002023-03-26 00:30:00으로 뒤로 옮겨요.

더 알아보기 (Learn more)