天天看點

Python 處理日期與時間的全面總結

作者:流着看看

時間相關概念

Python time子產品

時間格式化

計時器功能

time子產品其他内置函數

time子產品包含的屬性

datetime子產品

date類

time類

datetime類

timedelta類

tzinfo類

pytz子產品

時區轉換

夏令時處理

dateutil子產品

parser.parse()

rrule.rrule()

Arrow

UTC 時間

當地時間

解析時間

Unix 時間戳

格式化日期和時間

轉換為區域時間

工作日

移動時間

夏令時

人性化的日期和時間

ISO 8601類

秒 在1967年的第13屆國際度量衡會議上決定以原子時定義的秒作為時間的國際标準機關:铯133原子基态的兩個超精細能階間躍遷對應輻射的9,192,631,770個周期的持續時間, 起始曆元定在1958年1月1日0時。

原子鐘是一種時鐘,它以原子共振頻率标準來計算及保持時間的準确。原子鐘是世界上已知最準确的時間測量和頻率标準。

GMT 格林威治标準時間(Greenwich Mean Time),是指位于倫敦郊區的皇家格林威治天文台的标準時間,因為本初子午線(Prime meridian)被定義為通過那裡的經線。GMT也叫世界時UT。

UTC 協調世界時間(Coordinated Universal Time), 又稱世界标準時間,基于國際原子鐘,誤差為每日數納秒。協調世界時的秒長與原子時的秒長一緻,在時刻上則要求盡量與世界時接近(規定二者的內插補點保持在 0.9秒以内)。

閏秒 不隻有閏年,還有閏秒。閏秒是指為保持協調世界時接近于世界時時刻,由國際計量局統一規定在年底或年中(也可能在季末)對協調世界時增加或減少1秒的調整。由于地球自轉的不均勻性和長期變慢性(主要由潮汐摩擦引起的),會使世界時(民用時)和原子時之間相差超過到±0.9秒時,就把世界時向前撥1秒(負閏秒,最後一分鐘為59秒)或向後撥1秒(正閏秒,最後一分鐘為61秒);閏秒一般加在公曆年末或公曆六月末。

時區 是地球上的區域使用同一個時間定義。有關國際會議決定将地球表面按經線從南到北,劃分成24個時區,并且規定相鄰區域的時間相差1小時。當人們跨過一個區域,就将自己的時鐘校正1小時(向西減1小時,向東加1小時),跨過幾個區域就加或減幾小時。比如我大中國處于東八區,表示為GMT+8。

夏令時 (Daylight Saving Time:DST),又稱日光節約時制、日光節約時間或夏令時間。這是一種為節約能源而人為規定地方時間的制度,在夏天的時候,白天的時間會比較長,是以為了節約用電,是以在夏天的時候某些地區會将他們的時間定早一小時,也就是說,原本時區是8點好了,但是因為夏天太陽比較早出現,是以把時間向前挪,在原本8點的時候,訂定為該天的9點(時間提早一小時)~如此一來,我們就可以利用陽光照明,省去了花費電力的時間,是以才會稱之為夏季節約時間!

Unix時間戳 指的是從協調世界時(UTC)1970年1月1日0時0分0秒開始到現在的總秒數,不考慮閏秒。

在 Python 文檔裡,time是歸類在Generic Operating System Services中,換句話說, 它提供的功能是更加接近于作業系統層面的。通讀文檔可知,time 子產品是圍繞着 Unix Timestamp 進行的。

該子產品主要包括一個類 struct_time,另外其他幾個函數及相關常量。需要注意的是在該子產品中的大多數函數是調用了所在平台C library的同名函數, 是以要特别注意有些函數是平台相關的,可能會在不同的平台有不同的效果。另外一點是,由于是基于Unix Timestamp,是以其所能表述的日期範圍被限定在 1970 – 2038 之間,如果你寫的代碼需要處理在前面所述範圍之外的日期,那可能需要考慮使用datetime子產品更好。

Python 處理日期與時間的全面總結

擷取目前時間和轉化時間格式

time() 傳回時間戳格式的時間 (相對于1.1 00:00:00以秒計算的偏移量)

ctime() 傳回字元串形式的時間,可以傳入時間戳格式時間,用來做轉化

asctime() 傳回字元串形式的時間,可以傳入struct_time形式時間,用來做轉化

localtime() 傳回目前時間的struct_time形式,可傳入時間戳格式時間,用來做轉化

gmtime() 傳回目前時間的struct_time形式,UTC時區(0時區) ,可傳入時間戳格式時間,用來做轉化

struct_time共有9個元素,其中前面6個為年月日時分秒,後面三個分别代表的含義為:

tm_wday 一周的第幾天(周日是0)

tm_yday 一年的第幾天

tm_isdst 是否是夏令時

time.mktime()

将一個以struct_time格式轉換為時間戳

