Python時(shí)間處理模塊的常用選擇:八大模塊

時(shí)間數(shù)據(jù)

時(shí)間格式是數(shù)據(jù)類型中基礎(chǔ)也不容忽視的一類鸽斟。不像整數(shù)那樣大道至簡(jiǎn)也不像字符串那樣包羅萬象,卻獨(dú)有魅力利诺,時(shí)間數(shù)據(jù)本身除了加減富蓄、比較運(yùn)算外,也有下周慢逾、去年立倍、時(shí)區(qū)等更專項(xiàng)的時(shí)間切換灭红。在各類編程語言里都提供時(shí)間對(duì)象的支持,在MySQL里也有DATETIME類型口注。商業(yè)里的DAU变擒、GMV、LTV也少不了時(shí)間限定和時(shí)間屬性寝志,因此數(shù)據(jù)分析時(shí)少不了對(duì)時(shí)間數(shù)據(jù)類型的處理與轉(zhuǎn)換娇斑。
Python通過套件time、datetime材部、timeit處理時(shí)間類型數(shù)據(jù)毫缆,但面對(duì)一些情況時(shí)會(huì)不夠靈活和易用,在時(shí)間序列生成和截?cái)喾矫孀浇笠娭饫值迹谑钦Q生了Arrow苦丁、Pendulum、Maya等庫增強(qiáng)了Python的時(shí)間處理能力物臂。本篇對(duì)4個(gè)標(biāo)準(zhǔn)庫和6大第三方模塊進(jìn)行介紹旺拉,在面對(duì)需求時(shí)能拿到最趁手的工具。

本文所用庫概覽

模塊概覽

在Python中進(jìn)行時(shí)間類型數(shù)據(jù)處理能用到的模塊有:

  • time:Python內(nèi)置時(shí)間庫棵磷,通過時(shí)間戳或元組表示時(shí)間蛾狗;
  • datetime:內(nèi)置日期庫,處理日期時(shí)間對(duì)象和屬性泽本;
  • dateutil:基于datetime庫的實(shí)用拓展淘太,增強(qiáng)了對(duì)時(shí)間間隔和時(shí)間序列的處理姻僧;
  • pd.Timestamp:pandas庫用于時(shí)間處理的類规丽;
  • Arrow:優(yōu)秀的Python時(shí)間庫,簡(jiǎn)化了時(shí)間類型數(shù)據(jù)的解析和輸出撇贺;
  • Pendulum:可以和Arrow對(duì)標(biāo)的時(shí)間處理庫赌莺,pendulum意為鐘擺;
  • Delorean:在dateutil基礎(chǔ)上進(jìn)一步拓展的時(shí)間庫松嘶,以《回到未來》中的時(shí)間旅行車命名艘狭;
  • moment:靈感來源于Moment.js,目前相對(duì)原始翠订;
  • Maya:和Arrow等庫對(duì)標(biāo)巢音,增強(qiáng)了對(duì)時(shí)區(qū)的處理,有調(diào)用pendulum的部分功能尽超;

在深入這些庫的使用之前官撼,先補(bǔ)充一些先驗(yàn)知識(shí):
epoch:時(shí)間基準(zhǔn)點(diǎn)至特定時(shí)間的總秒數(shù),一般用一個(gè)浮點(diǎn)數(shù)值記錄似谁,這個(gè)基準(zhǔn)點(diǎn)在Unix及類Unix系統(tǒng)中是格林威治時(shí)間1970年01月01日00時(shí)0分0秒傲绣,因此也稱為Unix時(shí)間戳(Timestamp)掠哥。因?yàn)榈厍蚴且粋€(gè)橢球體,當(dāng)英國是中午時(shí)中國北京已經(jīng)在吃晚飯了秃诵,不同經(jīng)度地區(qū)的0點(diǎn)相對(duì)于格林威治的0點(diǎn)有一個(gè)時(shí)差续搀,也就有時(shí)區(qū)(timezone)的區(qū)分,以UTC(世界協(xié)調(diào)時(shí))作為基準(zhǔn)菠净,中國采用的東八區(qū)就可表示為UTC+8禁舷,對(duì)應(yīng)北京時(shí)間減8個(gè)小時(shí)就是UTC時(shí)間。
基于以上需要考慮的問題毅往,在時(shí)間類中榛了,表示一個(gè)時(shí)間有兩種基本選擇:
一是用浮點(diǎn)數(shù)記錄一個(gè)時(shí)間戳epoch,時(shí)間小于1970年則是負(fù)數(shù)煞抬,二是用元組或字典記錄年月日時(shí)分秒時(shí)區(qū)等霜大,在Python的time模塊就是記錄了epoch和一個(gè)元組叫struct_time,這兩者之間可以互相轉(zhuǎn)換革答。

