時(shí)間格式對(duì)于任何一個(gè)工程師來說都是繞不開的知識(shí),爬蟲工程師同樣如此。爬蟲工程師要將不同網(wǎng)站的相同類型內(nèi)容存放在同一個(gè)數(shù)據(jù)表當(dāng)中,常見的有:
* 站點(diǎn) A 的時(shí)間格式為 “2018-5”
* 站點(diǎn) B 的時(shí)間格式為 “3天前”
* 站點(diǎn) C 的時(shí)間格式為 “5-10 8:25”
在數(shù)據(jù)庫存儲(chǔ)的時(shí)候,應(yīng)該選用哪種時(shí)間格式合適呢?新建字段的時(shí)候是選擇 DATE 格式還是 DATETIME 格式?YEAR 又是什么?
Python 內(nèi)置時(shí)間函數(shù)有 time 和 datetime,什么時(shí)候適合用 time ?什么時(shí)候選擇 datetime 呢?
Mysql 時(shí)間類型
在數(shù)據(jù)庫建表的時(shí)候,通常有5中字段類型讓人選擇:TIME、DATE、DATETIME、TIMESTAMP、YEAR。
每種類型的存儲(chǔ)空間和時(shí)間格式如下:
- TIME類型 :存儲(chǔ)空間[3 bytes] - 時(shí)間格式[HH:MM:SS] - 時(shí)間范圍[-838:59:59 到 ~ 838:59:59]
- DATE類型 :存儲(chǔ)空間[3 bytes] - 時(shí)間格式[YYYY-MM-DD] - 時(shí)間范圍[1000-01-01 到 9999-12-31] (可以理解為年月日)
- DATETIME類型 :存儲(chǔ)空間[8 bytes] - 時(shí)間格式[YYYY-MM-DD HH:MM:SS] - 時(shí)間范圍[1000-01-01 00:00:00 到 9999-12-31 23:59:59] (可以理解為年月日時(shí)分秒)
- TIMESTAMP類型 :存儲(chǔ)空間[4 bytes] - 時(shí)間格式[YYYY-MM-DD HH:MM:SS] - 時(shí)間范圍[1970-01-01 00:00:01 到 2038-01-19 03:14:07] (以秒為計(jì)算)
- YEAR類型 :存儲(chǔ)空間[1 bytes] - 時(shí)間格式[YYYY] - 時(shí)間范圍[1901 到 2155](按年計(jì)算)
YEAR 這樣的時(shí)間格式用的是比較少的,而 TIME 用的也不多,常見的還是 DATE、DATETIME 和時(shí)間戳 TIMESTAMP。
Python 的 time
Python提供了三種時(shí)間函數(shù),時(shí)間模塊 time、基本時(shí)間日期模塊 datetime 和日歷模塊 Calendar。Python 的 time 模塊下有很多函數(shù)可以轉(zhuǎn)換常見日期格式。如函數(shù) time.time() 用于獲取當(dāng)前時(shí)間戳:
import time
timestamp = time.time()
print(timestamp, type(timestamp))
輸出的時(shí)間戳是 float 類型:
1544788687.041193 <class 'float'>
時(shí)間戳單位最適于做日期運(yùn)算。但是1970年之前的日期就無法以此表示了。太遙遠(yuǎn)的日期也不行,UNIX和Windows只支持到2038年。Time 模塊包含了以下內(nèi)置函數(shù),既有時(shí)間處理的,也有轉(zhuǎn)換時(shí)間格式的:

Python 的日歷
Calendar 函數(shù)都是日歷相關(guān)的,星期一是默認(rèn)的每周第一天,星期天是默認(rèn)的最后一天。更改設(shè)置需調(diào)用calendar.setfirstweekday()函數(shù)。模塊包含了以下內(nèi)置函數(shù):

