Django

장고(Django)에서 datetime 객체를 조작할 때 유의할 점. (UTC 시간대를 로컬 타임존으로 정확하게 변환하기)

cocojen 2024. 8. 14. 13:46

datetime 객체를 다루는 과정에서 타임존을 신경 쓰지 않으면, 날짜가 불일치하는 등의 문제가 발생할 수 있다. 날짜 객체들이 사용하기 어려운 건 아닌데, 소홀히 하기 쉬워서 오류가 발생하기 쉬운 것 같다. 이번 포스트에서는 데이터베이스에 저장된 UTC 시간을 가져와서 사용할 때 주의해야 할 사항을 정리해 보겠다.

 


[Prerequisite]

Naive & Aware datetime object 

- naive : datetime object에 tzinfo(타임존 정보)가 없는 datetime 객체

- aware: datetime object에 tzinfo(타임존 정보)가 있는 datetime 객체

 

 

Django 프로젝트에서는 아래와 같이 세팅 파일에 USE_TZ = True로 설정하면, 모든 datetime 정보를 데이터베이스에 UTC로 저장해 준다.

USE_TZ = True

 

 

위처럼 설정해 놓으면 장고가 알아서 UTC로 저장해 주기 때문에, 타임존에 대해 무감각해질 수 있는데, 가져와서 변환하는 것은 우리의 몫이다. DB에 (UTC로) 저장되어 있는 datetime 필드를 가져와서 현재 날짜로 변환할 때, timezone 을 고려하여 변환해야 한다. 타임존을 고려하지 않으면 한국 시간은 UTC보다 9시간 빠르기 때문에, 일자가 쉽게 뒤바뀔 수 있다. 아래는 그 예시이다.

 

from django.utils import timezone
from myapp.models import Post  # 필요한 모델을 import 합니다.

# 1. UTC로 저장되어있는 시간 데이터 가져오기 (위에서 Timezone support 를 enabled 했을 경우 데이터베이스에서 가져온 시간)
post = Post.objects.get(id=1)
print(post.created_at)  # 결과는 2024-08-13 15:00:00+00:00 (UTC 시간으로 저장된 것으로 한국 시간으로 8월 14일 00시임)

# 2. UTC 시간을 고려하지 않고 변환하기
naive_created_at = post.created_at.strftime('%Y-%m-%d')
print(naive_created_at)  # 결과는 2024-08-13 : 잘못된 값.

# 3. UTC 시간을 로컬 타임존으로 변환하기
aware_created_at = timezone.localtime(post.created_at).strftime('%Y-%m-%d')
print(aware_created_at)  # 결과는 2024-08-14 (로컬 타임존 기준 날짜로 변환됨) : 의도한 결과

 

이번에 알게된 점)

2025년 1월 1일 00시에 생성된 Post Object가 있다면, UTC 시간 설정이 되어있는 db 에는 post.created_at 이 datetime.datetime(2024, 12, 31, 15, 0, tzinfo=datetime.timezone.utc) 로 저장되어있을 것이다. 따라서 2025년에 생성된 post 들을 모두 불러오기 위해서 단순히 year 로 필터링을 한다면 이 Post 는 결과에 포함되지 않을 것이라고 예상했다 (created_at__year=2025 이런식으로). 하지만 sql 을 보면 알아서 잘 timezone aware 하게 변환을 해주는 것을 알 수 있다.

 

TL;DR :

  • Naive datetime 객체를 사용하면 UTC 시간대가 고려되지 않아 의도치 않은 결과가 나올 수 있다.
  • Django 에서 타임존 서포트를 활성화하면 DB에 저장할 때 알아서 UTC로 저장해준다
  • UTC로 저장된 날짜 정보를 사용할때는 django utils의 timezone.localtime()을 통해 로컬 타임존으로 변환해야 올바른 날짜를 얻을 수 있다.

 

datetime 객체를 조작할 때는 항상 일관된 접근 방식을 사용하여 예기치 않은 오류를 방지하자!