Working with POSIXct
objects in R can be slow. To floor a million timestamps down to the nearest quarter-of-hour takes ~7 seconds on my laptop using the usual functions: lubridate::floor_date()
and clock::date_floor()
.
Here is a base R function that achieves the same result in 10 ms:
round_time = function(x, precision, method = round) {
if ("POSIXct" %in% class(x) == FALSE)
stop("x must be POSIXct")
tz = attributes(x)$tzone
secs_rounded = method(as.numeric(x) / precision) * precision
as.POSIXct(secs_rounded, tz = tz, origin = "1970-01-01")
}
You can use it like this:
# A million timestamps:
times = Sys.time() + rnorm(10^6, sd = 10^8)
# Round down to nearest quarter-of-hour
round_time(times, precision = 60*15, method = floor)
# Round up to nearest 5 seconds
round_time(times, precision = 5, method = ceiling)
# Round to the nearest minute (method = round is default):
round_time(times, precision = 60)
Let’s benchmark it against lubridate and clock to verify the ~700x speedup:
times = Sys.time() + rnorm(10^6, sd = 10^8)
bench::mark(round_time(times, precision = 60*15, method = floor))
bench::mark(clock::date_floor(times, precision = "minute", n = 15))
bench::mark(lubridate::floor_date(times, unit = "15 minutes"))