Python 處理日期與時(shí)間的全面總結(jié)


Python的時(shí)間處理模塊在日常的使用中用的較多,但是使用的時(shí)候基本上都是要查資料,還是有些麻煩的,梳理下,便于以后方便的使用。
目錄
時(shí)間相關(guān)概念 Python time模塊 時(shí)間格式化 計(jì)時(shí)器功能 time模塊其他內(nèi)置函數(shù) time模塊包含的屬性 datetime模塊 date類 time類 datetime類 timedelta類 tzinfo類 pytz模塊 時(shí)區(qū)轉(zhuǎn)換 夏令時(shí)處理 dateutil模塊 parser.parse() rrule.rrule() Arrow UTC 時(shí)間 當(dāng)?shù)貢r(shí)間 解析時(shí)間 Unix 時(shí)間戳 格式化日期和時(shí)間 轉(zhuǎn)換為區(qū)域時(shí)間 工作日 移動(dòng)時(shí)間 夏令時(shí) 人性化的日期和時(shí)間 ISO 8601類
時(shí)間相關(guān)概念
秒?在1967年的第13屆國際度量衡會(huì)議上決定以原子時(shí)定義的秒作為時(shí)間的國際標(biāo)準(zhǔn)單位:銫133原子基態(tài)的兩個(gè)超精細(xì)能階間躍遷對(duì)應(yīng)輻射的9,192,631,770個(gè)周期的持續(xù)時(shí)間, 起始?xì)v元定在1958年1月1日0時(shí)。
原子鐘是一種時(shí)鐘,它以原子共振頻率標(biāo)準(zhǔn)來計(jì)算及保持時(shí)間的準(zhǔn)確。原子鐘是世界上已知最準(zhǔn)確的時(shí)間測量和頻率標(biāo)準(zhǔn)。
GMT?格林威治標(biāo)準(zhǔn)時(shí)間(Greenwich Mean Time),是指位于倫敦郊區(qū)的皇家格林威治天文臺(tái)的標(biāo)準(zhǔn)時(shí)間,因?yàn)楸境踝游缇€(Prime meridian)被定義為通過那里的經(jīng)線。GMT也叫世界時(shí)UT。
UTC?協(xié)調(diào)世界時(shí)間(Coordinated Universal Time), 又稱世界標(biāo)準(zhǔn)時(shí)間,基于國際原子鐘,誤差為每日數(shù)納秒。協(xié)調(diào)世界時(shí)的秒長與原子時(shí)的秒長一致,在時(shí)刻上則要求盡量與世界時(shí)接近(規(guī)定二者的差值保持在 0.9秒以內(nèi))。
閏秒?不只有閏年,還有閏秒。閏秒是指為保持協(xié)調(diào)世界時(shí)接近于世界時(shí)時(shí)刻,由國際計(jì)量局統(tǒng)一規(guī)定在年底或年中(也可能在季末)對(duì)協(xié)調(diào)世界時(shí)增加或減少1秒的調(diào)整。由于地球自轉(zhuǎn)的不均勻性和長期變慢性(主要由潮汐摩擦引起的),會(huì)使世界時(shí)(民用時(shí))和原子時(shí)之間相差超過到±0.9秒時(shí),就把世界時(shí)向前撥1秒(負(fù)閏秒,最后一分鐘為59秒)或向后撥1秒(正閏秒,最后一分鐘為61秒);閏秒一般加在公歷年末或公歷六月末。
時(shí)區(qū)?是地球上的區(qū)域使用同一個(gè)時(shí)間定義。有關(guān)國際會(huì)議決定將地球表面按經(jīng)線從南到北,劃分成24個(gè)時(shí)區(qū),并且規(guī)定相鄰區(qū)域的時(shí)間相差1小時(shí)。當(dāng)人們跨過一個(gè)區(qū)域,就將自己的時(shí)鐘校正1小時(shí)(向西減1小時(shí),向東加1小時(shí)),跨過幾個(gè)區(qū)域就加或減幾小時(shí)。比如我大中國處于東八區(qū),表示為GMT+8。
夏令時(shí)?(Daylight Saving Time:DST),又稱日光節(jié)約時(shí)制、日光節(jié)約時(shí)間或夏令時(shí)間。這是一種為節(jié)約能源而人為規(guī)定地方時(shí)間的制度,在夏天的時(shí)候,白天的時(shí)間會(huì)比較長,所以為了節(jié)約用電,因此在夏天的時(shí)候某些地區(qū)會(huì)將他們的時(shí)間定早一小時(shí),也就是說,原本時(shí)區(qū)是8點(diǎn)好了,但是因?yàn)橄奶焯柋容^早出現(xiàn),因此把時(shí)間向前挪,在原本8點(diǎn)的時(shí)候,訂定為該天的9點(diǎn)(時(shí)間提早一小時(shí))~如此一來,我們就可以利用陽光照明,省去了花費(fèi)電力的時(shí)間,因此才會(huì)稱之為夏季節(jié)約時(shí)間!
Unix時(shí)間戳?指的是從協(xié)調(diào)世界時(shí)(UTC)1970年1月1日0時(shí)0分0秒開始到現(xiàn)在的總秒數(shù),不考慮閏秒。
Python time模塊
在 Python 文檔里,time是歸類在Generic Operating System Services中,換句話說, 它提供的功能是更加接近于操作系統(tǒng)層面的。通讀文檔可知,time 模塊是圍繞著 Unix Timestamp 進(jìn)行的。
該模塊主要包括一個(gè)類 struct_time,另外其他幾個(gè)函數(shù)及相關(guān)常量。需要注意的是在該模塊中的大多數(shù)函數(shù)是調(diào)用了所在平臺(tái)C library的同名函數(shù), 所以要特別注意有些函數(shù)是平臺(tái)相關(guān)的,可能會(huì)在不同的平臺(tái)有不同的效果。另外一點(diǎn)是,由于是基于Unix Timestamp,所以其所能表述的日期范圍被限定在 1970 – 2038 之間,如果你寫的代碼需要處理在前面所述范圍之外的日期,那可能需要考慮使用datetime模塊更好。

