如何将两个时间戳间的时间序列按午夜拆分为多段日期
解决方案
可以通过tidyverse结合日期序列生成、条件判断来实现,核心思路是先为每个组生成覆盖整个时段的所有日期,再根据日期位置(首日/中间日/末日)分别设置对应的起始和结束时间:
library(tidyverse) library(lubridate) df <- tibble( Group = c("A", "B", "C"), Begin = as_datetime(c("2023-07-15 01:40:11", "2023-07-22 05:54:44", "2023-08-05 16:43:09")), End = as_datetime(c("2023-07-15 13:43:15", "2023-07-25 10:50:45", "2023-08-06 10:42:12")) ) df_split <- df %>% # 生成每个组覆盖的所有日期序列 mutate( date_seq = map2(Begin, End, ~seq(date(.x), date(.y), by = "day")) ) %>% # 展开日期序列为单独行 unnest(date_seq) %>% # 根据日期位置设置对应的Begin和End时间 mutate( # 首日保留原Begin时间,否则设为当天00:00:00 new_begin = if_else(date_seq == date(Begin), Begin, as_datetime(date_seq)), # 末日保留原End时间,否则设为当天23:59:59 new_end = if_else(date_seq == date(End), End, as_datetime(date_seq) + days(1) - seconds(1)) ) %>% # 选择需要的列并重命名 select(Group, Begin = new_begin, End = new_end) df_split
运行后输出结果:
# A tibble: 7 × 3 Group Begin End <chr> <dttm> <dttm> 1 A 2023-07-15 01:40:11 2023-07-15 13:43:15 2 B 2023-07-22 05:54:44 2023-07-22 23:59:59 3 B 2023-07-23 00:00:00 2023-07-23 23:59:59 4 B 2023-07-24 00:00:00 2023-07-24 23:59:59 5 B 2023-07-25 00:00:00 2023-07-25 10:50:45 6 C 2023-08-05 16:43:09 2023-08-05 23:59:59 7 C 2023-08-06 00:00:00 2023-08-06 10:42:12
关键步骤说明
- 生成日期序列:用
map2结合seq函数,为每个组生成从Begin日期到End日期的所有日期,确保覆盖整个时段。 - 展开行:
unnest将日期序列拆分为单独的行,每个日期对应一行记录。 - 条件设置时间:
- 当日期是
Begin的日期时,保留原Begin时间;否则设为当天的00:00:00。 - 当日期是
End的日期时,保留原End时间;否则设为当天的23:59:59(通过date + days(1) - seconds(1)计算得到)。
- 当日期是
注:你提供的期望输出中C组首日的End时间是2023-08-05 23:59:09,这应该是笔误,正确的完整日结束时间应为23:59:59,上述代码按逻辑生成正确结果。
内容的提问来源于stack exchange,提问作者TobKel
相关产品推荐
相关产品推荐

