左手用R右手Python系列14——日期与时间处理

时间:2022-05-08
本文章向大家介绍左手用R右手Python系列14——日期与时间处理,主要内容包括R、提取季度、月份、周、日期(支持短横杠和左斜杠表示的日期格式)、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

日期与时间格式数据处理通常在数据过程中要相对复杂一些,因为其不仅涉及到不同国家表示方式的差异,本身结构也较为复杂,在R语言和Python中,存在着不止一套方法来处理日期与时间,因而做一个清洗的梳理与对比将会很有价值。

本文针对R语言与Python中常用日期与时间函数进行简要对比介绍,力求简单明了,覆盖常用的处理方法。

R

在R语言中,涉及到日期与时间处理的函数主要有以下四套:

  • as.Date()函数:
  • POSIXt/POSIXct函数:
  • chron包:
  • lubridate包:

前两个是R语言的base包内置函数,as.Date主要用于处理常用的日期数据(无时间),POSIXt/POSIXct函数则可以用于处理日期时间数据(同时控制时区)。lubridate包和chron包(无法控制时区)则不仅包含常用的日期与时间数据处理函数,还完善了一些日期日期计算与时区时区转换的若干函数。

Sys.Date() #当前日期 #[1] “2017-10-03” date() #显示当前日期和时间 Sys.time() #显示当前日期与时间 #[1] “2017-10-03 14:21:07 CST”

以上三个函数是R的内建日期函数,之后的案例会频繁用到。

as.Date()

日期与时间变量的格式通常在文件导入之后就丢失了(有些特殊文件格式确实会有保留机制),导入之后会统一还原为字符串,需要我们自行根据其格式进行日期与时间格式的转换。

R语言默认的日期格式按照识别优先级,分别是”%Y-%m-%d” 或者 “%Y/%m/%d”,倘若你导入之前的日期是此种格式,那么在使用as.Date()格式进行日期转换时,便无需显式声明该日期的原始格式,软件会自动按照优先级进行匹配转换。

wodate<-c("2016-07-13","2016-07-12");class(wodate)
[1] "character"
mydata<-as.Date(wodate);class(mydata);mydata
[1] "Date"[1] "2016-07-13" "2016-07-12"
wodate<-c("2016/07/13","2016/07/12");class(wodate)
[1] "character"
mydata<-as.Date(wodate);class(mydata);mydata
[1] "Date"[1] "2016-07-13" "2016-07-12"

而且在月份和具体日期上并没有严格规定的占位(比如1月写成01,5日写成05,写作2016-7-3这种格式也是可以识别的)。

as.Date("2016/7/13")
[1] "2016-07-13"
as.Date("2016-7-13")
[1] "2016-07-13"
as.Date("2016-7-3")
[1] "2016-07-03"

除了这两种可自动识别的日期写法格式之外,剩余的日期格式均需要做格式声明:

wodate<-c("07/13/2016","07/12/2016")###月日年
mydate<-as.Date(wodate,"%m/%d/%Y");mydate
[1] "2016-07-13" "2016-07-12"
wodate<-c("07|13|2016","07|12|2016")###月日年
mydate<-as.Date(wodate,"%m|%d|%Y");mydate
[1] "2016-07-13" "2016-07-12"
wodate<-c("07~13~2016","07~12~2016")###月日年
mydate<-as.Date(wodate,"%m~%d~%Y");mydate
[1] "2016-07-13" "2016-07-12"

可以看到,只要正确声明了原始的日期格式,as.Date()都可以完美的解析出标准日期并输出。

当你已经获得了一个标准日期格式之后,你可以通过format(date,format=) 函数进行日期元素的提取,比如你可以从标准日期中提取出年份、月份、具体日期、季度、星期、周度等。当然base包中也提供了一套简单调用函数:

years()quarters()months()weekdays()days()

#########日期格式代码:########———————————————-  
代码      |           值      |
-------------------------------
%d        |   日期(十进制数) |
%m        |   月份(十进制数) |
%b        |   月份(缩略的)   |
%B        |   月份(全称)     |
%y        |   年(2位数)      |
%Y        |   年(4位数)      |
-------------------------------