獲取當(dāng)前時(shí)間和轉(zhuǎn)化時(shí)間格式
time() 返回時(shí)間戳格式的時(shí)間 (相對(duì)于1.1 00:00:00以秒計(jì)算的偏移量) ctime() 返回字符串形式的時(shí)間,可以傳入時(shí)間戳格式時(shí)間,用來做轉(zhuǎn)化 asctime() 返回字符串形式的時(shí)間,可以傳入struct_time形式時(shí)間,用來做轉(zhuǎn)化 localtime() 返回當(dāng)前時(shí)間的struct_time形式,可傳入時(shí)間戳格式時(shí)間,用來做轉(zhuǎn)化 gmtime() 返回當(dāng)前時(shí)間的struct_time形式,UTC時(shí)區(qū)(0時(shí)區(qū)) ,可傳入時(shí)間戳格式時(shí)間,用來做轉(zhuǎn)化
>>>?import?time
>>>?time.time()
1473386416.954
>>>?time.ctime()
'Fri?Sep?09?10:00:25?2016'
>>>?time.ctime(time.time())
'Fri?Sep?09?10:28:08?2016'
>>>?time.asctime()
'Fri?Sep?09?10:22:40?2016'
>>>?time.asctime(time.localtime())
'Fri?Sep?09?10:33:00?2016'
>>>?time.localtime()
time.struct_time(tm_year=2016,?tm_mon=9,?tm_mday=9,?tm_hour=10,?tm_min=1,?tm_sec=19,?tm_wday=4,?tm_yday=253,?tm_isdst=0)
>>>?time.localtime(time.time())
time.struct_time(tm_year=2016,?tm_mon=9,?tm_mday=9,?tm_hour=10,?tm_min=19,?tm_sec=11,?tm_wday=4,?tm_yday=253,?tm_isdst=0)
>>>?time.gmtime()
time.struct_time(tm_year=2016,?tm_mon=9,?tm_mday=9,?tm_hour=2,?tm_min=13,?tm_sec=10,?tm_wday=4,?tm_yday=253,?tm_isdst=0)
>>>?time.gmtime(time.time())
time.struct_time(tm_year=2016,?tm_mon=9,?tm_mday=9,?tm_hour=2,?tm_min=15,?tm_sec=35,?tm_wday=4,?tm_yday=253,?tm_isdst=0)
struct_time共有9個(gè)元素,其中前面6個(gè)為年月日時(shí)分秒,后面三個(gè)分別代表的含義為:
tm_wday 一周的第幾天(周日是0) tm_yday 一年的第幾天 tm_isdst 是否是夏令時(shí)
時(shí)間格式化
time.mktime()
將一個(gè)以struct_time格式轉(zhuǎn)換為時(shí)間戳
>>>?time.mktime(time.localtime())
1473388585.0
time.strftime(format[,t]) 把一個(gè)struct_time時(shí)間轉(zhuǎn)化為格式化的時(shí)間字符串。如果t未指定,將傳入time.localtime()。如果元組中任何一個(gè)元素越界,ValueError的錯(cuò)誤將會(huì)被拋出。
%c 本地相應(yīng)的日期和時(shí)間表示 %x 本地相應(yīng)日期 %X 本地相應(yīng)時(shí)間 %y 去掉世紀(jì)的年份(00 – 99) %Y 完整的年份 %m 月份(01 – 12) %b 本地簡化月份名稱 %B 本地完整月份名稱 %d 一個(gè)月中的第幾天(01 – 31) %j 一年中的第幾天(001 – 366) %U 一年中的星期數(shù)。(00 – 53星期天是一個(gè)星期的開始。)第一個(gè)星期天之前的所有天數(shù)都放在第0周。 %W 和%U基本相同,不同的是%W以星期一為一個(gè)星期的開始。 %w 一個(gè)星期中的第幾天(0 – 6,0是星期天) %a 本地(locale)簡化星期名稱 %A 本地完整星期名稱 %H 一天中的第幾個(gè)小時(shí)(24小時(shí)制,00 – 23) %I 第幾個(gè)小時(shí)(12小時(shí)制,01 – 12) %p 本地am或者pm的相應(yīng)符,“%p”只有與“%I”配合使用才有效果。 %M 分鐘數(shù)(00 – 59) %S 秒(01 – 61),文檔中強(qiáng)調(diào)確實(shí)是0 – 61,而不是59,閏年秒占兩秒 %Z 時(shí)區(qū)的名字(如果不存在為空字符) %% ‘%’字符
>>>?time.strftime("%Y-%m-%d?%H:%M:%S",?time.localtime())
'2016-09-09?10:54:21'
time.strptime(string[,format])
把一個(gè)格式化時(shí)間字符串轉(zhuǎn)化為struct_time。實(shí)際上它和strftime()是逆操作。
>>>?time.strptime(time.ctime())
time.struct_time(tm_year=2016,?tm_mon=9,?tm_mday=9,?tm_hour=11,?tm_min=0,?tm_sec=4,?tm_wday=4,?tm_yday=253,?tm_isdst=-1)
計(jì)時(shí)器功能
time.sleep(secs)
線程推遲指定的時(shí)間運(yùn)行。單位為秒。
time.clock()
這個(gè)需要注意,在不同的系統(tǒng)上含義不同。在UNIX系統(tǒng)上,它返回的是“進(jìn)程時(shí)間”,它是用秒表示的浮點(diǎn)數(shù)(時(shí)間戳)。而在WINDOWS中,第一次調(diào)用,返回的是進(jìn)程運(yùn)行的實(shí)際時(shí)間。而第二次之后的調(diào)用是自第一次調(diào)用以后到現(xiàn)在的運(yùn)行時(shí)間。(實(shí)際上是以WIN32上QueryPerformanceCounter()為基礎(chǔ),它比毫秒表示更為精確)
import?time
time.sleep(1)
print("clock1:%s"?%?time.clock())
time.sleep(1)
print("clock2:%s"?%?time.clock())
time.sleep(1)
print("clock3:%s"?%?time.clock())
運(yùn)行結(jié)果為:
clock1:1.57895443216e-06
clock2:1.00064381867
clock3:2.00158724394
其中第一個(gè)clock()輸出的是程序運(yùn)行時(shí)間,第二、三個(gè)clock()輸出的都是與第一個(gè)clock的時(shí)間間隔
time模塊其他內(nèi)置函數(shù)
altzone() 返回格林威治西部的夏令時(shí)地區(qū)的偏移秒數(shù)。如果該地區(qū)在格林威治東部會(huì)返回負(fù)值(如西歐,包括英國)。對(duì)夏令時(shí)啟用地區(qū)才能使用。 tzset() 根據(jù)環(huán)境變量TZ重新初始化時(shí)間相關(guān)設(shè)置。
time模塊包含的屬性
timezone 是當(dāng)?shù)貢r(shí)區(qū)(未啟動(dòng)夏令時(shí))距離格林威治的偏移秒數(shù)(>0,美洲;<=0大部分歐洲,亞洲,非洲)。 tzname 包含一對(duì)根據(jù)情況的不同而不同的字符串,分別是帶夏令時(shí)的本地時(shí)區(qū)名稱和不帶的。
import?time
print(time.timezone)
print(time.tzname)
print(time.tzname[0].decode("GBK"))
print(time.tzname[1].decode("GBK"))
運(yùn)行結(jié)果
-28800
('\xd6\xd0\xb9\xfa\xb1\xea\xd7\xbc\xca\xb1\xbc\xe4',?'\xd6\xd0\xb9\xfa\xcf\xc4\xc1\xee\xca\xb1')
中國標(biāo)準(zhǔn)時(shí)間
中國夏令時(shí)
datetime模塊
datetime 比 time 高級(jí)了不少,可以理解為 datetime 基于 time 進(jìn)行了封裝,提供了更多實(shí)用的函數(shù)。