模塊特性與實(shí)踐

time&datetime

time是Python內(nèi)置的時(shí)間庫战坤,功能簡(jiǎn)約但實(shí)用,通常和同為內(nèi)置庫的datetime残拐、pytz及calendar互相配合解決各類時(shí)間表示途茫、計(jì)算、輸出等需求溪食。
time的常用方法有:

  • time.time():得到當(dāng)前時(shí)間戳Timestamp囊卜,是一個(gè)浮點(diǎn)數(shù);
  • time.localtime([secs]):將一個(gè)時(shí)間戳轉(zhuǎn)換為當(dāng)前時(shí)區(qū)的struct_time错沃。secs參數(shù)未提供栅组,則以當(dāng)前時(shí)間為準(zhǔn),相當(dāng)于獲取當(dāng)前時(shí)間now()枢析;
  • time.gmtime(ts):時(shí)間戳轉(zhuǎn)struct_time玉掸;struct_time是一個(gè)包含了9個(gè)元素的元組,對(duì)應(yīng)著改時(shí)間對(duì)象的年月日醒叁、本年第幾天等屬性司浪;
  • time.mktime(t):struct_time轉(zhuǎn)時(shí)間戳;
  • 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模塊生成的時(shí)間對(duì)象t租谈,如果是時(shí)間戳形式表示的,是不能直接得到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ù)時(shí)常需要從字符串形式變成時(shí)間對(duì)象,就會(huì)用到strptime页慷,是string parse time的簡(jiǎn)寫憔足,即從字符串?dāng)?shù)據(jù)類型中解析成時(shí)間類型。strftime是把時(shí)間類型格式化為字符串酒繁,是strptime的逆操作滓彰,f是format的縮寫。
時(shí)間類型格式化有一套特定的占位符州袒,下面介紹的符號(hào)在其他時(shí)間模塊里也通用揭绑,因此常用的占位符還是需要心里有數(shù)才能靈活“組裝”出自己需要的字符串效果的。下面表格列出了常用的時(shí)間格式化占位符郎哭,更全面的表可查閱time模塊文檔他匪。

常用時(shí)間格式化符號(hào)

time模塊常和datetime模塊組合使用,time側(cè)重在時(shí)間夸研,datetime在日期方面方法更豐富邦蜜,且datetime會(huì)和pytz及calendar配合處理時(shí)間對(duì)象。
在datetime里也有strftime和strptime亥至,不過需要注意的是悼沈,兩個(gè)庫輸入?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中新建時(shí)間對(duì)象可以直接使用datetime(y, m,d,tzinfo)輸入?yún)?shù)溶握,用datetime.now()獲得當(dāng)前時(shí)間杯缺,通過datetime.fromtimestamp(ts)可以將時(shí)間戳ts轉(zhuǎn)為時(shí)間對(duì)象,生成的datetime時(shí)間對(duì)象在獲取屬性時(shí)用到的語句類似dt.year睡榆,有year/month/day/hour/second/tzinfo等可以用。tzinfo是時(shí)區(qū)屬性袍榆,datetime在時(shí)區(qū)相關(guān)處理時(shí)通常用到pytz胀屿。

