r - 计算 R 中 2 个时间戳之间的秒数,不包括周末
问题描述
如果我有一个包含 2 列 YMD HMS 的数据框,我如何计算两个不包括周末的时间差(以秒为单位)?
col 2 - col 1 = 以秒为单位的时间;需要排除周末秒
Dates1 <- as.POSIXct("2011-01-30 12:00:00") + rep(0, 10)
Dates2 <- as.POSIXct("2011-02-04") + seq(0, 9, 1)
df <- data.frame(Dates1 = Dates1, Dates2 = Dates2)
我需要它给我 (388800 - 43200) = 345600; 我减去 43200 的原因是因为这是从中午到午夜的周日周末时间,时钟停止。
解决方案
这是使用lubridate
和其他tidyverse
软件包的解决方案。好处lubridate
是它可以无缝地处理许多奇怪的时间问题,从时区到闰年,再到夏令时的切换。(如果您关心这些,只需确保您的数据有时区。)
我在这里使用的概念是intervals
in lubridate(使用%--%
运算符创建)。间隔实际上就是它听起来的样子:一个非常有用的类,它基本上有一个开始日期时间和一个结束日期时间。
我生成了两个数据集:一个用于您的开始和结束时间,另一个用于周末开始和结束时间,每个都有自己的间隔列。在周末数据集中,请注意,开始和结束时间被任意设置为一年中的周六和周日。您应该使用对您有意义的值来设置它们,或者从数据中找出一种方法来设置它。:)
从那里,我们将使用 lubridate 的函数找到您的间隔和周末间隔之间的重叠intersect
,因此稍后我们可以计算相关的周末秒数并将它们减去。
但首先我们使用crossing
fromtidyr
来确保我们在weekends
数据集中针对每个周末检查您的每个间隔。它只是运行两个数据集的笛卡尔积(参见这个 SO 答案)。
最后,我们使用int_length
计算周末秒数,将每个间隔的周末秒数相加,计算每个间隔的总秒数,然后从总秒数中减去周末秒数。瞧!我们有总秒数,不包括周末。
这个解决方案的另一个好处是它非常灵活。我已将周末定义为周六 0:00 至周一 0:00……但您可以删除周五晚上、周一凌晨,无论您喜欢什么并满足您的分析要求。
library(dplyr)
library(tidyr)
library(tibble)
library(lubridate) # makes dates and times easier!
test <- tribble(
~start_time, ~end_time,
"2019-05-22 12:35:42", "2019-05-23 12:35:42", # same week no weekends
"2019-05-22 12:35:42", "2019-05-26 12:35:42", # ends during weekend
"2019-05-22 12:35:42", "2019-05-28 12:35:42", # next week full weekend
"2019-05-26 12:35:42", "2019-05-29 12:35:42", # starts during weekend
"2019-05-22 12:35:42", "2019-06-05 12:35:42" # two weeks two weekends
) %>%
mutate(
id = row_number(),
timespan = start_time %--% end_time
)
weekend_beginnings <- ymd_hms("2019-05-18 00:00:00") + weeks(0:51)
weekend_endings <- ymd_hms("2019-05-20 00:00:00") + weeks(0:51)
weekends <- weekend_beginnings %--% weekend_endings
final_answer <- crossing(test, weekends) %>%
mutate(
weekend_intersection = intersect(timespan, weekends),
weekend_seconds = int_length(weekend_intersection)
) %>%
group_by(id, start_time, end_time, timespan) %>%
summarise(
weekend_seconds = sum(weekend_seconds, na.rm = TRUE)
) %>%
mutate(
total_seconds = int_length(timespan),
weekday_seconds = total_seconds - weekend_seconds
)
glimpse(final_answer)