datetime模塊定義了下面這幾個(gè)類:
date:表示日期的類。常用的屬性有year, month, day time:表示時(shí)間的類。常用的屬性有hour, minute, second, microsecond datetime:表示日期時(shí)間 timedelta:表示時(shí)間間隔,即兩個(gè)時(shí)間點(diǎn)之間的長度 tzinfo:與時(shí)區(qū)有關(guān)的相關(guān)信息
注:上面這些類型的對(duì)象都是不可變(immutable)的。
date類
date類定義了一些常用的類方法與類屬性:
max、min:date對(duì)象所能表示的最大、最小日期 resolution:date對(duì)象表示日期的最小單位。這里是天 today():返回一個(gè)表示當(dāng)前本地日期的date對(duì)象 fromtimestamp(timestamp):根據(jù)給定的時(shí)間戮,返回一個(gè)date對(duì)象 fromordinal(ordinal):將Gregorian日歷時(shí)間轉(zhuǎn)換為date對(duì)象(特殊歷法用不上)
from?datetime?import?date
import?time
print('date.max:',?date.max)
print('date.min:',?date.min)
print('date.resolution:',?date.resolution)
print('date.today():',?date.today())
print('date.fromtimestamp():',?date.fromtimestamp(time.time()))
執(zhí)行結(jié)果:
date.max:?9999-12-31
date.min:?0001-01-01
date.resolution:?1?day,?0:00:00
date.today():?2016-09-12
date.fromtimestamp():?2016-09-12
date提供的實(shí)例方法和屬性:
.year:返回年 .month:返回月 .day:返回日 .replace(year, month, day):生成一個(gè)新的日期對(duì)象,用參數(shù)指定的年,月,日代替原有對(duì)象中的屬性。(原有對(duì)象仍保持不變) .weekday():返回weekday,如果是星期一,返回0;如果是星期2,返回1,以此類推 .isoweekday():返回weekday,如果是星期一,返回1;如果是星期2,返回2,以此類推 .isocalendar():返回格式如(year, wk num, wk day) .isoformat():返回格式如’YYYY-MM-DD’的字符串 .strftime(fmt):自定義格式化字符串。與time模塊中的strftime類似。 .toordinal():返回日期對(duì)應(yīng)的Gregorian Calendar日期
from?datetime?import?date
today?=?date.today()
print('today:',?today)
print('.year:',?today.year)
print('.month:',?today.month)
print('.replace():',?today.replace(year=2017)?)
print('.weekday():',?today.weekday())
print('.isoweekday():',?today.isoweekday())
print('.isocalendar():',?today.isocalendar())
print('.isoformat():',?today.isoformat())
print('.strftime():',?today.strftime('%Y-%m-%d')?)
print('.toordinal():',?today.toordinal())
執(zhí)行結(jié)果:
today:?2016-09-12
.year:?2016
.month:?9
.replace():?2017-09-12
.weekday():?0
.isoweekday():?1
.isocalendar():?(2016,?37,?1)
.isoformat():?2016-09-12
.strftime():?2016-09-12
.toordinal():?736219
date還對(duì)某些操作進(jìn)行了重載,它允許我們對(duì)日期進(jìn)行如下一些操作:
date2 = date1 + timedelta # 日期加上一個(gè)間隔,返回一個(gè)新的日期對(duì)象 date2 = date1 – timedelta # 日期減去一個(gè)間隔,返回一個(gè)新的日期對(duì)象 timedelta = date1 – date2 # 兩個(gè)日期相減,返回一個(gè)時(shí)間間隔對(duì)象 date1 < date2 # 兩個(gè)日期進(jìn)行比較
time類
time類的構(gòu)造函數(shù)如下:(其中參數(shù)tzinfo,它表示時(shí)區(qū)信息。)
class datetime.time(hour[, minute[, second[, microsecond[, tzinfo]]]])
time類定義的類屬性:
min、max:time類所能表示的最小、最大時(shí)間。其中,time.min = time(0, 0, 0, 0), time.max = time(23, 59, 59, 999999) resolution:時(shí)間的最小單位,這里是1微秒
time類提供的實(shí)例方法和屬性:
.hour、.minute、.second、.microsecond:時(shí)、分、秒、微秒 .tzinfo:時(shí)區(qū)信息 .replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]):創(chuàng)建一個(gè)新的時(shí)間對(duì)象,用參數(shù)指定的時(shí)、分、秒、微秒代替原有對(duì)象中的屬性(原有對(duì)象仍保持不變); .isoformat():返回型如”HH:MM:SS”格式的字符串表示; .strftime(fmt):返回自定義格式化字符串。
像date一樣,也可以對(duì)兩個(gè)time對(duì)象進(jìn)行比較,或者相減返回一個(gè)時(shí)間間隔對(duì)象。這里就不提供例子了。
datetime類
datetime是date與time的結(jié)合體,包括date與time的所有信息。它的構(gòu)造函數(shù)如下:datetime.datetime(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]),各參數(shù)的含義與date、time的構(gòu)造函數(shù)中的一樣,要注意參數(shù)值的范圍。
datetime類定義的類屬性與方法:
min、max:datetime所能表示的最小值與最大值; resolution:datetime最小單位; today():返回一個(gè)表示當(dāng)前本地時(shí)間的datetime對(duì)象; now([tz]):返回一個(gè)表示當(dāng)前本地時(shí)間的datetime對(duì)象,如果提供了參數(shù)tz,則獲取tz參數(shù)所指時(shí)區(qū)的本地時(shí)間; utcnow():返回一個(gè)當(dāng)前utc時(shí)間的datetime對(duì)象; fromtimestamp(timestamp[, tz]):根據(jù)時(shí)間戮創(chuàng)建一個(gè)datetime對(duì)象,參數(shù)tz指定時(shí)區(qū)信息; utcfromtimestamp(timestamp):根據(jù)時(shí)間戮創(chuàng)建一個(gè)datetime對(duì)象; combine(date, time):根據(jù)date和time,創(chuàng)建一個(gè)datetime對(duì)象; strptime(date_string, format):將格式字符串轉(zhuǎn)換為datetime對(duì)象;
from?datetime?import?datetime
import?time
print('datetime.max:',?datetime.max)
print('datetime.min:',?datetime.min)
print('datetime.resolution:',?datetime.resolution)
print('today():',?datetime.today())
print('now():',?datetime.now())
print('utcnow():',?datetime.utcnow())
print('fromtimestamp(tmstmp):',?datetime.fromtimestamp(time.time()))
print('utcfromtimestamp(tmstmp):',?datetime.utcfromtimestamp(time.time()))
運(yùn)行結(jié)果:
datetime.max:?9999-12-31?23:59:59.999999
datetime.min:?0001-01-01?00:00:00
datetime.resolution:?0:00:00.000001
today():?2016-09-12?19:57:00.761000
now():?2016-09-12?19:57:00.761000
utcnow():?2016-09-12?11:57:00.761000
fromtimestamp(tmstmp):?2016-09-12?19:57:00.761000
utcfromtimestamp(tmstmp):?2016-09-12?11:57:00.761000
datetime類提供的實(shí)例方法與屬性(很多屬性或方法在date和time中已經(jīng)出現(xiàn)過,在此有類似的意義,這里只羅列這些方法名,具體含義不再逐個(gè)展開介紹,可以參考上文對(duì)date與time類的講解。):
year、month、day、hour、minute、second、microsecond、tzinfo:
date():獲取date對(duì)象; time():獲取time對(duì)象; replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]): timetuple() utctimetuple() toordinal() weekday() isocalendar() isoformat([sep]) ctime():返回一個(gè)日期時(shí)間的C格式字符串,等效于ctime(time.mktime(dt.timetuple())); strftime(format)
像date一樣,也可以對(duì)兩個(gè)datetime對(duì)象進(jìn)行比較,或者相減返回一個(gè)時(shí)間間隔對(duì)象,或者日期時(shí)間加上一個(gè)間隔返回一個(gè)新的日期時(shí)間對(duì)象。
timedelta類
通過timedelta函數(shù)返回一個(gè)timedelta對(duì)象,也就是一個(gè)表示時(shí)間間隔的對(duì)象。函數(shù)參數(shù)情況如下所示:
class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])
其沒有必填參數(shù),簡單控制的話第一個(gè)整數(shù)就是多少天的間隔的意思:
datetime.timedelta(10)
兩個(gè)時(shí)間間隔對(duì)象可以彼此之間相加或相減,返回的仍是一個(gè)時(shí)間間隔對(duì)象。而更方便的是一個(gè)datetime對(duì)象如果減去一個(gè)時(shí)間間隔對(duì)象,那么返回的對(duì)應(yīng)減去之后的datetime對(duì)象,然后兩個(gè)datetime對(duì)象如果相減返回的是一個(gè)時(shí)間間隔對(duì)象。這很是方便。
tzinfo類
tzinfo是一個(gè)抽象類,不能被直接實(shí)例化。需要派生子類,提供相應(yīng)的標(biāo)準(zhǔn)方法。datetime模塊并不提供tzinfo的任何子類。最簡單的方式是使用pytz模塊。
pytz模塊
pytz是Python的一個(gè)時(shí)區(qū)處理模塊(同時(shí)也包括夏令時(shí)),在理解時(shí)區(qū)處理模塊之前,需要先要了解一些時(shí)區(qū)的概念。