format(date,format=):

#输出年份:
format(Sys.Date(),format="%Y")  #[1] "2017" 
format(Sys.Date(),format="%y")  #[1] "17"
#输出月份:
format(Sys.Date(),format="%b") #[1] "10月"  
format(Sys.Date(),format="%B") #[1] "十月" 
format(Sys.Date(),format="%m") #[1] "10"
#输出星期:
format(Sys.Date(),format="%A") #[1] "星期二"
format(Sys.Date(),format="%a") #[1] "周二"#
自定义输出:  
format(Sys.Date(),format="%Y年%m月%d日")  
#[1] "2017年10月03日"

直接使用内置函数提取日期:

weekdays(Sys.Date())  #取日期对象所处的周几;  
[1] "星期二"
months(Sys.Date())    #取日期对象的月份;      
[1] "十月"
days(Sys.Date())      #提取日期对象的具体日期。
[1] 3
quarters(Sys.Date())  #提取日期对象的季度;     
[1] "Q4"

使用as.Date()函数可以非常方面的输出连续 时间序列:

seq(from=as.Date("1976-07-04"),by="1 day",length=10)
 [1] "1976-07-04" "1976-07-05" "1976-07-06" "1976-07-07" "1976-07-08" "1976-07-09" "1976-07-10" "1976-07-11" "1976-07-12"[10] "1976-07-13"seq(from=as.Date("2000-06-01"),to=as.Date("2001-08-01"),by="2 weeks")
 [1] "2000-06-01" "2000-06-15" "2000-06-29" "2000-07-13" "2000-07-27" "2000-08-10" "2000-08-24" "2000-09-07" "2000-09-21"[10] "2000-10-05" "2000-10-19" "2000-11-02" "2000-11-16" "2000-11-30" "2000-12-14" "2000-12-28" "2001-01-11" "2001-01-25"[19] "2001-02-08" "2001-02-22" "2001-03-08" "2001-03-22" "2001-04-05" "2001-04-19" "2001-05-03" "2001-05-17" "2001-05-31"[28] "2001-06-14" "2001-06-28" "2001-07-12" "2001-07-26"

POSIXt/POSIXct函数:

这两个函数虽然都可以同时处理日期与时间数据,并且控制时区,但是 其内部对于日期与时间储存的格式不同,POSIXct类将日期/时间值作为1970年1月1日以来的秒数存储,而POSIXt类则将其作为一个具有秒、分、小时、日、月、年等元素的列表存储。因而POSIXct函数使用的更为频繁,这里以POSIXct函数为主进行讲解。

POSIXct函数与as.Date()函数类似,在日期输入时,默认支持的日期格式是包含月日年,由斜杠或者破折号分割。日期与时间之间用空格隔开,时间格式为小时:分钟:秒数。

2017/10/03 2017/10/03 11:56 2017/10/03 11:56:45

以上是三种POSIXct支持的日期输入格式。

mydata<-c("2017/10/03","2017/10/03","2017/10/03 11:56","2017/10/03 11:56:45")
as.POSIXlt(mydata)
[1] "2017-10-03 CST" "2017-10-03 CST" "2017-10-03 CST" "2017-10-03 CST"
mydata<-c("2017-10-03 11:56","2017-10-03 11:56:45")
as.POSIXlt(mydata)
[1] "2017-10-03 11:56:00 CST" "2017-10-03 11:56:00 CST"

对于一些复杂的日期/时间格式,你可以通过声明正确的格式,让as.POSIXlt完成标准输出。

as.POSIXlt("03/10月/2017 12:09:30",format="%d/%b/%Y %H:%M:%S")
[1] "2017-10-03 12:09:30 CST"
as.POSIXlt("03/十月/2017 12:09:30",format="%d/%B/%Y %H:%M:%S")
[1] "2017-10-03 12:09:30 CST"

备注: (这里的月份格式是基于PC系统日期格式而定,我的系统是简体中文,所以月份对应的b、B分别表示为10月、十月,如果是英文系统,应该对应Oct、October)。

