在編碼中牽扯到時間問題的時候,總是容易被時區問題搞混,一直以來,都是反覆試驗應付過去,今天終於搞清楚了箇中緣由,一個心結也得以化解。
Python 的時區問題
datetime.today() / datetime.now()
這兩個函式獲得的是當前的系統時間,但得到的datetime物件中的tzinfo是空的,即使系統中設定了時區。
datetime.utcnow()
這個函式獲得當前的utc時間,應該是根據當前系統時間和時區來計算的。
例如系統時間為14:00,時區為 Asia/Shanghai (北京時間),utcnow返回時間為 6:00。同樣,得到的物件中的tzinfo 為空。
環境變數 TZ 對以上函式的影響:
當系統中設定了環境變數 TZ 的時候,或者在python中設定了 os.environ[‘TZ’] 的時候,上面的函式獲取的時間便是TZ對應時區的時間。其實這裡可以認為 TZ 影響的不是這些函式,而是影響的系統時間,這可以從date命令的返回結果看出。datetime.now() 與 date命令返回的結果總是一致的。
Django的時區問題
明白了上面幾個python中的函式,django的時區問題看起來就簡單了。
在django的setting中,有一個設定是 TIME_ZONE, 來設定程式中使用的時區。
從django的文件中得知,TIME_ZONE的作用就是改變 os.environ[‘TZ’] ,但改變os.environ[‘TZ’] 並不會改變系統環境變數 TZ , 因此,如果 TIME_ZONE 的設定於系統時區設定不一致,則在程式中 datetime.now() 獲得的時間就與 date 命令的時間不一致了。
因此,TIME_ZONE 應該設定為程式希望使用的時區。對於一個本地的程式,TIME_ZONE 設定為與系統時區一樣即可;而對於一個國際化的應用,TIME_ZONE 最好設定為UTC,在顯示的時候再根據當前使用者所在的時區做調整。
手冊
classmethod datetime.now([tz])
Return the current local date and time. If optional argument tz is None or not specified, this is like today(), but, if possible, supplies more precision than can be gotten from going through a time.time() timestamp (for example, this may be possible on platforms supplying the C gettimeofday() function).
Else tz must be an instance of a class tzinfo subclass, and the current date and time are converted to tz‘s time zone. In this case the result is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)). See also today(), utcnow().
classmethod datetime.utcnow()
Return the current UTC date and time, with tzinfo None. This is like now(), but returns the current UTC date and time, as a naivedatetime object. See also now().
時區轉換程式碼
import pytz .... #dt the datetime var dt.replace(tzinfo=pytz.utc).astimezone(pytz.timezone('Asia/Shanghai'))