python中處理時間的模塊有三個,datetime,time,calendar,融匯貫通三個模塊,才能隨心所欲地用python處理時間。本文就是為此而寫。關注並回復「time」得notebook
概述datetime模塊主要是用來表示日期的,就是我們常說的年月日時分秒。
calendar模塊主要是用來表示年月日,是星期幾之類的信息。
time模塊主要側重點在時分秒。
粗略從功能來看,我們可以認為三者是一個互補的關係,各自專注一塊。方便用戶依據不同的使用目的選用趁手的模塊。
從time模塊說起三個模塊中,time模塊是基礎。為了學習time模塊,我們需要先知道幾個與時間相關的概念:
1,epoch假設我們要將時間表示成毫秒數,比方說1000000毫秒,那有一個問題必須解決,這個1000000毫秒的起點是什麼時間,也就是我們的時間基準點是什麼時間?好比我說你身高1.8米,那這個身高是指相對於你站立的地面說的。這個時間基準點就是epoch,在Unix系統中,這個基準點就是1970年1月1日0點整那個時間點。
Unix時間戳(英文為Unix time, POSIX time 或 Unix timestamp)是從Epoch(1970年1月1日00:00:00 UTC)開始所經過的秒數,不考慮閏秒。
2,GMT, UTC上面我們說epoch表示1970年的起始點,那這個1970年又是相對於哪個基準時間呢?一般來說,就是相對於格林尼治時間,也叫做GMT(Greenwich Mean Time) 時間,還叫做UTC(Coordinated Universal Time),為啥一個時間基準有兩個名字?歷史上,先有的GMT,後有的UTC。
UTC是我們現在用的時間標準,GMT是老的時間計量標準。UTC是根據原子鐘來計算時間,而GMT是根據地球的自轉和公轉來計算時間。
所以,可以認為UTC是真正的基準時間,GMT相對UTC的偏差為0。
在實際中,我們的計算機中有一個硬體模塊RCT,裡面會實時記錄UTC 時間,該模塊有單獨的電池供電,即使關機也不影響。
有了epoch這個時間基準,又有了UTC這個基準的基準,我們就可以精確地表示一個時間了。
時間戳,epoch,utc三者之間的關係如下圖所示:
3,DST, tzone儘管我們已經可以精確地表示一個時間,很多情況下,我們還是要根據地區實際情況對時間進行一個調整,最常見的就是時區,tzone,相信大家都比較熟悉。此時,當我們說5點5分這個時間時,還需加上是哪個時區的5點5分才能精確說明一個時間。
另外一個對時間做出調整的就是DST。
DST 全稱是Daylight Saving Time,是說,為了充分利用日光,減少用電,人為地對時間做出一個調整,這取決於不同國家和地區的政策法規。比如說,假設你冬天7點天亮起床,但夏天6點天亮,那麼在夏天到來時人為將時間加1個小時,這樣就可以讓你還是覺得7點起床,但實際上是提前一個小時了。
那麼,好奇的我們,一定要問一問,python是如何知道tzone和DST這兩個的值呢?答案是通過環境變量。
這裡我們只以linux為例來說明一下。
在linux中有TZ環境變量,其值類似這樣:CST+08EDT,M4.1.0,M10.5.0,這個字符串可以做如下解讀,用空格分開他們,分成三部分
第一部分中的CST表示時區的名字,即China Standard Time,也就是我們說的北京時間,+8表示北京時間加上8小時就是UTC時間
第二部分EDT表示DST的名字,我們說DST是因各個國家地區的政策法規不同而不同的,EDT後面也可以像CST後面一樣加一個時間調整值,但由於我們國內只在86年到92年實行過一段時間DST,現在已經廢止,所以後面不用加調整時間。
第三部分表示的是實行DST的開始和結束時間,我們就不細解讀了。
4,時間的表示,獲取,轉換time模塊中獲取時間的基本方法是now = time.time()它返回的是從epoch到現在的秒數(用浮點數表示),用的是UTC時間。
如下圖所示:
我們自然而然地想把這個秒數轉為年月日時分秒的形式,而這種轉換又分兩種:
time模塊給我們提供了兩個方法,
time.gmtime(t)
time.localtime(t)
二者都返回一個類struct_time的實例,如下圖所示:
可以看到local time 確實比 gmt time 多了8個小時,說明確實是根據北京時區進行了調整。前面我們講過 CST+08表示的就是北京時間比utc要加8個小時。
struct_time實例具有如下屬性:
相比用秒數表示的時間,這樣的表示更適合我們理解。
除了以上屬性,struct_time還有一個tm_zone屬性。如下圖所示:
這兩個函數如果調用時不傳參數,它們內部會調用time.time(),並用返回的秒數做轉換。
相反的,python同樣提供了將這兩種struct_time轉為秒數的方法。
calendar.timegm()
方法用來把UTC的struct_time(gmtime的返回對象)轉為從epoch開始的秒數
time.mktime()
用來把用時區調整過的struct_time(即localtime的返回對象)對象轉為從epoch開始的秒數
如下圖所示:
struct_time中已經有時區信息了,為啥還要專門分兩個函數呢?
因為我們有可能從字符串中構建struct_time,而字符串中可能沒有時區信息。
時間和表示時間的字符串之間進行轉換time模塊中的strftime和strptime就是做這個用的。
看名字大家就應該知道它們的含義:
strftime 即 string format time,用來將時間格式化成字符串
strptime 即string parse time,用來將字符串解析成時間。
需要注意的是,這裡的時間都是struct_time對象。
關於怎麼格式化時間,就借用官網文檔的內容了。
這裡給一個簡單的例子:
除了這兩個函數,time模塊中還提供了兩個簡便方法,來幫助將時間轉為字符串
asctime
用來將一個struct_time對象轉為標準24字符的字符串,如下所示:
ctime
它與asctime作用相同,只不過它接收的是秒數,在內部,會先把秒數通過localtime轉為struct_time,再往後就與asctime一樣了。
如下圖所示:
以上就是time模塊的核心內容,下面,我們要開始學習datetime模塊。
datetime模塊time模塊解決了時間的獲取和表示,datetime模塊則進一步解決了快速獲取並操作時間中的年月日時分秒信息的能力。
1, datetime的時區問題現在,讓我們對時間中的時區進行一個小結。
首先,timestamp是基於utc的,它代表從epoch開始的秒數,而epoch是基於utc。在所有的時間表示中,它就是一個轉換橋梁。
然後,我們學會了將timestamp轉變成utc的struct_time和cst的struct_time。此時,struct_time中攜帶了時區信息。
緊接著,為了將struct_time變回timestamp,我們分別學習了 calendar.timegm和time.mktime。這兩個方法會忽略struct_time中的時區信息,分別按照utc和local時區(也就是環境變量中的時區)進行轉換。
當我們開始使用datetime.datetime時,時區問題變得複雜了。因為datetime有兩種,一種是有時區信息的,一種是沒有時區信息的。如下所示:
可以看到,如果沒有使用pytz指定utc時區,默認的datetime是沒有時區信息的。沒有時區信息,意味著,這個datetime的具體時間是啥留給使用該對象的我們來解釋了。
即使我們從timestamp中創建datetime,默認情況下,也是忽略了時區信息。
上述方法,得到的datetime是按照local時區轉換過的,但是datetime並不攜帶時區信息。這裡略有點繞,需要注意一下。
此時,必須明確指定時區,才能讓datetime攜帶時區信息。
為了將struct_time轉變為datetime,我們必須先轉成timestamp,在這步轉換中,必須合理地使用 calendar.gmtime和time.mktime。否則timestamp就會是錯誤的值。
2、時區的最佳實踐因為時區的存在,如何表示和存儲時間就是一個麻煩的問題。最佳的方案就是存儲時使用UTC,顯示時使用local。
但是萬事沒絕對,你還是需要根據你實際的情況決定如何使用時區。
3、datetime和str的轉換:string轉datetimedt = datetime.datetime.strptime('2020-11-18 11:39:31 CST', "%Y-%m-%d %H:%M:%S %Z")上面的轉換中,儘管字符串中有時區信息,但是得到的dt對象仍然是沒有時區信息的。這就是python中datetime容易令人困惑的地方,除非明確指定,否則datetime對象就是沒有時區信息的。
要判斷一個datetime對象有時區信息,需要同時滿足兩個條件:
dt.tzinfo.utcoffset(None) 返回不為空稍加驗證,即可知道。
datetime轉string可以看到,時區信息已經丟失了。
Note: datetime和time模塊中都有strftime、striptime。作用還是不一樣的。
datetime轉時間戳time_time = time.mktime(date_time.timetuple())上述代碼中,需要確保date_time是local的,否則表示就會錯誤。
時間戳轉datetime文章前面已有。
總結表示時間是一個挺複雜的事情,因為時間本身就是複雜的。認真學習一下時間的表示和轉換,無疑是有long term value的。因為時間是永恆的。