有内置的lubridate::int_overlaps
函数,但它只返回一个逻辑值,而不是它们重叠的时间长度。幸运的是,intersection
函数有一个针对Interval
对象的方法。唯一的问题是如果没有重叠,它会返回长度为NA
而不是长度为0
。因此我们可以像这样封装它:
library(lubridate)
int_overlaps_numeric <- function (int1, int2) {
stopifnot(c(is.interval(int1), is.interval(int2)))
x <- intersect(int1, int2)@.Data
x[is.na(x)] <- 0
as.duration(x)
}
这个过程构建了重叠的时间间隔,然后提取其长度(以秒为单位)。如果长度是NA
,则将它更改为零,并返回。as.duration
只是为了美观打印。现在你只需要给它两个时间间隔即可:
int1 <- as.interval(5, Sys.time())
int2 <- as.interval(5, Sys.time()+3)
int_overlaps_numeric(int1, int2)
"1.99299597740173s"
所以你需要将所有的假期和班次都转换成区间。假设你想将这些重叠数据与 shift_time
数据帧中的其他数据关联起来,因此我们将使用 dplyr
在其中完成所有工作。但是,你需要将每个班次与所有假日向量进行比较,因此我们应该再添加另一个帮助函数(使用purrr::map
)。library(dplyr)
library(purrr)
check_shift_against_holidays <- function(shift, holidays) {
map(shift, ~sum(int_overlaps_numeric(.x, holidays))) %>%
unlist() %>%
as.duration()
}
该函数需要接收两个区间向量参数。对于第一个向量的每个元素,它会计算与第二个向量的所有元素的重叠数量,然后相加。然后将结果从列表转换回向量,并重新分类为duration
以便于美观打印。这里的注意点是,如果holidays
向量中有任何重叠,那么这些小时数将被重复计算。
holiday_intervals <- as.interval(days(1), ymd(public_holidays$date))
shift_time %>%
mutate(
shift = interval(ymd_hms(started_at), ymd_hms(ended_at)),
holiday_hours = check_shift_against_holidays(shift, holiday_intervals)
)
started_at ended_at shift holiday_hours
1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 2019-09-01 02:00:00 UTC--2019-09-01 11:30:00 UTC 0s
2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 2019-09-02 05:00:00 UTC--2019-09-02 19:00:00 UTC 0s
3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 2019-11-04 20:00:00 UTC--2019-11-05 04:00:00 UTC 14400s (~4 hours)
如果您真的反对创建任何新的中间变量:
shift_time %>%
mutate(
holiday_hours = check_shift_against_holidays(
ymd_hms(started_at) %--% ymd_hms(ended_at),
holiday_intervals
)
)
started_at ended_at holiday_hours
1 2019-09-01 02:00:00 AEST 2019-09-01 11:30:00 AEST 0s
2 2019-09-02 05:00:00 AEST 2019-09-02 19:00:00 AEST 0s
3 2019-11-04 20:00:00 AEDT 2019-11-05 04:00:00 AEDT 14400s (~4 hours)
lubridate::as.duration(lubridate::intersect(interval_1, interval_2))
来代替创建int_overlaps_numeric()
函数。 - Ashirwad