欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python中的時區(qū)問題

 更新時間:2021年01月14日 15:45:20   作者:易遲  
這篇文章主要介紹了python中的時區(qū)問題的相關資料,幫助大家更好的理解和使用python,感興趣的朋友可以了解下

問題背景

使用 Python 進行了許久的開發(fā),一直沒有踩到時區(qū)的坑,最近新的業(yè)務中引入了比較多的服務,而且使用 grpc 進行數(shù)據(jù)通訊,不幸踩到了時區(qū)的坑,果然偷的懶最終還是會有報應的,于是梳理下對應的時區(qū)問題,同時發(fā)現(xiàn)系統(tǒng)中之前的數(shù)據(jù)庫 Mongo 中的時區(qū)問題,一起整理如下。

基礎概念

幾個時間概念

首先是幾個常見的時間概念

  • GMT 時間:格林威治時間,基準時間
  • UTC 時間:Coordinated Universal Time,全球協(xié)調時間,更精準的基準時間,與 GMT 基本等同
  • CST 中國基準時間:為 UTC 時間 + 8 小時,即 UTC 時間的 0 點對應于中國基準時間的 8 點,即為一般稱為東八區(qū)的時間

ISO 8601

一種標準化的時間表示方法,表示格式為 :YYYY-MM-DDThh:mm:ss ± timezone,可以表示不同時區(qū)的時間,時區(qū)部分用Z 表示為 UTC 標準時區(qū)。兩個例子:

  • 1997-07-16T08:20:30Z 表示的是 UTC 時間的 1997 年 7 月 16 號 8:20:30
  • 1997-07-16T19:20:30+08:00 表示的是東八區(qū)時間的 1997 年 7 月 16 號 19:20:30

時間戳

1970年1月1日 00:00:00 UTC+00:00時區(qū)的時刻稱為epoch time,記為0,當前的時間戳即為從 epoch time 到現(xiàn)在的秒數(shù),一般叫做 timestamp,因此一個時間戳一定對應于一個特定的 UTC 時間,同時也對應于其他時區(qū)的一個確定的時間。因此時間戳可以認為是一個相對安全的時間表示方法。

datetime 實踐

datetime 是 python 中最基礎的一個時間管理包,下面分別利用 datetime 去實踐下對應的時區(qū)概念

datetime 類型

datetime 分成兩種類型:

  • naive,本地類型的時間,當 datetime 中沒有指定時區(qū)信息時就是這種類型,此類型的時區(qū)是根據(jù)運行環(huán)境確定對應的時區(qū)。因此這種類型的時間會因為運行環(huán)境的不同而得到不同時間戳
  • aware,帶有時區(qū)類型的時間,這種類型的時間對象由于時間和時區(qū)都是確定的,因此對應于確定的時間戳

舉例如下:

from datetime import datetime, timezone

now = datetime.now()
now.tzinfo   # None 
utc_now = datetime.now(timezone.utc)
utc_now.tzinfo # UTC

可以看到上面的例子中,now 沒有指定時區(qū),為 naive 類型的時間,其時區(qū)與運行環(huán)境相關。而 utc_now 指定了 UTC 時區(qū),為 aware 類型的時間。

獲取當前時間

  • datetime.now() 可用于獲取當前時間,支持設置對應的時區(qū),如果不設置時區(qū)默認獲取的是本地的時間,根據(jù)是否指定時區(qū)可能穿件出 naive 類型的時間或者 aware 類型的時間,但是對應的時間戳都是符合預期的。
  • datetime.utcnow() 謹慎使用 獲取是當前 UTC 對應的時間,但是生成的 datetime 對象是沒有指定時區(qū)的,因此使用的是本地時區(qū),創(chuàng)建的是 naive 類型的時間。因此如果運行環(huán)境為東八區(qū),得到的時間是 UTC 對應的時間,但是時區(qū)是東八區(qū),最終得到的時間會比預期早 8 個小時,轉化得到時間戳也是不符合預期的。

舉例如下:

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)境下運行上面的代碼,now.timestamp() 得到時間戳轉化為對應的時間為東八區(qū)的 2021-01-07 23:58:49,但是 unow.timestamp() 得到的時間戳對應的時間為東八區(qū)的 2021-01-07 15:58:49,對應于 UTC 時間 2021-01-07 07:58:49,和 UTC 的當前時間完全對不上。

時間戳操作

  • datetime.timestamp() 生成當前時間對應的時間戳
  • datetime.fromtimestamp() 根據(jù)時間戳生成運行環(huán)境時區(qū)對應的時間
  • datetime.utcfromtimestamp() 謹慎使用 根據(jù)時間戳生成對應的 UTC 時間,由于生成的 datetime 是沒有指定時區(qū)的,因此獲取時間戳看起來得到的是 8 個小時之前時間的時間戳

