日常的開發過程中總會與到日期與時間的處理,尤其是最近的2個項目都還會遇到時區問題,個人在開發的過程中也遇到過不同的問題,這里總結一下Python操作日期與時間相關的方案。
《PythonCookBook》中關於日期時間的操作
這本書中關於日期時間的操作非常值得參考:第三章:數字日期和時間
個人之前總結的博客
pymysql往數據庫中插入datetime類型的"空數據"與MySQL5.7sql_mode的一個問題
關於時區操作的pytz模塊 ***
有的時候我們會看到類似"10/Sep/2015:06:47:35"或"2015-9-10T06:47:35"這樣的時間字符串。首先要強調的是上面兩種表達方式無論哪一種都是錯誤的表達方式,因為沒有時區的時間字符串是沒有意義的!!!
整個世界被分為12個時區,從-12~+12,負數代表西時區,而正數代表東時區,以英國的0時區為中心。比如中國的時區可以用+8來表示,更多的使用+08:00或+0800來表示,讀作“東八區”。有些時候我們用CST時間表示中國標准時間,或者在某些操作系統中使用’Asia/Shanghai’代表東八區。
所以正確的時間字符串應當是"10/Sep/2015:06:47:35 +0800"或"2015-9-10T06:47:35+0800"的包含時區的格式,如果不是,那么請確認你得到這份包含時間數據的語境以確保知道其時區,因為畢竟不同時區的同一時間實際上是不同的時間。
獲取0時區的操作
直接使用內置的datetime模塊中的utcnow方法:
使用pytz模塊轉換時區
使用第三方模塊 pytz:
注意1
時區的英文名稱,比如這里使用的’Asia/Shanghai',我們如何才能知道其他地區的時區呢?可以通過pytz.all_timezones這個屬性獲取。
注意2
時間格式化函數strftime()及其參數’%Y-%m-%d %H:%M:%S%z’。
這個函數的意思是將datetime類型的時間格式化成其參數所描述的格式,在上面的程序中很明顯地,Y代表年,m代表月,d代表日,H代表小時,M代表分鍾,S代表秒,z代表時區。
字符串與時間戳相互轉換的arrow模塊 ***
將包含時區的時間字符串轉換成時間戳 ***
相關的案例代碼如下:
import time from datetime import datetime import pytz import arrow tz = pytz.timezone("Asia/Shanghai") dt = datetime.utcnow() print("dt>>>",dt) # dt>>> 2020-09-28 11:05:43.693912 time_now = time.time() print("time_now>>>",time_now) # time_now>>> 1601291143.693969 # 格式化方式1 cst_time1 = tz.fromutc(dt).strftime("%Y-%m-%d %H:%M:%S%z") print("sct_time1>>>",cst_time1) # sct_time1>>> 2020-09-28 19:05:43+0800 arrow1 = arrow.get(cst_time1,"YYYY-MM-DD HH:mm:ssZ").timestamp print("arrow1>>>",arrow1) # arrow1>>> 1601291143 # 格式化方式2 cst_time2 = tz.fromutc(dt).strftime("%d/%b/%Y:%H:%M:%S%z") print("cst_time2>>>",cst_time2) # cst_time2>>> 28/Sep/2020:19:05:43+0800 arrow2 = arrow.get(cst_time2,"DD/MMM/YYYY:HH:mm:ssZ").timestamp print("arrow2>>>",arrow2) # arrow2>>> 1601291143 # 格式化方式3 cst_time3 = tz.fromutc(dt).strftime("%Y-%m-%dT%H:%M:%S %z") print("cst_time3>>>",cst_time3) # cst_time3>>> 2020-09-28T19:05:43 +0800 arrow3 = arrow.get(cst_time3,"YYYY-MM-DDTHH:mm:ss Z").timestamp print("arrow3>>>",arrow3) # arrow3>>> 1601291143 # 格式化方式4 cst_time4 = tz.fromutc(dt).strftime("%c %z") print("cst_time4>>>",cst_time4) # cst_time4>>> Mon Sep 28 19:05:43 2020 +0800 arrow4 = arrow.get(cst_time4,"ddd MMM DD HH:mm:ss YYYY Z").timestamp print("arrow4>>>",arrow4) # arrow4>>> 1601291143
有一點稍稍讓人感到困擾,arrow需要的字符串格式化參數與Python標准庫datetime的不同,雖然看起來大同小異,不過還是需要稍微熟悉一下。
將時間戳轉換成時間字符串 ***
下面的代碼分別使用Python標准庫和arrow兩種方法進行舉例:
import time from datetime import datetime import pytz import arrow tz = pytz.timezone("Asia/Shanghai") dt = datetime.utcnow() print("dt>>>",dt) # dt>>> 2020-09-28 11:51:32.814224 time_now = time.time() print("time_now>>>",time_now) # time_now>>> 1601293892.814267 ### python標准庫方案 ret1 = tz.fromutc(datetime.utcfromtimestamp(time_now)).strftime("%Y-%m-%d %H:%M:%S %z") print("標准庫方案>>>",ret1,type(ret1)) # 標准庫方案>>> 2020-09-28 19:51:32 +0800 <class 'str'> ### arrow方案 ret2 = arrow.get(time_now).to(tz).format("YYYY-MM-DD HH:mm:ss Z") print("arrow方案>>>",ret2,type(ret2)) # arrow方案>>> 2020-09-28 19:51:32 +0800 <class 'str'>
~~~
開始的時間是當天的0點的獲取方式
# 開始時間是當天的0點 until = datetime.now() now_date_str = until.strftime("%Y-%m-%d") year, month, day = now_date_str.split("-") since = datetime(int(year), int(month), int(day), 00, 00, 00)
使用字符串格式化進行時區轉換
實現的方式比較low(0-0),當作是筆記把!!!
注意這種方式是在特定的業務場景下使用的,下面我會詳細介紹。
在實際的業務中,我使用SDK獲取到的日期的格式是這樣的:
"created_time": "2020-09-11T18:42:32+0800"
后面的 +0800 就是“東八區”的意思。我需要將獲取到的數據經過結構的構建與邏輯的處理最后存入到MySQL數據庫中。
但是數據的日期在數據庫中必須按照 UTC0時區 的格式存儲(歷史原因...),所以我還需要額外的處理一下時區。網上找了很多這方面的資料,但是感覺還是跟自己業務邏輯相差比較遠,根據自己的認真觀察,發現存入數據庫的日期數據其實就比當前獲取的時間晚8小時——所以干脆進行timedelta操作就可以了...
下面是實現的demo:
# 業務代碼略 ret2 = cam.api_get(fields=fields) updated_time = ret2["updated_time"] print("updated_time>>>>>",updated_time) # updated_time>>>>> 2020-09-23T00:02:02+0800 ### 如果是東8區時間 往后推8小時!!! if "0800" in updated_time: # 按照東8區的格式格式化 print(updated_time, type(updated_time)) # 2020-09-23T00:02:02+0800 <class 'str'> publish_time = datetime.strptime(updated_time, "%Y-%m-%dT%H:%M:%S+0800") # 往后推8小時就是UTC時間 publish_time = publish_time - timedelta(hours=8) # 如果是UTC時間直接處理並寫入數據庫 elif "0000" in updated_time: # 按照UTC的格式格式化 publish_time = datetime.strptime(updated_time, "%Y-%m-%dT%H:%M:%S+0000") else: raise Exception("時間格式不規范") ### 需要轉換成str類型才能寫入數據庫!!! publish_time = str(publish_time) print("<<<<<",publish_time) # <<<<< 2020-09-22 16:02:02
~~~