I want to convert a number to time in R - 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

Related

how to calculate time interval and divide it by integer in r?

i have time string as "08:00","06:00"
and i wanna calculate difference between them
and divide it by 15 mins.
then results should be 8 in integer
i don't how to code in R
anybody can help me ?
Something like this using difftime?
difftime(
as.POSIXct("08:00", format = "%H:%M"),
as.POSIXct("06:00", format = "%H:%M"),
units = "mins") / 15
#Time difference of 8 mins
Or to convert to numeric
as.numeric(
difftime(as.POSIXct("08:00", format = "%H:%M"),
as.POSIXct("06:00", format = "%H:%M"),
units = "mins") / 15)
#[1] 8
It would be easy with lubridate, where we convert the strings in hm format and divide by 15 minutes.
library(lubridate)
(hm(a) - hm(b))/minutes(15)
#[1] 8
data
a <- "08:00"
b <- "06:00"

lubridate convert decimals into months

i have estimated a variable age.first.union as a time difference using lubridate by subracting the date of wedding wdow from the date of birth wdob. I got the following numeric vector
head(wm$age.first.union, 3)
[1] 15.43014 12.67123 17.34247
I would like to have the decimals converted into months (and possibly also into days, but that's a minor detail), so the first value would be 15 years and 5 months. What I did was to create a series of new variables and then perform some calculations. To get the number of months, first, I duplicated and truncated the age.first.union variable. Then I estimated the difference between the two to get only the decimal part and then used proportions (e.g. 0.43 : 10 = x : 12 ) to get the months.
I looked into the lubridate documentation but I could not find much on this. I tried the following
years(floor(dseconds(15.43014)))
but I got only the years
[1] "15y 0m 0d 0H 0M 0S"
One idea would be to get the durations in seconds
seconds(floor(dyears(15.43014)))
[1] "486604895S"
but then the challenge would be that months have difference lengths. Even an approximation of years = 365 days, and months = 30 days would be more then perfect, but I do not know how to do it apart from lengthy calculations.
One final idea would be to have years and month using the calculation as described at the beginning of this post, and then merge the two variables into the final one using something similar to make_date (but it looks like a make_duration does not seem to exist yet).
The whole process looks quite cumbersome to me, anyone has a different take?
Many thanks
Manolo
While lubridate provides a function decimal_date to convert a fractional date to D-M-Y date, you seem to be dealing with durations. So this won't work.
However, you can quite easily define a custom function to extract the integer year, month and fractional day (based on an average 30.42 days per month in a regular year):
age <- c(15.43014 12.67123 17.34247)
f <- function(x) {
year <- floor(x);
month <- floor((x - year) * 12);
day <- ((x - year) * 12 - month) * 30.42;
return(sprintf("%i years, %i months, %3.2f days", year, month, day))
}
lapply(age, f);
#[[1]]
#[1] "15 years, 5 months, 4.92 days"
#
#[[2]]
#[1] "12 years, 8 months, 1.67 days"
#
#[[3]]
#[1] "17 years, 4 months, 3.34 days"
Update
If you want to return the integer year, month and fractional day you can define f as
f <- function(x) {
year <- floor(x);
month <- floor((x - year) * 12);
day <- ((x - year) * 12 - month) * 30.42;
return(list(year = year, month = month, day = day))
}
which gives you e.g.
sapply(age, f);
# [,1] [,2] [,3]
#year 15 12 17
#month 5 8 4
#day 4.918306 1.665799 3.335249
We can define our own ym S3 class to represent year/month objects. Here we define several ym methods as well as extractor functions for years and months. The as.data.frame.ym method is a partial implementation. We have defined a month to be 1/12th of a year.
as.ym <- function(x, ...) structure(x, class = "ym")
as.data.frame.ym <- function(x, ...)
structure(list(x), row.names = seq_along(x), class = "data.frame")
years.ym <- as.integer
months.ym <- function(x) 12 * as.numeric(x) %% 1
format.ym <- function(x, ...) paste0(years.ym(x), "Y ", round(months.ym(x)), "M")
print.ym <- function(x, ...) print(format(x), ...)
# test
x <- c(15.43014, 12.67123, 17.34247) # test input
xx <- as.ym(x)
xx
## [1] "15Y 5M" "12Y 8M" "17Y 4M"
DF <- data.frame(x, xx)
DF
x xx
1 15.43014 15Y 5M
2 12.67123 12Y 8M
3 17.34247 17Y 4M
years.ym(xx)
## [1] 15 12 17
months.ym(xx)
## [1] 5.16168 8.05476 4.10964
class(xx)
## [1] "ym"
Days
To extend this to include days, as well, we assume that there are 365.25 days in a year and, again, we use 12 months in a year. We create a ymd S3 class for this.
as.ymd <- function(x, ...) structure(x, class = "ymd")
as.data.frame.ymd <- function(x, ...)
structure(list(x), row.names = seq_along(x), class = "data.frame")
years.ymd <- as.integer
months.ymd <- function(x) as.integer(12 * as.numeric(x) %% 1)
days.ymd <- function(x) (365.25 * as.numeric(x)) %% (365.25 / 12)
format.ymd <- function(x, ...)
paste0(years.ymd(x), "Y ", as.integer(months.ymd(x)), "M ", round(days.ymd(x), 1), "D")
print.ymd <- function(x, ...) print(format(x), ...)
xx <- as.ymd(x)
xx
## [1] "15Y 5M 4.9D" "12Y 8M 1.7D" "17Y 4M 3.3D"
DF <- data.frame(x, xx)
DF
x xx
1 15.43014 15Y 5M 4.9D
2 12.67123 12Y 8M 1.7D
3 17.34247 17Y 4M 3.3D
years.ymd(xx)
## [1] 15 12 17
months.ymd(xx)
## [1] 5 8 4
days.ymd(xx)
## [1] 4.921135 1.666758 3.337167
class(xx)
## [1] "ymd"

Parse time data with subseconds

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

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"

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")})

Resources