time.strftime(format[,t]) 把一個struct_time時間轉化為格式化的時間字元串。如果t未指定,将傳入time.localtime()。如果元組中任何一個元素越界,ValueError的錯誤将會被抛出。

%c 本地相應的日期和時間表示

%x 本地相應日期

%X 本地相應時間

%y 去掉世紀的年份(00 – 99)

%Y 完整的年份

%m 月份(01 – 12)

%b 本地簡化月份名稱

%B 本地完整月份名稱

%d 一個月中的第幾天(01 – 31)

%j 一年中的第幾天(001 – 366)

%U 一年中的星期數。(00 – 53星期天是一個星期的開始。)第一個星期天之前的所有天數都放在第0周。

%W 和%U基本相同,不同的是%W以星期一為一個星期的開始。

%w 一個星期中的第幾天(0 – 6,0是星期天)

%a 本地(locale)簡化星期名稱

%A 本地完整星期名稱

%H 一天中的第幾個小時(24小時制,00 – 23)

%I 第幾個小時(12小時制,01 – 12)

%p 本地am或者pm的相應符,“%p”隻有與“%I”配合使用才有效果。

%M 分鐘數(00 – 59)

%S 秒(01 – 61),文檔中強調确實是0 – 61,而不是59,閏年秒占兩秒

%Z 時區的名字(如果不存在為空字元)

%% ‘%’字元

time.strptime(string[,format])

把一個格式化時間字元串轉化為struct_time。實際上它和strftime()是逆操作。

time.sleep(secs)

線程推遲指定的時間運作。機關為秒。

time.clock()

這個需要注意,在不同的系統上含義不同。在UNIX系統上,它傳回的是“程序時間”,它是用秒表示的浮點數(時間戳)。而在WINDOWS中,第一次調用,傳回的是程序運作的實際時間。而第二次之後的調用是自第一次調用以後到現在的運作時間。(實際上是以WIN32上QueryPerformanceCounter()為基礎,它比毫秒表示更為精确)

運作結果為:

其中第一個clock()輸出的是程式運作時間,第二、三個clock()輸出的都是與第一個clock的時間間隔

altzone() 傳回格林威治西部的夏令時地區的偏移秒數。如果該地區在格林威治東部會傳回負值(如西歐,包括英國)。對夏令時啟用地區才能使用。

tzset() 根據環境變量TZ重新初始化時間相關設定。

timezone 是當地時區(未啟動夏令時)距離格林威治的偏移秒數(>0,美洲;<=0大部分歐洲,亞洲,非洲)。

tzname 包含一對根據情況的不同而不同的字元串,分别是帶夏令時的本地時區名稱和不帶的。

運作結果

datetime 比 time 進階了不少,可以了解為 datetime 基于 time 進行了封裝,提供了更多實用的函數。

Python 處理日期與時間的全面總結

datetime子產品定義了下面這幾個類:

date:表示日期的類。常用的屬性有year, month, day

time:表示時間的類。常用的屬性有hour, minute, second, microsecond

datetime:表示日期時間

timedelta:表示時間間隔,即兩個時間點之間的長度

tzinfo:與時區有關的相關資訊

注:上面這些類型的對象都是不可變(immutable)的。

date類定義了一些常用的類方法與類屬性:

max、min:date對象所能表示的最大、最小日期

resolution:date對象表示日期的最小機關。這裡是天

today():傳回一個表示目前本地日期的date對象

fromtimestamp(timestamp):根據給定的時間戮,傳回一個date對象

fromordinal(ordinal):将Gregorian月曆時間轉換為date對象(特殊曆法用不上)

執行結果:

date提供的執行個體方法和屬性:

.year:傳回年

.month:傳回月

.day:傳回日

.replace(year, month, day):生成一個新的日期對象,用參數指定的年,月,日代替原有對象中的屬性。(原有對象仍保持不變)

.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():傳回日期對應的Gregorian Calendar日期

date還對某些操作進行了重載,它允許我們對日期進行如下一些操作:

date2 = date1 + timedelta # 日期加上一個間隔,傳回一個新的日期對象

date2 = date1 – timedelta # 日期減去一個間隔,傳回一個新的日期對象

timedelta = date1 – date2 # 兩個日期相減,傳回一個時間間隔對象

date1 < date2 # 兩個日期進行比較

time類的構造函數如下:(其中參數tzinfo,它表示時區資訊。)

class datetime.time(hour[, minute[, second[, microsecond[, tzinfo]]]])

time類定義的類屬性:

min、max:time類所能表示的最小、最大時間。其中,time.min = time(0, 0, 0, 0), time.max = time(23, 59, 59, 999999)

resolution:時間的最小機關,這裡是1微秒

time類提供的執行個體方法和屬性:

.hour、.minute、.second、.microsecond:時、分、秒、微秒