import pytz
sh=pytz.timezone('Asia/Shanghai') #新建一個(gè)時(shí)區(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對(duì)象的年份
#Out[]: 2020
#屬性有.hour .minute .second .microsecond 等
datetime.weekday() #返回星期幾,星期一為 0包雀,星期天為 6
#方法還有 .isoweekday() .toordinal() 等
datetime.combine(dt.date(),dt.time()) 
#combine:將一個(gè)date對(duì)象和一個(gè)time對(duì)象組合成一個(gè)datetime對(duì)象
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)

兩個(gè)datetime日期相減得到的是一個(gè)時(shí)間間隔對(duì)象(imedelta)宿崭,timedelta可以和數(shù)值進(jìn)行乘法和整除運(yùn)算,兩個(gè)timedelta對(duì)象之間可以進(jìn)行加減運(yùn)算才写,但不能比較大小葡兑,datetime對(duì)象可以和timedelta對(duì)象進(jìn)行加減得到新的datetime實(shí)現(xiàn)時(shí)間偏移奖蔓。
datetime也會(huì)和內(nèi)置的calendar庫進(jìn)行配合,顧名思義讹堤,calendar庫主要用來處理和輸出整年吆鹤、整月的日歷。

print(calendar.calendar(2020)) #打印2020年日歷
#calendar.prcal(2020) #兩個(gè)語句效果相同
calendar.prmonth(2019,2) #打印2019年2月的日歷
calendar.isleap(2020) #是否閏年
# True
calendar.weekday(2020,11,20) #指定日期為星期幾洲守,
#4 代表星期五


calendar

這幾個(gè)庫其他的實(shí)用方法有:

  • time.sleep(secs):線程推遲指定的時(shí)間運(yùn)行疑务,單位為秒;
  • time.asctime([t]) :把一個(gè)表示時(shí)間的元組或者struct_time表示為這種形式:'Sun Jun 20 23:21:05 1993'梗醇,如沒有參數(shù)知允,將會(huì)將time.localtime()作為參數(shù)傳入;
  • time.ctime([secs]):把一個(gè)時(shí)間戳(按秒計(jì)算的浮點(diǎn)數(shù))轉(zhuǎn)化為time.asctime()的形式叙谨。如果參數(shù)未給或者為None的時(shí)候温鸽,將會(huì)默認(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)了對(duì)時(shí)間間隔和時(shí)間序列的處理虫溜,因此dateutil類型直接繼承了datetime類型雹姊,dateutil庫生成的時(shí)間對(duì)象就是datetime。Anaconda下該庫已經(jīng)安裝衡楞,模塊里有parser吱雏、easter、relativedelta瘾境、rrule等實(shí)用類進(jìn)行時(shí)間處理歧杏。

import dateutil #anaconda下已經(jīng)安裝,直接import
dt=dateutil.parser.parse('April 29 2020 14:20')
#可以從字符串解析迷守,不需要手動(dòng)寫匹配的占位符犬绒。
dt=dateutil.parser.parse('April 29') #會(huì)取當(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對(duì)象,parser.parse(string)可以從各種類型的字符串例如一句自然語言中解析出日期兑凿,但輸入的參數(shù)string必須是字符串凯力,輸入時(shí)間戳不行(這個(gè)和下面提到的Arrow等庫不同)。
因?yàn)榻馕鰹閐atetime類型的對(duì)象礼华,所以可以使用datetime的各種方法和屬性咐鹤,例如需要知道是哪一年仍然使用dt.year獲取。
一些datetime類的方法可以基于dt實(shí)例使用圣絮,要實(shí)現(xiàn)從時(shí)間戳轉(zhuǎn)時(shí)間對(duì)象祈惶,就可以使用dt.fromtimestamp(ts),獲取當(dāng)前時(shí)間,就可以使用dt.now()捧请。

dt.fromtimestamp(dt.timestamp()) #時(shí)間戳與時(shí)間對(duì)象互轉(zhuǎn)
dt.strftime('%Y-%m-%d') #只能輸入一個(gè)參數(shù)
#時(shí)間對(duì)象轉(zhuǎn)字符串
dateutil.easter.easter(2020,method=3) 
#計(jì)算輸入年份復(fù)活節(jié)的日期

