在用 Python 進行數據處理,尤其是時間序列數據的處理,經常會涉及處理時間或日期的地方,有些看似簡單的問題,經常會混淆,甚至被困住。
本文分享的內容來自 Lemon 整理的《Python時間使用指南》,完整版的可以在公眾號 「檸檬數據」獲取。
首先要介紹的,是大家平時用的較多的 datetime 模塊,它屬於 Python 的內置模塊,功能相對較全。
針對 Datetime 模塊, 《Python時間使用指南》從構建時間對象實例、時間轉換、時間對象的運算三個方面進行了梳理,共涉及 13 個知識點,整理的大綱如下:
datetime構建時間對象實例import datetime
# from datetime import date, datetime,time,timedelta,tzinfo
import time時間實例的構造包括 日期(如 2020年10月12日),時間(如 20點10分01秒),或者是包含 date 和 time 的 datetime (如 2020年10月12日20點10分01秒),下面 Lemon 來跟大家介紹下具體的構造過程。
日期(date)實例的構造date 是一個理想化的簡單型日期,屬性有 year , month , day 。
# 構造日期 date 實例
d1 = datetime.date(2020,10,12)
d1datetime.date(2020, 10, 12)# 構造日期 date 實例
d1 = datetime.date(2020,10,12)
print(d1)2020-10-12除了上面的構造方式,在 date 實例化的時候,還可以通過 date.today() 來構造當天的日期。
datetime.date.today()datetime.date(2020, 10, 14)date 類型的日期,可以通過 .year , .month , .day 來獲取日期所屬的 年份,月份,和具體的日期號,這幾個方法在數據分析中經常會用到。
# 獲取日期所屬的 年份,月份,和具體的日期號
print(f'日期所屬的年份為:{d1.year}')
print(f'日期所屬的月份為:{d1.month}')
print(f'日期具體的日期號為:{d1.day}')日期所屬的年份為:2020
日期所屬的月份為:10
日期具體的日期號為:12
時間 time 實例的構造time 是一個獨立於任何特定日期的理想化時間,其屬性有 hour,minute, second , microsecond 和 tzinfo 。
# 構造時間 time 實例
t1 = datetime.time(20,10,1)
t1datetime.time(20, 10, 1)# 獲取日期所屬的 年份,月份,和具體的日期號
print(f'time 所屬的小時為:{t1.hour}')
print(f'time 所屬的分鐘為:{t1.minute}')
print(f'time 所屬的秒為:{t1.second}')time 所屬的小時為:20
time 所屬的分鐘為:10
time 所屬的秒為:1
datetime 實例的構造datetime 是日期和時間的結合,其屬性有 year,month,day,hour,minute, second , microsecond 和 tzinfo 。
# 構造時間 datetime 實例
dt1 = datetime.datetime(2020,10,11,20,10,1)
dt1datetime.datetime(2020, 10, 11, 20, 10, 1)除了上面的構造方式,在 datetime 實例化的時候,還有其他的一些方式,包括使用 datetime.now() 和 datetime.today(),以及在 date 的基礎上使用 combine 方法等。
dt2 = datetime.datetime.now()
dt2datetime.datetime(2020, 10, 14, 15, 12, 20, 303269)dt3 = datetime.datetime.today()
dt3datetime.datetime(2020, 10, 14, 15, 12, 20, 308733)dt4 = datetime.datetime.combine(d1,t1)
dt4datetime.datetime(2020, 10, 12, 20, 10, 1)通過 datetime 的實例化,是我們使用時間是經常用到的方法,在日常使用過程中,我們可能只需要具體到某天,或者只需要具體到某天的某個時間點,這時候,也可以通過 datetime 的一些方法來實現。
# 從 datetime 來獲取日期
dt4.date()datetime.date(2020, 10, 12)# 從 datetime 來獲取具體的時間點
dt4.time()datetime.time(20, 10, 1)同樣的 datetime 類型的時間,可以通過 .year , .month , .day 來獲取日期所屬的 年份,月份,和具體的日期號。
# 獲取日期所屬的 年份,月份,和具體的日期號
print(f'日期所屬的年份為:{dt4.year}')
print(f'日期所屬的月份為:{dt4.month}')
print(f'日期具體的日期號為:{dt4.day}')日期所屬的年份為:2020
日期所屬的月份為:10
日期具體的日期號為:12還有一個可能涉及到的時間是獲取某天屬於星期幾,可以通過 weekday() 和 isoweekday() 方法來實現。
# 從 datetime 來獲取日期是星期幾
# 使用 weekday 方法
# 數字從0開始,0代表星期一,1代表星期二,以此類推
dt4.weekday()0# 從 datetime 來獲取日期是星期幾
# 使用 isoweekday 方法
# 數字從1開始,1代表星期一,2代表星期二,以此類推
dt4.isoweekday()1datetime 還有一種方法,在這裡也值得介紹下,如果 datetime 的值由於某些原因弄錯了,我們也可以通過 replace() 方法來進行更正。這個方法在進行數據清洗的時候會有用。
replace 方法的參數如下:
datetime.replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, * fold=0)
dt5 = dt4.replace(year=2019)
dt5datetime.datetime(2019, 10, 12, 20, 10, 1)
timedelta 對象的構造timedelta 對象表示兩個 date 或者 time 或者 datetime 的時間間隔。
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
所有參數都是可選的並且默認為 0。這些參數可以是整數或者浮點數,也可以是正數或者負數。
只有 days, seconds 和 microseconds 會存儲在內部。參數單位的換算規則如下:
delta = datetime.timedelta(weeks=3,
days=10,
hours=6,
minutes=50,
seconds=30,
microseconds=1000,
milliseconds=10000,
)
deltadatetime.timedelta(days=31, seconds=24640, microseconds=1000)
tzinfo 介紹datetime.tzinfo 返回 datetime 對象的時區,前提是在創建 datetime 對象時需傳入 tzinfo 參數,如果沒有傳入則返回值為 None 。
# 如果沒有 pytz 庫,則需要自行安裝
import pytz
sh = pytz.timezone('Asia/Shanghai')
d_tz = datetime.datetime(2020,10,12,hour=8,tzinfo=sh)
d_tz.tzinfo<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>
時間轉換時間的三種存在方式:時間對象,時間字符串,時間戳。
時間對象,比如前面介紹的 date 、 datetime 、 time 對象等;時間字符串,如:"2020-10-12";時間戳,如 time.time() 返回的就是時間戳。
在數據處理過程中,經常會遇到需要將不同形式的時間進行轉換。這裡給大家介紹下常用的方法:
時間對象轉字符串時間對象轉換為字符串,可以通過 isoformat 或 strftime 方法來實現。
strftime 的英文全稱是 str format time ,根據給定的格式將時間對象轉換為字符串
# 將 date 時間對象轉換為字符串
d1 = datetime.date(2020,10,12)
d1.isoformat()'2020-10-12'# 用 srtftime 來轉換
# YYYY-MM-DD 形式
d1.strftime('%Y-%m-%d')'2020-10-12'# MM DD,YYYY 形式
d1.strftime('%b %d,%Y')'Oct 12,2020'# 將 time 時間對象轉換為字符串
t1 = datetime.time(20,10,1)
t1.strftime('%H:%M:%S')'20:10:01'# 將 datetime 時間對象轉換為字符串
dt2 = datetime.datetime.now()
dt2.strftime('%Y-%m-%d %H:%M:%S')'2020-10-14 15:12:20'dt2.isoformat()'2020-10-14T15:12:20.403113'python 中常見的時間日期格式化符號:
指令意義示例%a當地工作日的縮寫。Sun, Mon, ..., Sat (en_US);So, Mo, ..., Sa (de_DE)%A本地化的星期中每日的完整名稱。Sunday, Monday, ..., Saturday (en_US);Sonntag, Montag, ..., Samstag (de_DE)%w以十進位數顯示的工作日,其中0表示星期日,6表示星期六。0, 1, ..., 6%d補零後,以十進位數顯示的月份中的一天。01, 02, ..., 31%b當地月份的縮寫。Jan, Feb, ..., Dec (en_US);Jan, Feb, ..., Dez (de_DE)%B本地化的月份全名。January, February, ..., December (en_US);Januar, Februar, ..., Dezember (de_DE)%m補零後,以十進位數顯示的月份。01, 02, ..., 12%y補零後,以十進位數表示的,不帶世紀的年份。00, 01, ..., 99%Y十進位數表示的帶世紀的年份。0001, 0002, ..., 2013, 2014, ..., 9998, 9999%H以補零後的十進位數表示的小時(24 小時制)。00, 01, ..., 23%I以補零後的十進位數表示的小時(12 小時制)。01, 02, ..., 12%p本地化的 AM 或 PM 。AM, PM (en_US);am, pm (de_DE)%M補零後,以十進位數顯示的分鐘。00, 01, ..., 59%S補零後,以十進位數顯示的秒。00, 01, ..., 59%f以十進位數表示的微秒,在左側補零。000000, 000001, ..., 999999%zUTC 偏移量,格式為 ±HHMM[SS[.ffffff]] (如果是簡單型對象則為空字符串)。(空), +0000, -0400, +1030, +063415, -030712.345216%Z時區名稱(如果對象為簡單型則為空字符串)。(空), UTC, GMT%j以補零後的十進位數表示的一年中的日序號。001, 002, ..., 366%U以補零後的十進位數表示的一年中的周序號(星期日作為每周的第一天)。在新的一年中第一個星期日之前的所有日子都被視為是在第 0 周。00, 01, ..., 53%W以十進位數表示的一年中的周序號(星期一作為每周的第一天)。在新的一年中第一個第期一之前的所有日子都被視為是在第 0 周。00, 01, ..., 53%c本地化的適當日期和時間表示。Tue Aug 16 21:30:00 1988 (en_US);Di 16 Aug 21:30:00 1988 (de_DE)%x本地化的適當日期表示。08/16/88 (None);08/16/1988 (en_US);16.08.1988 (de_DE)%X本地化的適當時間表示。21:30:00 (en_US);21:30:00 (de_DE)%%字面的 '%' 字符。%字符串轉時間對象字符串轉時間對象,用的是 strptime 方法,與 strftime 方法剛好相反。
strptime 的英文全稱是 str parse time ,將字符串解析為給定相應格式的時間對象。
s1 = '2020-10-09'
d = datetime.datetime.strptime(s1,'%Y-%m-%d')
ddatetime.datetime(2020, 10, 9, 0, 0)下面提供了 strftime 方法與 strptime 方法的比較:
strftimestrptime用法根據給定的格式將對象轉換為字符串將字符串解析為給定相應格式的 datetime對象方法類型實例方法類方法方法date; datetime; timedatetime籤名strftime(format)strptime(date_string, format)需要注意的是,strftime 方法可供 date、time 和 datetime 對象使用,而 strptime 方法僅供 datetime 對象使用。
時間戳轉換為時間對象時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數。
# 獲取當前的時間戳
ts_1 = time.time()
ts_11602660751.071785# 獲取當天00:00:00的時間戳
ts_2 = int(time.time()/86400)*86400
ts_21602633600# 獲取當天23:59:59的時間戳
# 一天有 24*60*60 = 86400 秒
ts_3 = int(time.time()/86400)*86400+86400-1
ts_31602719999# 將時間戳轉換為時間對象
datetime.datetime.fromtimestamp(ts_1)datetime.datetime(2020, 10, 14, 15, 32, 31, 71785)# 將時間戳轉換為時間對象
datetime.date.fromtimestamp(ts_1)datetime.date(2020, 10, 14)
將時間對象轉換為時間戳鑑於,時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數。
因此,將時間對象轉換為時間戳時,直接計算兩個時間對象的 timedelta ,並將timedelta 以 「秒」 來表示就可以了。
dt1datetime.datetime(2020, 10, 11, 20, 10, 1)# 注意這裡要用 北京時間
dt_s = datetime.datetime(1970,1,1,8)
dt_sdatetime.datetime(1970, 1, 1, 8, 0)timedelta_1 = dt1 -dt_s
# 返回時間間隔包含了多少秒
timedelta_s = timedelta_1.total_seconds()
timedelta_s1602418201.0這裡我們來反推下,看我們將時間對象轉換為時間戳,是否正確。
# 將時間戳轉換為時間對象
datetime.datetime.fromtimestamp(timedelta_s)datetime.datetime(2020, 10, 11, 20, 10, 1)
時間對象的運算獲取當天最小時間和最大時間# 獲取當天最小時間
datetime.datetime.combine(datetime.date.today(),datetime.time.min)datetime.datetime(2020, 10, 14, 0, 0)# 獲取當天最大時間
datetime.datetime.combine(datetime.date.today(),datetime.time.max)datetime.datetime(2020, 10, 14, 23, 59, 59, 999999)
獲取當前日期的前幾天/後幾天# 獲取明天
datetime.date.today() + datetime.timedelta(days=1)datetime.date(2020, 10, 15)# 獲取明天
datetime.date.today() - datetime.timedelta(days=1)datetime.date(2020, 10, 13)
獲取本周或本月第一天及最後一天d_today = datetime.date.today()
d_todaydatetime.date(2020, 10, 14)# 獲取本周第一天
d_today - datetime.timedelta(d_today.weekday())datetime.date(2020, 10, 12)# 獲取本周最後一天
d_today + datetime.timedelta(6-d_today.weekday())datetime.date(2020, 10, 18)
計算兩個日期相差多少天# timedelta 對象的計算
td1 = dt2 - dt1
td1datetime.timedelta(days=2, seconds=68539, microseconds=403113)td1.days2注意下,如果需要計算兩個日期之間總共相差多少秒,應該用 total_seconds() 方法。
td1.seconds68539td1.total_seconds()241339.403113參考文檔:
https://docs.python.org/zh-cn/3/library/datetime.html#strftime-strptime-behaviorhttps://segmentfault.com/a/1190000012112097https://blog.csdn.net/qq_34493908/article/details/80888052https://zhuanlan.zhihu.com/p/96384066