Python關於時區與時間相關的操作匯總


  日常的開發過程中總會與到日期與時間的處理,尤其是最近的2個項目都還會遇到時區問題,個人在開發的過程中也遇到過不同的問題,這里總結一下Python操作日期與時間相關的方案。

《PythonCookBook》中關於日期時間的操作

  這本書中關於日期時間的操作非常值得參考:第三章:數字日期和時間

個人之前總結的博客

      time模塊

      datetime模塊 

      分割處理存放連續時間字符串的列表

      datetime模塊格式化以及去掉前導0的操作說明

      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  

~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM