在R中创建非标准轮班重复日期时间序列的技术求助
非标准轮班日期时间序列生成与事件关联(R实现)
需求与问题
需要生成A、B、C三类非标准轮班的日期时间序列,用于关联其他表的事件数据。轮班规则:
- 以08:00为每日轮班起止点,模式为:3个交替的24小时出勤/1天休息周期,随后是96小时(4天)连续休息
- 2022年各轮班出勤日期:
- 结转A班:1日、3日
- A班:8日、10日、12日、17日、19日...
- B班:2日、4日、6日、11日、13日...
- C班:5日、7日、9日、14日、16日...
核心问题:
- 如何在一年内循环生成符合规则的轮班序列
- 轮班跨午夜,无需秒级表即可关联事件(受限于美国山地时间US MST,时区调整不可行)
解决方案
思路
- 摒弃秒级冗余数据:仅存储轮班的
start_time(当日08:00)和end_time(次日08:00),后续通过区间判断关联事件 - 模式化循环生成:将轮班的「3次出勤+4天休息」模式封装为函数,批量生成符合规则的出勤日期
完整代码
library(lubridate) # 设置时区为美国山地时间 tz <- "America/Denver" # ---------------------- # 处理结转A班(2022年1月1日、3日) # ---------------------- carryover_A_dates <- ymd(c("2022-01-01", "2022-01-03"), tz = tz) carryover_A <- data.frame( shift = "A", start_time = carryover_A_dates + hours(8), end_time = carryover_A_dates + days(1) + hours(8) ) # ---------------------- # 封装轮班序列生成函数 # ---------------------- generate_shift_intervals <- function(start_date_str, end_date_str, shift_name, tz) { start_date <- ymd(start_date_str, tz = tz) end_date <- ymd(end_date_str, tz = tz) current_date <- start_date shift_dates <- c(current_date) # 按规则生成后续出勤日期:出勤→休息→出勤→休息→出勤→4天休息,循环 while (current_date <= end_date) { # 第二个出勤日:间隔1天休息,+2天 current_date <- current_date + days(2) if (current_date <= end_date) shift_dates <- c(shift_dates, current_date) # 第三个出勤日:再间隔1天休息,+2天 current_date <- current_date + days(2) if (current_date <= end_date) shift_dates <- c(shift_dates, current_date) # 4天休息后回到出勤日:间隔5天(第三个出勤日到下一个出勤日差5天) current_date <- current_date + days(5) } # 生成每个出勤日的时间区间 data.frame( shift = shift_name, start_time = shift_dates + hours(8), end_time = shift_dates + days(1) + hours(8) ) } # 生成各轮班常规序列 df_A <- generate_shift_intervals("2022-01-08", "2022-12-30", "A", tz) df_B <- generate_shift_intervals("2022-01-02", "2022-12-31", "B", tz) df_C <- generate_shift_intervals("2022-01-05", "2023-01-01", "C", tz) # 合并所有轮班数据并排序 df_all <- rbind(carryover_A, df_A, df_B, df_C) df_all <- df_all[order(df_all$start_time), ]
事件关联方法
使用lubridate的%within%函数直接判断事件时间是否落在轮班区间内,无需秒级表:
# 示例事件表 events <- data.frame( event_id = 1:3, datetime = ymd_hms(c("2022-01-01 10:30:00", "2022-01-02 23:15:00", "2022-01-08 09:45:00"), tz = tz) ) # 为事件匹配对应轮班 events$shift <- sapply(events$datetime, function(dt) { matches <- df_all$shift[dt %within% interval(df_all$start_time, df_all$end_time)] if (length(matches) == 0) NA else matches })
方案优势
- 数据量极小:仅存储区间起止时间,避免百万级秒级数据
- 扩展性强:函数可快速适配其他年份或轮班规则
- 关联高效:区间判断逻辑简单,无需时区转换即可处理跨午夜轮班
内容的提问来源于stack exchange,提问作者tbtvem
相关产品推荐
相关产品推荐

