6. 시간대를 정하라
사고 시나리오
섹션 제목: “사고 시나리오”“7월 3일 00:00 만료”라고 저장했다. 이게 한국 시간인지 UTC인지 아무도 모른다. 한국 시간으로 보면 자정 만료지만, UTC로 저장돼 있었다면 실제 만료는 한국 오전 9시다. 쿠폰 만료, 예약, 구독 갱신, 정산 마감이 몇 시간씩 밀리거나 당겨진다. 더 교묘한 버전도 있다: 저장은 UTC로 잘 해놓고, “하루” 범위 조회를 UTC 날짜 경계로 잘라서 사용자의 자정~오전 9시 데이터가 전날로 집계되는 경우.
저장은 UTC 하나로 통일하고, 사용자에게 보여줄 때와 “하루”의 경계를 계산할 때만 사용자 시간대로 변환한다. 저장·경계·표시 세 지점 각각에 시간대 결정이 있다는 것을 인지해야 한다.
실무 처방
섹션 제목: “실무 처방”- DB에는 UTC 기준(ISO 8601, Z 접미)으로 저장한다. 서버 로컬 시간 저장 금지 — 서버 런타임은 대개 UTC라 개발 머신과 다르게 동작한다.
- 날짜만 받는 입력(“7월 3일”)은 반드시 어느 시간대의 자정인지 정의한다. 사용자용 서비스라면 사용자 시간대의 자정이다.
- 일별 집계·기간 조회의 경계를 사용자 시간대로 계산한 뒤 UTC로 변환해 필터링한다. 저장된 문자열의 날짜 부분을 그대로 자르면 UTC 날짜로 집계된다.
- 화면 표시 함수에 시간대를 명시한다. 지정 없이 로컬 변환에 맡기면 서버 렌더링(UTC)과 브라우저(사용자 시간대)가 다른 값을 그린다.
- 시간대 경계 테스트를 넣는다: 사용자 시간대의 자정 직전·직후 데이터가 옳은 날짜로 집계되는가.
체크리스트
섹션 제목: “체크리스트”- 저장이 전부 UTC ISO 8601이다
- “하루”의 경계가 사용자 시간대 기준으로 계산된다 (집계 포함)
- 표시 함수에 시간대가 명시돼 있다 (서버·브라우저 렌더 일치)
- 자정 경계 케이스 테스트가 있다