dateutil計(jì)算時(shí)間間隔的方法封裝在relativedelta里凡涩,通過輸入?yún)?shù)months等明確間隔的時(shí)間距離,tz用于處理時(shí)區(qū)疹蛉。

dt+dateutil.relativedelta.relativedelta(months=1, weeks=1)
#時(shí)間偏移
# datetime.datetime(2021, 1, 14, 14, 15, 39, 173204)
relativedelta(datetime(2003, 10, 24, 10, 0),dt) #得到一個(gè)時(shí)間間隔
relativedelta(NOW, johnbirthday) #得到一個(gè)人的年齡
#下周五對(duì)應(yīng)的時(shí)間
dt+relativedelta(weekday=FR)

rrule類用于生成和處理一個(gè)時(shí)間序列活箕。rrule的主要參數(shù)有:

  • freq:聲明序列重復(fù)的周期;
  • count:生成多少個(gè)時(shí)間對(duì)象氧吐;
  • dtstart:開始的時(shí)間點(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ī)則生成時(shí)間序列

以上例子生成的是一個(gè)由4個(gè)時(shí)間對(duì)象組成的序列筑舅,開始時(shí)間是2020年12月7號(hào)座慰,每月重復(fù)一條記錄。rrule.rrulestr()是把字符串輸入當(dāng)參數(shù)翠拣。

pandas

實(shí)際在進(jìn)行數(shù)據(jù)分析時(shí)版仔,通常都會(huì)用到pandas庫卻不一定會(huì)導(dǎo)入datetime等庫,而pandas模塊也提供了Timestamp误墓、Timedelta等類用于時(shí)間類型數(shù)據(jù)的處理轉(zhuǎn)換蛮粮。直接使用pd.Timestamp也更容易進(jìn)行廣播運(yùn)算。

pandas的Timestamp對(duì)象用法和datetime庫基本一致谜慌,各種dt.year屬性都有然想,也有dt.isleapyear用于判斷是否是閏年。pd.Timedelta對(duì)應(yīng)datetime的timedelta欣范,表示時(shí)間間隔变泄。

df['時(shí)間']=pd.to_datetime(df['dt']) 
df['years']=df['時(shí)間'].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['時(shí)間'].apply(lambda x:x.hour+x.minute/60+x.second/3600)

用pandas處理時(shí)間格式數(shù)據(jù)》講述了一個(gè)處理Excel文件中時(shí)間數(shù)據(jù)的案例。

Arrow

Arrow是一個(gè)優(yōu)秀的Python時(shí)間處理庫恼琼,現(xiàn)在其他有追求的第三方時(shí)間處理庫都喜歡在文檔里對(duì)標(biāo)Arrow妨蛹,足矣見Arrow的影響力。Arrow通過收束接口增強(qiáng)了其易用性晴竞,可以快速上手使用蛙卤,get統(tǒng)籌各種輸入的解析,replace負(fù)責(zé)各種時(shí)間要素的修改噩死,format解決各類格式化輸出的需求颤难,range處理時(shí)間序列生成問題。
Arrow解析字符串或datetime對(duì)象得到的是一個(gè)自定義時(shí)間對(duì)象甜滨,通過dt.time乐严、dt.datetime、dt.timestamp等將時(shí)間數(shù)據(jù)從Arrow內(nèi)置對(duì)象轉(zhuǎn)為time等庫的時(shí)間對(duì)象衣摩,一些例子如下。

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可輸入U(xiǎn)nix時(shí)間戳,也可輸入datetime對(duì)象
dt.datetime #轉(zhuǎn)為dateime類型
dt.naive #轉(zhuǎn)為當(dāng)?shù)貢r(shí)區(qū)的datetime類型
dt.floor('hour') #從小時(shí)處截?cái)喟纾r(shí)之后的數(shù)清零
d1.replace(hour=3)
d1.shift(weeks=+4) #當(dāng)前時(shí)間4周后
d1.to('Asia/Shanghai') #換時(shí)區(qū)
dt.format('YYYY-MM-DD') #輸出格式化字符串
arrow.Arrow.range('hour',arrow.now(),arrow.now().shift(hours=5))
#arrow生成時(shí)間序列
dt.humanize() #dt的自然語言表示

