左手用R右手Python系列14——日期与时间处理
日期与时间格式数据处理通常在数据过程中要相对复杂一些,因为其不仅涉及到不同国家表示方式的差异,本身结构也较为复杂,在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内置的时间对象之外,还有datetime\time模块。
- 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
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)