怎么在python中對(duì)時(shí)區(qū)進(jìn)行設(shè)置?相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
全州ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!首先是幾個(gè)常見的時(shí)間概念
GMT 時(shí)間:格林威治時(shí)間,基準(zhǔn)時(shí)間
UTC 時(shí)間:Coordinated Universal Time,全球協(xié)調(diào)時(shí)間,更精準(zhǔn)的基準(zhǔn)時(shí)間,與 GMT 基本等同
CST 中國(guó)基準(zhǔn)時(shí)間:為 UTC 時(shí)間 + 8 小時(shí),即 UTC 時(shí)間的 0 點(diǎn)對(duì)應(yīng)于中國(guó)基準(zhǔn)時(shí)間的 8 點(diǎn),即為一般稱為東八區(qū)的時(shí)間
一種標(biāo)準(zhǔn)化的時(shí)間表示方法,表示格式為 :YYYY-MM-DDThh:mm:ss ± timezone,可以表示不同時(shí)區(qū)的時(shí)間,時(shí)區(qū)部分用Z 表示為 UTC 標(biāo)準(zhǔn)時(shí)區(qū)。兩個(gè)例子:
1997-07-16T08:20:30Z 表示的是 UTC 時(shí)間的 1997 年 7 月 16 號(hào) 8:20:30
1997-07-16T19:20:30+08:00 表示的是東八區(qū)時(shí)間的 1997 年 7 月 16 號(hào) 19:20:30
1970年1月1日 00:00:00 UTC+00:00時(shí)區(qū)的時(shí)刻稱為epoch time,記為0,當(dāng)前的時(shí)間戳即為從 epoch time 到現(xiàn)在的秒數(shù),一般叫做 timestamp,因此一個(gè)時(shí)間戳一定對(duì)應(yīng)于一個(gè)特定的 UTC 時(shí)間,同時(shí)也對(duì)應(yīng)于其他時(shí)區(qū)的一個(gè)確定的時(shí)間。因此時(shí)間戳可以認(rèn)為是一個(gè)相對(duì)安全的時(shí)間表示方法。
datetime 是 python 中最基礎(chǔ)的一個(gè)時(shí)間管理包,下面分別利用 datetime 去實(shí)踐下對(duì)應(yīng)的時(shí)區(qū)概念
datetime 分成兩種類型:
naive,本地類型的時(shí)間,當(dāng) datetime 中沒有指定時(shí)區(qū)信息時(shí)就是這種類型,此類型的時(shí)區(qū)是根據(jù)運(yùn)行環(huán)境確定對(duì)應(yīng)的時(shí)區(qū)。因此這種類型的時(shí)間會(huì)因?yàn)檫\(yùn)行環(huán)境的不同而得到不同時(shí)間戳
aware,帶有時(shí)區(qū)類型的時(shí)間,這種類型的時(shí)間對(duì)象由于時(shí)間和時(shí)區(qū)都是確定的,因此對(duì)應(yīng)于確定的時(shí)間戳
舉例如下:
from datetime import datetime, timezone now = datetime.now() now.tzinfo # None utc_now = datetime.now(timezone.utc) utc_now.tzinfo # UTC
可以看到上面的例子中,now 沒有指定時(shí)區(qū),為 naive 類型的時(shí)間,其時(shí)區(qū)與運(yùn)行環(huán)境相關(guān)。而 utc_now 指定了 UTC 時(shí)區(qū),為 aware 類型的時(shí)間。
datetime.now() 可用于獲取當(dāng)前時(shí)間,支持設(shè)置對(duì)應(yīng)的時(shí)區(qū),如果不設(shè)置時(shí)區(qū)默認(rèn)獲取的是本地的時(shí)間,根據(jù)是否指定時(shí)區(qū)可能穿件出 naive 類型的時(shí)間或者 aware 類型的時(shí)間,但是對(duì)應(yīng)的時(shí)間戳都是符合預(yù)期的。
datetime.utcnow() 謹(jǐn)慎使用 獲取是當(dāng)前 UTC 對(duì)應(yīng)的時(shí)間,但是生成的 datetime 對(duì)象是沒有指定時(shí)區(qū)的,因此使用的是本地時(shí)區(qū),創(chuàng)建的是 naive 類型的時(shí)間。因此如果運(yùn)行環(huán)境為東八區(qū),得到的時(shí)間是 UTC 對(duì)應(yīng)的時(shí)間,但是時(shí)區(qū)是東八區(qū),最終得到的時(shí)間會(huì)比預(yù)期早 8 個(gè)小時(shí),轉(zhuǎn)化得到時(shí)間戳也是不符合預(yù)期的。
舉例如下:
from datetime import datetime now = datetime.now() now.timestamp() # 1610035129.323702 unow = datetime.utcnow() unow.timestamp() # 1610006329.323797
最終在 2021-01-07 23:58:49 在東八區(qū)環(huán)境下運(yùn)行上面的代碼,now.timestamp() 得到時(shí)間戳轉(zhuǎn)化為對(duì)應(yīng)的時(shí)間為東八區(qū)的 2021-01-07 23:58:49,但是 unow.timestamp() 得到的時(shí)間戳對(duì)應(yīng)的時(shí)間為東八區(qū)的 2021-01-07 15:58:49,對(duì)應(yīng)于 UTC 時(shí)間 2021-01-07 07:58:49,和 UTC 的當(dāng)前時(shí)間完全對(duì)不上。
datetime.timestamp() 生成當(dāng)前時(shí)間對(duì)應(yīng)的時(shí)間戳
datetime.fromtimestamp() 根據(jù)時(shí)間戳生成運(yùn)行環(huán)境時(shí)區(qū)對(duì)應(yīng)的時(shí)間
datetime.utcfromtimestamp() 謹(jǐn)慎使用 根據(jù)時(shí)間戳生成對(duì)應(yīng)的 UTC 時(shí)間,由于生成的 datetime 是沒有指定時(shí)區(qū)的,因此獲取時(shí)間戳看起來得到的是 8 個(gè)小時(shí)之前時(shí)間的時(shí)間戳
對(duì)于上面的例子,我們使用前面得到的當(dāng)前時(shí)間戳 1610035129 進(jìn)行測(cè)試如下:
from datetime import datetime timestamp = 1610035129 d1 = datetime.fromtimestamp(timestamp) # 2021-01-07 23:58:49 d2 = datetime.utcfromtimestamp(timestamp) # 2021-01-07 15:58:49
最終得到 d1 是本地時(shí)區(qū)正確的時(shí)間,但是 d2 是 UTC 的是啊金,但是沒有指定的時(shí)區(qū),因此看起來就是就是本地 8 個(gè)小時(shí)前的時(shí)間了
默認(rèn)構(gòu)建的 datetime 是沒有時(shí)區(qū)信息的,可以通過 datetime.replace() 為時(shí)間設(shè)置上時(shí)區(qū),但是這樣必須保證對(duì)應(yīng)的時(shí)間與時(shí)區(qū)信息匹配,否則就會(huì)導(dǎo)致錯(cuò)誤的時(shí)區(qū)的時(shí)間,一個(gè)簡(jiǎn)單例子就是:
from datetime import datetime, timedelta, timezone tz_utc_8 = timezone(timedelta(hours=8)) # 創(chuàng)建時(shí)區(qū)UTC+8:00,即東八區(qū)對(duì)應(yīng)的時(shí)區(qū) now = datetime.now() # 默認(rèn)構(gòu)建的時(shí)間無(wú)時(shí)區(qū) dt = now.replace(tzinfo=tz_utc_8) # 強(qiáng)制設(shè)置為UTC+8:00
設(shè)置上對(duì)應(yīng)的時(shí)區(qū)后,對(duì)應(yīng)的日期與時(shí)間是不變的,但是由于設(shè)置了全新的時(shí)區(qū),如果與之前的時(shí)區(qū)不同,那么對(duì)應(yīng)的時(shí)間戳就會(huì)改變,使用此方法時(shí)要謹(jǐn)慎
可以將一個(gè)帶有時(shí)區(qū)信息的時(shí)間轉(zhuǎn)換為另一個(gè)時(shí)區(qū)的時(shí)間,通過 datetime.astimezone() 可以實(shí)現(xiàn),一個(gè)簡(jiǎn)單的例子是:
from datetime import datetime, timedelta, timezone utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc) # 構(gòu)建了 UTC 的當(dāng)前時(shí)間 bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8))) # 將時(shí)區(qū)轉(zhuǎn)化為東八區(qū)的時(shí)間
通過 astimezone() 進(jìn)行轉(zhuǎn)換后,雖然時(shí)間變化了,但是對(duì)應(yīng)的是同樣的基準(zhǔn)時(shí)間,因此對(duì)應(yīng)的時(shí)間戳是不變的,
在 Grpc 的使用中,設(shè)計(jì)到時(shí)間戳對(duì)象 Timestamp 與時(shí)間的轉(zhuǎn)換,Timestamp 對(duì)象支持通過 python 中的時(shí)間戳構(gòu)建,即當(dāng)前時(shí)間的對(duì)應(yīng)的時(shí)間戳秒數(shù),也支持通過 datetime 構(gòu)建。對(duì)應(yīng)的接口如下:
Timestamp.FromSeconds() 此方法是根據(jù)時(shí)間戳生成 Grpc 的時(shí)間戳對(duì)象,沒有特殊的地方
Timestamp.FromDatetime() 謹(jǐn)慎使用 此方法根據(jù) datetime 時(shí)間生成時(shí)間戳對(duì)象,隱含期望 datetime 是 UTC 時(shí)間,如果錯(cuò)誤傳入東八區(qū)時(shí)間,會(huì)導(dǎo)致得到一個(gè) 8 個(gè)小時(shí)后的絕對(duì)時(shí)間
我們?cè)趯?shí)踐中有混用這兩個(gè)方法,最終發(fā)現(xiàn)調(diào)用 FromDatetime() 時(shí)獲得的時(shí)間戳是完全不符合預(yù)期的。一個(gè)簡(jiǎn)單例子如下:
from datetime import datetime from google.protobuf.timestamp_pb2 import Timestamp now = datetime.now() now_timestamp = int(now.timestamp()) # 1610245593 t1 = Timestamp() t1.FromSeconds(now_timestamp) # 1610245593 t2 = Timestamp() t2.FromDatetime(now) # 1610274393
可以看到通過 FromDatetime() 得到訂單時(shí)間戳與預(yù)期是不相符的,只有傳入的 datetime 是 UTC 的時(shí)間時(shí)兩者才是一致的
而轉(zhuǎn)換為 datetime 對(duì)象的接口為:
Timestamp.ToSeconds() 此方法是根據(jù)時(shí)間戳對(duì)象得到對(duì)應(yīng)的整數(shù)時(shí)間戳,沒有問題
Timestamp.ToDatetime() 謹(jǐn)慎使用 此方法是根據(jù) grpc 的時(shí)間戳對(duì)象生成 datetime,隱含輸出的 datetime 是 UTC 時(shí)間 ,而生成的 datetime 是沒有時(shí)區(qū)信息的,默認(rèn)會(huì)按照本地時(shí)區(qū)進(jìn)行處理,不做處理的情況下得到的就是 8 個(gè)小時(shí)前,對(duì)應(yīng)的時(shí)間戳也是錯(cuò)誤的
與上面的問題類似,通過 ToDatetime() 得到的時(shí)間是 UTC 時(shí)間,但是由于得到的 datetime 沒有指定時(shí)區(qū),只有在 UTC 的運(yùn)行環(huán)境下得到的時(shí)間才是符合預(yù)期的。
之前的在使用 Pymongo 進(jìn)行數(shù)據(jù)存儲(chǔ)時(shí),直接使用的是 Pymongo 的默認(rèn)設(shè)置,運(yùn)行環(huán)境設(shè)置為東八區(qū),在使用中直接將沒有指定時(shí)區(qū)的 datetime 存入數(shù)據(jù)庫(kù)中,之后再取出進(jìn)行使用工作起來看起來一切正常。但是本次在梳理時(shí)區(qū)時(shí)查看數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)時(shí),就發(fā)現(xiàn)了一個(gè)明顯的問題,數(shù)據(jù)庫(kù)中存儲(chǔ)的看起來日期與時(shí)間是對(duì)的,但是是 UTC 的時(shí)間,也就是說實(shí)際存儲(chǔ)的時(shí)間比預(yù)期晚 8 小時(shí)了,但是為什么又能正常工作呢?確認(rèn)后結(jié)果如下:
Pymongo 在沒有指定時(shí)區(qū)的情況下, 默認(rèn)不認(rèn)為此時(shí)間為本地時(shí)間,事實(shí)上認(rèn)為此時(shí)間為 UTC 時(shí)間,最終會(huì)利用此時(shí)間計(jì)算得到對(duì)應(yīng)的時(shí)間戳并進(jìn)行存儲(chǔ),所以最終存儲(chǔ)的時(shí)間戳?xí)?8 小時(shí);
而在默認(rèn)設(shè)置下,從 Pymongo 中返回的時(shí)間也沒有時(shí)區(qū),而時(shí)間依舊是 UTC 時(shí)間,因此會(huì)導(dǎo)致計(jì)算得到時(shí)間又早了 8 小時(shí),因此時(shí)間看起來是正常的。
如何才能保證存入正確時(shí)間,返回的也是符合預(yù)期的呢?
存入的時(shí)間可以設(shè)置上對(duì)應(yīng)的時(shí)區(qū),即避免存入 naive 類型的時(shí)間,應(yīng)該存入 aware 類型的時(shí)間,避免輸入是認(rèn)為是 UTC 的時(shí)間
在 Pymongo 中設(shè)置輸出帶時(shí)區(qū)的時(shí)間,避免默認(rèn)輸出時(shí)間的問題,Pymongo 可以通過 tz_aware 指定輸出帶時(shí)區(qū)的時(shí)間,通過 tzinfo 指定輸出時(shí)間的時(shí)區(qū),這個(gè)設(shè)置在構(gòu)建 Pymongo 時(shí)傳入即可。對(duì)應(yīng)如下:
from datetime import timedelta, timezone db = MongoClient(settings.MONGODB_DSN, tz_aware=True, tzifo=timezone(timedelta(hours=8))).get_default_database()
根據(jù)上面的的實(shí)踐,分別對(duì)三個(gè)部分進(jìn)行使用如下:
datetime 的使用中,如果運(yùn)行環(huán)境設(shè)置為非 UTC 時(shí)區(qū),建議禁用 utc 相關(guān)的方法,比如 utcnow ,utcfromtimestamp() ,同時(shí)盡量避免使用 naive 使用,保證時(shí)間與運(yùn)行環(huán)境解耦;
grpc 的使用中盡量避免調(diào)用 FromDatetime() 和 ToDatetime() 這種包含隱含信息的方法,盡量通過時(shí)間戳與 grpc 的 TimeStamp 對(duì)象進(jìn)行交互;
Pymongo 中盡量傳入的帶有時(shí)區(qū)的時(shí)間,輸出也配置上時(shí)區(qū)輸出,避免隱含的問題;
一條總原則就是:與第三方的服務(wù)交互或存儲(chǔ)時(shí),盡量只使用時(shí)間戳這種絕對(duì)機(jī)制,這樣才能從根本上杜絕問題。
看完上述內(nèi)容,你們掌握怎么在python中對(duì)時(shí)區(qū)進(jìn)行設(shè)置的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
文章名稱:怎么在python中對(duì)時(shí)區(qū)進(jìn)行設(shè)置-創(chuàng)新互聯(lián)
網(wǎng)站URL:http://jinyejixie.com/article4/ccpcoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站制作、小程序開發(fā)、定制開發(fā)、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容