要知道時(shí)區(qū)之間的轉(zhuǎn)換關(guān)系,其實(shí)這很簡單:把當(dāng)?shù)貢r(shí)間減去當(dāng)?shù)貢r(shí)區(qū),剩下的就是格林威治時(shí)間了。例如北京時(shí)間的18:00就是18:00+08:00,相減以后就是10:00+00:00,因此就是格林威治時(shí)間的10:00。
Python的datetime可以處理2種類型的時(shí)間,分別為offset-naive和offset-aware。前者是指沒有包含時(shí)區(qū)信息的時(shí)間,后者是指包含時(shí)區(qū)信息的時(shí)間,只有同類型的時(shí)間才能進(jìn)行減法運(yùn)算和比較。
datetime模塊的函數(shù)在默認(rèn)情況下都只生成offset-naive類型的datetime對(duì)象,例如now()、utcnow()、fromtimestamp()、utcfromtimestamp()和strftime()。其中now()和fromtimestamp()可以接受一個(gè)tzinfo對(duì)象來生成offset-aware類型的datetime對(duì)象,但是標(biāo)準(zhǔn)庫并不提供任何已實(shí)現(xiàn)的tzinfo類,只能自己實(shí)現(xiàn)。
下面就是實(shí)現(xiàn)格林威治時(shí)間和北京時(shí)間的tzinfo類的例子:
ZERO_TIME_DELTA?=?timedelta(0)
LOCAL_TIME_DELTA?=?timedelta(hours=8)?#?本地時(shí)區(qū)偏差
class?UTC(tzinfo):
????def?utcoffset(self,?dt):
????????return?ZERO_TIME_DELTA
????def?dst(self,?dt):
????????return?ZERO_TIME_DELTA
class?LocalTimezone(tzinfo):
????def?utcoffset(self,?dt):
????????return?LOCAL_TIME_DELTA
????def?dst(self,?dt):
????????return?ZERO_TIME_DELTA
????def?tzname(self,?dt):
????????return?'+08:00'
一個(gè)tzinfo類需要實(shí)現(xiàn)utcoffset、dst和tzname這3個(gè)方法。其中utcoffset需要返回夏時(shí)令的時(shí)差調(diào)整;tzname需要返回時(shí)區(qū)名,如果你不需要用到的話,也可以不實(shí)現(xiàn)。
一旦生成了一個(gè)offset-aware類型的datetime對(duì)象,我們就能調(diào)用它的astimezone()方法,生成其他時(shí)區(qū)的時(shí)間(會(huì)根據(jù)時(shí)差來計(jì)算)。而如果拿到的是offset-naive類型的datetime對(duì)象,也是可以調(diào)用它的replace()方法來替換tzinfo的,只不過這種替換不會(huì)根據(jù)時(shí)差來調(diào)整其他時(shí)間屬性。因此,如果拿到一個(gè)格林威治時(shí)間的offset-naive類型的datetime對(duì)象,直接調(diào)用replace(tzinfo=UTC())即可轉(zhuǎn)換成offset-aware類型,然后再調(diào)用astimezone()生成其他時(shí)區(qū)的datetime對(duì)象。
看上去一切都很簡單,但不知道你還是否記得上文所述的夏時(shí)令。提起夏時(shí)令這個(gè)玩意,真是讓我頭疼,因?yàn)樗鼪]有規(guī)則可循:有的國家實(shí)行夏時(shí)令,有的國家不實(shí)行,有的國家只在部分地區(qū)實(shí)行夏時(shí)令,有的地區(qū)只在某些年實(shí)行夏時(shí)令,每個(gè)地區(qū)實(shí)行夏時(shí)令的起止時(shí)間都不一定相同,而且有的地方TMD還不是用幾月幾日來指定夏時(shí)令的起止時(shí)間的,而是用某月的第幾個(gè)星期幾這種形式。
pytz模塊,使用Olson TZ Database解決了跨平臺(tái)的時(shí)區(qū)計(jì)算一致性問題,解決了夏令時(shí)帶來的計(jì)算問題。由于國家和地區(qū)可以自己選擇時(shí)區(qū)以及是否使用夏令時(shí),所以pytz模塊在有需要的情況下得更新自己的時(shí)區(qū)以及夏令時(shí)相關(guān)的信息。
pytz提供了全部的timezone信息,如:
import?pytz
print(len(pytz.all_timezones))
print(len(pytz.common_timezones))
運(yùn)行結(jié)果:
588
436
如果需要獲取某個(gè)國家的時(shí)區(qū),可以使用如下方式:
import?pytz
print(pytz.country_timezones('cn'))
執(zhí)行結(jié)果:
[u'Asia/Shanghai', u'Asia/Urumqi']
中國一個(gè)有兩個(gè)時(shí)區(qū),一個(gè)為上海,一個(gè)為烏魯木齊,我們來看下我們有什么區(qū)別:
from?datetime?import?datetime
import?pytz
print(pytz.country_timezones('cn'))
tz1?=?pytz.timezone(pytz.country_timezones('cn')[0])
print(tz1)
print(datetime.now(tz1))
tz2?=?pytz.timezone(pytz.country_timezones('cn')[1])
print(tz2)
print(datetime.now(tz2))
執(zhí)行結(jié)果:
[u'Asia/Shanghai',?u'Asia/Urumqi']
Asia/Shanghai
2016-09-14?09:55:39.384000+08:00
Asia/Urumqi
2016-09-14?07:55:39.385000+06:00
可以看到上海是東八區(qū),而烏魯木齊是東六區(qū)。
時(shí)區(qū)轉(zhuǎn)換
操作起來有而比較簡單,本地時(shí)區(qū)與UTC的互轉(zhuǎn):
from?datetime?import?datetime
import?pytz
now?=?datetime.now()
tz?=?pytz.timezone('Asia/Shanghai')
print(tz.localize(now))
print(pytz.utc.normalize(tz.localize(now)))
執(zhí)行結(jié)果:
2016-09-14?10:25:44.633000+08:00
2016-09-14?02:25:44.633000+00:00
使用astimezone()可以進(jìn)行時(shí)區(qū)與時(shí)區(qū)之間的轉(zhuǎn)換。
from?datetime?import?datetime
import?pytz
utc?=?pytz.utc
beijing_time?=?pytz.timezone('Asia/Shanghai')
japan_time?=?pytz.timezone('Asia/Tokyo')
now?=?datetime.now(beijing_time)
print("Beijing?Time:",now)
print("UTC:",now.astimezone(utc))
print("JAPAN?TIME:",now.astimezone(japan_time))
執(zhí)行結(jié)果:
Beijing?Time:?2016-09-14?10:19:22.671000+08:00
UTC:?2016-09-14?02:19:22.671000+00:00
JAPAN?TIME:?2016-09-14?11:19:22.671000+09:00
另外可以采用 replace來修改時(shí)區(qū),時(shí)區(qū)多出6分鐘(不要使用)。具體原因?yàn)椋?/p>
民國17年(1928年),國民政府統(tǒng)一中國,原中央觀象臺(tái)的業(yè)務(wù)由南京政府中央研究院的天文研究所和氣象研究所分別接收。天文研究所編寫的曆書基本上沿襲中央觀象臺(tái)的做法,仍將全國劃分為5個(gè)標(biāo)準(zhǔn)時(shí)區(qū),只是在有關(guān)交氣、合朔、太陽出沒時(shí)刻等處,不再使用北平的地方平時(shí),而改以南京所在的標(biāo)準(zhǔn)時(shí)區(qū)的區(qū)時(shí)即東經(jīng)120°標(biāo)準(zhǔn)時(shí)替代。從北平地方平時(shí)改為東經(jīng)120°標(biāo)準(zhǔn)時(shí),兩者相差了352秒。
from?datetime?import?datetime
import?pytz
now?=?datetime.now()
print(now)
tz?=?pytz.timezone('Asia/Shanghai')
print(now.replace(tzinfo=tz))
執(zhí)行結(jié)果:
2016-09-14?10:29:20.200000
2016-09-14?10:29:20.200000+08:06
夏令時(shí)處理
由于用到的場景比較少,不做細(xì)化學(xué)習(xí)。
dateutil模塊
安裝模塊:pip install Python-dateutil
parser.parse()
解析時(shí)間到datetime格式,支持大部分時(shí)間字符串。沒指定時(shí)間默認(rèn)是0點(diǎn),沒指定日期默認(rèn)是今天,沒指定年份默認(rèn)是今年。
from?dateutil?import?parser
print(parser.parse("8th?March,2004"))
print(parser.parse("8?March,2004"))
print(parser.parse("March?8th,2004"))
print(parser.parse("March?8,2004"))
print(parser.parse("2016-09-14"))
print(parser.parse("20160914"))
print(parser.parse("2016/09/14"))
print(parser.parse("09/14/2016"))
print(parser.parse("09,14"))
print(parser.parse("12:00:00"))
print(parser.parse("Wed,?Nov?12"))
執(zhí)行結(jié)果:
2004-03-08?00:00:00
2004-03-08?00:00:00
2004-03-08?00:00:00
2004-03-08?00:00:00
2016-09-14?00:00:00
2016-09-14?00:00:00
2016-09-14?00:00:00
2016-09-14?00:00:00
2016-09-09?00:00:00
2016-09-14?12:00:00
2016-11-12?00:00:00
rrule.rrule()
函數(shù)主要功能:按照規(guī)則生成日期和時(shí)間。函數(shù)原型如下。
rrule(self, freq, dtstart=None, interval=1, wkst=None, count=None, until=None, bysetpos=None, bymonth=None, bymonthday=None, byyearday=None, byeaster=None, byweekno=None, byweekday=None, byhour=None, byminute=None, bysecond=None, cache=False)
其中:
freq:可以理解為單位。可以是 YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY。即年月日周時(shí)分秒。 dtstart,until:是開始和結(jié)束時(shí)間。 wkst:周開始時(shí)間。 interval:間隔。 count:指定生成多少個(gè)。 byxxx:指定匹配的周期。比如byweekday=(MO,TU)則只有周一周二的匹配。byweekday可以指定MO,TU,WE,TH,FR,SA,SU。即周一到周日。
更多參考:http://dateutil.readthedocs.io/en/stable/index.html
Arrow
Arrow 提供了一個(gè)友好而且非常易懂的方法,用于創(chuàng)建時(shí)間、計(jì)算時(shí)間、格式化時(shí)間,還可以對(duì)時(shí)間做轉(zhuǎn)化、提取、兼容 python datetime 類型。它包括dateutil模塊,根據(jù)其文檔描述Arrow旨在“幫助你使用更少的代碼來處理日期和時(shí)間”。
UTC 時(shí)間
使用utcnow()功能創(chuàng)建 UTC 時(shí)間。
使用to()方法,我們將 UTC 時(shí)間轉(zhuǎn)換為本地時(shí)間。
import?arrow
utc?=?arrow.utcnow()
print(utc)
print(utc.to('local'))
當(dāng)?shù)貢r(shí)間
本地時(shí)間是特定區(qū)域或時(shí)區(qū)中的時(shí)間。
import?arrow
now?=?arrow.now()
print(now)
print(now.to('UTC'))
使用now()功能創(chuàng)建本地時(shí)間。to()方法用于將本地時(shí)間轉(zhuǎn)換為 UTC 時(shí)間。
解析時(shí)間
get()方法用于解析時(shí)間。
import?arrow
d1?=?arrow.get('2012-06-05?16:20:03',?'YYYY-MM-DD?HH:mm:ss')
print(d1)
d2?=?arrow.get(1504384602)
print(d2)
該示例從日期和時(shí)間字符串以及時(shí)間戳解析時(shí)間。
Unix 時(shí)間戳
import?arrow
utc?=?arrow.utcnow()
print(utc)
unix_time?=?utc.timestamp
print(unix_time)
date?=?arrow.Arrow.fromtimestamp(unix_time)
print(date)
該示例顯示本地時(shí)間和 Unix 時(shí)間。然后,它將 Unix 時(shí)間轉(zhuǎn)換回 date 對(duì)象。
使用fromtimestamp()方法,我們將 Unix 時(shí)間轉(zhuǎn)換回 Arrow 日期對(duì)象。
也可以將日期格式化為 Unix 時(shí)間。
import?arrow
utc?=?arrow.utcnow()
print(utc.format('X'))
通過將’X’說明符傳遞給format()方法,我們將當(dāng)前本地日期打印為 Unix 時(shí)間。
格式化日期和時(shí)間
日期和時(shí)間可以用format()方法格式化。
import?arrow
now?=?arrow.now()
year?=?now.format('YYYY')
print("Year:?{0}".format(year))
date?=?now.format('YYYY-MM-DD')
print("Date:?{0}".format(date))
date_time?=?now.format('YYYY-MM-DD?HH:mm:ss')
print("Date?and?time:?{0}".format(date_time))
date_time_zone?=?now.format('YYYY-MM-DD?HH:mm:ss?ZZ')
print("Date?and?time?and?zone:?{0}".format(date_time_zone))
格式說明:

轉(zhuǎn)換為區(qū)域時(shí)間
import?arrow
utc?=?arrow.utcnow()
print(utc.to('US/Pacific').format('HH:mm:ss'))
print(utc.to('Europe/Bratislava').format('HH:mm:ss'))
print(utc.to('Europe/Moscow').format('HH:mm:ss'))
工作日
可以使用weekday()或format()方法找到日期的工作日。
import?arrow
d1?=?arrow.get('1948-12-13')
print(d1.weekday())
print(d1.format('dddd'))
移動(dòng)時(shí)間
shift()方法用于移動(dòng)時(shí)間。
import?arrow
now?=?arrow.now()
print(now.shift(hours=5).time())
print(now.shift(days=5).date())
print(now.shift(years=-8).date())
夏令時(shí)
import?arrow
now?=?arrow.now()
print(now.format("YYYY-MM-DD?HH:mm:ss?ZZ"))
print(now.dst())
該示例使用dst()顯示夏令時(shí)。
人性化的日期和時(shí)間
在社交網(wǎng)站上,我們經(jīng)常可以看到諸如“一個(gè)小時(shí)前”或“ 5 分鐘前”之類的術(shù)語,這些術(shù)語可以為人們提供有關(guān)帖子創(chuàng)建或修改時(shí)間的快速信息。Arrow 包含humanize()方法來創(chuàng)建此類術(shù)語。
import?arrow
now?=?arrow.now()
d1?=?now.shift(minutes=-15).humanize()
print(d1)
d2?=?now.shift(hours=5).humanize()
print(d2)
ISO 8601類
國際標(biāo)準(zhǔn)ISO 8601,是國際標(biāo)準(zhǔn)化組織的日期和時(shí)間的表示方法,全稱為《數(shù)據(jù)存儲(chǔ)和交換形式·信息交換·日期和時(shí)間的表示方法》,在API接口開發(fā)中涉及的比較多。
>>>?import?dateutil.parser
>>>?dateutil.parser.parse('2008-09-03T20:56:35.450686Z')?#?RFC?3339?format
datetime.datetime(2008,?9,?3,?20,?56,?35,?450686,?tzinfo=tzutc())
>>>?dateutil.parser.parse('2008-09-03T20:56:35.450686')?#?ISO?8601?extended?format
datetime.datetime(2008,?9,?3,?20,?56,?35,?450686)
>>>?dateutil.parser.parse('20080903T205635.450686')?#?ISO?8601?basic?format
datetime.datetime(2008,?9,?3,?20,?56,?35,?450686)
>>>?dateutil.parser.parse('20080903')?#?ISO?8601?basic?format,?date?only
datetime.datetime(2008,?9,?3,?0,?0)
或者使用如下方式解析:
>>>?datetime.datetime.strptime("2008-09-03T20:56:35.450686Z",?"%Y-%m-%dT%H:%M:%S.%fZ")
另外還可以使用iso8601模塊
原文鏈接:https://www.biaodianfu.com/python-datetime.html
文章轉(zhuǎn)載:Python編程學(xué)習(xí)圈
(版權(quán)歸原作者所有,侵刪)
![]()

點(diǎn)擊下方“閱讀原文”查看更多