Arrow的具體用法可參考前文《Python處理時(shí)間數(shù)據(jù)的另一種選擇既琴,在標(biāo)準(zhǔn)庫之外》。

arrow庫用法概覽

Pendulum

Pendulum也是一款很優(yōu)秀的Python時(shí)間處理模塊泡嘴,其內(nèi)置數(shù)據(jù)類型拓展自datetime甫恩,與datetime有著很好的兼容性。Pendulum比dateutil功能更豐富酌予,足矣和Arrow對(duì)標(biāo)磺箕。Arrow的易用性體現(xiàn)在接口簡(jiǎn)潔,Pendulum的易用性表現(xiàn)在很多datetime的方法都兼容抛虫,而且Pendulum的文檔頁面也更美觀漂亮松靡。Pendulum[?pend??l?m]意為鐘擺,是很好的時(shí)間意向建椰。Pendulum通過其內(nèi)置的DateTime對(duì)象實(shí)現(xiàn)和拓展datetime.datetime的功能雕欺,同時(shí)封裝出Duration、Period及Timezones處理時(shí)間偏移棉姐、時(shí)區(qū)屠列、時(shí)間序列。

import pendulum
dt=pendulum.now() #獲取本地時(shí)區(qū)的當(dāng)前時(shí)間
#DateTime(2020,12,8,18,0,8,697484,tzinfo=Timezone('Asia/Shanghai'))
pendulum.tomorrow() #明天的這個(gè)時(shí)候
dt.year # 2020
dt.week_of_year #dt所在周是本年第幾周
dt.age #dt對(duì)應(yīng)日期目前的年齡
dt.strftime('%Y-%m-%d')
d2=dt.set(year=2019) #把年份變成2019
dt.add(years=-1) #把時(shí)間變成1年前伞矩,注意是years不是year
period = pendulum.period(dt, dt.add(days=8))
list(period.range('days',2)) #時(shí)間序列

其他的一些實(shí)用方法如下:

  • pendulum.datetime(2020,5,7):輸入年月日等生成DateTime笛洛,對(duì)應(yīng)著datetime.datetime()的寫法;
  • pendulum.today():獲取當(dāng)天時(shí)間, .tomorrow() .yesterday() 等可以用乃坤;
  • pendulum.local(args):獲取當(dāng)?shù)貢r(shí)間的對(duì)象苛让,可以輸入年月日等;
  • pendulum.parse(text):從文本中解析出時(shí)間對(duì)象侥袜,有個(gè)類似的方法是pendulum.from_format(text,s)蝌诡;
  • pendulum.from_timestamp(ts):把時(shí)間戳ts轉(zhuǎn)為時(shí)間對(duì)象;
  • dt.int_timestamp:把dt表示為整數(shù)的timestamp枫吧,對(duì)應(yīng)的還有.float_timestamp浦旱;
  • pendulum.timezone("Europe/Paris"):生成一個(gè)時(shí)區(qū)對(duì)象;
  • d2.diff_for_humans(dt):將時(shí)間間隔按自然語言輸出九杂;

Pendulum的一些函數(shù)需要輸入DateTime作為參數(shù)時(shí)颁湖,輸入datetime對(duì)象也兼容,例如Period時(shí)期對(duì)象的start例隆、end對(duì)象輸入DateTime對(duì)象或datetime對(duì)象都可以甥捺,更詳細(xì)的Pendulum特性可閱讀《挑戰(zhàn)Arrow,需要怎樣的實(shí)力镀层?Pendulum使用筆記》镰禾。

pendulum-xmind

Delorean