这里需要说明的是,以上通过as.POSIXlt函数输出的时间/日期格式,仍然可以使用format(date,format=)函数或者years()quarters()months()weekdays()days()进行时间与日期函数元素的提取。

因为以上格式输出多了小时、分钟、秒等,所以类似提取日期函数元素一样,内置函数中也提供了hours()seconds()minutes()进行小时、分钟和秒的提取。

hours(as.POSIXlt("03/十月/2017 12:09:30",format="%d/%B/%Y %H:%M:%S"))
[1] 12
minutes(as.POSIXlt("03/十月/2017 12:09:30",format="%d/%B/%Y %H:%M:%S"))
[1] 9
seconds(as.POSIXlt("03/十月/2017 12:09:30",format="%d/%B/%Y %H:%M:%S"))
[1] 30

chron包:

chron包也提供了时间与日期函数的处理方法,但是该包最大的不同是在输出格式上比较特别,它将时间与日期作为两部分独立的对象。

library("chron")
chron(dates=c("10/01/17","10/03/17"),times=c("12:30:45","15:40:02"))
[1] (10/01/17 12:30:45) (10/03/17 15:40:02)

chron函数需要两个必备参数,日期部分和时间部分,日期接受的默认参数是月份(十进制)、日期值(十进制)、年份(四位或者两位),中间用“/”隔开,时间格式按照常规格式书写,用冒号隔开。当你的输入日期与时间符合以上默认格式时,可不必显式声明收入格式。当你不指定输出日期与时间格式时,默认输出格式与默认收入格式相同,日期与时间之间被组合成一个日期时间单位,中间用空格隔开。

chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"))
[1] (17/10/01 12:30:45) (17/10/03 15:40:02)

当你输入的日期不符合chron函数默认时间格式时,需要显式声明收入日期的格式,便于chron函数进行识别与解析,此时可不指定输出格式,输出按照默认格式输出。

chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"),out.format=c("y-m-d","h:m:s"))
[1] (17-10-01 12:30:45) (17-10-03 15:40:02)

当你输入格式与默认格式不符,而且同时想要自定义输出格式的时候,需要同时声明输入格式和输出格式。

mydata<-chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"),out.format=c("y-m-d","h:m:s"))

同样,chron格式日期仍然可以支持format函数或者years()quarters()months()weekdays()days()hours()seconds()minutes()函数的调用进行时间 与日期元素提取。

format(mydata,format="%Y") 
format(mydata,format="%m") 
format(mydata,format="%d") 
[1] "2017" "2017"
[1] "10" "10"
[1] "01" "03"
years(mydata);quarters(mydata);months(mydata);weekdays(mydata);days(mydata);hours(mydata);minutes(mydata);seconds(mydata)
[1] 2017 2017
[1] 4Q 4Q
[1] Oct Oct
[1] Sun Tue
[1] 1 3
[1] 12 15
[1] 30 40
[1] 45  2

lubridate包:

lubridate包是著名的ggplot2作者哈德利威科姆大神写的,为了配合他的数据可视化百宝箱tidyverse一起工作。该包封装了大量简化 时间与日期操作的函数,也是我平时用于处理时间日期使用频率最高的包。 library(“lubridate”)

lubridate可以识别的日期格式非常丰富。

ymd()/mdy()/dmy()#转化日期:
ymd("20110604")       #[1] "2011-06-04"
mdy("06-04-2011")     #[1] "2011-06-04"
dmy("04/06/2011")     #[1] "2011-06-04"

year() #从日期中提取年份:

year("2016-10-24")   #[1] 2016
year("2016/10/24")   #[1] 2016

提取季度、月份、周、日期(支持短横杠和左斜杠表示的日期格式)

quarter()/month()/week()/day()

quarter("2016/10/24")  #[1] 4
month("2016/10/24")    #[1] 10
week("2016/10/24")     #[1] 43
day("2016/10/24")      #[1] 24

提取时间元素(小时、分钟、秒) hour()/minute()/second()

