__date/__year/__month같은 날짜 필터가 로컬에서만 0건 나온다면, 로컬 MySQL의 타임존 테이블이 비어 있어서CONVERT_TZ가NULL을 반환하는 게 원인일 수 있다. (배경 개념은 Django + MySQL 타임존 글 참고)
이 글은 Windows에 직접 설치된 MySQL에서 공식 SQL 덤프로 타임존 테이블을 적재하는 실전 절차다.
timezone_posix.sql을 꺼낸다.Get-Content ...sql | mysql.exe -u root -p mysql 로 import.CONVERT_TZ('2026-06-08 05:00:00','UTC','Asia/Seoul') 가 NULL이 아니라 14:00:00이면 성공.먼저 문제가 실재하는지 확인한다. (읽기 전용, 안전)
& "C:\Program Files\MySQL\MySQL Server 8.4\bin\mysql.exe" -u root -p -e "SELECT COUNT(*) AS tz_rows FROM mysql.time_zone_name; SELECT CONVERT_TZ('2026-06-08 05:00:00','UTC','Asia/Seoul') AS converted;"
mysql.exe는 보통 PATH에 등록돼 있지 않다.C:\Program Files\MySQL\MySQL Server <버전>\bin\mysql.exe전체 경로로 호출한다. (경로에 공백이 있어 PowerShell에서는&호출 연산자가 필요하다.)
적재 전 결과 예:
+---------+
| tz_rows |
+---------+
| 1 | <- 사실상 비어 있음
+---------+
+-----------+
| converted |
+-----------+
| NULL | <- CONVERT_TZ 실패
+-----------+
converted가 NULL이면 타임존 테이블 적재가 필요하다.
https://dev.mysql.com/downloads/timezones.html 에 접속하면 두 종류가 보인다.
timezone_2026b_posix_sql.zip - POSIX standard ← 이것을 받는다
timezone_2026b_leaps_sql.zip - Non POSIX with leap seconds ← 받지 않는다
Asia/Seoul(UTC+9 고정, 서머타임 없음) 날짜 변환을 프로덕션과 동일하게 만드는 것이다. 프로덕션도 일반적으로 POSIX 기준이므로 POSIX를 받아야 동작이 일치한다.2026b는 IANA 타임존 DB 버전이다. 한국은 서머타임이 없어 버전 차이의 영향을 받지 않으니, 페이지에 보이는 최신 POSIX 버전을 받으면 된다.다운로드에는 Oracle 계정 로그인이 요구될 수 있다. 페이지 하단의 "No thanks, just start my download" 링크로 로그인 없이 받을 수도 있다.
받은 zip을 풀면 timezone_posix.sql 파일이 들어 있다.
Expand-Archive -Path "$env:USERPROFILE\Downloads\timezone_2026b_posix_sql.zip" -DestinationPath "$env:USERPROFILE\Downloads\timezone_2026b_posix_sql" -Force
Get-ChildItem "$env:USERPROFILE\Downloads\timezone_2026b_posix_sql" -Recurse -Filter *.sql | Select-Object FullName
출력된 .sql 전체 경로를 STEP 3에 사용한다. (예: C:\Users\<사용자>\Downloads\timezone_2026b_posix_sql\timezone_posix.sql)
mysql에 importroot 비밀번호 입력이 필요하므로, 비밀번호가 로그에 남지 않도록 터미널에서 직접 실행한다.
Get-Content "C:\Users\<사용자>\Downloads\timezone_2026b_posix_sql\timezone_posix.sql" | & "C:\Program Files\MySQL\MySQL Server 8.4\bin\mysql.exe" -u root -p mysql
Enter password: 프롬프트에 root 비밀번호를 입력한다. 에러 없이 프롬프트로 돌아오면 성공이다.
Get-Content ...sql | — PowerShell은 mysql < file.sql 같은 입력 리다이렉션을 지원하지 않는다('<' 연산자는 예약되어 있습니다 에러). 대신 Get-Content로 파일을 읽어 파이프로 넘긴다.& "...\mysql.exe" — 경로에 공백(Program Files)이 있으므로 &(호출 연산자)로 실행한다.-u root -p — -p만 쓰면 프롬프트로 비밀번호를 물어본다. 명령줄에 비밀번호를 붙이지 않는 편이 안전하다.mysql — import 대상 데이터베이스 이름이다. 앱 DB(smartsilvercenter)가 아니라 시스템 스키마 mysql에 넣는다. 타임존 테이블은 서버 전역으로 공유되므로, 한 번 넣으면 모든 DB의 쿼리에 자동 적용된다. 이 인자를 빼면 No database selected 에러가 난다.즉, "특정 DB에 적용"이 아니라 "이 MySQL 서버 전체에 적용"이다. 결과적으로
smartsilvercenter의CONVERT_TZ가 동작하게 된다.
& "C:\Program Files\MySQL\MySQL Server 8.4\bin\mysql.exe" -u root -p -e "SELECT COUNT(*) AS tz_rows FROM mysql.time_zone_name; SELECT CONVERT_TZ('2026-06-08 05:00:00','UTC','Asia/Seoul') AS converted;"
적재 후 결과 예:
+---------+
| tz_rows |
+---------+
| 598 | <- 타임존 이름이 채워짐
+---------+
+---------------------+
| converted |
+---------------------+
| 2026-06-08 14:00:00 | <- UTC 05:00 + 9 = KST 14:00, 정상 동작
+---------------------+
| 항목 | 적재 전 | 적재 후 |
|---|---|---|
tz_rows | 1 | 598 |
converted | NULL | 2026-06-08 14:00:00 |
converted가 NULL에서 한국시간으로 바뀌면 CONVERT_TZ가 정상 동작하는 것이다.
개념 검증(CONVERT_TZ)이 끝났으면, 실제로 깨졌던 날짜 필터 API가 정상 응답하는지 확인한다.
/api/v2/broadcasting/?start_date=2026-04-26&end_date=2026-06-07
적재 전 0건이던 응답이 정상 건수로 돌아오면 완전히 해결된 것이다.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
→ 비밀번호 오타. 명령을 다시 실행하고 비밀번호를 정확히 입력한다. (이 경우 import는 아무것도 적재되지 않았으므로, 올바른 비밀번호로 STEP 3를 다시 실행하면 된다.)
'<' 연산자는 나중에 사용하도록 예약되어 있습니다
→ PowerShell에서 mysql < file.sql을 쓴 경우다. Get-Content file.sql | mysql.exe ... 파이프 형태로 바꾼다.
'mysql'은(는) ... 인식되지 않습니다
→ mysql이 PATH에 없다. & "C:\Program Files\MySQL\MySQL Server 8.4\bin\mysql.exe" 전체 경로로 호출한다.
No database selected
→ import 명령 끝에 대상 DB mysql을 빠뜨린 경우다. ... mysql.exe -u root -p mysql처럼 맨 끝에 mysql을 붙인다.
Windows 네이티브 MySQL에서
CONVERT_TZ가NULL을 뱉으면, MySQL 공식 사이트의 POSIX standard 타임존 SQL 덤프를 받아Get-Content ...sql | mysql.exe -u root -p mysql로 시스템 스키마mysql에 import하면 된다. 코드 변경 없이 로컬이 프로덕션과 동일하게 동작한다.