dateutil庫在datetime庫基礎(chǔ)上進(jìn)行拓展,Delorean站在dateutil的肩膀上進(jìn)一步增強(qiáng)了時(shí)間處理能力,其接口更偏向面向?qū)ο蟮膶懛ㄎ庹欤瑫r(shí)間戳使用epoch定義屋休,其時(shí)間對(duì)象和datetime對(duì)象兼容性也很高,并且內(nèi)置時(shí)間對(duì)象可以直接和datetime.timedelta進(jìn)行運(yùn)算备韧。
Delorean是《回到未來》中的主角的時(shí)間旅行車劫樟,作為一個(gè)以epoch表示時(shí)間的程序庫挺契合的。
Delorean抽象了多個(gè)接口用于解析和轉(zhuǎn)換其他格式數(shù)據(jù)為時(shí)間對(duì)象织堂,解析字符串用parse叠艳、處理時(shí)間戳用epoch、輸入的是datetime對(duì)象直接用Delorean()易阳。獲取對(duì)象的年月日等屬性附较,需轉(zhuǎn)datetime再使用datetime的接口。

from delorean import Delorean
dt=Delorean() #獲取當(dāng)前時(shí)間闽烙,相當(dāng)于now
dt=delorean.parse('2020/12/07')
dt.datetime.year #獲取年份
dt.replace(hour=8) #改時(shí)間
dt.shift('US/Eastern') #改時(shí)區(qū)
dt - timedelta(hours=2) #兩小時(shí)之前
list(delorean.stops(freq=delorean.DAILY,count=10))

Delorean修改時(shí)間要素是用replace翅睛,而改時(shí)區(qū)是使用的shift。除了用stops生成時(shí)間序列外黑竞,還有range_daily()捕发、range_hourly()等快速方法生成每天或每小時(shí)的時(shí)間序列。Delorean和datetime的協(xié)作很方便很魂,但接口不夠簡(jiǎn)潔和成體系扎酷,獲取屬性還需要轉(zhuǎn)為datetime,顯得常用的功能卻沒有優(yōu)先封裝遏匆,與Arrow法挨、Pendulum等庫還有些差距,是一個(gè)值得了解的Python時(shí)間庫幅聘,詳細(xì)了解其用法可看前文《設(shè)定基準(zhǔn)點(diǎn)去時(shí)間旅行|Delorean使用筆記》凡纳。

delorean-xmind

moment

和Arrow類似,moment也是靈感來自Moment.js庫帝蒿。moment是一個(gè)在發(fā)展中的庫荐糜,基本功能不缺,但也不是很完善葛超,其文檔 建議優(yōu)先考慮Arrow及Pendulum庫暴氏。
moment將數(shù)據(jù)的輸入封裝在moment.date里,在解析能力上绣张,比Arrow的get更進(jìn)一步答渔,例如get傳入tomorrow或者2 weeks ago是會(huì)報(bào)錯(cuò)的,這是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的時(shí)間對(duì)象也是自定義的對(duì)象宋雏,獲取其屬性使用dt.year的寫法,和其他庫一致端朵,進(jìn)行時(shí)間偏移用的add和subtract方法好芭,同時(shí)也有replace的接口燃箭,而且寫dt.replace(day=2)或者dt.replace(days=2)都沒出問題冲呢。輸出格式化的字符串使用format。通過dt.datetime轉(zhuǎn)為dateime類型杈抢,而輸出時(shí)間戳是用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對(duì)象

moment目前的接口還是偏少协饲,生成一個(gè)時(shí)間序列目前還不能實(shí)現(xiàn)。
使用moment時(shí)乘凸,一個(gè)小問題是用pip install moment可能會(huì)安裝不上,需要通過pip install moment --user 去安裝累榜。

Maya

