PostgreSQL(포스트그레스큐엘)에서 시간대(time zone)를 다룰 때 흔히 사용되는 'AT TIME ZONE 'UTC'' 구문이 예상치 못한 함정을 가지고 있어 개발자들의 주의가 요구됩니다. 이 구문은 단순히 시간대만 변경하는 것이 아니라, 시간대 정보가 포함된 'timestamptz' 타입을 시간대 정보가 없는 'timestamp' 타입으로 암묵적으로 변환시키는 부작용이 있습니다. 이로 인해 월 단위 덧셈과 같은 시간대에 의존적인 연산에서 데이터 불일치나 오류가 발생할 수 있습니다.
PostgreSQL에는 'timestamp'와 'timestamptz' 두 가지 타임스탬프 타입이 있습니다. 'timestamp'는 시간대 정보 없이 날짜와 시각만 저장하므로, 특정 시점을 정확히 나타내려면 해석하는 시간대 정보가 필요합니다. 반면 'timestamptz'는 내부적으로 UTC(협정 세계시) 시각을 저장하며, 사용자의 세션 시간대에 맞춰 자동으로 변환하여 보여줍니다. 문제는 'AT TIME ZONE 'UTC''를 'timestamptz'에 적용하면, 결과가 'timestamp' 타입으로 바뀌면서 시간대 정보가 사라진다는 점입니다. 예를 들어, '2026-02-28 16:00:00-08'::timestamptz에 이 구문을 적용하면 '2026-03-01 00:00:00'이라는 'timestamp' 타입의 결과가 나옵니다. 이처럼 타입이 변환되면, 월별 차이 계산 등 'timestamptz' 타입 간의 비교가 필요한 쿼리에서 문제가 발생할 수 있습니다. 특히 UTC 기준의 월초가 다른 시간대에서는 전월 말일이 될 수 있어, 'INTERVAL '1 months'' 같은 월 단위 덧셈 연산 시 의도와 다른 결과가 나올 위험이 있습니다.
이러한 문제를 해결하기 위해서는 'AT TIME ZONE 'UTC''를 적용한 후에도 연산 결과가 여전히 'timestamp' 타입임을 인지하고, 필요에 따라 다시 'AT TIME ZONE 'UTC''를 적용하여 'timestamptz' 타입으로 되돌려야 합니다. 예를 들어, '((b.month_start AT TIME ZONE 'UTC') + INTERVAL '1 months') AT TIME ZONE 'UTC''와 같이 두 번의 변환을 통해 정확한 비교를 수행할 수 있습니다. 또한, PostgreSQL 16 버전부터는 'date_add(b.month_start, interval '1 month', 'UTC')'와 같이 시간대를 세 번째 인수로 지정하여 'timestamptz' 타입을 유지하며 월을 더하는 기능이 추가되어 이러한 복잡성을 줄일 수 있습니다. 이처럼 시간대 처리는 복잡하고 미묘한 부분이 많으므로, 개발 시에는 데이터베이스의 시간 처리 방식에 대한 깊은 이해와 함께 애플리케이션 레벨에서 명확한 시간 관리 전략을 수립하는 것이 중요합니다.