1. 程式人生 > >Django設定TIME_ZONE為中國,及其規則與善後問題

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 有專門的方法):

  1. 使用 manage.py shell
     進入 Django shell 環境,用 Model.objects.all() 迴圈遍歷包含DateTimeField 欄位的模型,減去 timedelta(hours=8)
  2. 使用資料庫 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 後,處理時間方面,有兩條 “黃金法則”:

  1. 保證儲存到資料庫中的是 UTC 時間;
  2. 在函式之間傳遞時間引數時,確保時間已經轉換成 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