You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中计算排除非工作时间/周末后的客户工单处理时长

计算客户查询的有效工作时长(排除非工作时间)

需求回顾

针对包含客户ID、任务类型、时间戳的数据框,需为每个客户计算:

  • 第一条Task == "New"的时间,与最后一条Task == "Closed"的时间之间的有效工作分钟数
  • 工作时间规则:中欧时间(CET/CEST,自动处理夏令时)周一至周五8:00-17:00,排除非工作时段、周末

解决方案步骤

我们可以用dplyr做数据分组提取,lubridate处理时区转换,bizdays包快速计算工作时长,代码如下:

1. 加载依赖包

library(dplyr)
library(lubridate)
library(bizdays)

2. 提取关键时间点

按客户分组,提取每个客户的首次"New"时间和末次"Closed"时间:

customer_time_points <- df1 %>%
  group_by(ID) %>%
  summarise(
    new_utc = first(Date_time[Task == "New"]),
    last_closed_utc = last(Date_time[Task == "Closed"]),
    .groups = "drop"
  )

3. 时区转换为中欧时间

原数据是UTC时区,转换为Europe/Berlin时区(自动识别CET/CEST夏令时切换):

customer_time_points <- customer_time_points %>%
  mutate(
    new_cet = with_tz(new_utc, tzone = "Europe/Berlin"),
    last_closed_cet = with_tz(last_closed_utc, tzone = "Europe/Berlin")
  )

4. 定义工作时间规则

创建符合要求的工作日历,指定周末、工作时段:

# 创建工作日历:排除周六周日,工作时间8:00-17:00
cet_work_calendar <- create.calendar(
  name = "CET_Workdays",
  weekdays = c("saturday", "sunday"),
  workhours = workhours(from = "08:00", to = "17:00"),
  start.date = min(customer_time_points$new_cet),
  end.date = max(customer_time_points$last_closed_cet)
)

5. 计算有效工作分钟数

bizhours函数直接返回两个时间之间的工作小时数,乘以60转换为分钟:

customer_work_duration <- customer_time_points %>%
  mutate(
    work_minutes = bizhours(new_cet, last_closed_cet, cet_work_calendar) * 60
  )

结果示例

运行后customer_work_duration会包含每个客户的ID、关键时间点,以及最终的有效工作分钟数。比如示例中的customer2,会自动忽略4月到8月之间的非工作时段、周末,只计算周一至周五8-17点的时长。

替代方案(无bizdays包)

如果不想额外安装包,可以通过循环遍历每一天,判断是否为工作日,再计算当天的有效工作时长总和,代码示例如下(仅作参考,推荐用bizdays更高效):

calc_work_minutes <- function(start, end) {
  total_min <- 0
  current_day <- floor_date(start, "day")
  end_day <- floor_date(end, "day")
  
  while(current_day <= end_day) {
    # 判断是否为工作日(周一至周五)
    if(wday(current_day, week_start = 1) %in% 1:5) {
      # 当天工作时段的起止
      work_start <- current_day + hours(8)
      work_end <- current_day + hours(17)
      
      # 计算当天的有效时间段
      period_start <- max(start, work_start)
      period_end <- min(end, work_end)
      
      if(period_start < period_end) {
        total_min <- total_min + as.duration(period_end - period_start)/dminutes(1)
      }
    }
    current_day <- current_day + days(1)
  }
  return(total_min)
}

# 应用函数
customer_work_duration <- customer_time_points %>%
  rowwise() %>%
  mutate(work_minutes = calc_work_minutes(new_cet, last_closed_cet)) %>%
  ungroup()

内容的提问来源于stack exchange,提问作者Lazline Brown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 21:07:07