Ali Altıntaş
Ali Altıntaş

Reputation: 305

Convert HH:MM:SS to hours (for more than 24 hours) in R

I would like to convert hours more than 24 hours in R.

For example, I have a dataframe which contains hours and minutes like [HH:MM]:

[1] "111:15" "221:15" "111:15" "221:15" "42:05"

I want them to be converted in hours like this:

"111.25" "221.25" "111.25" "221.25" "42.08333333"

as.POSIXct() 

function works for general purpose, but not for more than 24 hours.

Upvotes: 0

Views: 2154

Answers (4)

G. Grothendieck
G. Grothendieck

Reputation: 269346

strapplyc Here ia a solution using strapplyc in the gsubfn package. It passes the match to each of the parenthesized regular expressions (i.e. the hours and the minutes) to the function described in the third argument. The function can be specified using the usual R function notation and it also supports a short form using a formula (used here) where the right hand side of the formula is the function body and the left hand side represent the arguments and defaults to the free variables (m, h) in the right hand side. We suppose that the original character vector is ch.

library(gsubfn)
strapply(ch, "(\\d+):(\\d+)", ~ as.numeric(h) + as.numeric(m)/60, simplify = TRUE)

numeric processing Another way is to replace the : with a . and manipulate it numerically into what we want:

num <- as.numeric(chartr(":", ".", ch))
trunc(num) + 100 * (num %% 1) / 60

sub This is yet another approach:

h <- as.numeric(sub(":.*", "", ch))
m <- as.numeric(sub(".*:", "", ch))
h + m / 60

The codes above each gives a numberic result but we could wrap each in as.character(...) if a character result were desired.

read.table

as.matrix(read.table(text = ch, sep = ":")) %*% c(1, 1/60)

eval/parse. This one maipulates each one into an R expression which is evaluated. This one is short but the use of eval is often frowned upon:

sapply(parse(text = sub(":", "+(1/60)*", ch)), eval)

ADDED additional solutions.

Upvotes: 0

Sven Hohenstein
Sven Hohenstein

Reputation: 81683

You can split the strings with strsplit and use sapply to transform all values.

vec <- c("111:15", "221:15", "111:15", "221:15", "42:05")

sapply(strsplit(vec, ":"), function(x) {
  x <- as.numeric(x)
  x[1] + x[2] / 60
})

The result:

[1] 111.25000 221.25000 111.25000 221.25000  42.08333

Upvotes: 2

Rob
Rob

Reputation: 1490

Another possibility is a vectorized function such as:

FUN <- function(time){
    hours <- sapply(time,FUN=function(x) as.numeric(strsplit(x,split=":")[[1]][1]))
    minutes <- sapply(time,FUN=function(x) as.numeric(strsplit(x,split=":")[[1]][2]))
    result <- hours+(minutes/60)
    return(as.numeric(result))
}

Where you use strsplit to extract the hours and minutes, of which you then take the sum after dividing the minutes by 60.

You can then use the function like this:

FUN(c("111:15","221:15","111:15","221:15","42:05"))

[1] 111.25000 221.25000 111.25000 221.25000  42.08333

Upvotes: 0

Jake Burkhead
Jake Burkhead

Reputation: 6535

I would just parse the strings with regex. Grab the bit before the : then add on the bit after the : divided by 60

> foo = c("111:15", "221:15", "111:15", "221:15", "42:05")
> foo
[1] "111:15" "221:15" "111:15" "221:15" "42:05" 
> as.numeric(gsub("([^:]+).*", "\\1", foo)) + as.numeric(gsub(".*:([0-9]{2})$", "\\1", foo))/60
[1] 111.25000 221.25000 111.25000 221.25000  42.08333

Upvotes: 0

Related Questions