计算R中两个时间戳之间的秒数(不包括周末)

时间:2019-05-22 18:25:41

标签: r timestamp difftime weekend

如果我有一个包含两列的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的原因是因为那是从中午到午夜的星期日周末时间。

2 个答案:

答案 0 :(得分:2)

这是使用lubridate和其他tidyverse软件包的解决方案。关于lubridate的好处是,它可以无缝地处理许多随时间变化的怪异问题,从时区到leap年,再到夏令时。 (如果您关心这些,只需确保您的数据具有时区即可。)

我在这里使用的概念是lubridate中的intervals(使用%--%运算符创建)。间隔实际上就是它的听起来:一个非常有用的类,基本上具有开始日期时间和结束日期时间。

我生成两个数据集:一个用于您的开始和结束时间,另一个用于 weekend 的开始和结束时间,每个数据集都有自己的间隔列。在周末数据集中,请注意,开始时间和结束时间可任意设置为每年的星期六和星期日。您应该使用对您有意义的值进行设置,或者找出一种从数据中进行设置的方法。 :)

从那里,我们将使用lubridate的intersect函数查找您的间隔和周末间隔之间的重叠,因此稍后我们可以计算相关的周末秒数并将其减去。

但是首先我们使用crossing中的tidyr,以确保我们在weekends数据集中对照每个周末检查每个间隔。它只是运行两个数据集的笛卡尔积(请参见this SO answer)。

最后,我们使用int_length来计算周末秒数,总结每个间隔的周末秒数,计算每个间隔的总秒数,然后从中减去 weekend 总计秒。瞧!我们总共有秒,不包括周末。

此解决方案的另一个好处是它非常灵活。我将周末定义为周六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)

答案 1 :(得分:0)

这是适用于矢量的切口:

#' Seconds difference without weekends
#'
#' @param a, b POSIXt
#' @param weekends character, day of the week (see [base::strptime()]
#'   for the "%w" argument), "0" is Sunday, "6" is Saturday; defaults
#'   to `c("0","6")`: Saturday and Sunday
#' @return
#' @md
secs_no_weekend <- function(a, b, weekends = c("0", "6")) {
  mapply(function(a0, b0) {
    astart <- as.POSIXct(format(a0, "%Y-%m-%d 00:00:00"))
    aend <- as.POSIXct(format(a0, "%Y-%m-%d 24:00:00"))
    bstart <- as.POSIXct(format(b0, "%Y-%m-%d 00:00:00"))
    days <- seq.POSIXt(astart, bstart, by = "day")
    ndays <- length(days)
    if (ndays == 1) {
      d <- b0 - a0
    } else {
      d <- rep(60 * 60 * 24, ndays)
      d[1] <- `units<-`(aend - a0, "secs")
      d[ndays] <- `units<-`(b0 - bstart, "secs")
      wkend <- format(days, "%w")
      d[ wkend %in% weekends ] <- 0
    }
    as.numeric(sum(d))
  }, a, b)
}