.tzinfo:時區資訊

.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]]):建立一個新的時間對象,用參數指定的時、分、秒、微秒代替原有對象中的屬性(原有對象仍保持不變);

.isoformat():傳回型如”HH:MM:SS”格式的字元串表示;

.strftime(fmt):傳回自定義格式化字元串。

像date一樣,也可以對兩個time對象進行比較,或者相減傳回一個時間間隔對象。這裡就不提供例子了。

datetime是date與time的結合體,包括date與time的所有資訊。它的構造函數如下:datetime.datetime(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]),各參數的含義與date、time的構造函數中的一樣,要注意參數值的範圍。

datetime類定義的類屬性與方法:

min、max:datetime所能表示的最小值與最大值;

resolution:datetime最小機關;

today():傳回一個表示目前本地時間的datetime對象;

now([tz]):傳回一個表示目前本地時間的datetime對象,如果提供了參數tz,則擷取tz參數所指時區的本地時間;

utcnow():傳回一個目前utc時間的datetime對象;

fromtimestamp(timestamp[, tz]):根據時間戮建立一個datetime對象,參數tz指定時區資訊;

utcfromtimestamp(timestamp):根據時間戮建立一個datetime對象;

combine(date, time):根據date和time,建立一個datetime對象;

strptime(date_string, format):将格式字元串轉換為datetime對象;

運作結果:

datetime類提供的執行個體方法與屬性(很多屬性或方法在date和time中已經出現過,在此有類似的意義,這裡隻羅列這些方法名,具體含義不再逐個展開介紹,可以參考上文對date與time類的講解。):

year、month、day、hour、minute、second、microsecond、tzinfo:

date():擷取date對象;

time():擷取time對象;

replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]):

timetuple()

utctimetuple()

toordinal()

weekday()

isocalendar()

isoformat([sep])

ctime():傳回一個日期時間的C格式字元串,等效于ctime(time.mktime(dt.timetuple()));

strftime(format)

像date一樣,也可以對兩個datetime對象進行比較,或者相減傳回一個時間間隔對象,或者日期時間加上一個間隔傳回一個新的日期時間對象。

通過timedelta函數傳回一個timedelta對象,也就是一個表示時間間隔的對象。函數參數情況如下所示:

class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])

其沒有必填參數,簡單控制的話第一個整數就是多少天的間隔的意思:

datetime.timedelta(10)

兩個時間間隔對象可以彼此之間相加或相減,傳回的仍是一個時間間隔對象。而更友善的是一個datetime對象如果減去一個時間間隔對象,那麼傳回的對應減去之後的datetime對象,然後兩個datetime對象如果相減傳回的是一個時間間隔對象。這很是友善。

tzinfo是一個抽象類,不能被直接執行個體化。需要派生子類,提供相應的标準方法。datetime子產品并不提供tzinfo的任何子類。最簡單的方式是使用pytz子產品。

pytz是Python的一個時區處理子產品(同時也包括夏令時),在了解時區處理子產品之前,需要先要了解一些時區的概念。

Python 處理日期與時間的全面總結

要知道時區之間的轉換關系,其實這很簡單:把當地時間減去當地時區,剩下的就是格林威治時間了。例如中原標準時間的18:00就是18:00+08:00,相減以後就是10:00+00:00,是以就是格林威治時間的10:00。

Python的datetime可以處理2種類型的時間,分别為offset-naive和offset-aware。前者是指沒有包含時區資訊的時間,後者是指包含時區資訊的時間,隻有同類型的時間才能進行減法運算和比較。

datetime子產品的函數在預設情況下都隻生成offset-naive類型的datetime對象,例如now()、utcnow()、fromtimestamp()、utcfromtimestamp()和strftime()。其中now()和fromtimestamp()可以接受一個tzinfo對象來生成offset-aware類型的datetime對象,但是标準庫并不提供任何已實作的tzinfo類,隻能自己實作。

下面就是實作格林威治時間和中原標準時間的tzinfo類的例子:

一個tzinfo類需要實作utcoffset、dst和tzname這3個方法。其中utcoffset需要傳回夏時令的時差調整;tzname需要傳回時區名,如果你不需要用到的話,也可以不實作。

一旦生成了一個offset-aware類型的datetime對象,我們就能調用它的astimezone()方法,生成其他時區的時間(會根據時差來計算)。而如果拿到的是offset-naive類型的datetime對象,也是可以調用它的replace()方法來替換tzinfo的,隻不過這種替換不會根據時差來調整其他時間屬性。是以,如果拿到一個格林威治時間的offset-naive類型的datetime對象,直接調用replace(tzinfo=UTC())即可轉換成offset-aware類型,然後再調用astimezone()生成其他時區的datetime對象。

