如何在两个不同时间值之间提取营业时间

时间:2015-12-03 14:07:02

标签: r datetime time

为了评估服务台处理的故障单,我想知道故障单有多少工作时间。我可以轻松减去时间并获得总小时数。但是,应该计算的唯一时间是08:30至18:00。

例如:如果在11/23/2015 10:20创建了一个故障单,并在11/24/2015 17:20上完成了故障单,那么31'正常'几个小时过去了。我只对已经过的营业时间(8:30到18:00)感兴趣;在这种情况下16 hours and 30 minutes

3 个答案:

答案 0 :(得分:3)

library(lubridate)

   tickets <- data.frame(open = as.POSIXct(strptime(df$open, "%m/%d/%Y %H:%M")), 
                      closed = as.POSIXct(strptime(df$closed, "%m/%d/%Y %H:%M"))


excludeDayCount <- Vectorize(function(open, close) {

   # Check if the ticket was open and closed on the same day
   if (identical(as.Date(open), as.Date(close))) return (0)

   # All the holidays to be excluded need to be put here
   holidays <- as.POSIXct(strptime(c("12/24/2015", "12/25/2015"), 
                                  "%m/%d/%Y"))

   # Dates between open and close  
   day_seq <- floor_date(seq(open + days(1), close, by = "days"), "day")

   # Count holidays / weekend days
   return(sum(day_seq %in% holidays | wday(day_seq) %in% c(1,7)))

})

bizHrDiff <- function(open, close) {

    # Hours from the end of one work day until the start of another
    hours_between_days <- dhours(6) + dhours(8.5)

    # Number of days to exclude
    excl_days <- excludeDayCount(open, close)  
    # Number of days in include
    reg_days <- as.integer(as.Date(close) - as.Date(open)) - excl_days 



    # Total duration between dates
      span <- as.duration(interval(open, close))
      # Remove the number of holidays and weekends
      span <- span - ddays(excl_days)
      # Remove out of office hours
      span <- span - (reg_days * hours_between_days)




     # Return in hours
      return(time_length(span, unit = "hour"))


}

bizHrDiff(tickets$open, tickets$closed)

答案 1 :(得分:2)

I ran into similar needs recently and created a package based on @mvan 's script above. https://github.com/janzzon/difftimeOffice
Input needs to be as POSIX time.
Output is in seconds.
Specify helpdesk open hours by argument working_hours = c(8.5, 18).
Additional holliday days is not implemented (yet).

答案 2 :(得分:2)

我已经尝试过@mvan和@Steffan Jansson的解决方案。不幸的是,他们都不能满足我的需求。第一个返回不正确的信息。后者是为了减缓我的要求,并没有考虑夏令时。

我创建了一个更快的功能,并将夏令时考虑在内。您可以指定营业时间和假期。

<强>用法

该函数接受5个参数。其中3个是可选的。

  1. 开始时间戳(POSIXct)
  2. 结束时间戳(POSIXct)
  3. 营业日的开始时间(字符串:&#39; 00:00&#39;至&#39; 24:00&#39;)
  4. 营业日的结束时间(字符串:&#39; 00:00&#39;至&#39; 24:00&#39;)
  5. 假期列表(日期列表(as.Date))
  6. 示例:

    start <- as.POSIXct('2014-09-27 10:12:37', tz = 'Europe/Amsterdam')
    end <- as.POSIXct('2016-12-10 20:04:18', tz = 'Europe/Amsterdam')
    
    biz_hrs(start, end, '10:00', '17:00')
    

    您也可以在dataframe列上运行它。确保正确格式化每个值。如果结束值早于起始值,则该函数返回NA。要更改该编辑行6

    <强>代码

    library(lubridate)
    
    
    biz_hrs <- Vectorize(function(start, end, starting_time = '9:00', ending_time = '17:00', holidays = NULL){
    
    
          if(end < start){
    
            return(NA)
    
          } else {
    
            start_datetime <- as.POSIXct(paste0(substr(start,1,11), starting_time, ':00'))
            end_datetime <- as.POSIXct(paste0(substr(end,1,11), ending_time, ':00'))
    
            if(as.Date(start) == as.Date(end) & !as.Date(start) %in% holidays & !format(as.Date(start), "%u") %in% c(6,7)){ #if starting time stamp is on same day as ending time stamp and if day is not a holiday or weekend
    
              if(start > start_datetime & end < end_datetime){ #if starting time stamp is later than start business hour and ending time stamp is earlier then ending business hour.
                return(as.numeric(difftime(end, start), units = 'hours'))
              } else if(start > start_datetime & end > end_datetime & start < end_datetime){ #if starting time stamp is later than end business hour and ending time stamp is earlier then ending business hour.
                return(as.numeric(difftime(as.POSIXct(paste0(substr(start,1,11), ending_time, ':00')), start), units = 'hours'))
              } else if(start < start_datetime & end < end_datetime & end > start_datetime){ #if starting time stamp is earlier than end business hour and ending time stamp is later than starting business hour.
                return(as.numeric(difftime(end, start_datetime), units = 'hours'))
              } else if(start > end_datetime & end > end_datetime){ #if starting time stamp is later than end business hour and ending time stamp is later than ending business hour.
                return(0)
              } else if(start < start_datetime & end < start_datetime){ #if starting time stamp is earlier than start business hour and ending time stamp is earlier than starting business hour.
                return(0)
              } else {
                return(as.numeric(difftime(end_datetime, start_datetime), units = 'hours'))
              }
    
            } else { #if starting time stamp and ending time stamp occured on a different day.
    
              business_hrs <- as.numeric(difftime(as.POSIXct(paste0('2017-01-01', ending_time, ':00')),
                                                  as.POSIXct(paste0('2017-01-01', starting_time, ':00')) #calculate business hours range by specified parameters
              ), units = 'hours')
    
              start_day_hrs <- ifelse(start < as.POSIXct(paste0(substr(start,1,11), ending_time, ':00')) & !as.Date(start) %in% holidays & !format(as.Date(start), "%u") %in% c(6,7), #if start time stamp is earlier than specified ending time
                                      as.numeric(difftime(as.POSIXct(paste0(substr(start,1,11), ending_time, ':00')), start), units = 'hours'), #calculate time between time stamp and specified ending time
                                      0 #else set zero
              ) #calculate amount of time on starting day
              start_day_hrs <- pmin(start_day_hrs, business_hrs) #cap the maximum amount of hours dertermined by the specified business hours
              start_day_hrs
              end_day_hrs <- ifelse(end > as.POSIXct(paste0(substr(end,1,11), starting_time, ':00')) & !as.Date(end) %in% holidays & !format(as.Date(end), "%u") %in% c(6,7), #if end time stamp is later than specified starting time
                                    as.numeric(difftime(end, as.POSIXct(paste0(substr(end,1,11), starting_time, ':00'))), units = 'hours'), #calculate time between time stamp and specified starting time
                                    0) #calculate amount of time on ending day
              end_day_hrs <- pmin(end_day_hrs, business_hrs) #cap the maximum amount of hours dertermined by the specified business hours
              days_between <- seq(as.Date(start), as.Date(end), by = 1) #create a vector of dates (from and up to including) the starting time stamp and ending time stamp
              business_days <- days_between[!days_between %in% c(as.Date(start), as.Date(end)) & !days_between %in% holidays & !format(as.Date(days_between), "%u") %in% c(6,7)] #remove weekends and holidays from vector of dates
    
              return(as.numeric(((length(business_days) * business_hrs) + start_day_hrs + end_day_hrs))) #multiply the remaining number of days in the vector (business days) by the amount of business hours and add hours from the starting and end day. Return the result
    
            }
    
          }
    
    
        })