본문 바로가기

Backend study/Django

Django에서 시간대(Timezone) 다루기 - django.utils.timezone

웹 애플리케이션을 개발하다 보면 시간대 처리는 생각보다 복잡한 문제다. 특히 전 세계 사용자를 대상으로 하는 서비스라면 더욱 그렇다. Django는 이런 시간대 문제를 해결하기 위해 django.utils.timezone 모듈을 제공한다.

 

왜 시간대 처리가 중요한가?

한국에서 오후 3시에 작성한 글이 미국 사용자에게는 몇 시로 표시되어야 할까? 서버는 UTC로 저장하고, 각 사용자의 지역 시간으로 변환해서 보여주는 것이 일반적이다. Django는 이런 복잡한 처리를 쉽게 할 수 있도록 도와준다.

 

django.utils.timezone 핵심 기능

1. make_aware() - Naive datetime을 Aware datetime으로 변환

Python의 datetime 객체는 두 가지 종류가 있다:

  • Naive datetime: 시간대 정보가 없는 datetime
  • Aware datetime: 시간대 정보가 포함된 datetime
from datetime import datetime
from django.utils.timezone import make_aware, get_current_timezone

# Naive datetime (시간대 정보 없음)
naive = datetime(2025, 4, 23, 15, 0, 0)
print(naive)
# 출력: 2025-04-23 15:00:00

# Aware datetime으로 변환
aware = make_aware(naive, get_current_timezone())
print(aware)
# 출력: 2025-04-23 15:00:00+09:00  ← 타임존 정보 추가됨

 

2. get_current_timezone() - 현재 타임존 가져오기

Django 설정에서 정의한 TIME_ZONE을 가져온다.

from django.utils.timezone import get_current_timezone

tz = get_current_timezone()
print(tz)
# 출력: Asia/Seoul (settings.py의 TIME_ZONE이 'Asia/Seoul'인 경우)

3. now() - 현재 시간을 Aware datetime으로 가져오기

from django.utils import timezone

# 현재 시간 (aware datetime)
current_time = timezone.now()
print(current_time)
# 출력: 2025-04-23 15:30:00+00:00 (UTC)

# 로컬 타임존으로 변환
local_time = timezone.localtime(current_time)
print(local_time)
# 출력: 2025-04-24 00:30:00+09:00 (한국 시간)

4. is_aware()와 is_naive() - datetime 타입 확인

from django.utils import timezone
from datetime import datetime

naive = datetime.now()
aware = timezone.now()

print(timezone.is_naive(naive))  # True
print(timezone.is_aware(aware))   # True

 

settings.py 시간대 설정

Django 프로젝트의 시간대 처리는 settings.py에서 설정한다.

# settings.py

# 타임존 활성화 (권장)
USE_TZ = True

# 기본 타임존 설정
TIME_ZONE = 'Asia/Seoul'

# 날짜/시간 형식 (선택사항)
DATE_FORMAT = 'Y년 m월 d일'
TIME_FORMAT = 'H:i'
DATETIME_FORMAT = 'Y년 m월 d일 H:i'

USE_TZ 설정의 의미

  • USE_TZ = True (권장)
    • 모든 시간을 UTC로 데이터베이스에 저장
    • 템플릿과 폼에서는 TIME_ZONE 설정에 따라 자동 변환
    • 여러 시간대를 지원하는 애플리케이션에 적합
  • USE_TZ = False
    • TIME_ZONE에 설정된 시간대로 저장
    • 단일 시간대만 사용하는 로컬 애플리케이션에 적합

 

활용 예제

1. 모델에서 시간대 처리

from django.db import models
from django.utils import timezone

class Article(models.Model):
    title = models.CharField(max_length=200)
    # auto_now_add는 자동으로 timezone.now() 사용
    created_at = models.DateTimeField(auto_now_add=True)
    
    # 커스텀 저장 시간
    published_at = models.DateTimeField(default=timezone.now)
    
    def is_published(self):
        return self.published_at <= timezone.now()

2. 뷰에서 시간대 처리

from django.utils import timezone
from django.shortcuts import render
from .models import Article

def article_list(request):
    # 현재 시간 기준으로 게시된 글만 조회
    articles = Article.objects.filter(
        published_at__lte=timezone.now()
    )
    
    context = {
        'articles': articles,
        'current_time': timezone.localtime(timezone.now())
    }
    return render(request, 'articles/list.html', context)

3. 템플릿에서 시간대 표시

<!-- 자동으로 사용자의 TIME_ZONE으로 변환되어 표시 -->
<p>작성일: {{ article.created_at|date:"Y년 m월 d일 H:i" }}</p>

<!-- 특정 타임존으로 변환 -->
{% load tz %}
{% timezone "US/Eastern" %}
    <p>뉴욕 시간: {{ article.created_at|date:"Y-m-d H:i" }}</p>
{% endtimezone %}

4. 폼에서 시간 입력받기

from django import forms
from django.utils import timezone

class EventForm(forms.Form):
    title = forms.CharField(max_length=200)
    event_date = forms.DateTimeField()
    
    def clean_event_date(self):
        event_date = self.cleaned_data['event_date']
        
        # 과거 날짜는 허용하지 않음
        if event_date < timezone.now():
            raise forms.ValidationError("과거 날짜는 선택할 수 없습니다.")
        
        return event_date

자주 발생하는 문제와 해결법

1. RuntimeWarning: DateTimeField received a naive datetime

# 문제 코드
from datetime import datetime
article.published_at = datetime.now()  # Naive datetime

# 해결 방법
from django.utils import timezone
article.published_at = timezone.now()  # Aware datetime

2. 시간 비교 시 TypeError

# 문제 코드
from datetime import datetime
if article.created_at > datetime.now():  # Aware와 Naive 비교
    pass

# 해결 방법
from django.utils import timezone
if article.created_at > timezone.now():  # 둘 다 Aware
    pass

3. 특정 시간대로 datetime 생성하기

from django.utils import timezone
import pytz

# 한국 시간으로 특정 시간 생성
korea_tz = pytz.timezone('Asia/Seoul')
specific_time = korea_tz.localize(datetime(2025, 4, 23, 15, 0, 0))

# 또는
from django.utils.timezone import make_aware
specific_time = make_aware(
    datetime(2025, 4, 23, 15, 0, 0),
    timezone=pytz.timezone('Asia/Seoul')
)

 

 

 

Django의 timezone 모듈은 복잡한 시간대 처리를 간단하게 만들어준다. 핵심은 다음과 같다:

  1. USE_TZ = True로 설정하여 시간대 지원 활성화
  2. timezone.now()를 사용하여 현재 시간 가져오기
  3. make_aware()로 naive datetime을 aware로 변환
  4. 데이터베이스에는 UTC로 저장, 사용자에게는 로컬 시간으로 표시

 

728x90