0

I am attempting to add together two "timestamps" in R. I say timestamps in quotations because they are character variables and are not technically times. The data in the ExtractionTime column is the minute/second point of a video and the data in the PropertyTime column is the timestamp at the point of the video that needs to be cut. I ideally want to add ExtractionTime and PropertyTime and then return their sum in the ClipTime column. I have created code that does just this but it does not add minutes once the code hits 59 seconds. Any idea of how to do this? Thanks!

Here is some of my data:

ExtractionTime
<chr>
PropertyTime
<chr>
ClipTime
<lgl>
00:16:49    10:00:13    NA      
00:16:50    10:00:13    NA      
00:16:51    10:00:13    NA      
00:16:52    10:00:13    NA      
00:16:53    10:00:13    NA      
00:16:54    10:00:13    NA  

Here is my code:

time.combine=function(x, y)
  for (i in seq_len(length(x))) {
    first.ex<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\1", x))
    second.ex<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\2", x))
    third.ex<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\3", x))
    first.prop<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\1", y))
    second.prop<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\2", y))
    third.prop<-as.numeric(sub("(\\d+):(\\d+):(\\d+)", "\\3", y))
    
    first<-first.ex+first.prop
    second<-second.ex+second.prop
    third<-third.ex+third.prop

 combined.times<-paste(first,second,third, sep = ":")
    return(combined.times)
  }

test.df$ClipTime<-time.combine(test.df$ExtractionTime, test.df$PropertyTime)

Which results in...


ExtractionTime
<chr>
PropertyTime
<chr>
ClipTime
<chr>
00:16:49    10:00:13    10:16:62        
00:16:50    10:00:13    10:16:63        
00:16:51    10:00:13    10:16:64        
00:16:52    10:00:13    10:16:65        
00:16:53    10:00:13    10:16:66        
00:16:54    10:00:13    10:16:67

But what I want is...

ExtractionTime
<chr>
PropertyTime
<chr>
ClipTime
<chr>
00:16:49    10:00:13    10:17:02        
00:16:50    10:00:13    10:17:03        
00:16:51    10:00:13    10:17:04        
00:16:52    10:00:13    10:17:05        
00:16:53    10:00:13    10:17:06        
00:16:54    10:00:13    10:17:07

How can I get this data instead?

Jocelyn
  • 15
  • 4
  • [Convert hour:minute:second (HH:MM:SS) string to proper time class](https://stackoverflow.com/questions/12034424/convert-hourminutesecond-hhmmss-string-to-proper-time-class) to easily perform arithmetics. – Henrik Sep 10 '21 at 19:22

2 Answers2

1

Write it down simple like this:

library(tidyverse)
library(lubridate)

df = tribble(
  ~ExtractionTime, ~PropertyTime,
  "00:16:49", "10:00:13", 
  "00:16:50", "10:00:13", 
  "00:16:51", "10:00:13", 
  "00:16:52", "10:00:13", 
  "00:16:53", "10:00:13", 
  "00:16:54", "10:00:13", 
)

df %>% mutate(
  ExtractionTime = ExtractionTime %>% hms() %>% as.duration(),
  PropertyTime = PropertyTime %>% hms() %>% as.duration(),
  ClipTime = (ExtractionTime + PropertyTime) %>% as.period())
)

output

# # A tibble: 6 x 3
# ExtractionTime         PropertyTime       ClipTime  
# <Duration>             <Duration>         <Period>  
# 1 1009s (~16.82 minutes) 36013s (~10 hours) 10H 17M 2S
# 2 1010s (~16.83 minutes) 36013s (~10 hours) 10H 17M 3S
# 3 1011s (~16.85 minutes) 36013s (~10 hours) 10H 17M 4S
# 4 1012s (~16.87 minutes) 36013s (~10 hours) 10H 17M 5S
# 5 1013s (~16.88 minutes) 36013s (~10 hours) 10H 17M 6S
# 6 1014s (~16.9 minutes)  36013s (~10 hours) 10H 17M 7S

Update 1 OKAY. I didn't know the output had to be chr. So let's do it differently.

AddTime = function(t1, t2) {
  (t1 %>% hms() %>% as.duration()) + 
    (t2 %>% hms() %>% as.duration())
}

DurationToStr = function(t) {
  td = t %>% seconds_to_period
  sprintf('%02d:%02d:%02d', td@hour, minute(td), second(td))
}

df %>% mutate(
  ClipTime = AddTime(ExtractionTime, PropertyTime) %>% DurationToStr())

output

# A tibble: 6 x 3
  ExtractionTime PropertyTime ClipTime
  <chr>          <chr>        <chr>   
1 00:16:49       10:00:13     10:17:02
2 00:16:50       10:00:13     10:17:03
3 00:16:51       10:00:13     10:17:04
4 00:16:52       10:00:13     10:17:05
5 00:16:53       10:00:13     10:17:06
6 00:16:54       10:00:13     10:17:07
Marek Fiołka
  • 4,825
  • 1
  • 5
  • 20
0

You may be able to use lubridate to automate some of this, but I have two functions I use for quick conversion into and out of HH:MM:SS:

time2num <- function(x) {
  vapply(strsplit(x, ':'), function(y) sum(as.numeric(y) * c(60*60, 60, 1)),
         numeric(1), USE.NAMES=FALSE)
}
num2time <- function(x, digits.secs = getOption("digits.secs", 3)) {
  hr <- as.integer(x %/% 3600)
  min <- as.integer((x - 3600*hr) %/% 60)
  sec <- (x - 3600*hr - 60*min)
  if (anyNA(digits.secs)) {
    # a mostly-arbitrary determination of significant digits,
    # motivated by @Roland https://stackoverflow.com/a/27767973
    for (digits.secs in 1:6) {
      if (any(abs(signif(sec, digits.secs) - sec) > (10^(-3 - digits.secs)))) next
      digits.secs <- digits.secs - 1L
      break
    }
  }
  sec <- sprintf(paste0("%02.", digits.secs[[1]], "f"), sec)
  sec <- paste0(ifelse(grepl("^[0-9]\\.", sec), "0", ""), sec)
  out <- sprintf("%02i:%02i:%s", hr, min, sec)
  out[is.na(x)] <- NA_character_
  out
}

With that,

num2time(sum(time2num(c("00:16:49", "10:00:13"))), 0)
# [1] "10:17:02"

time2num converts a colon-delimited time-like string into a number (it just multiplies the smallest-to-largest significant digits by 1, 60, and 3600),

time2num(c("00:16:49", "10:00:13"))
# [1]  1009 36013

which can then be operated on as numeric, and then converted back to "HH:MM:SS" format.

r2evans
  • 141,215
  • 6
  • 77
  • 149