5.2 lubridate
lubridate
包是对Base R中POSIXct类的封装。所以无论从函数名还是功能等方面,lubridate包中的函数功能更加清晰明了。从获取当前日期、时间,解析时间日期中的年、月、日、星期,计算年月间隔天数等常用的时间日期功能,lubridate
包中都有相对应的功能函数。
在处理日期时间数据时,我常用lubridate
解决,本节将介绍包中部分函数用法。
5.2.1 安装包
install.packages("tidyverse")
# 仅仅只安装lubridate
install.packages('lubridate')
# 开发版
::install_github("tidyverse/lubridate") devtools
# 加载包
library(lubridate,warn.conflicts = FALSE)
5.2.2 当前时间日期
now
函数
now()函数是当前时间,只有一个参数tzone,默认为系统的timezone。
now()
#> [1] "2021-06-23 18:15:26 CST"
# now(tzone = 'Asia/Shanghai')
# base R
::Sys.time()
base#> [1] "2021-06-23 18:15:26 CST"
today
函数
时区同样默认为系统的timezone。
today(tzone = 'Asia/Shanghai')
#> [1] "2021-06-23"
#base R
::Sys.Date()
base#> [1] "2021-06-23"
5.2.3 构造日期时间
使用数值直接创建日期时间。
函数make_date()
和make_datetime()
函数默认时区10为“UTC”。
make_date(year = 2021, month = 5, day = 1, tz = "Asia/Shanghai")
make_datetime(
year = 1970L,
month = 1L,
day = 1L,
hour = 0L,
min = 0L,
sec = 0,
tz = "Asia/Shanghai"
)
- make_datetime
make_datetime(
year = year(today()),
month = month(today()),
day = day(today()),
hour = hour(now()),
min = minute(now()),
sec = second(now()),
tz = "asia/shanghai"
)#> [1] "2021-06-23 18:15:26 CST"
- as_datetime
as_datetime('2020-01-09 09:15:40',tz='asia/shanghai')
#> [1] "2020-01-09 09:15:40 CST"
as_date('2020-01-09') #ymd格式
#> [1] "2020-01-09"
# same above
#as_date('2020/01/09')
#as_date('20200109')
5.2.4 解析日期时间
数据源中日期列可能是各种的字符形式,需要转换为时间格式方便进行日期计算。商业环境中的数据是混乱的,生产库可能是不同的数据库系统,导致时间日期格式混乱,如果公司没有统一的用户层数据源,我们就需要自己清洗数据,将不同形式的日期格式转化为标准格式。
- 解析日期
# 整数和字符都可以
ymd(20200604)
#> [1] "2020-06-04"
ymd('20200604')
#> [1] "2020-06-04"
mdy(06042020)
#> [1] "2020-06-04"
dmy(04062020)
#> [1] "2020-06-04"
- 解析时间
ymd_hm("20100201 07-01", "20100201 07-1", "20100201 7-01")
#> [1] "2010-02-01 07:01:00 UTC" "2010-02-01 07:01:00 UTC"
#> [3] "2010-02-01 07:01:00 UTC"
ymd_hms("2013-01-24 19:39:07")
#> [1] "2013-01-24 19:39:07 UTC"
当需要处理unix时间戳时应.POSIXct()函数转化.
.POSIXct(1591709615)
#> [1] "2020-06-09 21:33:35 CST"
ymd_hms(.POSIXct(1591709615))
#> [1] "2020-06-09 21:33:35 UTC"
在使用unix时间戳转换时一定注意R环境和数据系统环境时区是否一直。
曾经我在使用阿里云的RDS数据库时没注意时区差异,导致我清洗出来的时间数据错误。
ymd_hms(.POSIXct(1591709615),tz = 'Asia/Shanghai')
#> [1] "2020-06-09 21:33:35 CST"
5.2.5 提取日期时间成分
#获取年
year(now())
#> [1] 2021
#获取月
month(now())
#> [1] 6
# 当前时间所在年份天数
yday(now())
#> [1] 174
# 当前时间所在月天数
mday(now())
#> [1] 23
# 周几
wday(now(),label = TRUE,week_start = 1)
#> [1] 周三
#> Levels: 周一 < 周二 < 周三 < 周四 < 周五 < 周六 < 周日
# 所在时刻
hour(now())
#> [1] 18
# 所在时刻
minute(now())
#> [1] 15
# 所在时刻
second(now())
#> [1] 27
5.2.6 处理时区
数据时区与本地R环境一致时,数据中的时区没必要处理,但是当数据是跨时区的或者不同生产系统的时区不一致,我们需要将数据时区处理一致。
1.时区查看
时区和所用系统设置相关
Sys.timezone()
#> [1] "Asia/Taipei"
# windows 系统默认的时区 中国台北
# linux 上是"Asia/Shanghai"
# mac 上是"Asia/Shanghai"
这里还有一个奇怪的点,Windows系统下时区设置为(UTC+08:00)北京,重庆,香港特别行政区,乌鲁木齐
,但是R返回的时区是Asia/Taipei
。
now()
#> [1] "2021-06-23 18:15:27 CST"
now()
输出结果中,CST是时区概念。
CST可以同时代表四个时间
- Central Standard Time (USA) UT-6:00
- Central Standard Time (Australia) UT+9:30
- China Standard Time UT+8:00
- Cuba Standard Time UT-4:00
2.时区调整
lubridate中用with_tz()
,force_tz()
处理时区问题
<- ymd_hms("2020-12-13 15:30:30")
time
time#> [1] "2020-12-13 15:30:30 UTC"
# Changes printing
with_tz(time, "Asia/Shanghai")
#> [1] "2020-12-13 23:30:30 CST"
# Changes time
force_tz(time, "Asia/Shanghai")
#> [1] "2020-12-13 15:30:30 CST"
- 时区差异
从下面三个时间观察时区,CST时间:中央标准时间;UTC时间:世界协调时间(UTC)是世界上不同国家用来调节时钟和时间的主要时间标准。
如:当UTC时间为0点时,中国CST时间为8点,因为零时区和中国北京时区相差8个时区.
::now() # now函数调用系统默认时区
lubridate#> [1] "2021-06-23 18:15:27 CST"
as_datetime(now()) #as_datetime默认是UTC
#> [1] "2021-06-23 10:15:27 UTC"
as_datetime(now(),tz = 'asia/shanghai')
#> [1] "2021-06-23 18:15:27 CST"
5.2.7 时间间隔
lubridate
中将时间间隔保存为interveal
类对象。
<- ymd_hms("2020-12-04 12:00:00", tz = "asia/shanghai")
arrive
arrive#> [1] "2020-12-04 12:00:00 CST"
<- ymd_hms("2020-12-10 14:00:00", tz = "asia/shanghai")
leave
leave#> [1] "2020-12-10 14:00:00 CST"
<- interval(arrive, leave)
res # same above
<- arrive %--% leave res
查看类
class(res)
#> [1] "Interval"
#> attr(,"package")
#> [1] "lubridate"
两个时间间隔是否重复
<- interval(ymd(20201020, tz = "asia/shanghai"), ymd(20201231, tz = "asia/shanghai"))
jsm
jsm#> [1] 2020-10-20 CST--2020-12-31 CST
int_overlaps(jsm, res)
#> [1] TRUE
更多详细用法?interveal
interval(start = NULL, end = NULL, tzone = tz(start))
%--% end
start
is.interval(x)
int_start(int)
int_start(int) <- value
int_end(int)
int_end(int) <- value
int_length(int)
int_flip(int)
int_shift(int, by)
int_overlaps(int1, int2)
int_standardize(int)
int_aligns(int1, int2)
int_diff(times)
5.2.8 时间日期计算
时间日期计算以number line
为依据计算。原文是Because the timeline is not as reliable as the number line
,我没理解这句话。
minutes(2)
#> [1] "2M 0S"
dminutes(2)
#> [1] "120s (~2 minutes)"
dhours(2)
#> [1] "7200s (~2 hours)"
注意闰年时计算年份的差异
leap_year(2019)
#> [1] FALSE
ymd(20190101) + dyears(1)
#> [1] "2020-01-01 06:00:00 UTC"
ymd(20190101) + years(1)
#> [1] "2020-01-01"
leap_year(2020)
#> [1] TRUE
ymd(20200101) + dyears(1) # 注意查看闰年时的差异
#> [1] "2020-12-31 06:00:00 UTC"
ymd(20200101) + years(1)
#> [1] "2021-01-01"
lubridate
中的函数都已向量化
<- ymd_hms("2020-12-01 09:00:00", tz = "asia/shanghai")
meeting <- meeting + weeks(0:5)
meeting %within% jsm
meeting #> [1] TRUE TRUE TRUE TRUE TRUE FALSE
除法计算
/ ddays(1)
res #> [1] 6.08
/ dminutes(1)
res #> [1] 8760
%/% months(1)
res #> [1] 0
%% months(1)
res #> [1] 2020-12-04 12:00:00 CST--2020-12-10 14:00:00 CST
as.period
用法
as.period(res %% months(1))
#> [1] "6d 2H 0M 0S"
对于日期而言,因为月天数、年天数不一致,导致不能直接加减天数,如下:
<- ymd("2020-01-31")
jan31 + months(0:11)
jan31 #> [1] "2020-01-31" NA "2020-03-31" NA "2020-05-31"
#> [6] NA "2020-07-31" "2020-08-31" NA "2020-10-31"
#> [11] NA "2020-12-31"
lubridate
中不存在的日期返回NA
解决方案是:%m+%
或%m-%
%m+% months(0:11)
jan31 #> [1] "2020-01-31" "2020-02-29" "2020-03-31" "2020-04-30" "2020-05-31"
#> [6] "2020-06-30" "2020-07-31" "2020-08-31" "2020-09-30" "2020-10-31"
#> [11] "2020-11-30" "2020-12-31"
%m-% months(0:11)
jan31 #> [1] "2020-01-31" "2019-12-31" "2019-11-30" "2019-10-31" "2019-09-30"
#> [6] "2019-08-31" "2019-07-31" "2019-06-30" "2019-05-31" "2019-04-30"
#> [11] "2019-03-31" "2019-02-28"
lubridate包中大部分函数默认时区为“UTC”,在涉及时间处理时需要注意时区。↩︎