Parse time data with subseconds - r

I have some time data
01:09:00
00:14:00
00:00:00
11:47:00
10:34:00
08:15:00
The data are measured in %M:%S:00 (to the first numbers are the minutes, the second numbers are the seconds). I would like to convert this into a total number of seconds. This is easy to do with lubridate but R keeps thinking the format is in %H:%M:%S.
Can lubridate calculate the total number of seconds elapsed in the format my data are in? If not, how is the best way to transform the data into an appropriate format?
I've thought about converting to character and just splicing out the minutes and seconds.

library(lubridate)
foo = function(x){
hms(sapply(strsplit(x, ":"), function(xx) paste("01", xx[1], xx[2], sep = ":")))
}
a = "01:09:00"
b = "00:14:00"
foo(a) - foo(b)
#[1] "1M -5S"
#OR
as.period(foo(a) - foo(b), unit = "secs")
#[1] "55S"

Maybe the following will do it.
NumSeconds <- function(x){
f <- function(y)
sum(sapply(strsplit(y, split=":"), as.numeric) * c(60, 1, 0))
unname(sapply(x, f))
}
x <- scan(what = "character", text = "
01:09:00
00:14:00
00:00:00
11:47:00
10:34:00
08:15:00")
NumSeconds(x)
[1] 69 14 0 707 634 495

You may use data.table::as.ITime and specify format as "%M:%S"*:
x <- c("01:09:00", "10:34:00")
as.integer(as.ITime(x, format = "%M:%S"))
# [1] 69 634
*The format argument is passed to strptime and...
Each input string is processed as far as necessary for the format specified: any trailing characters are ignored.
[...]
Note that %S does not read fractional parts on output.
Or, most likely faster, substr:
as.integer(substr(x, 1, 2)) * 60 + as.integer(substr(x, 4, 5))
# [1] 69 634

Related

convert string to time-format in R language

I have strings like this:
100
200
...
2300
how to transfer this to time format?
01:00:00
02:00:00
...
23:00:00
do I have to add 0 to the string?
I have tried
Data$Time <- formatC(Data$Time, digits = 6, flag = "0")
But it's not working
We can use sprintf to do the formatting and then convert to Time with as.ITime
library(data.table)
as.ITime(sub("(..)", "\\1:", sprintf("%04d:00", v1)))
#[1] "01:00:00" "02:00:00" "23:00:00"
As #Claudio mentioned, if it is a vector of strings, replace the %04d with %04s
data
v1 <- c(100, 200, 2300)

Converting to POSIXct a 24h+ hour

I can convert to POSIXct most of the time like for instance:
as.POSIXct( "20:16:32", format = "%H:%M:%S" )
[1] "2017-06-23 20:16:32 EDT"
But once the time goes beyond 24h, it fails:
as.POSIXct( "24:16:32", format = "%H:%M:%S" )
[1] NA
Which makes some sense as 24:16:32 should rather be read as 00:16:32
Such standards of 24+ are however well spread in the design of public transportation. I could of course replace all "24:" by "00:", but I am sure there is a more elegant way out.
Read the time string into a data frame dd and set next_day to 1 if the hour exceeds 24 or more or 0 if not. Subtract 24 from the hour if next_day is 1 and add 1 day's worth of seconds. Given that today is June 23, 2017 this would work for hours between 0 and 47.
x <- "24:16:32" # test input
dd <- read.table(text = x, sep = ":", col.names = c("hh", "mm", "ss"))
next_day <- dd$hh >= 24
s <- sprintf("%s %0d:%0d:%0d", Sys.Date(), dd$hh - 24 * next_day, dd$mm, dd$ss)
as.POSIXct(s) + next_day * 24 * 60 * 60
## "2017-06-24 00:16:32 EDT"

I want to convert a number to time in R

say I have a number 1234, and I need to convert that to 12:34 i.e 12:34pm and eventually convert that to minutes in the day starting from 0000.
A bit of integer division and modulo should work:
x <- c(1234,830)
(x %/% 100) * 60 + x %% 100
#[1] 754 510
If you absolutely need a time representation first:
tmp <- as.POSIXct(sprintf("%04d", x), format="%H%M")
tmp - trunc(tmp, "day")
#Time differences in mins
#[1] 754 510
We can do this with sub and times from chron
library(chron)
times(sub("(.{2})", "\\1:", sprintf("%04d:00", x)))
#[1] 12:34:00 08:30:00
If we need to convert to 'minute' then
library(lubridate)
minute(as.period(hms(sub("(.{2})", "\\1:", sprintf("%04d:00", x))), unit = "minute"))
#[1] 754 510
data
x <- c(1234,830)
Assuming your time integer is based on a 24 hour format (which should be otherwise you can't distinguish between am and pm):
time <- 1234
time_converted <- sub("(\\d+)(\\d{2})", "\\1:\\2", time)
> time_converted
[1] "12:34"
minutes <- as.POSIXlt(time_converted, format="%H:%M")$hour *60 + as.POSIXlt(time_converted, format="%H:%M")$min
> minutes
[1] 754
You could use:
x <- as.POSIXct(x = "1234", format = "%H%M", tz = "UTC")
minutes(x) + hour(x) * 60
Result:
[1] 754

Convert hours:minutes:seconds to minutes

I have a vector "Time.Training" in the format hours:minutes:seconds (e.g.
Time.Training <- c("1:00:00", "0:45:00", "0:30:00", "1:30:00")
I would like to convert this into minutes in the format:
Time.Training.Minutes <- c(60, 45, 30, 90)
I'm wondering if someone has a straightforward method of doing this in R.
Many thanks.
Matt
Using lubridate:
Time.Training<- c("1:00:00", "0:45:00", "0:30:00", "1:30:00")
library(lubridate)
res <- hms(Time.Training) # format to 'hours:minutes:seconds'
hour(res)*60 + minute(res) # convert hours to minutes, and add minutes
## [1] 60 45 30 90
Try this. We basically converting to POSIXlt class first by pasting a real date to the vector using the Sys.Date() function (because there is no hour class in base R) and then using hour and min arguments in order to achieve the output
Res <- as.POSIXlt(paste(Sys.Date(), Time.Training))
Res$hour*60 + Res$min
## [1] 60 45 30 90
Use as.difftime:
> Time.Training<- c("1:00:00", "0:45:00", "0:30:00", "1:30:00")
> strtoi(as.difftime(Time.Training, format = "%H:%M:%S", units = "mins"))
[1] 60 45 30 90
Here are some alternatives:
1) The chron package has a "times" class in which 1 unit is a day and there are 60 * 24 minutes in a day so:
library(chron)
60 * 24 * as.numeric(times(Time.Training))
giving:
[1] 60 45 30 90
1a) Another approach using chron is the following (giving the same answer):
library(chron)
ch <- times(Time.training)
60 * hours(ch) + minutes(ch)
2) Here is an approach using read.table and matrix/vector multiplication. No packages are needed:
c(as.matrix(read.table(text = Time.Training, sep = ":")) %*% c(60, 1, 1/60))
(Using "POSIXlt" is probably the most straight-forward approach without packages but another answer already provides that.)
Taking the hour column from the date time column and create a new cloumn hour and give only hour data in that column 2011-01-01 00:00:01
Ans :
bikeshare$hour<-sapply(bikeshare$datetime,function(x){format(x,"%H")})