看上去一切都很簡單,但不知道你還是否記得上文所述的夏時令。提起夏時令這個玩意,真是讓我頭疼,因為它沒有規則可循:有的國家實行夏時令,有的國家不實行,有的國家隻在部分地區實行夏時令,有的地區隻在某些年實行夏時令,每個地區實行夏時令的起止時間都不一定相同,而且有的地方TMD還不是用幾月幾日來指定夏時令的起止時間的,而是用某月的第幾個星期幾這種形式。

pytz子產品,使用Olson TZ Database解決了跨平台的時區計算一緻性問題,解決了夏令時帶來的計算問題。由于國家和地區可以自己選擇時區以及是否使用夏令時,是以pytz子產品在有需要的情況下得更新自己的時區以及夏令時相關的資訊。

pytz提供了全部的timezone資訊,如:

如果需要擷取某個國家的時區,可以使用如下方式:

[u'Asia/Shanghai', u'Asia/Urumqi']

中國一個有兩個時區,一個為上海,一個為烏魯木齊,我們來看下我們有什麼差別:

可以看到上海是東八區,而烏魯木齊是東六區。

操作起來有而比較簡單,本地時區與UTC的互轉:

使用astimezone()可以進行時區與時區之間的轉換。

另外可以采用 replace來修改時區,時區多出6分鐘(不要使用)。具體原因為:

民國17年(1928年),國民政府統一中國,原中央觀象台的業務由南京政府中央研究院的天文研究所和氣象研究所分別接收。天文研究所編寫的曆書基本上沿襲中央觀象台的做法,仍將全國劃分為5個標準時區,隻是在有關交氣、合朔、太陽出沒時刻等處,不再使用北平的地方平時,而改以南京所在的標準時區的區時即東經120°標準時替代。從北平地方平時改為東經120°標準時,兩者相差了352秒。

由于用到的場景比較少,不做細化學習。

安裝子產品:pip install Python-dateutil

解析時間到datetime格式,支援大部分時間字元串。沒指定時間預設是0點,沒指定日期預設是今天,沒指定年份預設是今年。

函數主要功能:按照規則生成日期和時間。函數原型如下。

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。即年月日周時分秒。

dtstart,until:是開始和結束時間。

wkst:周開始時間。

interval:間隔。

count:指定生成多少個。

byxxx:指定比對的周期。比如byweekday=(MO,TU)則隻有周一周二的比對。byweekday可以指定MO,TU,WE,TH,FR,SA,SU。即周一到周日。

更多參考:http://dateutil.readthedocs.io/en/stable/index.html

Arrow 提供了一個友好而且非常易懂的方法,用于建立時間、計算時間、格式化時間,還可以對時間做轉化、提取、相容 python datetime 類型。它包括dateutil子產品,根據其文檔描述Arrow旨在“幫助你使用更少的代碼來處理日期和時間”。

使用utcnow()功能建立 UTC 時間。

使用to()方法,我們将 UTC 時間轉換為本地時間。

本地時間是特定區域或時區中的時間。

使用now()功能建立本地時間。to()方法用于将本地時間轉換為 UTC 時間。

get()方法用于解析時間。

該示例從日期和時間字元串以及時間戳解析時間。

該示例顯示本地時間和 Unix 時間。然後,它将 Unix 時間轉換回 date 對象。

使用fromtimestamp()方法,我們将 Unix 時間轉換回 Arrow 日期對象。

也可以将日期格式化為 Unix 時間。

通過将’X’說明符傳遞給format()方法,我們将目前本地日期列印為 Unix 時間。

日期和時間可以用format()方法格式化。

格式說明:

Python 處理日期與時間的全面總結

可以使用weekday()或format()方法找到日期的工作日。

shift()方法用于移動時間。

該示例使用dst()顯示夏令時。

在社交網站上,我們經常可以看到諸如“一個小時前”或“ 5 分鐘前”之類的術語,這些術語可以為人們提供有關文章建立或修改時間的快速資訊。Arrow 包含humanize()方法來建立此類術語。

國際标準ISO 8601,是國際标準化組織的日期和時間的表示方法,全稱為《資料存儲和交換形式·資訊交換·日期和時間的表示方法》,在API接口開發中涉及的比較多。

或者使用如下方式解析:

另外還可以使用iso8601子產品:http://pyiso8601.readthedocs.io/en/latest/

其他日期與時間工具:

公曆轉農曆:https://pypi.python.org/pypi/LunarSolarConverter/

口語化日期:https://github.com/scrapinghub/dateparser

Moment:https://github.com/zachwill/moment

Delorean:https://github.com/myusuf3/delorean

When:https://whenpy.readthedocs.io/en/latest/

Pendulum:https://pendulum.eustace.io/

時間機器:https://github.com/spulec/freezegun

工作月曆:https://github.com/peopledoc/workalendar

中國法定節假日:https://github.com/NateScarlet/holiday-cn

繼續閱讀