Django的settings配置中有一個USE_TZ項,默認值為True。很多人不太清楚這個配置項具體是干什么的,只知道和時區有關。下面我們就來詳細聊聊它。
首先,我們要了解一下什么是offset-aware與offset-navie
offset-aware與offset-navie
在Python中,有一個datetime模塊,相信大家都很熟悉。但是很少有人知道這個模塊的時間還可以分下面兩種類型:
- offset-naive:不含時區的類型
- offset-aware:有時區的類型
並且,這兩種類型的時間是不可以直接比較的,比如做減法、加法、時間對比等,會拋出下面的異常:
TypeError: can't compare offset-naive and offset-aware datetimes
根本的原因在於兩者一個有時區信息,一個沒有。
我們可以通過查看datetime對象的tzinfo屬性,來判斷具體是兩者中的哪種:
>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2020, 5, 26, 18, 36, 59, 811729)
>>> now.tzinfo
>>> now.tzinfo==None
True
可以很清楚的看到,datetime.datetime.now()是一個offset-naive類型,不含時區信息的時間對象。
我們可以借助pytz模塊,將一個offset-naive類型的時間對象轉換為一個offset-aware類型的時間對象。
先安裝pytz模塊:
pip install pytz
來測試一下:
>>> import pytz
>>> now = now.replace(tzinfo=pytz.timezone('UTC'))
>>> now
datetime.datetime(2020, 5, 26, 18, 36, 59, 811729, tzinfo=<UTC>)
>>> now.tzinfo
<UTC>
反過來,也可以將一個offset-aware型轉換為offset-naive型:
>>> now = now.replace(tzinfo=None)
>>> now
datetime.datetime(2020, 5, 26, 18, 36, 59, 811729)
>>> now.tzinfo == None
True
USE_TZ配置
回到Django種來。我們知道,在安裝Django的同時,默認會安裝一個pytz模塊,然后在django.utils下就會有一個timezone模塊,其實它就是pytz.timezone。
首先,我們要清楚一件事。Django的settings配置中的USE_TZ默認值為True,也就是說,默認情況下Django數據庫里面存儲的日期數據是帶時區信息的,也就是offset-aware類型。
這就導致了我們有些時候,進行時間對比或者加減的操作,會拋出前面說的異常。
TypeError: can't compare offset-naive and offset-aware datetimes
那怎么辦呢?
最原始朴素的方法,自然是對時間類型進行轉換,采用上面的例子中的方法,統一起來,就可以進行比較了。
還有一種更簡單的方法,那就是將USE_TZ設置為False。此時,數據庫里保存的時間對象就不在包含時區信息了,和原生的datetime.datetime是一種類型,都是offset-naive類型,自然不會發生沖突。
Tips:應該在項目開始之初,創建數據表之前就設置USE_TZ為False,否則先前保存的時間數據可能依然帶有時區信息。
其實,還有一種更適用的方法,就是USE_TZ依然保持為True,但是不再使用datetime庫了,而是使用timezone來獲取now時間:
from django.utils import timezone
now = timezone.now()
這樣,大家都帶有時區信息,自然也是可以比較的。
