Django時(shí)間問(wèn)題
在用django1.8版本做項(xiàng)目的時(shí)候遇到時(shí)間的存儲(chǔ)與讀取不一致的問(wèn)題,網(wǎng)上找了很多帖子丽已,但都沒(méi)有講明白蟀瞧。本文將在項(xiàng)目中遇到的問(wèn)題及如何解決的盡可能詳細(xì)的記錄下來(lái)孤澎,當(dāng)然本文參考了網(wǎng)上大量相關(guān)文章届氢。
在django1.4以后欠窒,存在兩個(gè)概念:naive?time?與?active?time覆旭。簡(jiǎn)單點(diǎn)講,naive?time就是不帶時(shí)區(qū)的時(shí)間岖妄,相關(guān)Active?time就是帶時(shí)區(qū)的時(shí)間型将。舉例來(lái)說(shuō),使用datetime.datetime.utcnow()荐虐、datetime.datetime.now()輸出的類(lèi)似2015-05-11?09:10:33.080451就是不帶時(shí)區(qū)的時(shí)間(naive?time)七兜,而使用django.util.timezone.now()輸出的類(lèi)似2015-05-11?09:05:19.936835+00:00的時(shí)間就是帶時(shí)區(qū)的時(shí)間(Active?time),其中+00:00表示的就是時(shí)區(qū)相對(duì)性福扬。
另外一個(gè)概念UTC時(shí)間腕铸。這里不做過(guò)多介紹,需要知曉的是UTC時(shí)間表示的是格林尼治平均時(shí)即可铛碑,即零區(qū)時(shí)間狠裹。而北京時(shí)間表示的是東八區(qū)時(shí)間,即UTC+8汽烦。
下面列出了幾個(gè)常見(jiàn)的時(shí)區(qū)問(wèn)題涛菠,并提供相關(guān)原因,如有不對(duì)撇吞,歡迎指出俗冻。
問(wèn)題一:三個(gè)時(shí)間datetime.datetime.now()、datetime.datetime.utcnow()與django.util.timezone.now()的區(qū)別
datetime.datetime.now():輸出的永遠(yuǎn)是本地時(shí)間(naive?time)與配置無(wú)任任何關(guān)系牍颈。datetime.datetime.utcnow():如果setting中配置USE_TZ=True則輸出的是UTC時(shí)間(naive?time)迄薄,如果setting中配置USE_TZ=False,則該輸出時(shí)間與datetime.datetime.now()完全相同煮岁。django.util.timezone.now():如果setting中配置USE_TZ=True則輸出的是UTC時(shí)間(active?time)讥蔽,如果配置USE_TZ=False死姚,則與datetime.datetime.now()完全相同。
問(wèn)題二:django存儲(chǔ)到數(shù)據(jù)庫(kù)的時(shí)間比本地時(shí)間小8個(gè)小時(shí)勤篮?
首先要明確的一點(diǎn)都毒,Django1.4版本之前,對(duì)時(shí)區(qū)毫無(wú)概概念碰缔,對(duì)時(shí)間的存取账劲、展示不做任何處理,數(shù)據(jù)庫(kù)里存儲(chǔ)的通常是本地時(shí)間金抡,當(dāng)然都是naive?time瀑焦。
Django在1.4版本之后存儲(chǔ)如果設(shè)置了USE_TZ=True,則存儲(chǔ)到數(shù)據(jù)庫(kù)中的時(shí)間永遠(yuǎn)是UTC時(shí)間梗肝。這時(shí)如果settings里面設(shè)置了USE_TZ=True與TIME_ZONE?=?'UTC'榛瓮,用datetime.datetime.now()獲取的時(shí)間django會(huì)把這個(gè)時(shí)間當(dāng)成UTC時(shí)間存儲(chǔ)到數(shù)據(jù)庫(kù)中去。如果修改設(shè)置為USE_TZ=True與TIME_ZONE?=?'Asia/Shanghai'巫击,用datetime.datetime.now()獲取的時(shí)間由于不帶時(shí)區(qū)禀晓,django會(huì)把這個(gè)時(shí)間當(dāng)成Asia/Shanghai時(shí)間,即東八區(qū)時(shí)間坝锰,然后django會(huì)把這個(gè)時(shí)間轉(zhuǎn)成帶時(shí)區(qū)UTC時(shí)間存儲(chǔ)到數(shù)據(jù)庫(kù)中去粹懒,而讀的時(shí)候直接按UTC時(shí)間讀出來(lái),這就是網(wǎng)上很多人遇到的存儲(chǔ)到數(shù)據(jù)庫(kù)中的時(shí)間比本地時(shí)間會(huì)小8個(gè)小時(shí)的原因顷级。
問(wèn)題三:DateTimeField?role_cost_history.cost_time?received?a?naive?datetime?(2015-05-12?19:59:01.259517)?while?time?zone?support?is?active凫乖?
這個(gè)問(wèn)題是因?yàn)槿绻O(shè)置了USE_TZ=True之后,model里面認(rèn)為DateTimeField使用UTC時(shí)間(帶時(shí)區(qū)的時(shí)間)弓颈,這時(shí)用datetime.datetime.now()獲取的時(shí)間是不帶時(shí)區(qū)的就會(huì)報(bào)這個(gè)問(wèn)題帽芽。
問(wèn)題四:django.util.timezone.now()輸出時(shí)間比本地時(shí)間小8個(gè)小時(shí)
只要設(shè)置了USE_TZ=True,django.util.timezone.now()輸出地永遠(yuǎn)是UTC時(shí)間翔冀,不管你設(shè)置的TIME_ZONE是什么导街。如果USE_TZ=False,則django.util.timezone.now()輸出等同于datetime.datetime.now()橘蜜,也不管TIME_ZONE設(shè)置的是什么菊匿。
問(wèn)題五:模板顯示時(shí)間
在設(shè)置了USE_TZ=True之后,如果設(shè)置了TIME_ZONE?=?'Asia/Shanghai'计福,盡管數(shù)據(jù)庫(kù)中存儲(chǔ)的是UTC時(shí)間跌捆,但在模板顯示的時(shí)候,會(huì)轉(zhuǎn)成TIME_ZONE所示的本地時(shí)間進(jìn)行顯示象颖。
建議:為了統(tǒng)一時(shí)間佩厚,在django開(kāi)發(fā)時(shí),盡量使用UTC時(shí)間说订,即設(shè)置USE_TZ=True抄瓦,TIME_ZONE?=?'Asia/Shanghai'潮瓶,并且在獲取時(shí)間的時(shí)候使用django.util.timezone.now()。因?yàn)楹笈_(tái)程序使用時(shí)間時(shí)UTC時(shí)間就能滿(mǎn)足钙姊,也能保證證模板時(shí)間的正確顯示毯辅。
python datetime timezone 時(shí)區(qū)轉(zhuǎn)化
from datetime import datetime, timedelta, timezone
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)
cn_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(cn_dt)
jan_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
print(jan_dt)
cn_2_jan_dt = cn_dt.astimezone(timezone(timedelta(hours=9)))
print(cn_2_jan_dt)
import datetime
nowTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')#現(xiàn)在
pastTime = (datetime.datetime.now()-datetime.timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')#過(guò)去一小時(shí)時(shí)間
afterTomorrowTime = (datetime.datetime.now()+datetime.timedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')#后天
tomorrowTime = (datetime.datetime.now()+datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')#明天
print('\n',nowTime,'\n',pastTime,'\n',afterTomorrowTime,'\n',tomorrowTime)
Django 時(shí)間與時(shí)區(qū)設(shè)置問(wèn)題
在Django的配置文件settings.py中,有兩個(gè)配置參數(shù)是跟時(shí)間與時(shí)區(qū)有關(guān)的煞额,分別是TIME_ZONE和USE_TZ
如果USE_TZ設(shè)置為T(mén)rue時(shí)思恐,Django會(huì)使用系統(tǒng)默認(rèn)設(shè)置的時(shí)區(qū),即America/Chicago膊毁,此時(shí)的TIME_ZONE不管有沒(méi)有設(shè)置都不起作用胀莹。
如果USE_TZ?設(shè)置為False,而TIME_ZONE設(shè)置為None婚温,則Django還是會(huì)使用默認(rèn)的America/Chicago時(shí)間描焰。若TIME_ZONE設(shè)置為其它時(shí)區(qū)的話,則還要分情況栅螟,如果是Windows系統(tǒng)荆秦,則TIME_ZONE設(shè)置是沒(méi)用的,Django會(huì)使用本機(jī)的時(shí)間嵌巷。如果為其他系統(tǒng)萄凤,則使用該時(shí)區(qū)的時(shí)間,入設(shè)置USE_TZ = False,?TIME_ZONE = 'Asia/Shanghai', 則使用上海的UTC時(shí)間搪哪。
一、查看和修改Linux的時(shí)區(qū)
1. 查看當(dāng)前時(shí)區(qū)
命令 : "date -R"
2. 修改設(shè)置Linux服務(wù)器時(shí)區(qū)
方法 A
命令 : "tzselect"
方法 B 僅限于RedHat Linux 和 CentOS
命令 : "timeconfig"
方法 C 適用于Debian
命令 : "dpkg-reconfigure tzdata"
3. 復(fù)制相應(yīng)的時(shí)區(qū)文件坪圾,替換系統(tǒng)時(shí)區(qū)文件晓折;或者創(chuàng)建鏈接文件
cp /usr/share/zoneinfo/$主時(shí)區(qū)/$次時(shí)區(qū) /etc/localtime
例如:在設(shè)置中國(guó)時(shí)區(qū)使用亞洲/上海(+8)
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
4.注意
GMT(Greenwich Mean Time,格林威治標(biāo)準(zhǔn)時(shí)間):
是指位于英國(guó)倫敦郊區(qū)的皇家格林尼治天文臺(tái)的標(biāo)準(zhǔn)時(shí)間兽泄,因?yàn)楸境踝游缇€被定義在通過(guò)那里的經(jīng)線漓概。
UTC(Universal Time/Temps
Cordonné 世界標(biāo)準(zhǔn)時(shí)間)
CST(Central Standard Time 國(guó)家標(biāo)準(zhǔn)時(shí)間,一說(shuō)中原標(biāo)準(zhǔn)時(shí)間); 中國(guó)標(biāo)準(zhǔn)時(shí)間(China
Standard Time)
GMT + 8 = UTC + 8 = CST
二病梢、查看和修改Linux的時(shí)間
1胃珍、date
查看系統(tǒng)時(shí)間
# date
設(shè)置系統(tǒng)時(shí)間
# date --set “07/07/06 10:19" (月/日/年 時(shí):分:秒)
將當(dāng)前時(shí)間和日期寫(xiě)入BIOS,避免重啟后失效
命令 : "hwclock -w"
2蜓陌、hwclock/clock
查看硬件時(shí)間
# hwclock --show
或者 # clock --show
設(shè)置硬件時(shí)間
# hwclock --set --date="07/07/06 10:19" (月/日/年 時(shí):分:秒)
或者 # clock --set --date="07/07/06 10:19" (月/日/年 時(shí):分:秒)
3觅彰、硬件時(shí)間和系統(tǒng)時(shí)間的同步
按照前面的說(shuō)法,重新啟動(dòng)系統(tǒng)钮热,硬件時(shí)間會(huì)讀取系統(tǒng)時(shí)間填抬,實(shí)現(xiàn)同步,但是在不重新啟動(dòng)的時(shí)候隧期,需要用hwclock或clock命令實(shí)現(xiàn)同步飒责。
硬件時(shí)鐘與系統(tǒng)時(shí)鐘同步:
# hwclock --hctosys(hc代表硬件時(shí)間赘娄,sys代表系統(tǒng)時(shí)間)
或者
# clock --hctosys
系統(tǒng)時(shí)鐘和硬件時(shí)鐘同步: # hwclock --systohc 或者 # clock --systohc
針對(duì)中國(guó)時(shí)區(qū),修改操作如下
1.?? 修改文件/etc/sysconfig/clock內(nèi)容:
ZONE=Asia/Shanghai UTC=false ARC=false
2.???? rm /etc/localtime
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
查看系統(tǒng)時(shí)區(qū):
timedatectl | grep "Time zone"