hour("2011-08-10 14:20:01")     #[1] 14
minute("2011-08-10 14:20:01")   #[1] 20
second("2011-08-10 14:20:01")   [1] 1

以上函数均支持向量操作(这是显而易见,毕竟R中没有标量)。

Python:

Python中的常用时间与日期处理函数除了Pandas内置的时间对象之外,还有datetimetime模块。

  • datetime
  • timestamp
  • Pandas

1、datetime

import datetime
nowtime = datetime.datetime.now();nowtime  #获取当前时间与日期
datetime.datetime(2017, 10, 3, 13, 10, 41, 477912)
nowtime.strftime('%Y-%m-%d %H:%M:%S')   #对该日期进行格式化输出
'2017-10-03 13:10:41'type(nowtime)
datetime.datetime

datetime.datetime.now函数可以获取当前系统的日期,该日期是一个datetime.datetime对象,内部含有年份、月份、日、小时、分钟、秒和数值化日期的信息。可以通过strftime方法输出为我们常见的日期格式。

time = '2017-10-03 13:05:21'
mytime=datetime.datetime.strptime(time,'%Y-%m-%d %H:%M:%S')
mytime.strftime('%Y-%m-%d %H:%M:%S') 
'2017-10-03 13:05:21'

如果是外部输入的日期,可以先转化为datetime.datetime对象之后,使用strftime函数进行格式输出。

time = '10-03-2017 13:05:21'
mytime=datetime.datetime.strptime(time,'%m-%d-%Y %H:%M:%S')
mytime.strftime('%Y-%m-%d %H:%M:%S') '2017-10-03 13:05:21'

导入的日期需要声明正确的书写格式,输出时也可以自定义输出的日期显示格式。

mytime.strftime('%m-%d-%Y %H:%M:%S')'10-03-2017 13:05:21'

datetime.date对象可以直接输出year、month、day、hour、minute、second属性。

mytime.year;mytime.month;mytime.day;mytime.hour;mytime.minute;mytime.second
2017
10
3
13
5
21

2、timestamp

第二类日期时间对象是timestamp,又称时间戳。

import time
time.localtime() #获取系统当前日期:
time.struct_time(tm_year=2017, tm_mon=10, tm_mday=3, tm_hour=13, tm_min=33, tm_sec=38, tm_wday=1, tm_yday=276, tm_isdst=0)
a = "2017-10-03 13:40:00"
timeArray = time.strptime(a, "%Y-%m-%d %H:%M:%S")  #输入一个日期:
time.struct_time(tm_year=2017, tm_mon=10, tm_mday=3, tm_hour=13, tm_min=40, tm_sec=0, tm_wday=1, tm_yday=276, tm_isdst=-1)
otherStyleTime = time.strftime("%Y/%m/%d %H:%M:%S", timeArray);otherStyleTime  #按照定义的格式输出
'2017/10/03 13:40:00'

3、pandas日期对象

import pandas as pd
pandas中的date_range方法可以根据参数需要生成指定的时间序列:
pandas.date_range(start=None, end=None, periods=None, freq=’D’, tz=None, normalize=False, name=None, closed=None, **kwargs)

重点关注其中的前四个参数,start表示日期起点,end表示日期终点,periods表示日期长度,freq表示日期的频率。(四个参数必须满足其中三个方可输出时间序列,freq有默认为天的从参数)。

pd.date_range('2017-09-25 12:59:30','2017-10-03 12:59:30',freq="H")  
pd.date_range('2017-09-25 12:59:30',periods=10)
pd.date_range(end='2017-09-25 12:59:30',periods=10)
pd.date_range('2017-09-25 12:59:30','2017-10-03 12:59:30')

当然Python序列处理的函数在Python中无处不在,这里仅介绍以上几个经常会用到的高频函数。想要深入了解Python中的时间序列处理模式,还是需要深入研究其源文档。

本文参考文献: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431937554888869fb52b812243dda6103214cd61d0c2000 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.date_range.html

往期案例数据请移步本人GitHub: https://github.com/ljtyduyu/DataWarehouse/tree/master/File