In R I want to get the timing in a character string keeping the unit (e.g., if it is sec or min). Please see example code below.
T1 <- Sys.time()
T2 <- Sys.time()
duration <- T2-T1
# Looking at duration show unit:
duration
time_description <- paste("it took: ", round(duration, 2), sep="", col="")
# However int time description the unit is removed
time_description
Preferably without using additional packages.
Thanks in advance.
You can use units to extract the unit from difftime object.
time_description <- sprintf('it took %.2f %s', duration, units(duration))
time_description
#[1] "it took 0.39 secs"
Related
I'm getting weird units after I subtract POSIXct objects, which are returned from two calls to Sys.time(). I'm using Sys.time() to time some call to system()--something like this:
start <- Sys.time()
system("./something_complicated_that_takes_a_while")
end <- Sys.time()
cat(end - start, "seconds\n")
I get 1.81494815872775 seconds, which is very strange. The runtime was closer to 1.8 hours, though. Just to check, I can do this:
start <- Sys.time()
system("/bin/sleep 2")
end <- Sys.time()
cat(end - start, "seconds\n")
and I get 2.002262 seconds, so it's working fine here. Any idea what's going on here?
Your first code is ok , it is 1.8 hours not seconds , here is explanation
a <- Sys.time()
b <- Sys.time() + 2 * 60 *60 # i add 2 hours here
b - a
#> Time difference of 2.000352 hours
above the deference b - a gives the answer in hours not seconds , so if you want to use cat try
cat(b-a , attr(b - a , "units"))
#> 2.000352 hours
and if you want your output in seconds try this
difftime(b , a , units = "secs")
#> Time difference of 7201.266 secs
Although there seem to be numerous posts concerned with this issue or related issues, I could not find a post providing a solution in R.
The problem should be easy to solve once you know how to do it: I have vectors with milliseconds. I'd like to mutate them into hours, minutes, seconds (with three decimals). For example:
x <- c(29, 300, 1000, 213451)
The expected result is this:
# "00:00:00.029" "00:00:00.300" "00:00:01.000" "00:03:33.451"
What I've tried so far is this convoluted series of operations:
hrs = x / (60 * 60 * 1000)
mins = (hrs %% 1) * 60
secs <- sprintf(((mins %% 1) * 60), fmt = '%#.3f')
paste(trunc(hrs), trunc(mins), secs, sep = ":")
[1] "0:0:0.029" "0:0:0.300" "0:0:1.000" "0:3:33.451"
The result is better than nothing but still at a remove from the expected result and, what's more, the code to get there is anything but straightforward or elegant.
What's a quicker and more elegant way to convert milliseconds into the timestamp format?
EDIT:
Alternatively, what I've tried is this:
library(chron)
times(x / (24 * 60 * 60 * 1000))
But this fails to print the decimals.
You can set "%OSn" to give the seconds truncated to n decimal places, where n is between 0 and 6.
format(as.POSIXct(x / 1000, "UTC", origin = "1970-01-01"), "%H:%M:%OS3")
# [1] "00:00:00.029" "00:00:00.300" "00:00:01.000" "00:03:33.450"
I can run a piece of code for 5 or 10 seconds using the following code:
period <- 10 ## minimum time (in seconds) that the loop should run for
tm <- Sys.time() ## starting data & time
while(Sys.time() - tm < period) print(Sys.time())
The code runs just fine for 5 or 10 seconds. But when I replace the period value by 60 for it to run for a minute, the code never stops. What is wrong?
As soon as elapsed time exceeds 1 minute, the default unit changes from seconds to minutes. So you want to control the unit:
while (difftime(Sys.time(), tm, units = "secs")[[1]] < period)
From ?difftime
If ‘units = "auto"’, a suitable set of units is chosen, the
largest possible (excluding ‘"weeks"’) in which all the absolute
differences are greater than one.
Subtraction of date-time objects gives an object of this class, by
calling ‘difftime’ with ‘units = "auto"’.
Alternatively use proc.time, which measures various times ("user", "system", "elapsed") since you started your R session in seconds. We want "elapsed" time, i.e., the wall clock time, so we retrieve the 3rd value of proc.time().
period <- 10
tm <- proc.time()[[3]]
while (proc.time()[[3]] - tm < period) print(proc.time())
If you are confused by the use of [[1]] and [[3]], please consult:
How do I extract just the number from a named number (without the name)?
How to get a matrix element without the column name in R?
Let me add some user-friendly reproducible examples. Your original code with print inside a loop is quite annoying as it prints thousands of lines onto the screen. I would use Sys.sleep.
test.Sys.time <- function(sleep_time_in_secs) {
t1 <- Sys.time()
Sys.sleep(sleep_time_in_secs)
t2 <- Sys.time()
## units = "auto"
print(t2 - t1)
## units = "secs"
print(difftime(t2, t1, units = "secs"))
## use '[[1]]' for clean output
print(difftime(t2, t1, units = "secs")[[1]])
}
test.Sys.time(5)
#Time difference of 5.005247 secs
#Time difference of 5.005247 secs
#[1] 5.005247
test.Sys.time(65)
#Time difference of 1.084357 mins
#Time difference of 65.06141 secs
#[1] 65.06141
The "auto" units is very clever. If sleep_time_in_secs = 3605 (more than an hour), the default unit will change to "hours".
Be careful with time units when using Sys.time, or you may be fooled in a benchmarking. Here is a perfect example: Unexpected results in benchmark of read.csv / fread. I had answered it with a now removed comment:
You got a problem with time units. I see that fread is more than 20 times faster. If fread takes 4 seconds to read a file, read.csv takes 80 seconds = 1.33 minutes. Ignoring the units, read.csv is "faster".
Now let's test proc.time.
test.proc.time <- function(sleep_time_in_secs) {
t1 <- proc.time()
Sys.sleep(sleep_time_in_secs)
t2 <- proc.time()
## print user, system, elapsed time
print(t2 - t1)
## use '[[3]]' for clean output of elapsed time
print((t2 - t1)[[3]])
}
test.proc.time(5)
# user system elapsed
# 0.000 0.000 5.005
#[1] 5.005
test.proc.time(65)
# user system elapsed
# 0.000 0.000 65.057
#[1] 65.057
"user" time and "system" time are 0, because both CPU and the system kernel are idle.
I can run a piece of code for 5 or 10 seconds using the following code:
period <- 10 ## minimum time (in seconds) that the loop should run for
tm <- Sys.time() ## starting data & time
while(Sys.time() - tm < period) print(Sys.time())
The code runs just fine for 5 or 10 seconds. But when I replace the period value by 60 for it to run for a minute, the code never stops. What is wrong?
As soon as elapsed time exceeds 1 minute, the default unit changes from seconds to minutes. So you want to control the unit:
while (difftime(Sys.time(), tm, units = "secs")[[1]] < period)
From ?difftime
If ‘units = "auto"’, a suitable set of units is chosen, the
largest possible (excluding ‘"weeks"’) in which all the absolute
differences are greater than one.
Subtraction of date-time objects gives an object of this class, by
calling ‘difftime’ with ‘units = "auto"’.
Alternatively use proc.time, which measures various times ("user", "system", "elapsed") since you started your R session in seconds. We want "elapsed" time, i.e., the wall clock time, so we retrieve the 3rd value of proc.time().
period <- 10
tm <- proc.time()[[3]]
while (proc.time()[[3]] - tm < period) print(proc.time())
If you are confused by the use of [[1]] and [[3]], please consult:
How do I extract just the number from a named number (without the name)?
How to get a matrix element without the column name in R?
Let me add some user-friendly reproducible examples. Your original code with print inside a loop is quite annoying as it prints thousands of lines onto the screen. I would use Sys.sleep.
test.Sys.time <- function(sleep_time_in_secs) {
t1 <- Sys.time()
Sys.sleep(sleep_time_in_secs)
t2 <- Sys.time()
## units = "auto"
print(t2 - t1)
## units = "secs"
print(difftime(t2, t1, units = "secs"))
## use '[[1]]' for clean output
print(difftime(t2, t1, units = "secs")[[1]])
}
test.Sys.time(5)
#Time difference of 5.005247 secs
#Time difference of 5.005247 secs
#[1] 5.005247
test.Sys.time(65)
#Time difference of 1.084357 mins
#Time difference of 65.06141 secs
#[1] 65.06141
The "auto" units is very clever. If sleep_time_in_secs = 3605 (more than an hour), the default unit will change to "hours".
Be careful with time units when using Sys.time, or you may be fooled in a benchmarking. Here is a perfect example: Unexpected results in benchmark of read.csv / fread. I had answered it with a now removed comment:
You got a problem with time units. I see that fread is more than 20 times faster. If fread takes 4 seconds to read a file, read.csv takes 80 seconds = 1.33 minutes. Ignoring the units, read.csv is "faster".
Now let's test proc.time.
test.proc.time <- function(sleep_time_in_secs) {
t1 <- proc.time()
Sys.sleep(sleep_time_in_secs)
t2 <- proc.time()
## print user, system, elapsed time
print(t2 - t1)
## use '[[3]]' for clean output of elapsed time
print((t2 - t1)[[3]])
}
test.proc.time(5)
# user system elapsed
# 0.000 0.000 5.005
#[1] 5.005
test.proc.time(65)
# user system elapsed
# 0.000 0.000 65.057
#[1] 65.057
"user" time and "system" time are 0, because both CPU and the system kernel are idle.
I am using R and Rstudio. I am a complete newbie.
I mean to write to file the time elapsed in each iteration of a loop. So I define three variables: start <- Sys.time() (at the beginning of code), and similarly prevtime and currtime (at the beginning and end of each iteration).
The values of variables are (e.g., last iteration)
> currtime - start
Time difference of 5.486106 mins
> currtime - prevtime
Time difference of 1.239183 secs
R automatically sets units. But then if I execute
> write( currtime - start, file = "test.Rout", append = F )
> write( currtime - prevtime, file = "test.Rout", append = T )
I get in test.Rout
5.486106
1.239183
with no units.
Is there any way to force the units for writing to file (write), e.g., all to seconds, so there is no ambiguity?
I guess I could scan the output of currtime - prevtime and find the units, but I am sure there is a very simple way to do this.
I guess I could also use system.time(*{mycommands}*), but I think it would be easier to have variables assigned, since I might want to define time points in the middle of my loop, and get various time differences.
Try isolating the units and combining them to the time value:
start <- Sys.time()
currtime <- start + 180
diff.time <- currtime - start
timediff <- paste(diff.time, attr(diff.time, "units"))
write(timediff, file = "test.Rout", append = F )
Explanation
The object diff.time is of the class difftime. When you write it to file, the attributes are being dropped. Check str(diff.time) to see the structure:
str(diff.time)
Class 'difftime' atomic [1:1] 3
..- attr(*, "units")= chr "mins"
The attribute we are looking for is "units" and its value is "mins". We can extract that attribute and paste it to the time difference.
Checking attributes
We can check the attributes with attr("object", "name of attribute"):
attr(diff.time, "units")
[1] "mins"
We can also check with attributes and subset list-style:
attributes(diff.time)
$units
[1] "mins"
$class
[1] "difftime"