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

R语言:计算日期差值时排除周末及各州专属节假日

计算跨州专属节假日的工作日天数(R语言实现)

这个需求很常见呀,尤其是做跨州业务的数据分析时,得精准对应每个州的节假日来算工作日。我给你两种实用的解法,你可以根据自己的数据量和习惯选择:

先明确示例数据

先把你给出的示例数据补全整理好,方便后续测试:

# 节假日表:日期 + 对应州
holiday <- data.frame(
  h = as.Date(c("2016/05/3", "2016/05/3"), '%Y/%m/%d'),
  s = c('state1','state2'),
  stringsAsFactors = FALSE
)

# 待计算数据集:起始日期、结束日期、所属州
d <- data.frame(
  d1 = as.Date(c('2016/05/2','2016/05/2'), '%Y/%m/%d'),
  d2 = as.Date(c('2016/05/10','2016/05/10'), '%Y/%m/%d'),
  s = c('state1','state3'),
  stringsAsFactors = FALSE
)

方法一:用dplyr+lubridate逐行处理(直观易理解)

这种方法适合数据量不大的场景,步骤清晰,容易调试:

步骤说明

  1. 为每条记录生成起止日期之间的所有日期序列
  2. 过滤掉周末(仅保留周一到周五)
  3. 过滤掉当前州对应的专属节假日
  4. 统计剩余的工作日数量

代码实现

# 加载需要的包
library(dplyr)
library(lubridate)

# 逐行计算工作日天数
result <- d %>%
  rowwise() %>%
  # 生成当前记录的日期序列
  mutate(date_seq = list(seq(d1, d2, by = "day"))) %>%
  # 把日期序列展开成每行一个日期
  unnest(date_seq) %>%
  # 过滤周末:wday()返回1=周日,7=周六,保留2-6(周一到周五)
  filter(wday(date_seq) %in% 2:6) %>%
  # 左连接节假日表,匹配州和日期
  left_join(holiday, by = c("s" = "s", "date_seq" = "h")) %>%
  # 去掉匹配到的节假日(即h列不为空的行)
  filter(is.na(h)) %>%
  # 按原记录分组,统计剩余天数
  group_by(d1, d2, s) %>%
  summarise(work_days = n(), .groups = "drop")

# 查看结果
print(result)

输出结果

# A tibble: 2 × 4
  d1         d2         s      work_days
  <date>     <date>     <chr>      <int>
1 2016-05-02 2016-05-10 state1         6
2 2016-05-02 2016-05-10 state3         7
  • state1因为有5月3日的节假日,再加上两个周末,总共排除3天,剩余6个工作日
  • state3没有专属节假日,只排除两个周末,剩余7个工作日

方法二:用bizdays包创建专属日历(高效适合大数据)

如果你的数据集很大,生成所有日期序列会比较耗时,bizdays包专门处理工作日计算,效率更高:

步骤说明

  1. 创建基础工作日历(默认排除周末)
  2. 为每个有专属节假日的州创建自定义日历
  3. 注册这些日历,然后批量计算每条记录的工作日天数

代码实现

# 加载需要的包
library(bizdays)
library(dplyr)
library(purrr)

# 1. 创建基础日历:排除周末
cal_base <- create.calendar(
  name = "base_cal",
  weekdays = c("saturday", "sunday"),
  adjust.from = adjust.next,
  adjust.to = adjust.previous
)

# 2. 为每个州创建专属日历(添加对应州的节假日)
state_cals <- holiday %>%
  group_by(s) %>%
  summarise(holidays = list(h), .groups = "drop") %>%
  mutate(
    cal_name = paste0("cal_", s),
    # 基于基础日历,添加当前州的节假日
    calendar = map2(cal_name, holidays, ~create.calendar(
      name = .x,
      holidays = .y,
      weekdays = c("saturday", "sunday"),
      adjust.from = adjust.next,
      adjust.to = adjust.previous,
      base.calendar = "base_cal"
    ))
  )

# 3. 注册所有州的日历到bizdays中
walk(state_cals$calendar, register.calendar)

# 4. 批量计算每条记录的工作日天数
result <- d %>%
  mutate(
    # 匹配当前州对应的日历,没有专属节假日的用基础日历
    cal_name = ifelse(s %in% state_cals$s, paste0("cal_", s), "base_cal"),
    # 计算工作日天数
    work_days = bizdays(d1, d2, cal_name)
  ) %>%
  select(d1, d2, s, work_days)

# 查看结果
print(result)

这个方法的输出和方法一完全一致,但处理大数据时速度会快很多。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:36:18