Python 有很多種方式處理日期和時間,常見的時間處理的模塊是datetime、time、calendar。能融匯貫通的了解和使用這三個模塊,才能輕而易舉地用python處理時間。本文以此為目的,通過講述各個時間模塊的概述、函數及相關知識細節、以及相應的示例來講透它們的使用方式。
這三個模塊中,datetime(日期時間)模塊主要是用來表示日期的,就是我們常說的年月日時分秒,calendar(日曆)模塊主要是用來表示年月日,是星期幾之類的信息,time(時間)模塊主要側重點在時分秒,粗略從功能來看,我們可以認為三者是一個互補的關係,各自專注一塊。方便用戶依據不同的使用目的選用趁手的模塊。
文章著重點在於梳理出三個模塊的設計脈絡,便於大家記憶裡面的api。在需要的時候能夠去查找相應的方法。由於文章篇幅較長,故將三個模塊和示例的講解拆分成幾篇前後關聯的文章,本文中重點講解datetime模塊。
一、概述
time模塊是比較基礎的一個模塊,可滿足對時間類型數據的基本處理;而 datetime模塊可以看做是對time模塊的一個高級封裝,功能更加強大。time模塊解決了時間的獲取和表示,datetime模塊則進一步解決了快速獲取並操作時間中的年月日時分秒信息的能力。
datetime模塊是這三個時間模塊中使用的相對較為頻繁,datetime有六個類,比較常用的有datetime、date、time、timedelta這四個,類date和類time可以看作是類datetime的子類別,雖然是分開的,但實際上這三個類的使用方法(函數)基本上是一樣的,所以學精通類datetime的屬性和方法,基本上可以無障礙的使用另兩個類了。
需要特別注意的是,datetime模塊中的類time和time模塊間的區別,不要混淆它們的用法,它們其中一個只是datetime模塊中的一個類別,需要用from datetime import time來進行引用,而另一個是一個獨立的模塊,只需要用import time。如果同時使用這兩個'time',那請直接導入datetime模塊和time模塊,更細緻的導入datetime模塊中的類time會混淆兩者的使用。
timedelta是datetime模塊中的一個非常有用的模塊,時間類型數據的計算可以通過timedelta方便快捷的實行,可以通過timedelta設置一個時間間隔,然後與指定時間進行計算,既可以獲取某個時間範圍內的目標,也可以計算時間間隔前後的日期時間。
有一點需要提前說明一下,time類和datetime類都有一個屬性,它的值是一個tzinfo對象,裡面包含了該time或者datetime的時區信息,一般稱這個time或者datetime對象是aware的,它能夠準確換算成自epoch開始的秒數。
如果該屬性設置為None,那麼,這時的time對象或者datetime對象就沒有時區信息,具體它表示的是local time還是utc time,需要我們自己在程序中去決定。
這裡我們所說的local time是指我們所在時區的時間, utc time指的就是國際標準時間,也就是格林尼治時間。在本文中不會涉及講解市區和夏令時的相關操作,一切默認為localtime。
類datetime、date、time
datetime對象就是date對象和time對象的組合。
# 導入datetime模塊三個核心的類
from datetime import datetime # class one:datetime 日期時間
from datetime import date # class two:date 日期
from datetime import time # class three:time 時間
創建
直接將時間的值逐個以參數的形式來創建
datetime(year,month,day,hour,minute,second,mircosecond)date(year,month,day)time(hour,minute,second,mircosecond)## 直接創建
datetime(2020,1,1,19,30,0,520)
date(2020,1,1)
time(19,30,0,520)
執行結果:
datetime.datetime(2020, 1, 1, 19, 30, 0, 520)
datetime.date(2020, 1, 1)
datetime.time(19, 30, 0, 520)
獲取當前時間
獲取當前日期用today,因為日期的最小計算單位是天,當前日期就是今天;date對象只有today一種獲取當前時間的方法,datetime對象卻有today和now兩種,結果是一致的,time對象沒有獲取當前時間的方法,不過可以通過datetime對象來獲取。
datetime.now() # 獲取當前日期時間
datetime.today() # 獲取當前日期時間
date.today() # 獲取當前日期
執行結果:
datetime.datetime(2019, 12, 31, 14, 26, 21, 655429)
datetime.datetime(2019, 12, 31, 14, 26, 21, 658430)
datetime.date(2019, 12, 31)
三者間的關係
類date和類time可以從類datetime中分離出來,也可以通過combine方法合併成新的類datetime變量。
datetime.combine(datetime.date,datetime.time)dt = datetime.now() # 獲取當前日期時間
dt
dt.date() # 提取日期部分
dt.time() # 提取時間部分
datetime.combine(dt.date(),dt.time()) # 合併日期和時間
執行結果:
datetime.datetime(2019, 12, 31, 14, 28, 36, 804160)
datetime.date(2019, 12, 31)
datetime.time(14, 28, 36, 804160)
datetime.datetime(2019, 12, 31, 14, 28, 36, 804160)
其他創建方式
除了直接以參數形式創建時間和獲取當前時間這兩種方式之外,還有三種通過其他形式的時間格式轉換的方法可以創建時間:
fromtimestamp(timestamp) 以時間戳為參數fromordinal(ordinal) 以ISO日曆公曆序數為參數fromisoformat(date_string) 以字符串格式時間為參數其中時間戳最小單位為秒,包含了日期和時間的信息;ISO日曆公曆序數最小單位為天,僅包含了日期的信息。這兩種方法只適用於datetime對象和date對象,time對象無法使用。
fromisoformat方法三種類都可以使用,但是它有著固定的輸入格式要求,如果是非標準格式的字符串,那麼無法使用該方法,後面的strptime方法才可以裝換非標準格式的時間。
## datetime
datetime.fromtimestamp(1577777777.32452) # 時間戳轉時間(以秒為單位)
datetime.fromordinal(737425) # 多格勒公曆序樹轉日期(以天為單位)
datetime.fromisoformat("2020-01-01 12:00:00") # YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]]
## date
date.fromtimestamp(1577784872) # 時間戳轉時間(以秒為單位)
date.fromordinal(739032) # 多格勒公曆序樹轉日期(以天為單位)
date.fromisoformat("2020-01-01") # 字符轉時間,僅支持格式 YYYY-MM-DD,注意01的0也要有
## time
time.fromisoformat("12:45:10") # 字符轉時間,僅支持格式HH:MM:DD
執行結果:
datetime.datetime(2019, 12, 31, 15, 36, 17, 324520)
datetime.datetime(2020, 1, 1, 0, 0)
datetime.datetime(2020, 1, 1, 12, 0)
datetime.date(2019, 12, 31)
datetime.date(2024, 5, 26)
datetime.date(2020, 1, 1)
datetime.time(12, 45, 10)
類屬性
datetime每一個類裡面的參數,都是可以通過獲取類屬性的方式單獨取出來的。
date:year、month、daytime:hour、minute、second、mircoseconddatetime:year、month、day、hour、minute、second、mircoseconddt = datetime.today()
dt
dt.year
dt.month
dt.day
dt.hour
dt.minute
dt.second
dt.microsecond
執行結果:
2019
12
31
15
22
40
354681
使用方法
replace()
修改替換時間中的時間參數,適用於三種類,例如:
dt = datetime.now()
dt
dt.replace(year=2020,day=15,hour=12)
執行結果:
timetuple()
返回time模塊中的時間元組,適用於datetime對象和date對象,不適用於time對象,例如:
dt = datetime.now()
dt.timetuple()
執行結果:
datetime.datetime(2019, 12, 31, 15, 27, 5, 882867)
time.struct_time(tm_year=2019, tm_mon=12, tm_mday=31, tm_hour=15, tm_min=27, tm_sec=5, tm_wday=1, tm_yday=365, tm_isdst=-1)
toordinal()
返回ISO公曆序數,即從公元0年1月1日起到目標日期的天數。適用於datetime對象和date對象,不適用於time,例如:
dt = datetime.now()
dt.toordinal()
d = date.today()
d.toordinal()
執行結果:
737424
737424
timestamp()
返回時間戳,即從公元1970年1月1日0時0分0秒起,到目標時間的秒數。僅適用於datetime對象,不適用於time對象和date對象,例如:
dt = datetime.now()
dt.timestamp()
執行結果:
1577777225.882867
weekday()
返回目標日期的工作日,0代表星期一,6代表星期日,適用於datetime對象和date對象,不適用於time對象,例如:
dt = datetime.now()
dt.weekday()
d = date.today()
d.weekday()
執行結果:
1
1
isoweekday()
返回目標日期的工作日,1代表星期一,7代表星期日,它和weekday的區別僅僅在於起始序數的不同,適用於datetime對象和date對象,不適用於time對象,例如:
dt = datetime.now()
dt.isoweekday()
d = date.today()
d.isoweekday()
執行結果:
2
2
isocalendar()
返回一個包含目標日期的年份、在一年中的第幾周、周幾三個元素在內的元組,適用於datetime對象和date對象,不適用於time,例如:
dt = datetime.now()
dt.isocalendar()
d = date.today()
d.isocalendar()
執行結果:
(2020, 1, 2)
(2020, 1, 2)
isoformat(sep ='T',timespec ='auto')
返回一個標準化的時間字符串,適用三種類;datetime對象使用時返回完整的字符串,日期和時間的分隔部分默認為字符「T」,可設定;date對象使用時只返回日期部分的字符串,time對象使用時只返回時間部分的字符串,例如:
dt = datetime.now()
dt.isoformat() # 默認以字符「T」分隔日期和時間
dt.isoformat(sep=" ") # 以空格「 」分隔日期和時間
d = date.today()
d.isoformat() # 日期部分
t = datetime.now().time()
t.isoformat() # 時間部分
執行結果:
'2019-12-31T15:27:05.882867'
'2019-12-31 15:27:05.882867'
'2019-12-31'
'15:27:05.882867'
strftime(format)
返回表示日期和時間的字符串,由明確的格式字符串控制,適用三種類。
詳細的字符串格式如下所示:
格式含義示例%a工作日(縮寫)Sun, Mon, …, Sat%A工作日(全稱)Sunday, Monday, …, Saturday%w以十進位數表示的工作日,其中0是星期日,6是星期六。0,1,…,6%d月份中的一天,十進位數字表示。01,02,…,31%b月份,縮寫名稱。Jan, Feb, …, Dec%B月份,全名。January, February, …, December%m月份,十進位數字01,02,…,12%y年份(無世紀的年份,後兩位),十進位數字。00,01,…,99%Y年份(四位完整),十進位數字。0001,0002,…,2013,2014,…,9998,9999%H小時(24小時制),十進位數字。00,01,…,23%I小時(12小時制)01,02,…,12%pAM或PMAM, PM%M分鐘,十進位數字。00,01,…,59%S秒,以零填充的十進位數。00,01,…,59%f微秒,以零填充的十進位數。000000,000001,…,999999%zUTC偏移量的格式 ±HHMM[SS[.ffffff]](empty), +0000, -0400, +1030, +063415, -030712.345216%Z時區名稱(empty), UTC, EST, CST%j一年中的一天,十進位數字。001,002,…,366%U一年中的第幾周(星期日為一周的第一天),以零填充的十進位數表示。以周六所在年份為基準。00,01,…,53%W一年中的第幾周(星期一為一周的第一天),以零填充的十進位數表示。以周日所在年份為基準00,01,…,53%c日期和時間Tue Aug 16 21:30:00 2019%x日期12/30/19%X時間17:24:13%%文字'%'字符。%%G年份,以零填充的十進位數表示。0001,0002,…,2013,2014,…,9998,9999%u工作日,十進位數字,其中1為星期一。1,2,…,7%V一年中的第幾周(星期一為一周的第一天)。第01周是包含1月4日的一周。01,02,…,53
示例:
dt = datetime.now()
d = dt.date()
t = dt.time()
dt.strftime("%Y-%m-%d") # 常用日期一
d.strftime("%Y/%m/%d") # 常用日期二
t.strftime("%H:%M") # 時分
t.strftime("%p %I:%M") # 12時制時分
dt.strftime("%Y%m%d%H%M%S%f")+str(".txt") # 文件名
print("現在是北京時間{0}年{1}月{2}日,今天是{0}年的第{3}周,是{0}年的第{4}天".format(dt.strftime("%Y"),dt.strftime("%m"),dt.strftime("%d"),dt.strftime("%U"),dt.strftime("%j")))
執行結果:
'2019-12-31'
'2019/12/31'
'15:27'
'PM 03:27'
'20191231152705882867.txt'
現在是北京時間2019年12月31日,今天是2019年的第52周,是2019年的第365天
strptime(date_string, format)
將字符串解析為datetime指定格式的對象,由明確的格式字符串控制,與strftime方法相對應。其內部還是先調用的time模塊中的striptime方法,獲取struct_time對象,再利用struct_time對象中的年月日時分秒信息構建datetime對象。
strftime 即 string format time,用來將時間格式化成字符串
strptime 即string parse time,用來將字符串解析成時間。
strptime方法只適用於datetime對象。例如:
datetime.strptime("2020-01-01 12:00:00","%Y-%m-%d %H:%M:%S")
執行結果:
datetime.datetime(2020, 1, 1, 12, 0)
以上介紹的方法中:
只適用於類datetime的方法:timestamp( )、strptime( )適用三種類的方法:replace( )、isoformat( )、strftime( )類timedelta
在日常的實際使用中,我們經常需要對日期進行比較和加減運算。得益於python的操作符重載能力,python中可以方便地對date對象之間,或者datetime對象之間進行大小比較和減法(-)操作。
需要注意的是,這裡僅限於同類對象之間的比較和減法運算,而且,不包括與time模塊對象的比較和運算。datetime模塊中的三個類,time對象僅能與同類做比較,不能進行任何運算,而date對象和datetime對象是可以和同中類型對象做減法運算的。
示例一:
## time對象只能同類做比較
time(21,2,4) >time(20,3,2)
# output1: True
## datetime對象可以比較,也可以做運算
dt = datetime(2019, 12, 31, 15, 22, 40, 354681)
dt - datetime(2019,1,1,0,0,0)
dt > datetime(2020,1,1,0,0,0)
# output2: datetime.timedelta(days=363, seconds=62653, microseconds=913011)
# output3: False
## date對象可以比較,也可以做運算
date(2020,1,1) - date(2019,1,1)
date(2020,1,1) > date(2019,12,31)
# output4: datetime.timedelta(days=365)
# output5: True
datetime模塊中三種對象的比較運算對比:
類能否同類比較能否同類作運算(僅減法)能否和timedelta類進行運算datetime能能能date能能能time能不能不能
從示例中可以看到,datetime對象和date對象同類中做減法返回的結果是datetime.timedelta對象,而這個就是datetime模塊中專門用於時間運算的類。個人認為,類timedelta是datetime模塊中最有價值的一部分,需要重點學習一下。
timedelta參數轉換
timedelta對象表示持續時間,兩個日期或時間之間的差,它一共有7個參數可以用來定義timedelta對象。
timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)但不是所有參數都會保留顯示,timedelta對象定義後,內部僅存儲天(day),秒(seconds)和微秒(microseconds)。其餘參數將按以下單位換算轉換為天、秒、微秒:
毫秒轉換為1000微秒。一分鐘轉換為60秒。一個小時轉換為3600秒。一周轉換為7天。相應的轉換公式為:
days = days + weeks * 2 = 64seconds = seconds + milliseconds/1000 + minutes * 60 + hours * 3600microseconds= microseconds它們之間的裝換
1 days = 86400 seconds1 seconds = 1000000 microseconds示例:
t = timedelta(50,27,10,29000,7,8,2)
# output: datetime.timedelta(days=64, seconds=29276, microseconds=10)
timedelta對象的簡單運算
timedelta對象進行多種合理的時間運算,如timedelta對象間加減法,timedelta對象與數值的乘除法運算。
示例二:
## timedelta對象可以進行的運算
t = timedelta(50,27,10,29000,7,8,2)
d = timedelta(5,3,234,324,35,16,0)
t + d # timedelta對象間加減法
t - d
t * 2.3 # timedelta對象與數值乘除法
t / 2.8
示例三:
t // 2 # timedelta對象整除,返回timedelta對象
t // d # timedelta對象間整除,返回整數
t / d # timedelta對象間相除,返回float
t % d # timedelta對象間相除取餘數,返回timedelta對象
divmod(t,d) # 求模
執行結果:
datetime.timedelta(days=32, seconds=14638, microseconds=5)
11
11.305345573308651
datetime.timedelta(days=1, seconds=63739, microseconds=433436)
(11, datetime.timedelta(days=1, seconds=63739, microseconds=433436))
可以用total_seconds()方法獲得一個timedelta對象的秒數表示,可用於和時間戳進行運算。
timedelta.total_seconds(t)
t.days * 86400 + t.seconds + t.microseconds/1000000
# output1: 5558876.00001
# output2: 5558876.00001
正負值
timedelta對象含有三個屬性:days,seconds, microseconds,days屬性可以取負值,另外兩個屬性都只能是正值。示例
t = timedelta(days=27,seconds=47283,microseconds=123942)
t
n = -t # 去t的負數
n
t + n # 等於0
t.seconds + n.seconds # 秒數相加等於86399
t.microseconds + n.microseconds # 微秒相加等於1,000,000
# timedelta對象也可以使用abs()函數求絕對值
abs(n) # 返回對應正數的timedelta對象
執行結果:
datetime.timedelta(days=27, seconds=47283, microseconds=123942)
datetime.timedelta(days=-28, seconds=39116, microseconds=876058)
datetime.timedelta(0)
86399
1000000
datetime.timedelta(days=27, seconds=47283, microseconds=123942)
timedelta對象的計算運用
前面提到的只是timedelta對象的一些基礎內容,實際使用上更多的是和date對象或者datetime對象進行計算,計算主體是date對象或者datetime對象,timedelta對象作為輔助。
示例:
# date運算
date(2020,1,1) - timedelta(days=100)
date(2020,1,1) + timedelta(days=100)
# datetime運算
dt = datetime(2020,2,22,20,2,2)
dt
dt + timedelta(days=20,seconds=4023)
dt - timedelta(days=20,seconds=4023)
執行結果:
# date運算結果
datetime.date(2019, 9, 23)
datetime.date(2020, 4, 10)
# datetime運算結果
datetime.datetime(2020, 2, 22, 20, 2, 2)
datetime.datetime(2020, 3, 13, 21, 9, 5)
datetime.datetime(2020, 2, 2, 18, 54, 59)
通過以上對datetime模塊的各種對象的詳細介紹,相信足以對它的各種操作有了比較完整的了解,這些都是基礎的示例運用,更進一步的使用要通過實際運用中各種不一樣的需求來實踐。