timestamptz vs timestamp, KST로 하루 밀린 날짜 버그 잡기
포스트그레의 timestamp와 timestamptz 차이 때문에 KST 새벽 데이터가 하루 밀리던 집계 버그를 UTC 저장·표시 변환으로 잡은 방법이에요.
timestamptz vs timestamp, KST로 하루 밀린 날짜 버그 잡기
통계 화면을 열었는데 어제 만든 데이터가 오늘로, 아니면 오늘 새벽에 들어온 게 어제로 잡히던 적 없나요? 저도 관리자 대시보드에서 일별 집계가 하루씩 어긋나는 걸 보고 한참을 들여다봤어요. 범인은 결국 타임존이었어요.
timestamp와 timestamptz는 뭐가 다를까요
포스트그레(PostgreSQL)에는 시간 컬럼이 두 종류예요.
timestamp(timestamp without time zone): 넣은 값을 그대로 저장해요. 타임존 정보가 없어서 이게 UTC인지 KST인지 DB는 몰라요.timestamptz(timestamp with time zone): 입력을 세션 타임존 기준으로 해석해서 내부에는 항상 UTC로 저장하고, 읽을 때 다시 세션 타임존으로 바꿔 돌려줘요.
timestamp(저장값 그대로) vs timestamptz(내부 UTC 저장·조회 시 변환)
둘 다 8바이트라 크기는 같아요. 차이는 변환을 해주느냐예요. 직접 두 컬럼에 같은 값을 넣고 세션 타임존만 바꿔서 조회해 보니, timestamptz만 결과가 9시간씩 움직였어요.
왜 하필 하루가 밀릴까요
한국은 UTC+9라 KST가 UTC보다 9시간 빨라요. 그래서 KST 자정부터 오전 9시 사이(00:0008:59)에 들어온 데이터는 UTC로 바꾸면 전날 15:0023:59가 돼요.
여기서 저장된 UTC 값을 그대로 날짜만 잘라 집계하면, 그 9시간 구간의 기록이 전부 어제로 빠져버려요. 새벽 데이터가 하루 밀리는 정체가 이거였어요. 로그를 찍어 보니 created_at 값은 멀쩡한데 date_trunc('day', created_at) 결과만 하루 전이더라고요.
고친 방법
핵심은 저장은 UTC로, 자르기 직전에만 KST로 변환이에요. 집계 쿼리에서 UTC 값을 먼저 한국 시각으로 옮기고 날짜를 잘랐어요.
date_trunc('day', created_at AT TIME ZONE 'Asia/Seoul')AT TIME ZONE 'Asia/Seoul'이 UTC 시각을 한국 벽시계 시각으로 바꿔줘서, 그다음 날짜를 자르면 달력 기준으로 딱 맞아요. 이렇게 바꿔 적용해 봤더니 새벽 데이터가 제자리를 찾았어요.
- 컬럼은 timestamptz로 통일
- 날짜만 필요하면 date 타입
- 표시 직전에만 KST 변환
정리하면 세 가지예요.
- 시간 컬럼은
timestamptz로 통일해서 저장은 무조건 UTC로 눕혀요. - 생일·만료일처럼 날짜만 쓰는 값은 아예
date타입으로 두면 ±1일 버그 자체가 안 생겨요. - API와 로그는 UTC ISO로 주고받고, 화면에 보일 때만 타임존을 입혀서 표시해요.
플랜씨(plan-c)나 플랜엘(plan-l)처럼 날짜가 곧 데이터의 신뢰인 서비스에서는 이 규칙 하나로 새벽 집계 오류를 안 겪게 됐어요. 혼자 운영하다 보면 이런 조용한 버그가 제일 무서운데, 저장은 UTC로 눕히고 변환은 마지막에 한 번만, 이 순서만 지켜도 대부분 막을 수 있어요.
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.