# 타임존 설정 작업 계획 ## 개요 프로젝트 전체에 서울 타임존(Asia/Seoul, UTC+9)을 일관되게 적용합니다. --- ## 현재 상태 ### 완료된 설정 | 구성 요소 | 상태 | 비고 | |----------|------|------| | **MySQL 데이터베이스** | ✅ 완료 | DB 생성 시 Asia/Seoul로 설정됨 | | **config.py** | ✅ 완료 | `TIMEZONE = ZoneInfo("Asia/Seoul")` 설정됨 | | **SQLAlchemy 모델** | ✅ 정상 | `server_default=func.now()` → DB 타임존(서울) 따름 | ### 문제점 - Python 코드에서 `datetime.now()` (naive) 또는 `datetime.now(timezone.utc)` (UTC) 혼용 - 타임존이 적용된 현재 시간을 얻는 공통 유틸리티 없음 --- ## 수정 대상 파일 | 파일 | 라인 | 현재 코드 | 문제 | |------|------|----------|------| | `app/user/services/jwt.py` | 26, 51, 109 | `datetime.now()` | naive datetime | | `app/user/services/auth.py` | 170, 225, 485, 510 | `datetime.now()` | naive datetime | | `app/user/api/routers/v1/auth.py` | 437 | `datetime.now(timezone.utc)` | UTC 사용 (서울 아님) | | `app/social/services.py` | 408, 448, 509, 562, 578 | `datetime.now()` | naive datetime | | `app/social/worker/upload_task.py` | 73 | `datetime.now()` | naive datetime | | `app/utils/logger.py` | 89, 119 | `datetime.today()` | naive datetime | --- ## 작업 단계 ### 1단계: 타임존 유틸리티 생성 (신규 파일) **파일**: `app/utils/timezone.py` ```python """ 타임존 유틸리티 프로젝트 전역에서 일관된 서울 타임존(Asia/Seoul) 시간을 사용하기 위한 유틸리티입니다. 모든 datetime.now() 호출은 이 모듈의 함수로 대체해야 합니다. """ from datetime import datetime from config import TIMEZONE def now() -> datetime: """ 서울 타임존(Asia/Seoul) 기준 현재 시간을 반환합니다. Returns: datetime: 서울 타임존이 적용된 현재 시간 (aware datetime) Example: >>> from app.utils.timezone import now >>> current_time = now() # 2024-01-15 15:30:00+09:00 """ return datetime.now(TIMEZONE) def today_str(fmt: str = "%Y-%m-%d") -> str: """ 서울 타임존 기준 오늘 날짜를 문자열로 반환합니다. Args: fmt: 날짜 포맷 (기본값: YYYY-MM-DD) Returns: str: 포맷된 날짜 문자열 Example: >>> from app.utils.timezone import today_str >>> today_str() # "2024-01-15" >>> today_str("%Y/%m/%d") # "2024/01/15" """ return datetime.now(TIMEZONE).strftime(fmt) ``` ### 2단계: 기존 코드 수정 모든 `datetime.now()`, `datetime.today()`, `datetime.now(timezone.utc)`를 타임존 유틸리티 함수로 교체합니다. #### 2.1 app/user/services/jwt.py ```python # Before from datetime import datetime, timedelta expire = datetime.now() + timedelta(...) # After from datetime import timedelta from app.utils.timezone import now expire = now() + timedelta(...) ``` #### 2.2 app/user/services/auth.py ```python # Before from datetime import datetime user.last_login_at = datetime.now() if db_token.expires_at < datetime.now(): revoked_at=datetime.now() # After from app.utils.timezone import now user.last_login_at = now() if db_token.expires_at < now(): revoked_at=now() ``` #### 2.3 app/user/api/routers/v1/auth.py ```python # Before from datetime import datetime, timezone user.last_login_at = datetime.now(timezone.utc) # After from app.utils.timezone import now user.last_login_at = now() ``` #### 2.4 app/social/services.py ```python # Before from datetime import datetime, timedelta buffer_time = datetime.now() + timedelta(minutes=10) account.token_expires_at = datetime.now() + timedelta(...) account.connected_at = datetime.now() # After from datetime import timedelta from app.utils.timezone import now buffer_time = now() + timedelta(minutes=10) account.token_expires_at = now() + timedelta(...) account.connected_at = now() ``` #### 2.5 app/social/worker/upload_task.py ```python # Before from datetime import datetime upload.uploaded_at = datetime.now() # After from app.utils.timezone import now upload.uploaded_at = now() ``` #### 2.6 app/utils/logger.py ```python # Before from datetime import datetime today = datetime.today().strftime("%Y-%m-%d") # After from app.utils.timezone import today_str today = today_str() ``` > **참고**: logger.py에서는 **날짜만 사용하는 것이 맞습니다.** > 로그 파일명이 `{날짜}_app.log`, `{날짜}_error.log` 형식이므로 일별 로그 파일 관리에 적합합니다. > 시간까지 포함하면 매 시간/분마다 새 파일이 생성되어 로그 관리가 어려워집니다. --- ## 작업 체크리스트 | 순서 | 작업 | 파일 | 상태 | |------|------|------|------| | 1 | 타임존 유틸리티 생성 | `app/utils/timezone.py` | ✅ 완료 | | 2 | JWT 서비스 수정 | `app/user/services/jwt.py` | ✅ 완료 | | 3 | Auth 서비스 수정 | `app/user/services/auth.py` | ✅ 완료 | | 4 | Auth 라우터 수정 | `app/user/api/routers/v1/auth.py` | ✅ 완료 | | 5 | Social 서비스 수정 | `app/social/services.py` | ✅ 완료 | | 6 | Upload Task 수정 | `app/social/worker/upload_task.py` | ✅ 완료 | | 7 | Logger 유틸리티 수정 | `app/utils/logger.py` | ✅ 완료 | --- ## 예상 작업 범위 - **신규 파일**: 1개 (`app/utils/timezone.py`) - **수정 파일**: 6개 - **수정 위치**: 약 15곳 --- ## 참고 사항 ### naive datetime vs aware datetime - **naive datetime**: 타임존 정보가 없는 datetime (예: `datetime.now()`) - **aware datetime**: 타임존 정보가 있는 datetime (예: `datetime.now(TIMEZONE)`) ### 왜 서울 타임존을 사용하는가? 1. 데이터베이스가 Asia/Seoul로 설정됨 2. 서비스 대상 지역이 한국 3. Python 코드와 DB 간 시간 일관성 확보 ### 주의사항 - 기존 DB에 저장된 시간 데이터는 이미 서울 시간이므로 마이그레이션 불필요 - JWT 토큰 만료 시간 비교 시 타임존 일관성 필수 - 로그 파일명에 사용되는 날짜도 서울 기준으로 통일