参考书目:《深入浅出Pandas:利用Python进行数据处理与分析》
pandas的时间对象如下,本次介绍 period和DateOffest类。
#DateOffset 类似于时间差 Timedelta ,但它使用日历中时间日期的规则,而不是直接进行时间性质的算术计算,让时间更符合实际生活。
#比如,有些地区使用夏令时时,每日偏移时间有可能是 23 或 24 小时,甚至 25 个小时。
- #DateOffset 示例,以下所示了夏令时的情况:
-
- # 生成一个指定的时间,芬兰赫尔辛基时间执行夏令时
- ts = pd.Timestamp('2016-10-30 00:00:00', tz='Europe/Helsinki')
- ts
- # Timestamp('2016-10-30 00:00:00+0300', tz='Europe/Helsinki')
-
- # 增加一天
- ts + pd.Timedelta(days=1)
- # Timestamp('2016-10-30 23:00:00+0200', tz='Europe/Helsinki')
-
- # 按日历时间
- ts + pd.DateOffset(days=1)
- # Timestamp('2016-10-31 00:00:00+0200', tz='Europe/Helsinki')
#以下是增加工作日,出现跨周末的情况:
- friday = pd.Timestamp('2022-01-05')
- friday.day_name()
- #'Friday'
-
- # 增加两个工作日,从周五到周二
- two_business_days = 2 * pd.offsets.BDay() #BDay()表示工作日
- two_business_days.apply(friday)
- # Timestamp('2022-01-09 00:00:00')
-
- friday + two_business_days
- # Timestamp('2022-01-09 00:00:00')
-
- (friday + two_business_days).day_name()
- # 'Tuesday'
#所有的日期偏移对象都在 pandas.tseries.offsets 下,其中 pandas.tseries.offsets.DateOffset 是标准的日期范围时间偏移类型,
#用于日期范围的标准日期增量类型。它默认是一个日历日。
- from pandas.tseries.offsets import DateOffset
- ts = pd.Timestamp('2017-01-01 09:10:11')
- ts + DateOffset(months=3)
- # Timestamp('2017-04-01 09:10:11')
- ts + DateOffset(hours=2)
- # Timestamp('2017-01-01 11:10:11')
- ts + DateOffset()
- # Timestamp('2017-01-02 09:10:11')
Offset 支持向前或向后偏移:
- ts = pd.Timestamp('2020-06-06 00:00:00')
- ts.day_name()
- # 'Saturday'
-
- # 定义一个工作小时偏移,默认是周一到周五 9-17 点,我们从 10点开始
- offset = pd.offsets.BusinessHour(start='10:00')
-
- # 向前偏移一个工作小时,是一个周一,跳过了周日
- offset.rollforward(ts)
- # Timestamp('2020-06-08 10:00:00')
-
- # 向前偏移至最近的工作日,小时也会增加
- ts + offset
- # Timestamp('2020-06-08 11:00:00')
-
- # 向后偏移,会在周五下班前的一个小时
- offset.rollback(ts)
- # Timestamp('2020-06-05 17:00:00')
-
- ts - pd.offsets.Day(1) # 昨日
- ts - pd.offsets.Day(2) # 前日
- ts - pd.offsets.Week(weekday=0) - pd.offsets.Day(14) # 上周一
- ts - pd.offsets.MonthEnd() - pd.offsets.MonthBegin() # 上月一日
-
- #时间偏移操作会保留小时和分钟,有时候我们不在意具体的时间只开始从哪天开始,可以使用 normalize() 进行标准化到午夜 0 点:
- offset.rollback(ts).normalize()
- # Timestamp('2020-06-05 00:00:00')
#apply 可以使用偏移对象应用到一个时间上:
- ts = pd.Timestamp('2020-06-01 09:00')
- day = pd.offsets.Day() # 定义偏移对象
- day.apply(ts) # 偏移对象应用到时间上
- # Timestamp('2020-06-02 09:00:00')
- day.apply(ts).normalize() # 标准化/归一化
- # Timestamp('2020-06-02 00:00:00')
-
- ts = pd.Timestamp('2020-06-01 22:00')
- hour = pd.offsets.Hour()
- hour.apply(ts)
- # Timestamp('2020-06-01 23:00:00')
-
- hour.apply(ts).normalize()
- # Timestamp('2020-06-01 00:00:00')
-
- hour.apply(pd.Timestamp("2014-01-01 23:30")).normalize()
- # Timestamp('2014-01-02 00:00:00')
#上边我们偏移时只偏移了偏移对象的一个单位,可以传入参数支持多个单位和对象中的其他单位:
- d = datetime.datetime(2020, 6, 1, 9, 0)
- # datetime.datetime(2020, 6, 1, 9, 0)
-
- d + pd.offsets.Week() # 偏移一周
- # Timestamp('2020-06-08 09:00:00')
-
- d + pd.offsets.Week(weekday=4) # 偏移4个周中的日期
- # Timestamp('2020-06-05 09:00:00')
-
- # 取一周第几天
- (d + pd.offsets.Week(weekday=4)).weekday()
- # 4
-
- d - pd.offsets.Week() # 向后一周
- # Timestamp('2020-05-25 09:00:00')
-
- #参数也支持归一标准化 normalize:
- d + pd.offsets.Week(normalize=True)
- # Timestamp('2020-06-08 00:00:00')
-
- d - pd.offsets.Week(normalize=True)
- # Timestamp('2020-05-25 00:00:00')
-
- #再比如,YearEnd 支持 month 指定月份:
- d + pd.offsets.YearEnd()
- # Timestamp('2020-12-31 09:00:00')
-
- d + pd.offsets.YearEnd(month=6)
- # Timestamp('2020-06-30 09:00:00')
- rng = pd.date_range('2012-01-01', '2012-01-03')
- s = pd.Series(rng)
- rng
- # DatetimeIndex(['2012-01-01', '2012-01-02', '2012-01-03'], dtype='datetime64[ns]', freq='D')
- s
- '''
- 0 2012-01-01
- 1 2012-01-02
- 2 2012-01-03
- dtype: datetime64[ns]
- '''
-
- rng + pd.DateOffset(months=2)
- # DatetimeIndex(['2012-03-01', '2012-03-02', '2012-03-03'], dtype='datetime64[ns]', freq='D')
-
- s + pd.DateOffset(months=2)
- '''
- 0 2012-03-01
- 1 2012-03-02
- 2 2012-03-03
- dtype: datetime64[ns]
- '''
-
- s - pd.DateOffset(months=2)
- '''
- 0 2011-11-01
- 1 2011-11-02
- 2 2011-11-03
- dtype: datetime64[ns]
- '''
#时长也支持与时间偏移进行操作,而且和时长与时长的操作一样:
- s - pd.offsets.Day(2)
- '''
- 0 2011-12-30
- 1 2011-12-31
- 2 2012-01-01
- dtype: datetime64[ns]
- '''
-
- td = s - pd.Series(pd.date_range('2011-12-29', '2011-12-31'))
- td
- '''
- 0 3 days
- 1 3 days
- 2 3 days
- dtype: timedelta64[ns]
- '''
-
- td + pd.offsets.Minute(15)
- '''
- 0 3 days 00:15:00
- 1 3 days 00:15:00
- 2 3 days 00:15:00
- dtype: timedelta64[ns]
- '''
- #创建时间段对象 年
- pd.Period('2020')
- #季度
- pd.Period('2020Q3') #Q代表季度
#周期 dtype 拥有 freq 属性,并使用频率字符串以诸如 period[D]或period[M]之类的period[freq] 表示。
- pi = pd.period_range('2016-01-01', periods=3, freq='M')
- pi
- # PeriodIndex(['2016-01', '2016-02', '2016-03'], dtype='period[M]', freq='M')
-
- pi.dtype
- # period[M]
#可以使用 period_range 可以构造 Period 序列:
- prng = pd.period_range('1/1/2011', '1/1/2012', freq='M')
- prng
pd.period_range('2022-11-01 10:00',periods=10,freq='H')
pd.period_range('2022-Q1','2022-Q4',freq='Q-NOV')#NOV为一年最后时间
pd.period_range('2022-Q1','2022-Q4',freq='Q')
#从周期中添加和减去整数会按其自身的频率移动周期。 具有不同频率(跨度)的Period 之间不允许进行算术运算。
- # 一年一个周期
- p = pd.Period('2012', freq='A-DEC')
-
- p + 1 # 加一个周期,加一年
- # Period('2013', 'A-DEC')
-
- p - 3 # 减少一个周期,减去三年
- # Period('2009', 'A-DEC')
-
- # 两月一个周期
- p = pd.Period('2012-01', freq='2M')
- p + 2 # 加两个周期,到五月据的周期
- # Period('2012-05', '2M')
-
- p - 1 # 减去一个周期
- # Period('2011-11', '2M')
-
- # 周期频率不同不能计算,会报 IncompatibleFrequency 错误
- p == pd.Period('2012-01', freq='3M')
- # 频率从月转为天
- pi.astype('period[D]')
- # PeriodIndex(['2016-01-31', '2016-02-29', '2016-03-31'], dtype='period[D]', freq='D')
- # 转换为 DatetimeIndex
- pi.astype('datetime64[ns]')
- # DatetimeIndex(['2016-01-01', '2016-02-01', '2016-03-01'], dtype='datetime64[ns]', freq='MS')
-
-
- # 转换为 PeriodIndex
- dti = pd.date_range('2011-01-01', freq='M', periods=3)
- dti
- # DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31'], dtype='datetime64[ns]', freq='M')
- dti.astype('period[M]')
- # PeriodIndex(['2011-01', '2011-02', '2011-03'], dtype='period[M]', freq='M')
pd.date_range('2011-01-01','2022-01-06',freq='D').astype('period[M]')
pd.date_range('2011-01-01','2022-01-06',freq='D').astype('period[Q]')