48

In the following data frame the 'time' column is character in the format hour:minute:second

id <- c(1, 2, 3, 4)
time <- c("00:00:01", "01:02:00", "09:30:01", "14:15:25")
df <- data.frame(id, time)

How can I convert 'time' column to a dedicated time class, so that I can perform arithmetic calculations on it?

Henrik
  • 65,555
  • 14
  • 143
  • 159
AliCivil
  • 2,003
  • 6
  • 28
  • 43

6 Answers6

56

Use the function chron in package chron:

time<-c("00:00:01", "01:02:00", "09:30:01", "14:15:25")

library(chron)
x <- chron(times=time)

x
[1] 00:00:01 01:02:00 09:30:01 14:15:25

Do some useful things, like calculating the difference between successive elements:

diff(x)
[1] 01:01:59 08:28:01 04:45:24

chron objects store the values internally as a fraction of seconds per day. Thus 1 second is equivalent to 1/(60*60*24), or 1/86400, i.e. 1.157407e-05.

So, to add times, one simple option is this:

x + 1/86400
[1] 00:00:02 01:02:01 09:30:02 14:15:26
Andrie
  • 176,377
  • 47
  • 447
  • 496
  • 1
    And, what if I have the time in a 12 hour format? Example : `time<-c("01:00:01 am", "01:02:00 pm", "09:30:01 am", "02:15:25 pm")` . The `chron()`does not handle that. So, is there any other function for it? – sunitprasad1 Jan 13 '16 at 05:54
  • Is there a way to use it with HH:MM format? ```chron(times=time, format=c(times="h:m"))``` does not work... – Moysey Abramowitz Nov 08 '21 at 21:36
27

Using base R you could convert it to an object of class POSIXct, but this does add a date to the time:

id<-c(1,2,3,4)
time<-c("00:00:01","01:02:00","09:30:01","14:15:25")
df<-data.frame(id,time,stringsAsFactors=FALSE)

as.POSIXct(df$time,format="%H:%M:%S")
[1] "2012-08-20 00:00:01 CEST" "2012-08-20 01:02:00 CEST"
[3] "2012-08-20 09:30:01 CEST" "2012-08-20 14:15:25 CEST"

But that does allow you to perform arithmetic calculations on them.

Sacha Epskamp
  • 46,463
  • 20
  • 113
  • 131
  • How would you find a subset based on the hh:mm:ss? I don't think subset `(df, df$time >"2012-08-20 00:00:01 CEST" | df$time <"2012-08-20 14:15:25 CEST"` works. – hlyates Aug 03 '16 at 02:54
  • What if the time is in 12 hour format, using AM/PM? – Rodrigo May 10 '18 at 21:51
7

Another possible alternative could be:

time <- c("00:00:01","01:02:00","09:30:01","14:15:25")
converted.time <- as.difftime(time, units = "mins") #"difftime" class
secss <- as.numeric(converted.time, units = "secs")
hourss <- as.numeric(converted.time, units = "hours")
dayss <- as.numeric(converted.time, units="days")

Or even:

w <- strptime(x = time, format = "%H:%M:%S") #"POSIXlt" "POSIXt" class
Fábio
  • 771
  • 2
  • 14
  • 25
7

Using the ITime class in data.table package:

ITime is a time-of-day class stored as the integer number of seconds in the day.

library(data.table)
(it <- as.ITime(time))
# [1] "00:00:01" "01:02:00" "09:30:01" "14:15:25"

it + 10
# [1] "00:00:11" "01:02:10" "09:30:11" "14:15:35"


diff(it)
# [1] "01:01:59" "08:28:01" "04:45:24"
Henrik
  • 65,555
  • 14
  • 143
  • 159
6

lubridate allows good flexibility on the time format :

library(lubridate)

time_hms_1<-c("00:00:01", "01:02:00", "09:30:01", "14:15:25")
hms(time_hms_1)
#> [1] "1S"          "1H 2M 0S"    "9H 30M 1S"   "14H 15M 25S"


time_hms_2<-c("0:00:01", "1:02:00", "9:30:01", "14:15:25")
hms(time_hms_2)
#> [1] "1S"          "1H 2M 0S"    "9H 30M 1S"   "14H 15M 25S"

time_hm_1<-c("00:00", "01:02", "09:30", "14:15")
hm(time_hm_1)
#> [1] "0S"         "1H 2M 0S"   "9H 30M 0S"  "14H 15M 0S"

time_hm_2<-c("0:00", "1:02", "9:30", "14:15")
hm(time_hm_2)
#> [1] "0S"         "1H 2M 0S"   "9H 30M 0S"  "14H 15M 0S"

Created on 2020-07-03 by the reprex package (v0.3.0)

Waldi
  • 39,242
  • 6
  • 30
  • 78
4

Yet another alternative using the hms package.

id <- c(1, 2, 3, 4)
time <- c("00:00:01", "01:02:00", "09:30:01", "14:15:25")
df <- data.frame(id, time, stringsAsFactors = FALSE)

Convert column time to class hms

# install.packages("hms")
library(hms)
df$time <- as.hms(df$time)

Perform arithmetic calculations

diff(df$time)
#01:01:59
#08:28:01
#04:45:24
markus
  • 25,843
  • 5
  • 39
  • 58