메인 콘텐츠로 건너뛰기

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
시간대 버그는 디버깅하기 가장 어려운 버그에 속합니다 — 서버 위치에 따라 나타났다 사라지고, 개발 환경과 프로덕션에서 다르게 보이며, 종종 일광 절약 시간 전환 뒤에야 드러납니다. 근본 원인은 거의 항상 MySQL이 시간을 저장하는 방식과 애플리케이션이 시간을 읽기를 기대하는 방식의 불일치입니다.

DATETIME 대 TIMESTAMP

이 두 타입은 비슷해 보이지만 결정적인 순간 — 조회 — 에 다르게 동작합니다. TIMESTAMP는 값을 자동으로 변환합니다:
  • INSERT/UPDATE 시: 저장을 위해 세션 time_zone에서 UTC로 변환
  • SELECT 시: 표시를 위해 UTC에서 다시 세션 time_zone으로 변환
DATETIME은 아무 변환도 하지 않습니다. 써넣은 값이 그대로 돌아옵니다. 'America/New_York' 같은 이름 있는 시간대는 시간대 테이블이 로드되어 있어야 합니다(아래 이름 있는 시간대를 보세요) — 새로 초기화한 서버에는 그 테이블이 없습니다. 아래 예를 실행하기 전에 SELECT COUNT(*) FROM mysql.time_zone_name;으로 확인하세요; 0이면 먼저 로드하거나 '-05:00' 같은 숫자 오프셋으로 대체하세요.

2038년 문제

TIMESTAMP는 32비트 Unix 타임스탬프로 저장됩니다. 2038-01-19 03:14:07 UTC 이후의 날짜는 표현할 수 없습니다. 미래 날짜를 저장하는 모든 애플리케이션 — 예약, 구독, 예정된 이벤트 — 은 이 한계에 부딪히지 않도록 DATETIME을 사용해야 합니다.

서버 시간대와 세션 시간대

MySQL에는 서로 독립적인 2개의 시간대 설정이 있습니다:
time_zone이 SYSTEM으로 보이면 MySQL은 운영 체제의 시간대를 사용하고 있습니다. 이것은 OS가 바뀔 때까지(서버 이전, DST 전환) 동작합니다 — 그다음에는 타임스탬프가 어긋납니다. 모범 사례: 서버를 명시적으로 UTC로 설정하고, 표시 변환은 애플리케이션에서 처리하세요.
또는 런타임에:

이름 있는 시간대

'+00:00'과 'UTC'는 둘 다 유효하지만, 'America/New_York' 같은 이름 있는 시간대는 시간대 테이블이 로드되어 있어야 합니다. CONVERT_TZ()가 NULL을 반환하거나 이름 있는 시간대가 실패하면 테이블이 없는 것입니다.

AUTO_UPDATE 열

TIMESTAMP 열은 삽입과 갱신 시 자동 채우기를 지원합니다:
세션 시간대가 UTC이면 CURRENT_TIMESTAMP는 UTC로 평가되므로, 누가 어느 시간대에서 연결하든 created_at과 updated_at은 일관되게 저장됩니다. DATETIME과 NOW()로도 같은 일을 할 수 있습니다:
NOW()는 세션 시간대의 현재 날짜와 시간을 반환합니다 — 세션을 UTC로 통일해야 하는 또 하나의 이유입니다.

자주 묻는 질문

타임스탬프를 DATETIME에 UTC로 저장해야 하나요, TIMESTAMP를 써야 하나요?

날짜가 2038년 상한 안에 머문다면 TIMESTAMP가 더 깔끔합니다 — UTC 변환을 자동으로 처리합니다. 2038년 이후의 미래 날짜나 1970년 이전의 과거 날짜를 저장해야 하는 애플리케이션에서는 DATETIME을 사용하고, 삽입 전에 항상 UTC로 변환해서 애플리케이션 계층에서 UTC를 강제하세요.

서버 이전 후 타임스탬프가 어긋나는 이유는 무엇인가요?

이전 서버는 한 OS 시간대를 가리키는 time_zone = SYSTEM을 사용했고, 새 서버는 다른 시간대(또는 UTC)를 가리킵니다. UTC로 저장된 TIMESTAMP 값은 두 시간대 모두에서 올바르게 표시되지만, UTC가 아니라 시스템 시간대를 가정하고 저장된 값이 있다면 어긋납니다. 이전하기 전에 두 서버 모두에서 SELECT @@global.time_zone으로 점검하세요.

시간 부분 없이 날짜만 저장하려면 어떻게 하나요?

DATE를 사용하세요. 3바이트로 저장되고, 시각이나 시간대의 모호함이 없습니다. WHERE date_col = '2024-03-15' 같은 연산은 세션 시간대와 관계없이 모호하지 않습니다.

문제 해결

함께 보기