對于上面的例子,我們使用前面得到的當前時間戳 1610035129 進行測試如下:

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 是本地時區(qū)正確的時間,但是 d2 是 UTC 的是啊金,但是沒有指定的時區(qū),因此看起來就是就是本地 8 個小時前的時間了

時區(qū)設置

默認構建的 datetime 是沒有時區(qū)信息的,可以通過 datetime.replace() 為時間設置上時區(qū),但是這樣必須保證對應的時間與時區(qū)信息匹配,否則就會導致錯誤的時區(qū)的時間,一個簡單例子就是:

from datetime import datetime, timedelta, timezone
tz_utc_8 = timezone(timedelta(hours=8)) # 創(chuàng)建時區(qū)UTC+8:00,即東八區(qū)對應的時區(qū) now = datetime.now() # 默認構建的時間無時區(qū) dt = now.replace(tzinfo=tz_utc_8) # 強制設置為UTC+8:00

設置上對應的時區(qū)后,對應的日期與時間是不變的,但是由于設置了全新的時區(qū),如果與之前的時區(qū)不同,那么對應的時間戳就會改變,使用此方法時要謹慎

時區(qū)轉換

可以將一個帶有時區(qū)信息的時間轉換為另一個時區(qū)的時間,通過 datetime.astimezone() 可以實現(xiàn),一個簡單的例子是:

from datetime import datetime, timedelta, timezone
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc) # 構建了 UTC 的當前時間 bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8))) # 將時區(qū)轉化為東八區(qū)的時間

通過 astimezone() 進行轉換后,雖然時間變化了,但是對應的是同樣的基準時間,因此對應的時間戳是不變的,

Grpc 實踐

在 Grpc 的使用中,設計到時間戳對象 Timestamp 與時間的轉換,Timestamp 對象支持通過 python 中的時間戳構建,即當前時間的對應的時間戳秒數(shù),也支持通過 datetime 構建。對應的接口如下:

  • Timestamp.FromSeconds() 此方法是根據(jù)時間戳生成 Grpc 的時間戳對象,沒有特殊的地方
  • Timestamp.FromDatetime() 謹慎使用 此方法根據(jù) datetime 時間生成時間戳對象,隱含期望 datetime 是 UTC 時間,如果錯誤傳入東八區(qū)時間,會導致得到一個 8 個小時后的絕對時間

我們在實踐中有混用這兩個方法,最終發(fā)現(xiàn)調用 FromDatetime() 時獲得的時間戳是完全不符合預期的。一個簡單例子如下:

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() 得到訂單時間戳與預期是不相符的,只有傳入的 datetime 是 UTC 的時間時兩者才是一致的

而轉換為 datetime 對象的接口為:

  • Timestamp.ToSeconds() 此方法是根據(jù)時間戳對象得到對應的整數(shù)時間戳,沒有問題
  • Timestamp.ToDatetime() 謹慎使用 此方法是根據(jù) grpc 的時間戳對象生成 datetime,隱含輸出的 datetime 是 UTC 時間 ,而生成的 datetime 是沒有時區(qū)信息的,默認會按照本地時區(qū)進行處理,不做處理的情況下得到的就是 8 個小時前,對應的時間戳也是錯誤的

與上面的問題類似,通過 ToDatetime() 得到的時間是 UTC 時間,但是由于得到的 datetime 沒有指定時區(qū),只有在 UTC 的運行環(huán)境下得到的時間才是符合預期的。

Pymongo 實踐

之前的在使用 Pymongo 進行數(shù)據(jù)存儲時,直接使用的是 Pymongo 的默認設置,運行環(huán)境設置為東八區(qū),在使用中直接將沒有指定時區(qū)的 datetime 存入數(shù)據(jù)庫中,之后再取出進行使用工作起來看起來一切正常。但是本次在梳理時區(qū)時查看數(shù)據(jù)庫中存儲的數(shù)據(jù)時,就發(fā)現(xiàn)了一個明顯的問題,數(shù)據(jù)庫中存儲的看起來日期與時間是對的,但是是 UTC 的時間,也就是說實際存儲的時間比預期晚 8 小時了,但是為什么又能正常工作呢?確認后結果如下:

  • Pymongo 在沒有指定時區(qū)的情況下, 默認不認為此時間為本地時間,事實上認為此時間為 UTC 時間,最終會利用此時間計算得到對應的時間戳并進行存儲,所以最終存儲的時間戳會晚 8 小時;
  • 而在默認設置下,從 Pymongo 中返回的時間也沒有時區(qū),而時間依舊是 UTC 時間,因此會導致計算得到時間又早了 8 小時,因此時間看起來是正常的。

