TECH 으로 돌아가기
TECH HACKER NEWS 오늘 6분 읽기 27 READS

Postgres 'AT TIME ZONE UTC'의 함정: 타입이 바뀐다

Postgres 'AT TIME ZONE UTC'의 함정: 타입이 바뀐다
SOURCE IMAGE · HACKER NEWS

타임존 처리는 데이터베이스에서 가장 실수가 잦은 영역이다. 특히 PostgreSQL을 쓰는 팀이라면 값을 UTC로 맞추려고 습관적으로 AT TIME ZONE 'UTC'를 붙이는 경우가 많은데, 이 구문이 실제로 하는 일은 이름이 주는 인상과 다르다. 최근 공유된 한 기술 글은 이 표현식이 값의 시각을 '보정'해 주는 마법이 아니라 데이터 타입 자체를 바꿔 버리는 연산이라는 점을 짚는다. 그 결과 개발자가 의도하지 않은 타입으로 넘어가면서 조용히 버그가 쌓인다는 것이 핵심 지적이다.

timestamptz가 timestamp로 바뀐다

PostgreSQL에는 시간을 다루는 두 가지 타입이 있다. 하나는 타임존 정보를 함께 관리하는 timestamptz(timestamp with time zone)이고, 다른 하나는 타임존 개념이 없는 timestamp(timestamp without time zone)이다. AT TIME ZONE 'UTC'를 timestamptz 값에 적용하면 그 값을 UTC 기준의 벽시계 시각으로 해석한 뒤, 타임존을 뗀 timestamp 타입으로 되돌려 준다. 즉 이 연산의 본질은 시각 조정이 아니라 타입 변환이다. 원문은 이렇게 해서 사용자가 자기도 모르게 timestamp without time zone을 쓰게 되며, 이 타입은 일반적으로 권장되지 않는다고 강조한다.

권장되지 않는 이유는 단순히 취향의 문제가 아니다. 타임존이 사라진 값은 그 자체로 '언제'를 확정하지 못한다. 같은 2026-09-28 09:00:00이라도 그것이 UTC인지 KST인지에 대한 정보가 값 안에 남아 있지 않기 때문에, 이후 계산과 비교에서 맥락이 통째로 유실된다. 애플리케이션 코드가 암묵적으로 'UTC일 것'이라고 가정하는 순간, 그 가정이 깨지는 지점마다 버그가 생긴다.

비교와 날짜 연산에서 터지는 지뢰

타입이 섞이면 비교 자체가 어긋난다. 원문이 드는 대표적인 예가 timestamp와 timestamptz의 동등 비교가 항상 거짓이 된다는 점이다. 겉으로 같아 보이는 두 값을 =로 비교했는데 결과가 언제나 false로 나온다면, 조인 조건이나 WHERE 절, 중복 제거 로직이 소리 없이 어긋나게 된다. 예외를 던지지 않고 그냥 '아무것도 매칭되지 않는' 형태로 실패하기 때문에 발견이 늦다.

또 하나 지적되는 함정은 날짜 산술이다. + INTERVAL '1 months'처럼 개월 단위를 더하는 연산의 결과가 타임존에 의존한다는 것이다. 한 달을 더하는 계산은 월마다 일수가 다르고 서머타임 같은 변수까지 얽히기 때문에, 어떤 타임존 기준으로 계산하느냐에 따라 결과 시각이 달라질 수 있다. 결제 주기, 구독 갱신일, 리텐션 집계처럼 '정확히 한 달 뒤'가 매출과 직결되는 제품이라면 이 차이가 그대로 금액과 사용자 경험의 오차로 이어진다.

왜 두 번 써야 하는가

글의 부제가 암시하듯, AT TIME ZONE 'UTC'를 두 번 반복해야 하는 상황이 생기는 것도 이 타입 변환 규칙 때문이다. 이 연산은 방향이 대칭적이어서, timestamptz에 적용하면 timestamp가 되고 timestamp에 다시 적용하면 timestamptz로 돌아간다. 결국 원하는 타입이 timestamptz인데 중간에 한 번 변환이 일어났다면, 한 번 더 적용해 원래 타입 계열로 되돌리는 식의 처리가 필요해진다. 무심코 붙인 한 줄이 타입을 왕복시키는 셈이라, 구문을 '시각 보정'으로 오해하면 이 동작을 결코 직관적으로 예측할 수 없다.

실무자가 취할 태도

한국의 서비스 개발 현장에서 이 함정은 남 얘기가 아니다. 서버는 UTC로 돌리고 화면은 KST로 보여 주는 구성이 흔하고, ORM이 생성하는 쿼리나 리포팅용 수기 SQL에서 AT TIME ZONE이 무심코 섞여 들어가기 쉽다. 실무적으로는 저장과 연산의 기준 타입을 timestamptz로 일관되게 유지하고, 표시 단계에서만 타임존을 변환하는 원칙을 세우는 편이 안전하다. 타입이 섞인 비교나 개월 단위 산술이 들어간 쿼리는 리뷰 시 별도로 점검 대상에 올릴 만하다.

다만 이 글은 요약 수준의 문제 제기이며, 각 함정에 대한 세부 재현 조건이나 모든 상황에 통하는 정답 패턴까지 제시하는 것은 아니다. 소개된 사례들은 자신의 스키마와 쿼리에서 직접 재현해 확인한 뒤 대응 방침을 정하는 것이 바람직하다. 그럼에도 'AT TIME ZONE 'UTC'는 시각을 맞춰 주는 것이 아니라 타입을 바꾼다'는 한 문장만 팀 안에서 공유해도, 조용히 새어 나가던 시간 관련 버그의 상당수는 미리 걸러 낼 수 있다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://bookofrevenue.com/blog/6ab81e9a97a13f0001f7e4e1/post...
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...