在数据的导入处理过程中,会有很多类型的变量,其中一类比较特殊的就是日期时间型的变量,储存着时间。不过在导入的过程中,常常会因为数据采集的时候没有按照固定的规范来记录,导致在导入的时候出现将一串日期默认转换为字符串,从而使日期数据的信息丢失。扎UN哈UN为字符串或因子之后,不能进行时间的比较与计算,比如按照时间序列进行排序,根据采集日期和出生日期计算年龄,提取特定时间段的数据等等。刚开始的时候因为不熟悉时间类型的变量,所以我在比较时间的时候经常是先由自字符串拆分出来年月日或者时分秒的数据,然后再将这些数据转换为数字进行上述的比较排序与提取,但是当记录的时间变量有年月日时分秒的时候,转换成数值变量的时候就会将一个日期拆分成6个变量,这个时候会大大地增加数据框的复杂程度,而且在计算加减的时候,再遇到闰年闰月,就变得更加的复杂了,所以我就考虑不能再用上面的那种方法了,学习一下时间类型的变量可以直接进行相加减和比较等操作了。
我们理论结合实践。重点在整理关于日期时间的概念,然后从实际的应用场景中学习相关函数的使用。
概念
我想说的概念就是在平时的使用过程中会遇到哪些的情况,有哪些的需求,要完成什么样的目的等。一般来说,最常见到的情况是将日期导入R中,但是会出现导入的日期变成了字符串或因子型变量,这时候就需要把这些字符串类型的变量转换为日期或时间类型的变量。或者我们在作图的时候,需要时间序列作为坐标轴,如果希望使用特定格式的时间类型,如只有年,或者月或者其他的组合,那么转换成字符串会避免很多格式的错误或乱码。又或者需要根据两个时间点计算年龄或者间隔时间,这个时候就需要使用日期时间类型的变量进行计算,在R语言中,当日期时间类型的数据用作计算差值的时候,他会把每个日期时间换算成一个数值,日期类型数据的数值就是1970年1月1日到现在日期的天数,时间类型的数据就是1970年一月一日到现在时间的秒数,那么两个日期时间数据之间的计算就转换成了这两个数值的计算。下面就是常见的,能用来说实现上面需要的一些函数。
一、读取系统当前日期时间的函数(区分大小写):
Sys.Date():返回系统当前的日期;Sys.time():返回系统当前的日期和时间;上面的这两个函数返回的值都是日期时间类型的值,date()返回的是字符串类型的系统日期和时间。
> Sys.Date()
[1] "2020-03-29"
> Sys.time()
[1] "2020-03-29 11:18:45 CST"
> date()
[1] "Sun Mar 29 11:18:45 2020"
二、字符串转换为日期变量
函数:as.Date(),使用?as.Date可以查看函数的所有参数。
其最基本的形式为:as.Date(x,format=’ ',……),其中,x就是我们要转化的日期字符串,format是指定日期的格式,关于更全面的format参数格式,可见文章末尾附表。
> date <- '2020-03-29'
> my_date <- as.Date(date);my_date
[1] "2020-03-29"
> class(my_date)
[1] "Date"
这里的as.Date()函数只有一个x参数,因为formet参数默认的格式是"%Y-%m-%d",因为们要转化的字符串就是这种形式的,所以就不用写了。但是有的时候我们导入的字符串并不是这种格式的,那么就需要我们指定一下字符串的格式了。
> date <- '2020/03/29'
> my_date <- as.Date(date,"%Y/%m/%d");my_date
[1] "2020-03-29"
> class(my_date)
[1] "Date"
> date <- '2020/29/03'
> my_date <- as.Date(date,"%Y/%d/%m");my_date
[1] "2020-03-29"
> class(my_date)
[1] "Date"
> date <- '2020.03.29'
> my_date <- as.Date(date,"%Y.%m.%d");my_date
[1] "2020-03-29"
> class(my_date)
[1] "Date"
不论是什么样格式的字符串,只要能找到对应的format格式就能转换成功。
三、指定输出日期的格式
上面我们使用的as.Date()输出的日期形式都是‘2020-03-29’形式的,如果我们想更改输出日期的格式,可以用函数format(x,format=‘output_format’)
其中x是日期数据,就是例如‘2020-03-29’这样格式的。这个函数可以输出指定格式的日期值,并且可以提取日期中的某些部分,因为日期变量里还包含了好多的信息。
> date <- '2020-03-29'
> my_date <- as.Date(date);my_date
[1] "2020-03-29"
> format(my_date,format="%Y.%m.%d")
[1] "2020.03.29"
> format(my_date,format='%a')
[1] "周日"
> format(my_date,format='%A')
[1] "星期日"
> format(my_date,format='%B %Y')
[1] "三月 2020"
> months(my_date)#转化为月份
[1] "三月"
> weekdays(my_date)#转化为星期
[1] "星期日"
从中可以看出format可以返回特定格式的日期数据,同时也可以返回指定格式的值,这些值的格式见附录。或者直接用months()和weekdays()函数返回月份和星期几等信息。
四、生成日期数据
有的时候会需要自己创建日期值,如果是按照一三五七八十腊来算31天还有闰年闰月,写出来的代码就够人烦的了,所以很有必要认识几个函数能够直接生成连续的时间序列。
使用seq(from=as.Date(‘xxxx-xx-xx’), to=as.Date(‘xxxx-xx-xx’), by=‘1 day’)函数。
其中by参数可以是‘1 day’ ,‘1 year’,'1 week’等。
> seq(from=as.Date('2016-01-01'), to=as.Date('2020-03-29'), by='1 year')
[1] "2016-01-01" "2017-01-01" "2018-01-01" "2019-01-01"
[5] "2020-01-01"
这个函数直接生成时间值,还有一个函数ts(),他生成的不是时间值,而是生成时间序列,至于时间序列是什么东西,能怎么用,该怎么用,以后接触到了再聊,现在只简单介绍这个函数:
> values <- c(1:50)
> ts(values,start = c(2016,1),end = c(2020,3),frequency = 1)#按年生成
Time Series:
Start = 2016
End = 2022
Frequency = 1
[1] 1 2 3 4 5 6 7
> ts(values,start = c(2016,1),end = c(2020,3),frequency = 4)#按季度生成
Qtr1 Qtr2 Qtr3 Qtr4
2016 1 2 3 4
2017 5 6 7 8
2018 9 10 11 12
2019 13 14 15 16
2020 17 18 19
> ts(values,start = c(2016,1),end = c(2020,3),frequency = 12)#按月生成
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2016 1 2 3 4 5 6 7 8 9 10 11 12
2017 13 14 15 16 17 18 19 20 21 22 23 24
2018 25 26 27 28 29 30 31 32 33 34 35 36
2019 37 38 39 40 41 42 43 44 45 46 47 48
2020 49 50 1
五、字符串时间变量转换成日期时间变量
上面的内容都是日期类型的变量,就是年月日,但有时候我们也会使用精确到时分秒的变量,这个时候和上述的日期差不多,就是多了时分秒和一个时区。
需要用到的转换函数是as.POSIXct()和as.POSIXlt(),这两个函数的区别,仅仅找到一点,说是前者为“整数(秒数)”存储,后者为“字符串式”存储,但是我用的时候没找到区别,而且在查找帮助文档时,直接给出的帮助是as.POSIX*。
其基本格式都包括三个参数as.POSIXct(x,tz=’’,format=’’),另一个也一样。其中x是要转换的日期时间字符串,tz是time zone时区一般‘utc’,format是字符串的格式,也可在附表中找到。
> t <- '2020-03-29 11:15:47'
> as.POSIXlt(t,tz="","%Y-%m-%d %H:%M:%S")
[1] "2020-03-29 11:15:47 CST"
> as.POSIXct(t,tz="","%Y-%m-%d %H:%M:%S")
[1] "2020-03-29 11:15:47 CST"
返回值都一样,要说这两个函数的区别的话:
> unclass(as.POSIXlt("2020-03-29 10:00:00", "%Y-%m-%d %H:%M:%S", tz="UTC"))
$sec
[1] 0
$min
[1] 0
$hour
[1] 10
$mday
[1] 29
$mon
[1] 2
$year
[1] 120
$wday
[1] 0
$yday
[1] 88
$isdst
[1] 0
attr(,"tzone")
[1] "UTC"
> unclass(as.POSIXct("2020-03-29 10:00:00", "%Y-%m-%d %H:%M:%S", tz="UTC"))
[1] 1585476000
attr(,"tzone")
[1] "UTC"
unclass()函数是用来消除对象的类,类是面向对象编程语言的一种说法,等遇到了再细说。
另外,strptime()函数和as.POSIXlt()函数用法相同。
strptime("2020-03-29 10:00:00", "%Y-%m-%d %H:%M:%S", tz="UTC")
六、应用
已经转换好格式的日期时间变量,就可以直接进行像数值变量那种的相加减和比较大小了:
> t_c1 <- '2020-03-29 11:15:00'
> t_c2 <- '2020-03-29 11:15:47'
> t_t1 <- as.POSIXct(t_c1,tz="","%Y-%m-%d %H:%M:%S")
> t_t2 <- as.POSIXct(t_c2,tz="","%Y-%m-%d %H:%M:%S")
> t_t1 < t_t2
[1] TRUE
> a <- t_t2 - t_t1 + 1
> a == 48
[1] TRUE
> date_c1 <- '2020-03-28'
> date_c2 <- '2020-03-29'
> data_t1 <- as.Date(date_c1)
> data_t2 <- as.Date(date_c2)
> data_t1 < data_t2
[1] TRUE
> a <- data_t2 - data_t1 + 1
> a == 2
[1] TRUE
比较运算返回的逻辑值可用作数据框里的切片提取。
附录
日期时间格式
参数 | 含义 |
---|---|
%a | 当天为星期几,简称 |
%A | 当天为星期几,全称 |
%b | 月份为英文简称 |
%B | 月份为英文全称。其实和%b用起来有时候没差别 |
%c | 以“星期 月 日 时:分:秒 年"的格式输出 |
%C | 输出年份的前两位,比如2018输出20 |
%d | 输出日,01-31。比如2018-03-02输出02 |
%D | 以月/天/年的格式输出 |
%e | 输出日,1-31。比如2018-03-02输出2 |
%F | 等价于 %Y-%m-%d,输出日期 |
%g | 输出年的后两位,比如2006-01-08输出06 |
%G | 输出年份,比如2006-01-08输出2006 |
%h | 等价于%b |
%H | 小时,00-23 |
%I | 小时,01-12 |
%j | 一年的天数,001-366 |
%m | 月数,01-12 |
%M | 分钟数,00-59 |
%p | 只输出AM/PM,判断上午还是下午 |
%r | 以12小时制输出时间,并且输出AM/PM |
%R | 等价于%H:%M |
%S | 输出秒 |
%T | 输出等价于%H:%M:%S |
%u | 判断星期几,1-7,1代表星期一,也可以代表一周中的第几天 |
%U | 判断是今年第几周,00-53。星期天作为一周的第一天 |
%w | 星期几,取值为0-6,0代表星期日· |
%W | 判断是今年第几周,00-53。星期一作为一周的第一天 |
%x | 以 月/日/年格式输出时间 |
%X | 以 时/分/秒的格式输出时间 |
%y | 表示年份的后两位,0-68前两位用19补充,69-99前两位用20补充,比如02/27/92表示1992年 |
%Y | 表示年,取值0-9999 |
%z | 与UTC时间偏移 |
%Z | 输出时区简称 |