电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

python中的時區問題

瀏覽:6日期:2022-06-29 17:58:18
問題背景

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

基礎概念幾個時間概念

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

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

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

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

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

datetime 實踐

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

datetime 類型

datetime 分成兩種類型:

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

舉例如下:

from datetime import datetime, timezonenow = datetime.now()now.tzinfo # None utc_now = datetime.now(timezone.utc)utc_now.tzinfo # UTC

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

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

舉例如下:

from datetime import datetimenow = datetime.now()now.timestamp() # 1610035129.323702 unow = datetime.utcnow()unow.timestamp() # 1610006329.323797

最終在 2021-01-07 23:58:49 在東八區環境下運行上面的代碼,now.timestamp() 得到時間戳轉化為對應的時間為東八區的 2021-01-07 23:58:49,但是 unow.timestamp() 得到的時間戳對應的時間為東八區的 2021-01-07 15:58:49,對應于 UTC 時間 2021-01-07 07:58:49,和 UTC 的當前時間完全對不上。

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

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

from datetime import datetimetimestamp = 1610035129d1 = datetime.fromtimestamp(timestamp) # 2021-01-07 23:58:49 d2 = datetime.utcfromtimestamp(timestamp) # 2021-01-07 15:58:49

最終得到 d1 是本地時區正確的時間,但是 d2 是 UTC 的是啊金,但是沒有指定的時區,因此看起來就是就是本地 8 個小時前的時間了

時區設置

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

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

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

時區轉換

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

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

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

Grpc 實踐

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

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

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

from datetime import datetimefrom google.protobuf.timestamp_pb2 import Timestampnow = 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() 此方法是根據時間戳對象得到對應的整數時間戳,沒有問題 Timestamp.ToDatetime() 謹慎使用 此方法是根據 grpc 的時間戳對象生成 datetime,隱含輸出的 datetime 是 UTC 時間 ,而生成的 datetime 是沒有時區信息的,默認會按照本地時區進行處理,不做處理的情況下得到的就是 8 個小時前,對應的時間戳也是錯誤的

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

Pymongo 實踐

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

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

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

存入的時間可以設置上對應的時區,即避免存入 naive 類型的時間,應該存入 aware 類型的時間,避免輸入是認為是 UTC 的時間 在 Pymongo 中設置輸出帶時區的時間,避免默認輸出時間的問題,Pymongo 可以通過 tz_aware 指定輸出帶時區的時間,通過 tzinfo 指定輸出時間的時區,這個設置在構建 Pymongo 時傳入即可。對應如下:

from datetime import timedelta, timezone db = MongoClient(settings.MONGODB_DSN, tz_aware=True, tzifo=timezone(timedelta(hours=8))).get_default_database()總結

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

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

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

以上就是python中的時區問題的詳細內容,更多關于python 時區的資料請關注好吧啦網其它相關文章!

