5.2 lubridate

lubridate包是对Base R中POSIXct类的封装。所以无论从函数名还是功能等方面,lubridate包中的函数功能更加清晰明了。从获取当前日期、时间,解析时间日期中的年、月、日、星期,计算年月间隔天数等常用的时间日期功能,lubridate包中都有相对应的功能函数。

在处理日期时间数据时,我常用lubridate解决,本节将介绍包中部分函数用法。

5.2.1 安装包

install.packages("tidyverse")
# 仅仅只安装lubridate
install.packages('lubridate')
# 开发版
devtools::install_github("tidyverse/lubridate")
# 加载包
library(lubridate,warn.conflicts = FALSE)

5.2.2 当前时间日期

  • now函数

now()函数是当前时间,只有一个参数tzone,默认为系统的timezone。

now()
# now(tzone = 'Asia/Shanghai')
# base R
base::Sys.time()
  • today函数

时区同样默认为系统的timezone。

today(tzone = 'Asia/Shanghai')
#base R
base::Sys.Date()

5.2.3 构造日期时间

使用数值直接创建日期时间。

函数make_date()make_datetime()函数默认时区8为“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"
)
  • as_datetime
as_datetime('2020-01-09 09:15:40',tz='asia/shanghai')
as_date('2020-01-09') #ymd格式
# same above
#as_date('2020/01/09')
#as_date('20200109')

5.2.4 解析日期时间

数据源中日期列可能是各种的字符形式,需要转换为时间格式方便进行日期计算。商业环境中的数据是混乱的,生产库可能是不同的数据库系统,导致时间日期格式混乱,如果公司没有统一的用户层数据源,我们就需要自己清洗数据,将不同形式的日期格式转化为标准格式。

  • 解析日期
# 整数和字符都可以
ymd(20200604) 
ymd('20200604')
mdy(06042020)
dmy(04062020)
  • 解析时间
ymd_hm("20100201 07-01", "20100201 07-1", "20100201 7-01")
ymd_hms("2013-01-24 19:39:07")

当需要处理unix时间戳时应.POSIXct()函数转化.

unix在线转换

.POSIXct(1591709615)
ymd_hms(.POSIXct(1591709615))

在使用unix时间戳转换时一定注意R环境和数据系统环境时区是否一直。

曾经我在使用阿里云的RDS数据库时没注意时区差异,导致我清洗出来的时间数据错误。

ymd_hms(.POSIXct(1591709615),tz = 'Asia/Shanghai')

5.2.5 提取日期时间成分

#获取年
year(now())  
#获取月
month(now())
# 当前时间所在年份天数
yday(now())
# 当前时间所在月天数
mday(now())
# 周几
wday(now(),label = TRUE,week_start = 1)
# 所在时刻
hour(now())
# 所在时刻
minute(now())
# 所在时刻
second(now())

5.2.6 处理时区

数据时区与本地R环境一致时,数据中的时区没必要处理,但是当数据是跨时区的或者不同生产系统的时区不一致,我们需要将数据时区处理一致。

1.时区查看

时区和所用系统设置相关

Sys.timezone()
# windows 系统默认的时区 中国台北
# linux 上是"Asia/Shanghai"
# mac 上是"Asia/Shanghai"

这里还有一个奇怪的点,Windows系统下时区设置为(UTC+08:00)北京,重庆,香港特别行政区,乌鲁木齐,但是R返回的时区是Asia/Taipei

now()

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()处理时区问题

time <- ymd_hms("2020-12-13 15:30:30")
time

# Changes printing
with_tz(time, "Asia/Shanghai")
# Changes time
force_tz(time, "Asia/Shanghai")
  1. 时区差异

从下面三个时间观察时区,CST时间:中央标准时间;UTC时间:世界协调时间(UTC)是世界上不同国家用来调节时钟和时间的主要时间标准。

如:当UTC时间为0点时,中国CST时间为8点,因为零时区和中国北京时区相差8个时区.

lubridate::now() # now函数调用系统默认时区
as_datetime(now()) #as_datetime默认是UTC
as_datetime(now(),tz = 'asia/shanghai')

5.2.7 时间间隔

lubridate中将时间间隔保存为interveal类对象。

arrive <- ymd_hms("2020-12-04 12:00:00", tz = "asia/shanghai")
arrive

leave <- ymd_hms("2020-12-10 14:00:00", tz = "asia/shanghai")
leave

res <- interval(arrive, leave) 
# same above
res <- arrive %--% leave

查看类

class(res)

两个时间间隔是否重复

jsm <- interval(ymd(20201020, tz = "asia/shanghai"), ymd(20201231, tz = "asia/shanghai"))
jsm
int_overlaps(jsm, res)

更多详细用法?interveal

interval(start = NULL, end = NULL, tzone = tz(start))

start %--% end

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)
dminutes(2)
dhours(2)

注意闰年时计算年份的差异

leap_year(2019)
ymd(20190101) + dyears(1)
ymd(20190101) + years(1)

leap_year(2020)
ymd(20200101) + dyears(1)  # 注意查看闰年时的差异
ymd(20200101) + years(1)

lubridate中的函数都已向量化

meeting <- ymd_hms("2020-12-01 09:00:00", tz = "asia/shanghai")
meeting <- meeting + weeks(0:5)
meeting %within% jsm

除法计算

res / ddays(1)
res / dminutes(1)


res %/% months(1)
res %% months(1)

as.period用法

as.period(res %% months(1))

对于日期而言,因为月天数、年天数不一致,导致不能直接加减天数,如下:

jan31 <- ymd("2020-01-31")
jan31 + months(0:11)

lubridate中不存在的日期返回NA

解决方案是:%m+%%m-%

jan31 %m+% months(0:11)
jan31 %m-% months(0:11)

  1. lubridate包中大部分函数默认时区为“UTC”,在涉及时间处理时需要注意时区。↩︎