Maya站在datetime营勤、pendulum、snaptime等模塊的肩膀上發(fā)展有一定特色的時(shí)間處理能力壹罚,Maya自定義對(duì)象MayaDT也是通過epoch定義時(shí)間葛作,能很好地避免一些時(shí)區(qū)問題。
Maya的時(shí)間創(chuàng)建能力上排名前列猖凛,有豐富的接口用于從各種數(shù)據(jù)中解析出時(shí)間對(duì)象赂蠢,when和parse可以從一些自然語言字符串中解析出時(shí)間要素,這方面和moment不遑多讓辨泳,例如寫maya.when('tomorrow').when('2 weeks ago')等虱岂;當(dāng)然從time/datetime對(duì)象、時(shí)間戳轉(zhuǎn)Maya對(duì)象也是沒有壓力菠红。

import maya
maya.when('tomorrow') #明天的這個(gè)時(shí)候,直接從自然語言轉(zhuǎn)MayaDT
maya.parse('2020-12-08T03:15') #字符串轉(zhuǎn)maya時(shí)間對(duì)象
dt=maya.now() #獲取當(dāng)前時(shí)間
maya.MayaDT.from_datetime(datetime.now()) #datetime對(duì)象轉(zhuǎn)MayaDT
maya.MayaDT.from_struct(time.gmtime()) 
maya.MayaDT(1606533154) #時(shí)間戳轉(zhuǎn)Maya時(shí)間對(duì)象
dt.from_iso8601(text) #從符合ISO-8601標(biāo)準(zhǔn)的字符串中解析時(shí)間

在輸出和轉(zhuǎn)換方面第岖,有dt.datetime()方法將MayaDT對(duì)象轉(zhuǎn)為datetime對(duì)象,也能直接通過dt.year獲取MayaDT對(duì)象的屬性试溯,有dt.iso8601()輸出滿足ISO-8601標(biāo)準(zhǔn)的時(shí)間字符串蔑滓,和from_iso8601相對(duì)應(yīng)。幾個(gè)優(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的每小時(shí)間隔的時(shí)間值序列

Maya的很多方法調(diào)用了其他時(shí)間庫试读,例如dt.year等屬性用了datetime庫杠纵、snap方法是調(diào)用了snaptime庫、parse和add用到了Pendulum庫钩骇,很多需求Maya沒有自己去造輪子比藻,同時(shí)也顯得依賴項(xiàng)有些多铝量,要深入了解Maya的用法可以翻看前文《博采眾長(zhǎng)穿梭時(shí)空|Maya庫使用筆記》。

maya庫概覽

在程序運(yùn)行方面银亲,除了時(shí)間數(shù)據(jù)本身慢叨,量測(cè)代碼運(yùn)行時(shí)間、模擬特定時(shí)間環(huán)境务蝠,都是編程語言層的使用場(chǎng)景拍谐。在Python中,timeit庫用于量測(cè)一段代碼的運(yùn)行時(shí)間馏段,即可以方便地計(jì)算代碼跑一次的耗時(shí)轩拨,也能計(jì)算多次重復(fù)運(yùn)行的平均耗時(shí),在進(jìn)行代碼評(píng)測(cè)時(shí)小巧實(shí)用院喜。FreezeGun 是在進(jìn)行測(cè)試時(shí)常用的時(shí)間庫亡蓉,主要應(yīng)用場(chǎng)景是做測(cè)試時(shí)保證輸入的一致性;功能是調(diào)用freeze_time后喷舀,程序運(yùn)行返回的時(shí)間就是凍結(jié)所在的時(shí)間砍濒,相當(dāng)于測(cè)試任務(wù)是在那個(gè)時(shí)間運(yùn)行的。

from timeit import timeit
timeit('x=1')  #看執(zhí)行1000000次x=1的時(shí)間
def func():
    s=[i for i in range(1000)]
    return s
timeit('func()', number=1) #執(zhí)行函數(shù)func 一次的時(shí)間
from timeit import repeat
#repeat和timeit用法相似硫麻,多了一個(gè)repeat參數(shù)爸邢,表示重復(fù)測(cè)試的次數(shù)(可以不寫,默認(rèn)值為3.)庶香,返回值為一個(gè)時(shí)間的列表甲棍。
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)
freezegun的使用效果

總結(jié)