如何才能保證存入正確時間,返回的也是符合預期的呢?

  • 存入的時間可以設置上對應的時區(qū),即避免存入 naive 類型的時間,應該存入 aware 類型的時間,避免輸入是認為是 UTC 的時間
  • 在 Pymongo 中設置輸出帶時區(qū)的時間,避免默認輸出時間的問題,Pymongo 可以通過 tz_aware 指定輸出帶時區(qū)的時間,通過 tzinfo 指定輸出時間的時區(qū),這個設置在構建 Pymongo 時傳入即可。對應如下:
from datetime import timedelta, timezone
 
db = MongoClient(settings.MONGODB_DSN, tz_aware=True, tzifo=timezone(timedelta(hours=8))).get_default_database()

總結

根據(jù)上面的的實踐,分別對三個部分進行使用如下:

  1. datetime 的使用中,如果運行環(huán)境設置為非 UTC 時區(qū),建議禁用 utc 相關的方法,比如 utcnow ,utcfromtimestamp() ,同時盡量避免使用 naive 使用,保證時間與運行環(huán)境解耦;
  2. grpc 的使用中盡量避免調用 FromDatetime() 和 ToDatetime() 這種包含隱含信息的方法,盡量通過時間戳與 grpc 的 TimeStamp 對象進行交互;
  3. Pymongo 中盡量傳入的帶有時區(qū)的時間,輸出也配置上時區(qū)輸出,避免隱含的問題;

一條總原則就是:與第三方的服務交互或存儲時,盡量只使用時間戳這種絕對機制,這樣才能從根本上杜絕問題。

以上就是python中的時區(qū)問題的詳細內容,更多關于python 時區(qū)的資料請關注腳本之家其它相關文章!

相關文章

  • python實現(xiàn)機器人行走效果

    python實現(xiàn)機器人行走效果

    這篇文章主要為大家詳細介紹了python實現(xiàn)機器人行走效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • python小練習之爬魷魚游戲的評價生成詞云

    python小練習之爬魷魚游戲的評價生成詞云

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Python爬取熱火的魷魚游戲評價,大家可以在過程中查缺補漏,提升水平
    2021-10-10
  • python實現(xiàn)windows壁紙定期更換功能

    python實現(xiàn)windows壁紙定期更換功能

    這篇文章主要為大家詳細介紹了python實現(xiàn)windows壁紙定期更換功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 基于Python實現(xiàn)文件大小輸出

    基于Python實現(xiàn)文件大小輸出

    在數(shù)據(jù)庫中存儲時,使用 Bytes 更精確,可擴展性和靈活性都很高。下面通過本文給大家介紹基于Python實現(xiàn)文件大小輸出,對python文件輸出相關知識感興趣的朋友一起學習吧
    2016-01-01
  • Python面向對象之繼承和多態(tài)用法分析

    Python面向對象之繼承和多態(tài)用法分析

    這篇文章主要介紹了Python面向對象之繼承和多態(tài)用法,結合實例形式分析了Python面向對象程序設計中繼承與多態(tài)的原理及相關操作技巧,需要的朋友可以參考下
    2019-06-06
  • pycharm 使用心得(三)Hello world!

    pycharm 使用心得(三)Hello world!

    作為PyCharm編輯器的起步,我們理所當然的先寫一個Hello word,并運行它。(此文獻給對IDE不熟悉的初學者)
    2014-06-06
  • 簡單有效上手Python3異步asyncio問題

    簡單有效上手Python3異步asyncio問題

    這篇文章主要介紹了簡單有效上手Python3異步asyncio問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • python查詢文件夾下excel的sheet名代碼實例

    python查詢文件夾下excel的sheet名代碼實例

    這篇文章主要介紹了python查詢文件夾下excel的sheet名方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • python?selenium參數(shù)詳解和實現(xiàn)案例

    python?selenium參數(shù)詳解和實現(xiàn)案例

    這篇文章主要介紹了python?selenium參數(shù)詳解和實現(xiàn)案例,無頭模式添加,可以讓selenium模擬登錄,進入到后臺運行,本文以登錄打開公司內網下載數(shù)據(jù)為例,給大家詳細講解,需要的朋友可以參考下
    2022-10-10
  • python中列表的切片與修改知識點總結

    python中列表的切片與修改知識點總結

    在本篇文章里小編給大家分享了關于python中列表的切片與修改的相關知識點內容,需要的朋友們學習下。
    2019-07-07

最新評論