時間數(shù)據(jù)
時間格式是數(shù)據(jù)類型中基礎(chǔ)也不容忽視的一類。不像整數(shù)那樣大道至簡也不像字符串那樣包羅萬象,卻獨(dú)有魅力,時間數(shù)據(jù)本身除了加減、比較運(yùn)算外,也有下周、去年、時區(qū)等更專項(xiàng)的時間切換。在各類編程語言里都提供時間對象的支持,在MySQL里也有DATETIME類型。商業(yè)里的DAU、GMV、LTV也少不了時間限定和時間屬性,因此數(shù)據(jù)分析時少不了對時間數(shù)據(jù)類型的處理與轉(zhuǎn)換。
Python通過套件time、datetime、timeit處理時間類型數(shù)據(jù),但面對一些情況時會不夠靈活和易用,在時間序列生成和截斷方面捉襟見肘,于是誕生了Arrow、Pendulum、Maya等庫增強(qiáng)了Python的時間處理能力。本篇對4個標(biāo)準(zhǔn)庫和6大第三方模塊進(jìn)行介紹,在面對需求時能拿到最趁手的工具。
模塊概覽
在Python中進(jìn)行時間類型數(shù)據(jù)處理能用到的模塊有:
- time:Python內(nèi)置時間庫,通過時間戳或元組表示時間;
- datetime:內(nèi)置日期庫,處理日期時間對象和屬性;
- dateutil:基于datetime庫的實(shí)用拓展,增強(qiáng)了對時間間隔和時間序列的處理;
- pd.Timestamp:pandas庫用于時間處理的類;
- Arrow:優(yōu)秀的Python時間庫,簡化了時間類型數(shù)據(jù)的解析和輸出;
- Pendulum:可以和Arrow對標(biāo)的時間處理庫,pendulum意為鐘擺;
- Delorean:在dateutil基礎(chǔ)上進(jìn)一步拓展的時間庫,以《回到未來》中的時間旅行車命名;
- moment:靈感來源于Moment.js,目前相對原始;
- Maya:和Arrow等庫對標(biāo),增強(qiáng)了對時區(qū)的處理,有調(diào)用pendulum的部分功能;
在深入這些庫的使用之前,先補(bǔ)充一些先驗(yàn)知識:
epoch:時間基準(zhǔn)點(diǎn)至特定時間的總秒數(shù),一般用一個浮點(diǎn)數(shù)值記錄,這個基準(zhǔn)點(diǎn)在Unix及類Unix系統(tǒng)中是格林威治時間1970年01月01日00時0分0秒,因此也稱為Unix時間戳(Timestamp)。因?yàn)榈厍蚴且粋€橢球體,當(dāng)英國是中午時中國北京已經(jīng)在吃晚飯了,不同經(jīng)度地區(qū)的0點(diǎn)相對于格林威治的0點(diǎn)有一個時差,也就有時區(qū)(timezone)的區(qū)分,以UTC(世界協(xié)調(diào)時)作為基準(zhǔn),中國采用的東八區(qū)就可表示為UTC+8,對應(yīng)北京時間減8個小時就是UTC時間。
基于以上需要考慮的問題,在時間類中,表示一個時間有兩種基本選擇:
一是用浮點(diǎn)數(shù)記錄一個時間戳epoch,時間小于1970年則是負(fù)數(shù),二是用元組或字典記錄年月日時分秒時區(qū)等,在Python的time模塊就是記錄了epoch和一個元組叫struct_time,這兩者之間可以互相轉(zhuǎn)換。
模塊特性與實(shí)踐
time&datetime
time是Python內(nèi)置的時間庫,功能簡約但實(shí)用,通常和同為內(nèi)置庫的datetime、pytz及calendar互相配合解決各類時間表示、計算、輸出等需求。
time的常用方法有:
- time.time():得到當(dāng)前時間戳Timestamp,是一個浮點(diǎn)數(shù);
- time.localtime([secs]):將一個時間戳轉(zhuǎn)換為當(dāng)前時區(qū)的struct_time。secs參數(shù)未提供,則以當(dāng)前時間為準(zhǔn),相當(dāng)于獲取當(dāng)前時間now();
- time.gmtime(ts):時間戳轉(zhuǎn)struct_time;struct_time是一個包含了9個元素的元組,對應(yīng)著改時間對象的年月日、本年第幾天等屬性;
- time.mktime(t):struct_time轉(zhuǎn)時間戳;
- time.strftime("%Y-%m-%d",t):struct_time轉(zhuǎn)格式化字符串;
- time.strptime('2020-12-7',"%Y-%m-%d"):字符串轉(zhuǎn)struct_time;
import time
time.time() #type(time.time())==float
#Out[]:1607319973.764
time.localtime()
# time.struct_time(tm_year=2020, tm_mon=12, tm_mday=7, tm_hour=13, tm_min=46, tm_sec=13, tm_wday=0, tm_yday=342, tm_isdst=0)
st=time.gmtime(time.time())
st.tm_year #獲取屬性,st是元組,不能修改
# 2020
基于time模塊生成的時間對象t,如果是時間戳形式表示的,是不能直接得到t是在哪一年等屬性的,需要先轉(zhuǎn)struct_time形式,然后就可以寫st.tm_year獲取所在年。st是元組,不能修改,即不能用st.tm_year=2019來修改的st的實(shí)際值。
t=time.strptime('2020-12-7 13:52:15',"%Y-%m-%d %H:%M:%S")
# time.struct_time(tm_year=2020, tm_mon=12,...)
time.strftime("%Y-%m-%d %H:%M:%S",t)
# 2020-12-7 13:52:15
從文件中讀取數(shù)據(jù)時常需要從字符串形式變成時間對象,就會用到strptime,是string parse time的簡寫,即從字符串?dāng)?shù)據(jù)類型中解析成時間類型。strftime是把時間類型格式化為字符串,是strptime的逆操作,f是format的縮寫。
時間類型格式化有一套特定的占位符,下面介紹的符號在其他時間模塊里也通用,因此常用的占位符還是需要心里有數(shù)才能靈活“組裝”出自己需要的字符串效果的。下面表格列出了常用的時間格式化占位符,更全面的表可查閱time模塊文檔。
time模塊常和datetime模塊組合使用,time側(cè)重在時間,datetime在日期方面方法更豐富,且datetime會和pytz及calendar配合處理時間對象。
在datetime里也有strftime和strptime,不過需要注意的是,兩個庫輸入?yún)?shù)順序的區(qū)別,datetime的strftime,格式化字符串在后,代碼實(shí)例如下。
from datetime import datetime
dt=datetime.strptime('2020-12-7 13:52:15',"%Y-%m-%d %H:%M:%S")
datetime.strftime(dt,"%Y-%m-%d %H:%M:%S") #
# 2020-12-7 13:52:15
time.strftime("%Y-%m-%d %H:%M:%S",t)
# datetime庫內(nèi)部也是調(diào)用time的striptime
# datetime.strftime -> _wrap_strftime ->_time.strftime
在datetime中新建時間對象可以直接使用datetime(y, m,d,tzinfo)輸入?yún)?shù),用datetime.now()獲得當(dāng)前時間,通過datetime.fromtimestamp(ts)可以將時間戳ts轉(zhuǎn)為時間對象,生成的datetime時間對象在獲取屬性時用到的語句類似dt.year,有year/month/day/hour/second/tzinfo等可以用。tzinfo是時區(qū)屬性,datetime在時區(qū)相關(guān)處理時通常用到pytz。
import pytz
sh=pytz.timezone('Asia/Shanghai') #新建一個時區(qū)
dt=datetime(2020,12,7,hour=8,tzinfo=sh)
datetime.fromtimestamp(time.time())
#datetime.datetime(2020,12,8,16,59,42,797401)
dt.year #返回給定datetime對象的年份
#Out[]: 2020
#屬性有.hour .minute .second .microsecond 等
datetime.weekday() #返回星期幾,星期一為 0,星期天為 6
#方法還有 .isoweekday() .toordinal() 等
datetime.combine(dt.date(),dt.time())
#combine:將一個date對象和一個time對象組合成一個datetime對象
from datetime import timezone #如果不使用pytz庫
d1=datetime(2020, 11, 21,tzinfo=timezone(timedelta(hours=8)))
tdt=dt-d1
# datetime.timedelta(days=16)
dt+timedelta(20)
兩個datetime日期相減得到的是一個時間間隔對象(imedelta),timedelta可以和數(shù)值進(jìn)行乘法和整除運(yùn)算,兩個timedelta對象之間可以進(jìn)行加減運(yùn)算,但不能比較大小,datetime對象可以和timedelta對象進(jìn)行加減得到新的datetime實(shí)現(xiàn)時間偏移。
datetime也會和內(nèi)置的calendar庫進(jìn)行配合,顧名思義,calendar庫主要用來處理和輸出整年、整月的日歷。
print(calendar.calendar(2020)) #打印2020年日歷
#calendar.prcal(2020) #兩個語句效果相同
calendar.prmonth(2019,2) #打印2019年2月的日歷
calendar.isleap(2020) #是否閏年
# True
calendar.weekday(2020,11,20) #指定日期為星期幾,
#4 代表星期五
這幾個庫其他的實(shí)用方法有:
- time.sleep(secs):線程推遲指定的時間運(yùn)行,單位為秒;
- time.asctime([t]) :把一個表示時間的元組或者struct_time表示為這種形式:'Sun Jun 20 23:21:05 1993',如沒有參數(shù),將會將time.localtime()作為參數(shù)傳入;
- time.ctime([secs]):把一個時間戳(按秒計算的浮點(diǎn)數(shù))轉(zhuǎn)化為time.asctime()的形式。如果參數(shù)未給或者為None的時候,將會默認(rèn)time.time()為參數(shù)。它的作用相當(dāng)于time.asctime(time.localtime(secs));
- calendar.leapdays(n,m):年份n到m之間的閏年數(shù)量;
dateutil
dateutil模塊是基于datetime庫的實(shí)用拓展,增強(qiáng)了對時間間隔和時間序列的處理,因此dateutil類型直接繼承了datetime類型,dateutil庫生成的時間對象就是datetime。Anaconda下該庫已經(jīng)安裝,模塊里有parser、easter、relativedelta、rrule等實(shí)用類進(jìn)行時間處理。
import dateutil #anaconda下已經(jīng)安裝,直接import
dt=dateutil.parser.parse('April 29 2020 14:20')
#可以從字符串解析,不需要手動寫匹配的占位符。
dt=dateutil.parser.parse('April 29') #會取當(dāng)前年
# datetime.datetime(2020, 4, 29, 0, 0)
dt=dateutil.parser.parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
dateutil的parser類用于更方便地從字符串解析為datetime對象,parser.parse(string)可以從各種類型的字符串例如一句自然語言中解析出日期,但輸入的參數(shù)string必須是字符串,輸入時間戳不行(這個和下面提到的Arrow等庫不同)。
因?yàn)榻馕鰹閐atetime類型的對象,所以可以使用datetime的各種方法和屬性,例如需要知道是哪一年仍然使用dt.year獲取。
一些datetime類的方法可以基于dt實(shí)例使用,要實(shí)現(xiàn)從時間戳轉(zhuǎn)時間對象,就可以使用dt.fromtimestamp(ts),獲取當(dāng)前時間,就可以使用dt.now()。
dt.fromtimestamp(dt.timestamp()) #時間戳與時間對象互轉(zhuǎn)
dt.strftime('%Y-%m-%d') #只能輸入一個參數(shù)
#時間對象轉(zhuǎn)字符串
dateutil.easter.easter(2020,method=3)
#計算輸入年份復(fù)活節(jié)的日期
dateutil計算時間間隔的方法封裝在relativedelta里,通過輸入?yún)?shù)months等明確間隔的時間距離,tz用于處理時區(qū)。
dt+dateutil.relativedelta.relativedelta(months=1, weeks=1)
#時間偏移
# datetime.datetime(2021, 1, 14, 14, 15, 39, 173204)
relativedelta(datetime(2003, 10, 24, 10, 0),dt) #得到一個時間間隔
relativedelta(NOW, johnbirthday) #得到一個人的年齡
#下周五對應(yīng)的時間
dt+relativedelta(weekday=FR)
rrule類用于生成和處理一個時間序列。rrule的主要參數(shù)有:
- freq:聲明序列重復(fù)的周期;
- count:生成多少個時間對象;
- dtstart:開始的時間點(diǎn);
list(dateutil.rrule.rrule(freq=dateutil.rrule.MONTHLY, count=4, dtstart=datetime(2020, 12,7)))
# [datetime.datetime(2020, 12, 7, 0, 0),datetime.datetime(2021, 1, 7, 0, 0),...]
list(dateutil.rrule.rrulestr("""
DTSTART:20201207T090000
RRULE:FREQ=DAILY;INTERVAL=10;COUNT=4
"""))
#效果同上,rrulestr是根據(jù)字符串規(guī)則生成時間序列
以上例子生成的是一個由4個時間對象組成的序列,開始時間是2020年12月7號,每月重復(fù)一條記錄。rrule.rrulestr()是把字符串輸入當(dāng)參數(shù)。
pandas
實(shí)際在進(jìn)行數(shù)據(jù)分析時,通常都會用到pandas庫卻不一定會導(dǎo)入datetime等庫,而pandas模塊也提供了Timestamp、Timedelta等類用于時間類型數(shù)據(jù)的處理轉(zhuǎn)換。直接使用pd.Timestamp也更容易進(jìn)行廣播運(yùn)算。
pandas的Timestamp對象用法和datetime庫基本一致,各種dt.year屬性都有,也有dt.isleapyear用于判斷是否是閏年。pd.Timedelta對應(yīng)datetime的timedelta,表示時間間隔。
df['時間']=pd.to_datetime(df['dt'])
df['years']=df['時間'].apply(lambda x:x.year)
sdf=df.loc[df['years']==2018]
ddr=dd/(pd.Timestamp('2018-12-31')-pd.Timestamp('2018-1-1')).days
df['tfs']=df['時間'].apply(lambda x:x.hour+x.minute/60+x.second/3600)
《用pandas處理時間格式數(shù)據(jù)》講述了一個處理Excel文件中時間數(shù)據(jù)的案例。
Arrow
Arrow是一個優(yōu)秀的Python時間處理庫,現(xiàn)在其他有追求的第三方時間處理庫都喜歡在文檔里對標(biāo)Arrow,足矣見Arrow的影響力。Arrow通過收束接口增強(qiáng)了其易用性,可以快速上手使用,get統(tǒng)籌各種輸入的解析,replace負(fù)責(zé)各種時間要素的修改,format解決各類格式化輸出的需求,range處理時間序列生成問題。
Arrow解析字符串或datetime對象得到的是一個自定義時間對象,通過dt.time、dt.datetime、dt.timestamp等將時間數(shù)據(jù)從Arrow內(nèi)置對象轉(zhuǎn)為time等庫的時間對象,一些例子如下。
import arrow #在Anaconda下已經(jīng)安裝
arrow.get('2020-12-08 17:31:20')
#Out[]: <Arrow [2020-12-08T17:31:20+00:00]>
dt=arrow.get(1607334506) #get可輸入Unix時間戳,也可輸入datetime對象
dt.datetime #轉(zhuǎn)為dateime類型
dt.naive #轉(zhuǎn)為當(dāng)?shù)貢r區(qū)的datetime類型
dt.floor('hour') #從小時處截斷,小時之后的數(shù)清零
d1.replace(hour=3)
d1.shift(weeks=+4) #當(dāng)前時間4周后
d1.to('Asia/Shanghai') #換時區(qū)
dt.format('YYYY-MM-DD') #輸出格式化字符串
arrow.Arrow.range('hour',arrow.now(),arrow.now().shift(hours=5))
#arrow生成時間序列
dt.humanize() #dt的自然語言表示
Arrow的具體用法可參考前文《Python處理時間數(shù)據(jù)的另一種選擇,在標(biāo)準(zhǔn)庫之外》。
Pendulum
Pendulum也是一款很優(yōu)秀的Python時間處理模塊,其內(nèi)置數(shù)據(jù)類型拓展自datetime,與datetime有著很好的兼容性。Pendulum比dateutil功能更豐富,足矣和Arrow對標(biāo)。Arrow的易用性體現(xiàn)在接口簡潔,Pendulum的易用性表現(xiàn)在很多datetime的方法都兼容,而且Pendulum的文檔頁面也更美觀漂亮。Pendulum[?pend??l?m]意為鐘擺,是很好的時間意向。Pendulum通過其內(nèi)置的DateTime對象實(shí)現(xiàn)和拓展datetime.datetime的功能,同時封裝出Duration、Period及Timezones處理時間偏移、時區(qū)、時間序列。
import pendulum
dt=pendulum.now() #獲取本地時區(qū)的當(dāng)前時間
#DateTime(2020,12,8,18,0,8,697484,tzinfo=Timezone('Asia/Shanghai'))
pendulum.tomorrow() #明天的這個時候
dt.year # 2020
dt.week_of_year #dt所在周是本年第幾周
dt.age #dt對應(yīng)日期目前的年齡
dt.strftime('%Y-%m-%d')
d2=dt.set(year=2019) #把年份變成2019
dt.add(years=-1) #把時間變成1年前,注意是years不是year
period = pendulum.period(dt, dt.add(days=8))
list(period.range('days',2)) #時間序列
其他的一些實(shí)用方法如下:
- pendulum.datetime(2020,5,7):輸入年月日等生成DateTime,對應(yīng)著datetime.datetime()的寫法;
- pendulum.today():獲取當(dāng)天時間, .tomorrow() .yesterday() 等可以用;
- pendulum.local(args):獲取當(dāng)?shù)貢r間的對象,可以輸入年月日等;
- pendulum.parse(text):從文本中解析出時間對象,有個類似的方法是pendulum.from_format(text,s);
- pendulum.from_timestamp(ts):把時間戳ts轉(zhuǎn)為時間對象;
- dt.int_timestamp:把dt表示為整數(shù)的timestamp,對應(yīng)的還有.float_timestamp;
- pendulum.timezone("Europe/Paris"):生成一個時區(qū)對象;
- d2.diff_for_humans(dt):將時間間隔按自然語言輸出;
Pendulum的一些函數(shù)需要輸入DateTime作為參數(shù)時,輸入datetime對象也兼容,例如Period時期對象的start、end對象輸入DateTime對象或datetime對象都可以,更詳細(xì)的Pendulum特性可閱讀《挑戰(zhàn)Arrow,需要怎樣的實(shí)力?Pendulum使用筆記》。
Delorean
dateutil庫在datetime庫基礎(chǔ)上進(jìn)行拓展,Delorean站在dateutil的肩膀上進(jìn)一步增強(qiáng)了時間處理能力,其接口更偏向面向?qū)ο蟮膶懛ǎ瑫r間戳使用epoch定義,其時間對象和datetime對象兼容性也很高,并且內(nèi)置時間對象可以直接和datetime.timedelta進(jìn)行運(yùn)算。
Delorean是《回到未來》中的主角的時間旅行車,作為一個以epoch表示時間的程序庫挺契合的。
Delorean抽象了多個接口用于解析和轉(zhuǎn)換其他格式數(shù)據(jù)為時間對象,解析字符串用parse、處理時間戳用epoch、輸入的是datetime對象直接用Delorean()。獲取對象的年月日等屬性,需轉(zhuǎn)datetime再使用datetime的接口。
from delorean import Delorean
dt=Delorean() #獲取當(dāng)前時間,相當(dāng)于now
dt=delorean.parse('2020/12/07')
dt.datetime.year #獲取年份
dt.replace(hour=8) #改時間
dt.shift('US/Eastern') #改時區(qū)
dt - timedelta(hours=2) #兩小時之前
list(delorean.stops(freq=delorean.DAILY,count=10))
Delorean修改時間要素是用replace,而改時區(qū)是使用的shift。除了用stops生成時間序列外,還有range_daily()、range_hourly()等快速方法生成每天或每小時的時間序列。Delorean和datetime的協(xié)作很方便,但接口不夠簡潔和成體系,獲取屬性還需要轉(zhuǎn)為datetime,顯得常用的功能卻沒有優(yōu)先封裝,與Arrow、Pendulum等庫還有些差距,是一個值得了解的Python時間庫,詳細(xì)了解其用法可看前文《設(shè)定基準(zhǔn)點(diǎn)去時間旅行|Delorean使用筆記》。
moment
和Arrow類似,moment也是靈感來自Moment.js庫。moment是一個在發(fā)展中的庫,基本功能不缺,但也不是很完善,其文檔 建議優(yōu)先考慮Arrow及Pendulum庫。
moment將數(shù)據(jù)的輸入封裝在moment.date里,在解析能力上,比Arrow的get更進(jìn)一步,例如get傳入tomorrow或者2 weeks ago是會報錯的,這是arrow的get還不支持的寫法,但moment.date可以解析。
import moment
moment.date('2020-12-07 14:20:10')
#<Moment(2020-12-07T14:20:10)>
moment.date("2 weeks ago")
dt=moment.date("December 18, 2020")
moment.unix(1355875153626)
dt.year #獲取dt所在年份
moment的時間對象也是自定義的對象,獲取其屬性使用dt.year的寫法,和其他庫一致,進(jìn)行時間偏移用的add和subtract方法,同時也有replace的接口,而且寫dt.replace(day=2)或者dt.replace(days=2)都沒出問題。輸出格式化的字符串使用format。通過dt.datetime轉(zhuǎn)為dateime類型,而輸出時間戳是用dt.epoch()方法。
dt=moment.now() #還有utcnow()可以用
dt.add(days=2) #.subtract()
dt.replace(day=5)
dt.replace(days=5)
dt.format('YYYY-MM-DD')
dt.datetime #轉(zhuǎn)datetime對象
moment目前的接口還是偏少,生成一個時間序列目前還不能實(shí)現(xiàn)。
使用moment時,一個小問題是用pip install moment可能會安裝不上,需要通過pip install moment --user 去安裝。
Maya
Maya站在datetime、pendulum、snaptime等模塊的肩膀上發(fā)展有一定特色的時間處理能力,Maya自定義對象MayaDT也是通過epoch定義時間,能很好地避免一些時區(qū)問題。
Maya的時間創(chuàng)建能力上排名前列,有豐富的接口用于從各種數(shù)據(jù)中解析出時間對象,when和parse可以從一些自然語言字符串中解析出時間要素,這方面和moment不遑多讓,例如寫maya.when('tomorrow')和.when('2 weeks ago')等;當(dāng)然從time/datetime對象、時間戳轉(zhuǎn)Maya對象也是沒有壓力。
import maya
maya.when('tomorrow') #明天的這個時候,直接從自然語言轉(zhuǎn)MayaDT
maya.parse('2020-12-08T03:15') #字符串轉(zhuǎn)maya時間對象
dt=maya.now() #獲取當(dāng)前時間
maya.MayaDT.from_datetime(datetime.now()) #datetime對象轉(zhuǎn)MayaDT
maya.MayaDT.from_struct(time.gmtime())
maya.MayaDT(1606533154) #時間戳轉(zhuǎn)Maya時間對象
dt.from_iso8601(text) #從符合ISO-8601標(biāo)準(zhǔn)的字符串中解析時間
在輸出和轉(zhuǎn)換方面,有dt.datetime()方法將MayaDT對象轉(zhuǎn)為datetime對象,也能直接通過dt.year獲取MayaDT對象的屬性,有dt.iso8601()輸出滿足ISO-8601標(biāo)準(zhǔn)的時間字符串,和from_iso8601相對應(yīng)。幾個優(yōu)秀庫都有的輸出為自然語言功能在Maya里封裝為dt.slang_time(),并且還有slang_date也能使用,slang是俚語的意思。
dt=maya.when('2020, 12, 7')
dt.slang_time()
# '8 hours ago'
dt.add(days=10).slang_time()
# 'in 1 week'
list(maya.intervals(start=maya.now(),
end=maya.now().add(days=1),
interval=60*60))
#生成start到end的每小時間隔的時間值序列
Maya的很多方法調(diào)用了其他時間庫,例如dt.year等屬性用了datetime庫、snap方法是調(diào)用了snaptime庫、parse和add用到了Pendulum庫,很多需求Maya沒有自己去造輪子,同時也顯得依賴項(xiàng)有些多,要深入了解Maya的用法可以翻看前文《博采眾長穿梭時空|Maya庫使用筆記》。
在程序運(yùn)行方面,除了時間數(shù)據(jù)本身,量測代碼運(yùn)行時間、模擬特定時間環(huán)境,都是編程語言層的使用場景。在Python中,timeit庫用于量測一段代碼的運(yùn)行時間,即可以方便地計算代碼跑一次的耗時,也能計算多次重復(fù)運(yùn)行的平均耗時,在進(jìn)行代碼評測時小巧實(shí)用。FreezeGun 是在進(jìn)行測試時常用的時間庫,主要應(yīng)用場景是做測試時保證輸入的一致性;功能是調(diào)用freeze_time后,程序運(yùn)行返回的時間就是凍結(jié)所在的時間,相當(dāng)于測試任務(wù)是在那個時間運(yùn)行的。
from timeit import timeit
timeit('x=1') #看執(zhí)行1000000次x=1的時間
def func():
s=[i for i in range(1000)]
return s
timeit('func()', number=1) #執(zhí)行函數(shù)func 一次的時間
from timeit import repeat
#repeat和timeit用法相似,多了一個repeat參數(shù),表示重復(fù)測試的次數(shù)(可以不寫,默認(rèn)值為3.),返回值為一個時間的列表。
t = repeat('func()', 'from __main__ import func', number=100, repeat=5)
#在命令行中使用:
python -m timeit '"-".join(str(n) for n in range(100))'
from freezegun import freeze_time
@freeze_time("2012-01-14")
def test():
return datetime.now()
test()
#FakeDatetime(2012, 1, 14, 0, 0)
總結(jié)
在數(shù)據(jù)處理和數(shù)據(jù)分析過程中,主要需要解決的數(shù)據(jù)需求有以下幾點(diǎn):
- 生成時間對象,從字符串或者寫賦值語句得到一個時間對象;從內(nèi)置的time/datetime對象轉(zhuǎn)更容易處理的時間對象,如數(shù)據(jù)列是從Excel讀入的,去解析該列為時間對象;
- 對特定時間對象t,獲取年月日、分鐘等時間要素;
- 時間運(yùn)算;
- 時間間隔Timedelta,兩個時間對象相減;
- 一個時間對象+一個差值后得到新的時間對象,例如獲取t一周后的時間t2,
- 時間對象轉(zhuǎn)為特定格式的字符串;
- 時間序列的整體移動與抽樣;
- 非結(jié)構(gòu)日期處理,從自然語言中解析時間;
各個庫解決該需求的方式總結(jié)如下表。