이번에는 Django의 TIME_ZONE과 USE_TZ과 관련하여 파헤쳐보려고합니다.
장고에서 프로젝트를 생성하면 settings.py에 아래와같이 타임존관련 설정이 세팅되어있습니다.
TIME_ZONE = 'UTC'
USE_TZ = True
UTC타임존을 사용하고 타임존을 사용한다는 말 입니다.
타임존이 'UTC'인건 이해할 수 있습니다. 다만 타임존을 사용한다?? 이게 무슨말일까요
이제부터 파헤쳐보려 합니다.
**이글을 이해하기전 naive객체와 aware객체에 대한 이해가 더 필요하다면 아래의 글을 읽고 오시면 이해하시기 수월하실 것 입니다.
https://dingwan0331.tistory.com/179
[Python] Python datetime aware & naive 객체
파이썬의 시간을 다루기위해선 datetime모듈을 불러와 사용합니다. 많은 언어와 프레임워크에서 시간을 다룰때 문제가 있습니다. 바로 timezone에 관련한 것 입니다. 해당 시간이 어느나라 어느 지
dingwan0331.tistory.com
파이썬과 장고의 datetime에 관하여 간략설명
파이썬에서는 시간관련 모듈 datetime의 인스턴스인 datetime 활용하여 시간에 관련한 문제를 풉니다.(datetime.datetime)
장고에서는 django.utils.timezone이라던가 DateTimeField등을 활용하지만 결국 이것들또한 datetime 인스턴스 입니다.
이렇게 datetime 객체를 반환합니다.
일반적으로 사용하는 datetime객체는 두가지정보를 가지게됩니다.
- 날짜시간등 시간에 관한 정보
- 해당시간의 타임존 정보 (없는경우 None)
위와같이 타임존에 대한 정보는 선택사항입니다.
타임존의 정보가 있으면 aware객체 , 없으면 naive객체 입니다.
USE_TZ이란 무엇일까?
말 그대로 timezone의 사용여부를 의미하는것입니다.
Django가 datetime객체를 다룰때 타임존에관한것은 다루지 않으며 aware 객체가 들어올경우 대부분 에러를 반환합니다.
USE_TZ = False시 벌어지는 일
USE_TZ이 False일때 어떤일이 벌어지는지 살펴볼 필요가 있을 것 같습니다.
1. 모든 시간을 naive타임으로 인지하고 사용하게 됩니다.
2. DB에 오브젝트 생성시 aware datetime을 사용하지 못합니다.
import pytz
from datetime import datetime
class Time(models.Model):
date = models.DateTimeField()
kor = pytz.timezone('Asia/Seoul')
kor_now = datetime.now(kor_now) # aware 객체 생성
Time.objects.create(date=kor_now)
위와같은 코드작성시 아래와 같은 에러를 뱉습니다.
ValueError: MySQL backend does not support timezone-aware datetimes when USE_TZ is False.
3.DB에서 꺼내온 datetime 데이터 역시 naive객체로 반환합니다.
from django.db import models
class Model(models.Model):
date = models.DateTimeField()
Model.objects.last().date
# datetime.datetime(2023, 1, 5, 9, 42, 43, 128947)
4.timezone.now()인스턴스 반환이 naive객체가 됩니다.
timezone.now()는 USE_TZ 이 True일때는 aware객체를 반환합니다. 하지만 False경우는 naive객체를 반환합니다.
from django.utils import timezone
# USE_TZ = True
timezone.now()
# datetime.datetime(2023, 1, 5, 10, 23, 42, 622454, tzinfo=datetime.timezone.utc)
# USE_TZ = False
timezone.now()
# datetime.datetime(2023, 1, 5, 10, 23, 42, 622454)
5.timezone.localtime()의 default값을 사용하지 못합니다.
timezone.localtime()은 인자로받은 datetime객체를 settings.py에 설정된 TIME_ZONE을 tz으로 가진 datetime객체를 반환합니다.
tz을 가진 말 자체가 aware객체를 반환한다는 의미입니다.
# settings.py
TIME_ZONE = 'Asia/Seoul'
# test.py
import pytz
from datetime import datetime
from django.utils import timezone
utc = pytz.utc
utc_now = datetime.now(utc)
# datetime.datetime(2023, 1, 5, 10, 39, 21, 120208, tzinfo=<UTC>)
timezone.localtime(utc_now)
```
datetime.datetime(
2023, 1, 5, 19, 41, 18, 629448,
tzinfo=zoneinfo.ZoneInfo(key='Asia/Seoul')
)
```
위와같이 현재 TIME_ZONE을 반영하여 반환합니다.
인자가 없이 실행시 timezone.now()를 default값을 사용하여 반환합니다.
하지만 USE_TZ = False시 timezone.now()의 반환값이 naive 객체 이기에 아래와 같은 에러를 뱉습니다.
ValueError: localtime() cannot be applied to a naive datetime
주의점
1.주의할점은 python이 aware datetime을 사용하지 못하는것이 아니라 Django가 사용하지 못하는 것 입니다.
예를 들면 아래와 같은 코드가있습니다.
class Time(models.Model):
date = models.DateTimeField()
kor = pytz.timezone('Asia/Seoul')
kor_now = datetime.now(kor_now) # aware 객체 생성
kor_now = kor_now.replace(tzinfo=None) # aware를 다시 naive로 변경
Time.objects.create(date=kor_now)
aware객체를 사용하였지만 DB에 넣을때는 navie객체를 사용하였습니다. 이러면 문제가 전혀 되지 않습니다
2.timezone.localtime()의 default값을 사용하지 못하는것이지 aware객체를 넣으면 사용 가능합니다.
USE_TZ = True 일때
1. timezone.now()의 반환값은 aware객체 이며 tz은 utc입니다.
from django.utils import timezone
timezone.now()
# datetime.datetime(2023, 1, 5, 10, 48, 55, 653550, tzinfo=datetime.timezone.utc)
timezone으로 무엇을 설정하든 tz는 utc로 설정되어 반환됩니다.
2.timezone.localtime()의 인자가 없어도 예외를 일으키지 않는다.(localtime의 default값과 관련)
from django.utils import timezone
timezone.localtime()
```
datetime.datetime(
2023, 1, 5, 19, 41, 18, 629448,
tzinfo=zoneinfo.ZoneInfo(key='Asia/Seoul')
)
```
현재 timezone.now()의 리턴값이 현재 utc시간의 aware객체를 사용합니다.
3.db에 저장시 utc기준으로 저장된다.
아래는 TZ=Asia/Seoul로 설정 후 USE_TZ=True설정 후 4가지 종류의 datatime객체를 생성하여 DB에 넣은 것 입니다.
aware, naive객체 모두 utc기준으로 DB에 저장됩니다.
4.db에서 꺼내올때 utc aware객체로 꺼낸다.
db에 저장될때 어떠한방식, 환경에서 저장하였듯 꺼내올대는 utc aware객체로 꺼내옵니다.
Model.objects.get(id=9).date
```
datetime.datetime(
2023, 1, 5, 9, 26, 24, 168994,
tzinfo=datetime.timezone.utc
)
```
주의점
1. python이 aware datetime을 사용하지 못하는것이 아니라 Django가 사용하지 못하는 것 입니다.
예를 들면 아래와 같은 코드가있습니다.
class Time(models.Model):
date = models.DateTimeField()
kor = pytz.timezone('Asia/Seoul')
kor_now = datetime.now(kor_now) # aware 객체 생성
kor_now = kor_now.replace(tzinfo=None) # aware를 다시 naive로 변경
Time.objects.create(date=kor_now)
aware객체를 사용하였지만 DB에 넣을때는 navie객체를 사용하였습니다. 이러면 문제가 전혀 되지 않습니다
TimeZone은 언제 사용될까?
사실 이 블로그를 작성하면서 여러가지 실험해보았지만
timezone.localtime() 메서드를 제외하고는 사용되는 경우를 찾지 못하였습니다.
TimeZone은 대체적으로 템플릿기능에 많이 유효한 것 같습니다.
1.JsonResponse를 보내도 TimeZone과 무관하게 UTC 시간으로 반환됩니다.
2.db에서 꺼내올 경우에도 역시 UTC시간으로 반환됩니다.
3.DB에 넣을때도 UTC시간으로 반환됩니다.
'Python > Django' 카테고리의 다른 글
[Django] Django Custom Manager 클래스 사용해보기 (0) | 2023.01.01 |
---|---|
[Django]장고에서 앱이름 변경하기 (0) | 2022.11.26 |
[Django] Models class Manager (0) | 2022.06.26 |
[Django] ver.3 피드백 모음 (0) | 2022.06.19 |
[Django] Westagram 회원가입 기능 작성해보기 ver.3 (0) | 2022.06.13 |