Equivalent of datenum in R programming

I have previous experience of matlab but very new to R. The basic problem that I am having is like this -
I have a data which has 10 columns. The first 6 columns correspond to year, month, day, hour min and secs.
E.g data_example =
2013 6 15 11 15 0 ...
2013 6 15 11 20 0 ...
2013 6 15 11 25 0 ...
In matlab for dealing with dates as numbers I used to easily compute that using datenum(data_example(:,1:6))
but in R what is the best way to go about getting similar numerical representation of the 6 columns.
Here are some alternatives. They all make use of ISOdatetime :
1) Assuming DF is your data frame try ISOdatetime like this:
DF$datetime <- ISOdatetime(DF[[1]], DF[[2]], DF[[3]], DF[[4]], DF[[5]], DF[[6]])
2) or like this:
DF$datetime <- do.call(ISOdatetime, setNames(as.list(DF[1:6]), NULL))
3a) If this is a time series suitable for zoo (distinct times and all numeric) then we could use read.zoo in the zoo package together with ISOdatetime like this:
library(zoo)
z <- read.zoo(DF, index = 1:6, FUN = ISOdatetime)
3b) or using read.zoo to read from a file or character string (latter shown here):
# sample input lines
Lines <- "2013 6 15 11 15 0 1
2013 6 15 11 20 0 2
2013 6 15 11 25 0 3
"
library(zoo)
z <- read.zoo(text = Lines, index = 1:6, FUN = ISOdatetime)
which gives this zoo series:
> z
2013-06-15 11:15:00 2013-06-15 11:20:00 2013-06-15 11:25:00
1 2 3
Use the parse_date_time function from the Lubridate package.
x <- paste0(data_example[,1:6])
x <- parse_date_time(x,"%y%m%d %H%M")
More information in the documentation
EDIT
#joran told me to test it, and it didn't work, so I made some modifications:
data_example = data.frame(t(c(13,2,9,14,30)))
x <- paste0(data_example[,1:3],collapse="-")
y <- paste0(data_example[,4:5],collapse=":")
xy<- paste(x,y)
xy <- parse_date_time(xy,"%y%m%d %H%M")
xy
# "2013-02-09 14:30:00 UTC"
I don't know if there is a cleaner way to do it
The units of the returned value are a bit different in R than in Matlab (see comment in code). Also, since you have other columns in your data frame, you will first need to subset the data frame to contain only the relevant (6) date columns, then add them back to the data frame as a new column at the end.
test <- data.frame("year"=c(2013, 2013, 2013, 2001, 1970)
, "month"=c(6,6, 6, 4, 1)
, "day"=c(15,15, 15, 19, 1)
, "hour"=c(11,11, 11, 11, 0)
, "min"=c(15,20, 25, 30, 0)
, "second"=c(0,0, 0 ,0, 0))
# pad to the right # of digits
dates00 <- apply(test, c(1,2), sprintf, fmt="%02s")
# combine the date components in each row into a single string
dates0 <- apply(dates00, 1, paste, collapse=" ")
#format to a date object
dates <- as.POSIXct(dates0, format="%Y %m %d %H %M %S")
# numbers are seconds since "1970-01-01 00:00:00 UTC"; according
# to the help file for daynum, Matlab returns the number (from
# daynum) as fractional days since "January 0, 0000"
as.numeric(dates)

Resources