lifecarelog
제품소개

UTC로 저장하고 KST로 보여주기: Postgres 타임존 함정

동호회 앱 경기 시간이 어긋나는 건 대부분 타임존 정보가 빠진 자리예요. 저장은 UTC, 표시는 KST로 정리하는 실전 원칙을 담았어요.

4분 읽기

동호회 앱에서 경기 시간을 오후 8시로 등록했는데, 화면엔 다음날 새벽 5시로 뜬 적 없나요? 플랜비(plan-b)를 만들면서 직접 겪어 보니, 이런 어긋남은 대부분 코드 버그가 아니라 타임존 정보가 중간에 사라진 자리에서 생겨요.

시간은 세 번 경계를 넘어요

하나의 시각 값은 저장·전송·표시라는 3단계 경계를 넘나들어요. 이 중 한 곳에서라도 "이 시간이 어느 지역 기준인지"가 빠지면, 받는 쪽이 제멋대로 해석해요. 한국은 UTC보다 9시간 빠른데(KST = UTC+9), 이 9시간이 어디선가 한 번 더 더해지면 오후 8시가 다음날 새벽 5시로 밀려요.

입력(KST)저장(UTC)표시(KST)

저장은 UTC로 통일해요

가장 덜 헷갈리는 규칙은 하나예요. 저장은 항상 UTC, 보여줄 때만 KST로 변환. Postgres라면 timestamp가 아니라 timestamptz를 쓰세요. 이름은 비슷하지만 동작이 달라요. 둘 다 8바이트지만, timestamp는 지역 정보를 버리고 숫자만 남겨요. 반대로 timestamptz는 값을 내부적으로 UTC로 맞춰 저장하고, 읽을 때 세션 타임존으로 돌려줘요. 직접 확인해 보니 이 차이 하나로 새벽 버그가 사라지더라고요.

API 경계에서 오프셋을 붙여요

진짜 문제는 프런트와 서버 사이예요. 시각을 문자열로 주고받을 때 2026-08-01T20:00처럼 오프셋 없이 보내면, 서버가 이걸 UTC로 읽을지 KST로 읽을지 알 수 없어요. 그래서 API로 넘길 땐 끝에 Z+09:00이 붙은 ISO 8601 형식으로 보내는 게 안전해요. 자바스크립트라면 toISOString()이 UTC 기준 문자열을 만들어 주는데, 돌려 보니 이걸 전송 표준으로 정하고 나서 혼선이 확 줄었어요.

  • 저장은 UTC
  • 전송은 오프셋 포함
  • 표시만 KST 변환

날짜만 있는 값은 따로 다뤄요

생일이나 회비 납부일처럼 시각이 없는 순수 날짜는 timestamp에 넣지 마세요. 테스트해 보면 자정 근처에서 ±1일씩 밀리는 함정이 있어요. 플랜씨(plan-c)의 복리 계산처럼 날짜 경계가 결과를 바꾸는 곳이라면 특히 조심해야 해요. 이런 값은 date 타입이나 YYYY-MM-DD 문자열로 분리해서, 시간대 변환 자체가 일어나지 않게 막는 편이 마음 편했어요.

작은 도구를 혼자 운영하다 보면, 이런 경계 하나를 정리해 두는 게 나중에 반복되는 문의를 꽤 줄여 줘요. 시간은 저장할 때 한 번만 UTC로 눕혀두고, 보여줄 때 일으켜 세우면 돼요.

#타임존#Postgres#백엔드

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.