Getting the difference is easy: just subtract, i.e. max(df$c_time) - min(df$c_time)
. However, you might find units get wonky when applying this to multiple subsets, so using difftime
explicitly so you can set units is a good idea. In aggregate
:
aggregate(c_time ~ c_id, df, function(x){difftime(max(x), min(x), units ='secs')})
# c_id c_time
# 1 1 55
# 2 2 61
However, this isn't the time format you wanted. chron
has a nice times class, assuming you don't just want to work with strings. It subtracts better than difftime
:
aggregate(c_time ~ c_id, df, function(x){x <- chron::as.chron(x); max(x) - min(x)})
# c_id c_time
# 1 1 00:00:55
# 2 2 00:01:01
# or in dplyr
library(dplyr)
df %>% mutate(c_time = chron::as.chron(c_time)) %>%
group_by(c_id) %>%
summarise(range = max(c_time) - min(c_time))
# Source: local data frame [2 x 2]
#
# c_id range
# (int) (tims)
# 1 1 00:00:55
# 2 2 00:01:01
# or data.table
library(data.table)
setDT(df)[, .(c_id, c_time = chron::as.chron(c_time))
][, .(range = max(c_time) - min(c_time)), by = c_id]
# c_id range
# 1: 1 00:00:55
# 2: 2 00:01:01
Or use data.table
's ITime instead of chron::times
, though it returns seconds when subtracted:
setDT(df)[, .(c_id, c_time = as.ITime(c_time))
][, .(range = as.ITime(as.POSIXct(max(c_time) - min(c_time),
'UTC', origin))), by = c_id]
# c_id range
# 1: 1 00:00:55
# 2: 2 00:01:01
If you do in fact want strings instead of a formatted time, you can actually keep it in all base R:
aggregate(c_time ~ c_id, df,
function(x){format(as.POSIXct(as.numeric(difftime(max(x),
min(x),
units ='secs')),
'UTC', origin = origin),
'%T')})
# c_id c_time
# 1 1 00:00:55
# 2 2 00:01:01