Django設定TIME_ZONE為中國,及其規則與善後問題
Django預設的timezone是TIME_ZONE = ‘America/Chicago’
現在要改成我們中國的時區 只需編輯settings.py檔案
把time_zone的值改成TIME_ZONE=’Asia/Shanghai’即可
Django 1.4 之後,時區的問題總算解決了。雖然 pytz
庫 是可選的,但 pytz 可以幫助 Django 識別 TIME_ZONE = 'Asia/Shanghai'
對應的時區是
UTC+8 時間,因此建議啟用 USE_TZ = True
的同時也安裝 pytz。
1.4 之前,Django 對時區毫無概念,對時間的存取、展示不做任何處理,資料庫裡儲存的通常是本地時間(local time)。1.4 之後,在 settings
USE_TZ
= True
即讓 Django 內部把時間全部當成 UTC
時間(北京時間為 UTC+8 )對待。
但這麼做還沒完,還有一些瑣碎的善後工作要做 — 資料和老程式碼的遷移,不然時間的存取、展示都會有差錯。
遷移資料庫
如果之前設定了 TIME_ZONE = 'Asia/Shanghai'
,那麼實際儲存在資料庫中的是 UTC+8
的時間。啟用USE_TZ = True
我們要把資料庫中所有的時間戳(timestamp)欄位全部轉換成
UTC 時間。
轉換到 UTC 時間有兩個方法(注:PostgreSQL 有專門的方法):
-
使用
manage.py shell
Model.objects.all()
迴圈遍歷包含DateTimeField
欄位的模型,減去timedelta(hours=8)
; -
使用資料庫
UPDATE
語句;
第一個方法不推薦使用,因為 ORM 的 save()
方法會觸發 post_save
signal,可能會產生不希望看到的副作用。
第二個方法是安全的(注意備份資料庫),MySQL 下可以用如下 SQL 語句更新時間戳:
UPDATE `your_model` SET `last_modified` = DATE_SUB(`last_modified`, INTERVAL 8 HOUR) WHERE 1;
PostgreSQL 的時間欄位原生支援時區,所以處理方法不太一樣,詳見 Django 官方文件 Time zones。
遷移程式碼
啟用 USE_TZ
= True
後,處理時間方面,有兩條 “黃金法則”:
- 保證儲存到資料庫中的是 UTC 時間;
- 在函式之間傳遞時間引數時,確保時間已經轉換成 UTC 時間;
比如,通常獲取當前時間用的是:
import datetime now = datetime.datetime.now()
啟用 USE_TZ = True
後,需要寫成:
import datetime from django.utils.timezone import utc now = datetime.datetime.utcnow().replace(tzinfo=utc)
保證 now
變數存放的是 UTC 時間。
再如 fromtimestamp()
這個函式,啟用 USE_TZ
= True
後應使用 utcfromtimestamp()
函式替代。
模板
除非應用支援使用者設定自己所在的時區,通常我們不需要關心模板的時區問題。模板在展示時間的時候,會使用 settings.TIME_ZONE
中的設定自動把
UTC 時間轉成 settings.TIME_ZONE
所在時區的時間渲染。
如果確實需要支援使用者設定時區,參考 Django 官方文件 Time zones。