日歷模塊 Calendar 是用的次數(shù)比較少的(在爬蟲和Django開發(fā)的實(shí)際應(yīng)用較少)。出現(xiàn)較多的是 time 模塊和 dateteime 模塊。那 time 和 datetime 是什么關(guān)系呢?
- time模塊 -- 比較接近底層的
- datetime模塊 -- 基于time新增了很過功能,提供了更多函數(shù)
使用對(duì)比
1、獲取當(dāng)前時(shí)間
import datetime, time
''' 崔慶才丨靜覓、韋世東丨奎因 邀你關(guān)注微信公眾號(hào)【進(jìn)擊的Coder】 '''
print(time.time())
print(datetime.datetime.now())
得到的輸出結(jié)果是:
1544789253.025471
2018-12-14 20:07:33.025502
2、當(dāng)前時(shí)間格式化
import datetime, time
''' 崔慶才丨靜覓、韋世東丨奎因 邀你關(guān)注微信公眾號(hào)【進(jìn)擊的Coder】 '''
''' time當(dāng)前時(shí)間 '''
localtime = time.localtime(time.time())
print('當(dāng)前時(shí)間元組 :', localtime)
print('不格式化:', time.time())
res1 = time.strftime('%Y-%m-%d', localtime)
print('strftime 可以把時(shí)間格式化為日期形式 :', res1)
res2 = time.strftime('%Y-%m-%d %H:%M:%S', localtime)
print('strftime 可以把時(shí)間轉(zhuǎn)換為日期和時(shí)間 :', res2)
# ------------------------------------------------
''' datetime當(dāng)前時(shí)間 '''
time_now = datetime.datetime.now()
res3 = datetime.datetime.now().strftime('%Y-%m-%d')
res4 = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print('不格式化的當(dāng)前時(shí)間:', time_now)
print('datetime 也可以這樣用:', res3)
print('datetime 也可以這樣用:', res4)
得到的結(jié)果是:
當(dāng)前時(shí)間元組 : time.struct_time(tm_year=2018, tm_mon=12, tm_mday=14, tm_hour=20, tm_min=18, tm_sec=11, tm_wday=4, tm_yday=348, tm_isdst=0)
不格式化: 1544789891.681039
strftime 可以把時(shí)間格式化為日期形式 : 2018-12-14
strftime 可以把時(shí)間轉(zhuǎn)換為日期和時(shí)間 : 2018-12-14 20:18:11
不格式化的當(dāng)前時(shí)間: 2018-12-14 20:18:11.681079
datetime 也可以這樣用: 2018-12-14
datetime 也可以這樣用: 2018-12-14 20:18:11
這里可以看出這兩個(gè)模塊獲得的時(shí)間都不是人類容易閱讀的,都需要通過strftime函數(shù)進(jìn)行格式化。
3、文本時(shí)間轉(zhuǎn)換
這里我指的是爬蟲獲取的其他網(wǎng)站的時(shí)間,通常有幾種格式:
爬蟲得到的時(shí)間都是給人閱讀的,只不過分隔符不同。在入庫的時(shí)候,爬蟲工程師希望他們的時(shí)間格式是統(tǒng)一的,年月日時(shí)分秒或者年月日,如果可以就用時(shí)間戳,方便計(jì)算(年月日時(shí)分秒對(duì)應(yīng)年月日時(shí)分秒,年月日不可直接轉(zhuǎn)換為年月日時(shí)分秒)。
遇到日期類型 2018-01-06 的時(shí)間格式,是不可以用函數(shù)直接轉(zhuǎn)成長時(shí)間 (比如 2018-01-06 18:35:05) 格式的,強(qiáng)行操作會(huì)報(bào)錯(cuò)。當(dāng)遇到這種需要將時(shí)間格式統(tǒng)一的情況,沒有直接操作的辦法,只能對(duì)時(shí)間進(jìn)行轉(zhuǎn)換。轉(zhuǎn)換又分為兩種,相同時(shí)間格式轉(zhuǎn)換與不同時(shí)間格式轉(zhuǎn)換:
第一種情形
目標(biāo):2018-01-06 18:35:05 轉(zhuǎn)換為2018/01/06 18:35:05
它有兩種方法可以滿足
方法一的邏輯是不同格式的時(shí)間轉(zhuǎn)換要先轉(zhuǎn)成時(shí)間數(shù)組,然后再由時(shí)間數(shù)組格式化成想要的類型:
import datetime,time
a = '2013-10-10 23:40:00' # 想要轉(zhuǎn)換成 a = '2013/10/10 23:40:00'
timeArray = time.strptime(a, '%Y-%m-%d %H:%M:%S')
otherStyleTime = time.strftime('%Y/%m/%d %H:%M:%S', timeArray)
print(timeArray)
print(otherStyleTime)
從輸出結(jié)果:
time.struct_time(tm_year=2013, tm_mon=10, tm_mday=10, tm_hour=23, tm_min=40, tm_sec=0, tm_wday=3, tm_yday=283, tm_isdst=-1)
2013/10/10 23:40:00
可以看到,先通過 time.strptime 把它轉(zhuǎn)換成時(shí)間數(shù)組,然后通過 time.strftime 把時(shí)間數(shù)組格式化成我想要的格式。
方法二,由于最終格式化的時(shí)間也是字符串 str,所以當(dāng)遇到這種情況的時(shí)候,還可以直接用 replace 來進(jìn)行轉(zhuǎn)換:
a = '2013-10-10 23:40:00' # 想要轉(zhuǎn)換成 a = '2013/10/10 23:40:00'
print(a.replace('-', '/'))
輸出結(jié)果為:
2013/10/10 23:40:00
第二種情形
目標(biāo):2018-01-06 轉(zhuǎn)換為2018-01-06 18:35:05
它也有兩種方法可以滿足
它的邏輯是將年月日的字符串拼接上時(shí)分秒,然后再按照上面的兩種方法進(jìn)行轉(zhuǎn)換,比如:
a = '2013-10-10 ' # 想要轉(zhuǎn)換成 a = '2013/10/10 23:40:00'
ac = a + '00:00:00'
print(ac.replace('-', '/'))
得到輸出結(jié)果
2013/10/10 00:00:00
第三種情形
目標(biāo):2018-01-06 18:35:05 轉(zhuǎn)換為2018-01-06
思路與第一種一致,先轉(zhuǎn)換為時(shí)間數(shù)組,然后再由時(shí)間數(shù)組進(jìn)行格式化:
import datetime,time
a = '2013-10-10 23:40:00' # 想要轉(zhuǎn)換成 a = '2013/10/10'
timeArray = time.strptime(a, '%Y-%m-%d %H:%M:%S')
otherStyleTime = time.strftime('%Y/%m/%d', timeArray)
print(type(timeArray))
print(otherStyleTime)
得到結(jié)果輸出為(可以看到 timeArray 的類型是 time.struct_time):
<class 'time.struct_time'>
2013/10/10
4、時(shí)間的比較運(yùn)算
都知道字符串是不可以進(jìn)行比較計(jì)算的,那么我們就需要用到其他的格式進(jìn)行。time 的 strptime 轉(zhuǎn)換成時(shí)間數(shù)組是不可以進(jìn)行運(yùn)算的,但是 datetime 可以。
第一種 ,時(shí)間格式相同
import datetime,time
d1 = datetime.datetime.strptime('2012-03-05 17:41:20', '%Y-%m-%d %H:%M:%S')
d2 = datetime.datetime.strptime('2012-03-05 16:41:20', '%Y-%m-%d %H:%M:%S')
delta = d1 - d2
print(type(d1))
print(delta.seconds)
print(delta)
得到的輸出是:
<class 'datetime.datetime'>
3600
1:00:00
從結(jié)果上可以看到,格式相同的兩種時(shí)間,可以通過datetime.datetime.strptime進(jìn)行轉(zhuǎn)換后再運(yùn)算,在結(jié)果中還可以通過.seconds來計(jì)算 相差秒數(shù) 和通過.days來計(jì)算 相差天數(shù)
第二種 ,如果時(shí)間格式不一樣,但是轉(zhuǎn)換后的類型一樣,也是可以比較的:
import datetime,time
d1 = datetime.datetime.strptime('2012/03/05 17:41:20', '%Y/%m/%d %H:%M:%S')
d2 = datetime.datetime.strptime('2012-03-05 16:41:20', '%Y-%m-%d %H:%M:%S')
delta = d1 - d2
print(delta.seconds)
print(delta)
這段代碼里面時(shí)間的字符串形式就不一樣,但是通過同樣的函數(shù)進(jìn)行轉(zhuǎn)換后就可以比較計(jì)算了。
第三種 ,年月日時(shí)分秒與年月日的計(jì)算,其實(shí)原理是一樣的,轉(zhuǎn)換后他們的格式都一樣,所以也是可以計(jì)算的,2012/03/05 17:41:20與2012-03-05的時(shí)間相差:
import datetime,time
d1 = datetime.datetime.strptime('2012/03/05 17:41:20', '%Y/%m/%d %H:%M:%S')
d2 = datetime.datetime.strptime('2012-03-01', '%Y-%m-%d')
delta = d1 - d2
print(delta.days,delta.seconds)
print(delta)
print(type(delta))
輸出結(jié)果是
4 63680
4 days, 17:41:20
<class 'datetime.timedelta'>
通過print的結(jié)果可以得到幾點(diǎn)信息:
不同格式的時(shí)間在轉(zhuǎn)化后是可以進(jìn)行比較運(yùn)算的
可以通過.days和.seconds來進(jìn)行天數(shù)與時(shí)分秒的展示
計(jì)算后得到的數(shù)據(jù)類型是 'datetime.timedelta' 而不是str類型
比如計(jì)算3天后的時(shí)間:
import datetime,time
now = datetime.datetime.now()
delta = datetime.timedelta(days=3)
n_days = now + delta
print(type(n_days))
print(n_days.strftime('%Y-%m-%d %H:%M:%S'))
得到的結(jié)果是:
<class 'datetime.datetime'>
2018-01-21 10:26:14
用 datetime.timedelta 取得3天時(shí)間,然后將當(dāng)前時(shí)間加上3天,得到的是 'datetime.datetime' 類型數(shù)據(jù),變成人類閱讀的格式則需要 strftime 函數(shù)進(jìn)行格式化,最終得到想要的 2018-01-21 10:26:14。
5、時(shí)間戳
把字符串時(shí)間轉(zhuǎn)換為時(shí)間戳:
import datetime,time
a = '2013-10-10 23:40:00'
# 轉(zhuǎn)換為時(shí)間數(shù)組
timeArray = time.strptime(a, '%Y-%m-%d %H:%M:%S')
# 轉(zhuǎn)換為時(shí)間戳:
timeStamp = time.mktime(timeArray)
print(timeArray)
print(timeStamp)
輸出結(jié)果為:
time.struct_time(tm_year=2013, tm_mon=10, tm_mday=10, tm_hour=23, tm_min=40, tm_sec=0, tm_wday=3, tm_yday=283, tm_isdst=-1)
1381419600.0
可以看到time的時(shí)間數(shù)組與時(shí)間戳并不是同一樣?xùn)|西,他們是有區(qū)別的
6、strftime與strptime
這兩個(gè)是 python 中常用的
strftime 函數(shù):
函數(shù)接收以時(shí)間元組,并返回以可讀字符串表示的當(dāng)?shù)貢r(shí)間,格式由參數(shù) format 決定。
time.strftime(format[, t])
format -- 格式字符串。t -- 可選的參數(shù)t是一個(gè) struct_time 對(duì)象。
返回以可讀字符串表示的當(dāng)?shù)貢r(shí)間。
import time
t = (2009, 2, 17, 17, 3, 38, 1, 48, 0)
t = time.mktime(t)
print(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(t)))
得到結(jié)果輸出:
2009-02-17 09:03:38
strptime()
函數(shù)根據(jù)指定的格式把一個(gè)時(shí)間字符串解析為時(shí)間元組。
time.strptime(string[, format])
string -- 時(shí)間字符串。format -- 格式化字符串。
返回 struct_time 對(duì)象。
import datetime,time
d1 = datetime.datetime.strptime('20120305 17:41:20', '%Y%m%d %H:%M:%S')
d2 = datetime.datetime.strptime('2012-03-01', '%Y-%m-%d')
print(d1)
print(d2)
得到結(jié)果:
2012-03-05 17:41:20
2012-03-01 00:00:00
時(shí)間格式與入庫
前面鋪墊了這么多,最終的目的還是需要入庫。這里以4種數(shù)據(jù)庫時(shí)間類型為例:
字段名 => 數(shù)據(jù)類型
r_time => time
r_date => date
r_datetime => datetime
r_timestamp => timestamp
根據(jù)最上方所寫的 Mysql 時(shí)間類型,可以得出對(duì)應(yīng)的時(shí)間格式為:
時(shí)間格式 => 數(shù)據(jù)類型
17:35:05 => time
2018-3-1 => date
2018/3/1 17:35 => datetime
2018/3/1 17:35 => timestamp
time類型
time 類型的格式指定為 17:35:05,不可替換為(17-35-05 或者 17/35/05),會(huì)報(bào)錯(cuò)
可以簡寫成 17:35,數(shù)據(jù)庫會(huì)自動(dòng)補(bǔ)全后面的 00,入庫后最終數(shù)據(jù) 17:35:00
如果簡寫成 17,則入庫后變成 00:00:17
當(dāng)然,如果更奇葩的寫法 17:,17:35: 這種是會(huì)報(bào)錯(cuò)的
date類型
date 類型的格式指定為 2018-3-1 與 2018/3/1,最終入庫格式是(2018-03-01),它會(huì)自動(dòng)補(bǔ)全
可以簡寫成 [18/3/1]、[17/3/1]、[07/3/1]、[97/3/1],數(shù)據(jù)庫會(huì)自動(dòng)補(bǔ)全前面的年份,入庫后最終數(shù)據(jù) 2018-03-01、2017-03-01、2007-03-01、1997-03-01
不可簡寫成 [2017]、[2017/3],會(huì)報(bào)錯(cuò),必須是完整的日期格式
datetime類型
datetime 類型的格式指定為 2018-3-1 17:35:00 和 2018/3/1 17:35:00,最終入庫格式是 2018-03-01 17:35:00
它是 date 與 time 的結(jié)合,有很多共同特性
可以簡寫成 [18/3/1 17:35:05]、[17/3/1 17:35]、[07/3/1 17]、[97/3/1 17],數(shù)據(jù)庫會(huì)自動(dòng)補(bǔ)全前面的年份,入庫后最終數(shù)據(jù) 2018-03-01 17:35:05、2017-03-01 17:35:00、2007-03-01 17:00:00、1997-03-01 17:00:00??梢钥吹剿詣?dòng)將時(shí)間格式補(bǔ)全成統(tǒng)一格式,這里與 time 不同的是,如果只寫 17 不寫分秒,time 會(huì)默認(rèn)將 17 當(dāng)成秒,這里則是默認(rèn)當(dāng)成小時(shí)。
與 date 一樣,年月日不可省略,必須以年月日格式出現(xiàn)
timestamp類型
根據(jù)上面的描述,timestamp的入庫格式與datetime是一樣的,不同的是時(shí)間范圍和存儲(chǔ)空間,它的格式與用法跟datetime一致
以上,便是今天的分享,希望大家喜歡,覺得內(nèi)容不錯(cuò)的,歡迎點(diǎn)擊「在看」支持,謝謝各位。