The result of the following instruction:
as.difftime("5 11:04:36", "%d %H:%M:%S", units =("mins"))
is
Time difference of -7975.4 mins
It seems that this function is calculating the time difference between Sys.Time() and the given value.
I actually need an object to store a time span value extracted from a string (). Am I using the wrong function or is it not the right way of using it?
Look into lubridate
I think you want something like Duration-class, Period-class, or Timespan-class
# Duration
dur <- duration(hours = 10, minutes = 6)
# [1] "36360s (~10.1 hours)"
# Period
per <- period(hours = 10, minutes = 6)
# [1] "10H 6M 0S"
Related
I am trying to convert numeric values into times and dates. I am working with a data set so it would be appreciated if you should show an example using a dataset.
Here are some examples, converting 93537 into 09:35:57 (HH:MM:SS). Additionally, I need to convert 220703 into 22-07-03 (YY:MM:DD).
I will add an example of my code below:
CPLF_data$HMS <- substr(as.POSIXct(sprintf("%04.0f", CPLF_data$StartTime), format='%H%M%S'), 12, 16)
CPLF_data$YMD <- as.POSIXct(CPLF_data$Date, tz="UTC", origin ="1970-01-01", format ="%Y-%M-%D")
The first line is correct however, it does not show seconds.
The second line is incorrect.
Thank you.
I want my final product to be a new column with the times and dates in the correct format with their own columns.
Use chron times class to get the times or if a character string is wanted use as.character on that. Use as.Date to get a Date class object. The sub puts colons between the parts of the time after which we can convert it to times class. The sprintf pads the date with 0 on the left if it is only 5 characters and otherwise leaves it as 6 characters and then we convert that to Date class.
library(chron)
time <- 93537
date <- 220703
tt <- times(sub("(..)(..)$", ":\\1:\\2", time))
tt
## [1] "09:35:37"
as.character(tt)
## [1] "09:35:37"
dd <- as.Date(sprintf("%06d", date), "%y%m%d")
dd
## [1] "2022-07-03"
as.character(dd)
## [1] "2022-07-03"
Try the ymd_hms function in the lubridate package.
output$datetime <- ymd_hms(paste(input$year, input$month, input$day,
input$HH, input$MM, input$SS, sep="-"))
You can enter 00 if you don't have seconds, for example ....
Base R does not have a class for just "time" (of day), as.POSIXct doesn't deal with "times", it deals with "date-times". The lubridate:: package does give number-like HMS values, which may be relevant, but since each row has both date and time, it seems relevant to combine them instead of putting them into separate columns.
CPLF_data |>
transform(
StartTime = as.numeric(StartTime),
Date = as.numeric(Date)
) |>
transform(
DateTime = ISOdate(
2000 + Date %/% 10000, (Date %% 10000) %/% 100, Date %% 100,
StartTime %/% 10000, (StartTime %% 10000) %/% 100, StartTime %% 100)
)
# StartTime Date DateTime
# 1 93537 220703 2022-07-03 09:35:37
Note: I'm assuming that all years are 2-digits and at/after 2000. If this is not true, it's not difficult to work around it with some custom code. Also, over to you if you want to set the timezone of this timestamp by adding tz="US/Mountain" or whichever is more appropriate for the data.
Data
CPLF_data <- data.frame(StartTime = "93537", Date = "220703")
I have two data frames with time data every 15 minutes but one starts precisely on time (0:00, 0:15, 0:30, 0:45, etc.) and one starts slightly off (0:03, 0:18, 0:33, 0:48, etc). I would like to round the slightly off one to the nearest 15 minutes interval so that I may later merge the data frames so that the data corresponding to those times are in the same rows. The data is in 24 hour time and, as an example, in the format of:
Time
0:00
0:15
0:30
0:45
1:00
I have tried the code below but r returns the error:
library(lubridate)
p_data <- read.csv("Filter12.csv", header = TRUE)
p_data$Time <- round_date(p_data$Time, "15 mins")
Error in UseMethod("reclass_date", orig) :
no applicable method for 'reclass_date' applied to an object of class "character"
In addition: Warning message: All formats failed to parse. No formats found.
I then tried converting the time column from character to numeric but recieved the error:
p_data$Time <- as.numeric(p_data$Time)
Warning message:
NAs introduced by coercion
I am very new to r (just started learning this week) so I apologize if this is due to a lack of common knowledge.
Here an approach with lubridate. We first generate an arbitrary data set and then round it to 15minutes:
library(lubridate)
x <- seq(as.POSIXct("2021-05-19 10:00"), as.POSIXct("2021-05-19 11:00"), 240)
x
round_date(x, unit="15 mins")
Edit: here the same idea with minutes only. We use a fake date, append the time, round it to 15min and extract minutes only:
library(lubridate)
x <- c("0:03", "0:18", "0:33", "0:48")
format(round_date(as.POSIXct(paste("1900-01-01 ", x)), unit="15 mins"), "%M")
1) times Convert to times class, round it and then convert back to character. The hour must be less than 24 but that seems to be the case in the question.
library(chron)
x <- c("0:03", "0:18", "0:33", "0:48") # input
sub(":..$", "", round(times(paste0(x, ":00")), "00:15:00"))
## [1] "00:00" "00:15" "00:30" "00:45"
2) Base R Convert to difftime and then numeric minutes, round it and finally display in required form.
mins <- 15 * round(as.double(as.difftime(x, format = "%H:%M"), "mins") / 15)
format(as.POSIXct(60 * mins, origin = "1970-01-01", tz = "GMT"), "%H:%M") ###
## [1] "00:00" "00:15" "00:30" "00:45"
2a) A base R solution not using difftime or POSIXct is:
mins <- with(read.table(text = x, sep = ":"), 15 * round((60 * V1 + V2) / 15))
sprintf("%02d:%02d", mins %/% 60, mins %% 60)
## [1] "00:00" "00:15" "00:30" "00:45"
I am trying to convert milliseconds to hh:mm format. I tried this below:
x<-c(3159763, 2839300, 3821900)
t.adj <- 0
final <- strftime(as.POSIXlt.numeric(x/1000, format="%OS", origin="1970-01-01") - t.adj*3600,
format="%R", tz="GMT")
> final
[1] "00:52" "00:47" "01:03"
The issue here is the first element actual value is 52 mins 38sec so since it passes halfway, it should be 53 mins as 00:53. The second element is 47min 19sec so it can stay as 00:47 and the last one is 1 H 3 Min 41 s so it should be printed 01:04.
Does anyone have any idea to fix it in this function or possibly have another solution to this rounding issue?
Thanks!
You can use round_date from the lubridate package to round to the nearest minute after converting milliseconds to a POSIXct object and before formatting it with strftime
library(lubridate)
x <- c(3159763, 2839300, 3821900)
y <- as.POSIXct.numeric(x/1000, origin = '1970-01-01')
z <- lubridate::round_date(y, unit = 'minute')
strftime(z, format = '%R', tz='GMT')
[1] "00:53" "00:47" "01:04"
with(as.POSIXlt(x/1000, 'GMT', Sys.Date()),sprintf("%02d:%02d", hour,min+sec%/%30))
[1] "00:53" "00:47" "01:04"
EDIT:
You could do:
sprintf("%02d:%02d",(y<-round(x / 60000)) %/% 60, y %% 60)
In the question "average time in a column in hr:min:sec format" the following example is given:
Col_Time = c('03:08:20','03:11:30','03:22:18','03:27:39')
library(chron)
mean(times(Col_Time))
[1] 03:17:27
How can I get hr:min:sec as result for the standard deviation? If I use the R function sd, the result looks like that:
sd(times(Col_Time))
[1] 0.006289466
sd is operating on the number internally representing the time (days for chron::times, seconds for hms and POSIXct, settable for difftime), which is fine. The only problem is that it is dropping the class from the result so it isn't printed nicely. The solution, then, is just to convert back to the time class afterwards:
x <- c('03:08:20','03:11:30','03:22:18','03:27:39')
chron::times(sd(chron::times(x)))
#> [1] 00:09:03
hms::as.hms(sd(hms::as.hms(x)))
#> 00:09:03.409836
as.POSIXct(sd(as.POSIXct(x, format = '%H:%M:%S')),
tz = 'UTC', origin = '1970-01-01')
#> [1] "1970-01-01 00:09:03 UTC"
as.difftime(sd(as.difftime(x, units = 'secs')),
units = 'secs')
#> Time difference of 543.4098 secs
You can use lubridate package. The hms function will convert time from characters to HMS format. Then use seconds to convert to seconds and calculate mean/sd. Finally, use seconds_to_period to get the result in HMS format.
library(lubridate)
Col_Time = c('03:08:20','03:11:30','03:22:18','03:27:39')
#Get the mean
seconds_to_period(mean(seconds(hms(Col_Time))))
# [1] "3H 17M 26.75S"
#Get the sd
seconds_to_period(sd(seconds(hms(Col_Time))))
#[1] "9M 3.40983612739285S"
I have a bunch of datetime data and I'd like to see if there is any weekly pattern in it. So I'd like to compute the elapsed time (in seconds) since the beginning of the week with R.
How can I do that? I did the same thing for a daily pattern using difftime(time,as.Date(time)) but I can't use the same trick for the week as there is no as.Week().
You can do it in base R, and you already gave yourself the answer: difftime() with a proper offset.
Even midnight is good enough as you simply need to add dayOfTheWeek * 24 * 60 * 60 to is, and dayOfTheWeek is a field in POSIXlt.
If you want higher-end helper packages, my RcppBDT has a few functions from Boost Date_Time too.
Illustration:
R> now <- Sys.time()
R> midnight <- trunc(now, "days") # elegant way to get midnight; thanks #flodel
R> today <- as.POSIXlt(Sys.Date())
R> today$wday # it is Sunday
[1] 0
R>
R> difftime(now, midnight, unit="secs")
Time difference of 56630.6 secs
R>
So you could add today$wday * 24 * 60 * 60
R> as.numeric(difftime(now, midnight, unit="secs")) + today$wday*24*60*60
[1] 56630.6
R>
Here's my solution as well:
secs.in.week <- function(t) {
d <- as.integer(format(t, "%w"))
d <- ifelse(d, d-1, 6)
weekstart <- as.POSIXct(as.Date(t)-d) - 2 * 3600 # Convert UTC -> Local time. I'm on UTC+2h
as.numeric(difftime(t,weekstart), units="secs")
}