在數(shù)據(jù)處理和數(shù)據(jù)分析過程中,主要需要解決的數(shù)據(jù)需求有以下幾點(diǎn):

  • 生成時(shí)間對(duì)象赶掖,從字符串或者寫賦值語句得到一個(gè)時(shí)間對(duì)象感猛;從內(nèi)置的time/datetime對(duì)象轉(zhuǎn)更容易處理的時(shí)間對(duì)象,如數(shù)據(jù)列是從Excel讀入的奢赂,去解析該列為時(shí)間對(duì)象陪白;
  • 對(duì)特定時(shí)間對(duì)象t,獲取年月日膳灶、分鐘等時(shí)間要素咱士;
  • 時(shí)間運(yùn)算;
    • 時(shí)間間隔Timedelta轧钓,兩個(gè)時(shí)間對(duì)象相減序厉;
    • 一個(gè)時(shí)間對(duì)象+一個(gè)差值后得到新的時(shí)間對(duì)象,例如獲取t一周后的時(shí)間t2,
  • 時(shí)間對(duì)象轉(zhuǎn)為特定格式的字符串毕箍;
  • 時(shí)間序列的整體移動(dòng)與抽樣弛房;
  • 非結(jié)構(gòu)日期處理,從自然語言中解析時(shí)間而柑;

各個(gè)庫解決該需求的方式總結(jié)如下表文捶。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荷逞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粹排,更是在濱河造成了極大的恐慌种远,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顽耳,死亡現(xiàn)場(chǎng)離奇詭異坠敷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)斧抱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門常拓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辉浦,你說我怎么就攤上這事【シ” “怎么了宪郊?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拖陆。 經(jīng)常有香客問我弛槐,道長(zhǎng),這世上最難降的妖魔是什么依啰? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任乎串,我火速辦了婚禮,結(jié)果婚禮上速警,老公的妹妹穿的比我還像新娘叹誉。我一直安慰自己,他們只是感情好闷旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布长豁。 她就那樣靜靜地躺著,像睡著了一般忙灼。 火紅的嫁衣襯著肌膚如雪匠襟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天该园,我揣著相機(jī)與錄音酸舍,去河邊找鬼。 笑死里初,一個(gè)胖子當(dāng)著我的面吹牛啃勉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播青瀑,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼璧亮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼萧诫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起枝嘶,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤帘饶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后群扶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體及刻,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年竞阐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缴饭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骆莹,死狀恐怖颗搂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幕垦,我是刑警寧澤丢氢,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站先改,受9級(jí)特大地震影響疚察,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜仇奶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一貌嫡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧该溯,春花似錦岛抄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至论皆,卻和暖如春益楼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背点晴。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工感凤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粒督。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓陪竿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子族跛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • ??曾幾何時(shí)闰挡,我們中的一個(gè)人(Lacey)盯了一個(gè)多小時(shí)的python文檔中描述日期和時(shí)間格式化字符串的表格。當(dāng)我...
    編程自習(xí)室閱讀 689評(píng)論 0 2
  • Arrow簡(jiǎn)介 Arrow是一個(gè)優(yōu)秀的Python時(shí)間處理庫,比起Python內(nèi)置的多個(gè)日期時(shí)間庫桐绒,它簡(jiǎn)化了時(shí)間類...
    放翁lcf閱讀 733評(píng)論 0 4
  • 基礎(chǔ)庫與工具日志處理系統(tǒng)工具郵件數(shù)據(jù)庫打印輸出命令行參數(shù)解析命令行界面庫GUI 工具算法與設(shè)計(jì)模式并行計(jì)算夺脾、分布式...
    mocobk閱讀 447評(píng)論 0 0
  • 久違的晴天,家長(zhǎng)會(huì)茉继。 家長(zhǎng)大會(huì)開好到教室時(shí)咧叭,離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)烁竭。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,495評(píng)論 16 22
  • 今天感恩節(jié)哎菲茬,感謝一直在我身邊的親朋好友。感恩相遇颖变!感恩不離不棄生均。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,551評(píng)論 0 11