標簽: Python 編程
相關文章:
主站蜘蛛池模板: 变频器维修公司_plc维修_伺服驱动器维修_工控机维修 - 夫唯科技 变位机,焊接变位机,焊接变位器,小型变位机,小型焊接变位机-济南上弘机电设备有限公司 | 检验科改造施工_DSA手术室净化_导管室装修_成都特殊科室建设厂家_医疗净化工程公司_四川华锐 | 温湿度记录纸_圆盘_横河记录纸|霍尼韦尔记录仪-广州汤米斯机电设备有限公司 | 抖音短视频运营_企业网站建设_网络推广_全网自媒体营销-东莞市凌天信息科技有限公司 | uv固化机-丝印uv机-工业烤箱-五金蚀刻机-分拣输送机 - 保定市丰辉机械设备制造有限公司 | 合肥触摸一体机_触摸查询机厂家_合肥拼接屏-安徽迅博智能科技 | 旋振筛_不锈钢旋振筛_气旋筛_旋振筛厂家—新乡市大汉振动机械有限公司 | 臭氧灭菌箱-油桶加热箱-原料桶加热融化烘箱-南京腾阳干燥设备厂 臭氧发生器_臭氧消毒机 - 【同林品牌 实力厂家】 | 长沙发电机-湖南发电机-柴油发电机供应厂家-长沙明邦智能科技 | 水质监测站_水质在线分析仪_水质自动监测系统_多参数水质在线监测仪_水质传感器-山东万象环境科技有限公司 | 镀锌钢格栅_热镀锌格栅板_钢格栅板_热镀锌钢格板-安平县昊泽丝网制品有限公司 | 广西资质代办_建筑资质代办_南宁资质代办理_新办、增项、升级-正明集团 | 校园文化空间设计-数字化|中医文化空间设计-党建|法治廉政主题文化空间施工-山东锐尚文化传播公司 | 苏州防水公司_厂房屋面外墙防水_地下室卫生间防水堵漏-苏州伊诺尔防水工程有限公司 | 算命免费_生辰八字_免费在线算命 - 卜算子算命网 | 新材料分散-高速均质搅拌机-超声波分散混合-上海化烁智能设备有限公司 | 自动记录数据电子台秤,记忆储存重量电子桌称,设定时间记录电子秤-昆山巨天 | 铸钢件厂家-铸钢齿轮-减速机厂家-淄博凯振机械有限公司 | 常州翔天实验仪器厂-恒温振荡器-台式恒温振荡器-微量血液离心机 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | 涿州网站建设_网站设计_网站制作_做网站_固安良言多米网络公司 | DDoS安全防护官网-领先的DDoS安全防护服务商 | 水上浮桥-游艇码头-浮动码头-游船码头-码瑞纳游艇码头工程 | 空气弹簧|橡胶气囊|橡胶空气弹簧-上海松夏减震器有限公司 | 山东臭氧发生器,臭氧发生器厂家-山东瑞华环保设备 | 锻造液压机,粉末冶金,拉伸,坩埚成型液压机定制生产厂家-山东威力重工官方网站 | 心肺复苏模拟人|医学模型|急救护理模型|医学教学模型上海康人医学仪器设备有限公司 | 品牌策划-品牌设计-济南之式传媒广告有限公司官网-提供品牌整合丨影视创意丨公关活动丨数字营销丨自媒体运营丨数字营销 | 实验室装修_实验室设计_实验室规划设计- 上海广建净化工程公司 | 合肥废气治理设备_安徽除尘设备_工业废气处理设备厂家-盈凯环保 合肥防火门窗/隔断_合肥防火卷帘门厂家_安徽耐火窗_良万消防设备有限公司 | 莱州网络公司|莱州网站建设|莱州网站优化|莱州阿里巴巴-莱州唯佳网络科技有限公司 | 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 杭州货架订做_组合货架公司_货位式货架_贯通式_重型仓储_工厂货架_货架销售厂家_杭州永诚货架有限公司 | 药品/药物稳定性试验考察箱-埃里森仪器设备(上海)有限公司 | 工程管道/塑料管材/pvc排水管/ppr给水管/pe双壁波纹管等品牌管材批发厂家-河南洁尔康建材 | 东莞工厂厂房装修_无尘车间施工_钢结构工程安装-广东集景建筑装饰设计工程有限公司 | 直线模组_滚珠丝杆滑台_模组滑台厂家_万里疆科技 | 辽宁资质代办_辽宁建筑资质办理_辽宁建筑资质延期升级_辽宁中杭资质代办 | 车辆定位管理系统_汽车GPS系统_车载北斗系统 - 朗致物联 | 工程管道/塑料管材/pvc排水管/ppr给水管/pe双壁波纹管等品牌管材批发厂家-河南洁尔康建材 | 聚合氯化铝-碱式氯化铝-聚合硫酸铁-聚氯化铝铁生产厂家多少钱一吨-聚丙烯酰胺价格_河南浩博净水材料有限公司 | 量子管通环-自清洗过滤器-全自动反冲洗过滤器-北京罗伦过滤技术集团有限公司 |