根据日期时间复制和修改行

Duplicating and modifying rows based on datetime

我有一个 data.table 看起来像这样

library(dplyr)
library(data.table)

dt <- data.table(ID=c("A001","A002","A003","A004"),start_time=c('2019-06-18 05:18:00','2020-03-04 05:00:00',
                 '2019-05-10 19:00:00','2020-01-06 22:42:00'),end_time=c('2019-06-18 08:41:00','2020-03-04 05:04:00',
                 '2019-05-10 19:08:00','2020-01-07 03:10:00'))
 ID      

    start_time            end_time duration
1: A001 2019-06-18 05:18:00 2019-06-18 08:41:00 203 mins
2: A002 2020-03-04 05:59:00 2020-03-04 06:04:00   5 mins
3: A003 2019-05-10 19:00:00 2019-05-10 19:08:00   8 mins
4: A004 2020-01-06 22:42:00 2020-01-07 03:10:00 268 mins

持续时间简单计算为

dt$start_time <- as.POSIXct(dt$start_time, tz='UTC')  
dt$end_time <- as.POSIXct(dt$end_time, tz='UTC')
dt <- dt %>% mutate(duration = (end_time-start_time))

我需要从 start_time 复制持续时间大于一小时结束的行(涵盖 > 1 小时的记录)。我需要为他们更改开始时间(小时开始)、结束时间 - 小时结束或原始结束时间(如果是最后一行(最后查看小时))和相应的持续时间,以便最终输出看起来像:

    dt_expected <- data.table(ID=c("A001","A001","A001","A001","A002","A002","A003","A004","A004","A004","A004","A004","A004"),
start_time=c('2019-06-18 05:18:00','2019-06-18 06:00:00','2019-06-18 07:00:00','2019-06-18 08:00:00', '2020-03-04 05:59:00', '2020-03-04 06:00:00',  '2019-05-10 19:00:00',
'2020-01-06 22:42:00', '2020-01-06 23:00:00','2020-01-07 00:00:00','2020-01-07 01:00:00','2020-01-07 02:00:00','2020-01-07 03:00:00'),
end_time=c('2019-06-18 05:59:00','2019-06-18 06:59:00','2019-06-18 07:59:00','2019-06-18 08:41:00','2020-03-04 05:59:00','2020-03-04 06:04:00',   '2019-05-10 19:08:00',    '2020-01-06 22:59:00','2020-01-06 23:59:00','2020-01-07 00:59:00','2020-01-07 01:59:00', '2020-01-07 02:59:00','2020-01-07 03:10:00'), 
duration = c(12,60,60,41,1,4,8,18,60,60,60,60,10)) 

请注意,ID A002 的记录也应重复,因为持续时间发生在 2 个不同的小时内。

      ID          start_time            end_time duration
 1: A001 2019-06-18 05:18:00 2019-06-18 05:59:00       12
 2: A001 2019-06-18 06:00:00 2019-06-18 06:59:00       60
 3: A001 2019-06-18 07:00:00 2019-06-18 07:59:00       60
 4: A001 2019-06-18 08:00:00 2019-06-18 08:41:00       41
 5: A002 2020-03-04 05:59:00 2020-03-04 05:59:00        1
 6: A002 2020-03-04 06:00:00 2020-03-04 06:04:00        4
 7: A003 2019-05-10 19:00:00 2019-05-10 19:08:00        8
 8: A004 2020-01-06 22:42:00 2020-01-06 22:59:00       18
 9: A004 2020-01-06 23:00:00 2020-01-06 23:59:00       60
10: A004 2020-01-07 00:00:00 2020-01-07 00:59:00       60
11: A004 2020-01-07 01:00:00 2020-01-07 01:59:00       60
12: A004 2020-01-07 02:00:00 2020-01-07 02:59:00       60
13: A004 2020-01-07 03:00:00 2020-01-07 03:10:00       10

我认为这与您要查找的内容非常接近。

这会创建新的开始和结束时间行,使用 purrr 中的 map 每小时一行。

然后,对于每个 ID,它将使用 pmin.

确定 start_timeend_time

首先,对于 end_time,它取该行的 end_time 和比该行的 start_time 晚一小时之间的最小值。例如,A001 的第一行将有 6:00 的 end_time,这是 5:18 的 ceiling_date 时间到最近的小时,并且小于 6:18来自 map 生成的序列。对于 A001 的最后一行,end_time 是 8:41,小于 9:00 的 ceiling_date 时间。

start_time 将取最后一行的 end_time 和该行的 start_time 之间的最小值。例如,A001 的第二行将有 6:00,这是上面的行 end_time,它小于 map.[=32= 生成的序列中的 6:18 ]

请注意,duration 一行有 0 分钟 - 时间恰好在整点 (19:00:00)。这些可以被过滤掉。

library(purrr)
library(dplyr)
library(tidyr)
library(lubridate)

dt %>%
  rowwise() %>%
  mutate(start_time = map(start_time, ~seq.POSIXt(., ceiling_date(end_time, "hour"), by = "hour"))) %>%
  unnest(start_time) %>%
  group_by(ID) %>%
  mutate(end_time = pmin(ceiling_date(start_time, unit = "hour"), end_time),
         start_time = pmin(floor_date(lag(end_time, default = first(end_time)), unit = "hour"), start_time),
         duration = difftime(end_time, start_time, units = "mins"))

输出

   ID    start_time          end_time            duration
   <chr> <dttm>              <dttm>              <drtn>  
 1 A001  2019-06-18 05:18:00 2019-06-18 06:00:00 42 mins 
 2 A001  2019-06-18 06:00:00 2019-06-18 07:00:00 60 mins 
 3 A001  2019-06-18 07:00:00 2019-06-18 08:00:00 60 mins 
 4 A001  2019-06-18 08:00:00 2019-06-18 08:41:00 41 mins 
 5 A002  2020-03-04 05:59:00 2020-03-04 06:00:00  1 mins 
 6 A002  2020-03-04 06:00:00 2020-03-04 06:04:00  4 mins 
 7 A003  2019-05-10 19:00:00 2019-05-10 19:00:00  0 mins 
 8 A003  2019-05-10 19:00:00 2019-05-10 19:08:00  8 mins 
 9 A004  2020-01-06 22:42:00 2020-01-06 23:00:00 18 mins 
10 A004  2020-01-06 23:00:00 2020-01-07 00:00:00 60 mins 
11 A004  2020-01-07 00:00:00 2020-01-07 01:00:00 60 mins 
12 A004  2020-01-07 01:00:00 2020-01-07 02:00:00 60 mins 
13 A004  2020-01-07 02:00:00 2020-01-07 03:00:00 60 mins 
14 A004  2020-01-07 03:00:00 2020-01-07 03:10:00 10 mins