#' @title{TimeUnitsToSeconds}
#' @description Converts a number of minutes, hours, days, weeks or months to seconds.
#' @param x The period expressed in \code{units} units.
#' @param units The time unit, which can be seconds, minutes, hours, days, weeks or months.
#' @importFrom lubridate %m+%
#' @importFrom flipU StopForUserError
#' @export
TimeUnitsToSeconds <- function(x, units = "seconds") {
unit.list <- c("seconds", "minutes", "hours", "days", "weeks", "months")
if (!(units %in% unit.list)) {
StopForUserError("Unrecognized units.")
}
if (units == "months")
{
today <- Sys.Date()
future <- today %m+% months(x)
return((future - today) * 3600 * 24)
}
secs <- c(1, 60, 3600, 3600 * 24, 3600 * 24 * 7)
return(x * secs[match(units, unit.list)])
}
#' @title{RefreshIfOlderThan}
#' @description An R object will be automatically recalculated if its output is older than the duration specified.
#' Recalculation will only occur when someone looks at that R object, or something that is calculated using it.
#' @param x The period expressed in \code{units} units.
#' @param units The time unit. One of \code{"seconds"}, \code{"minutes"}, \code{"hours"}, \code{"days"},
#' \code{"weeks"} or \code{"months"}.
#' @details If \code{units} = \code{"months"}, then \code{x} must be an integer.
#' @examples
#' RefreshIfOlderThan(2, "hours")
#' RefreshIfOlderThan(1, "weeks")
#' @seealso \code{\link{UpdateEvery}}, \code{\link{UpdateAt}}
#' @importFrom flipU StopForUserError
#' @export
RefreshIfOlderThan <- function(x, units = "seconds") {
seconds <- TimeUnitsToSeconds(x, units)
if (seconds < 600)
StopForUserError("Update frequency must be at least 600 seconds.")
message(paste("R output expires in", seconds, "seconds"))
}
#' @title{UpdateEvery}
#' @description Sets a period of time, after which an R object is woken and updated.
#' @param x The period expressed in \code{units} units.
#' @param units The time unit. One of \code{"seconds"}, \code{"minutes"}, \code{"hours"}, \code{"days"},
#' \code{"weeks"} or \code{"months"}.
#' @param options Either \code{"wakeup"} in which case the object is updated even if its document is closed,
#' or \code{"snapshot"} which also updates any embedded snapshots of the document, or \code{"only when open"}
#' which only updates when the document is open.
#' @details If \code{units} = \code{"months"}, then \code{x} must be an integer. The update time
#' will roll back to the last day of the previous month if no such day exists \code{x} months
#' forward from today.
#' @examples
#' UpdateEvery(5, "days", "snapshot")
#' UpdateEvery(1, "months", NULL)
#' @seealso \code{\link{RefreshIfOlderThan}}, \code{\link{UpdateAt}}
#' @importFrom flipU StopForUserError
#' @export
UpdateEvery <- function(x, units = "seconds", options = "snapshot") {
seconds <- TimeUnitsToSeconds(x, units)
if (seconds < 600)
StopForUserError("Update frequency must be at least 600 seconds.")
message.string <- paste0("R output expires in ", seconds, " seconds")
message.string <- appendUpdateOption(message.string, options)
message(message.string)
}
#' Regularly update an R object starting at a particular Date/Time
#'
#' Sets date and time after which an R object is woken and updated, then a
#' frequency for periodic updates.
#' @param x Character vector to be parsed into the first update date and time by
#' \code{\link{AsDateTime}}. Each subsequent update occurs based on the
#' \code{frequency} and \code{units} after \code{x}.
#' @inheritParams AsDateTime
#' @param units The time unit for regular updates, which can be seconds, minutes, days, weeks or months.
#' @param frequency How often the regular updates should occur, expressed in \code{units} units.
#' @param options Either \code{"wakeup"} in which case the object is updated even if its document is closed,
#' or \code{"snapshot"} which also updates any embedded snapshots of the document, or \code{"only when open"}
#' which only updates when the document is open.
#' @details If \code{units} = "months" then \code{frequency} must be an integer. The update time
#' will roll back to the last day of the previous month if no such day exists after stepping
#' forwards a multiple of \code{frequency} months.
#' @references See \href{https://en.wikipedia.org/wiki/List_of_tz_database_time_zones}{Wikipedia} for a list of time zones.
#' @examples
#' ## Update once every month starting on 31-1-2017 at 10:00:00
#' UpdateAt("31-1-2017 10:00:00", time.zone = "Australia/Sydney", units = "months", frequency = 1,
#' options = "wakeup")
#'
#' ## Update every 3 days starting on 05-15-2017 at 18:00:00
#' UpdateAt("05-15-2017 18:00:00", us.format = TRUE, time.zone = "America/New_York",
#' units = "days", frequency = 3, options = "snapshot")
#' @seealso \code{\link{RefreshIfOlderThan}}, \code{\link{UpdateEvery}}
#' @importFrom lubridate %m+%
#' @importFrom flipU StopForUserError
#' @export
UpdateAt <- function(x, us.format = FALSE, time.zone = "UTC", units = "days", frequency = 1, options = "snapshot") {
if (TimeUnitsToSeconds(frequency, units) < 600)
StopForUserError("Update frequency must be at least 600 seconds.")
first.update <- AsDateTime(x, us.format = us.format, time.zone = time.zone,
on.parse.failure = "error")
now <- Sys.time()
attr(now, "tzone") <- time.zone
if (now < first.update)
{
secs <- round(difftime(first.update, now, units = "secs"))
}
else # first.update is in the past
{
secs.since.first <- as.numeric(round(difftime(now, first.update, units = "secs")))
if (units != "months")
{
secs.frequency <- round(TimeUnitsToSeconds(frequency, units))
secs <- secs.frequency - (secs.since.first %% secs.frequency)
}
else
{
next.update <- first.update
step <- 0
while (next.update < now)
{
step <- step + frequency
next.update <- first.update %m+% months(step)
}
secs <- round(difftime(next.update, now, units = "secs"))
}
}
message.string <- paste0("R output expires in ", secs, " seconds")
message.string <- appendUpdateOption(message.string, options)
message(message.string)
}
#' @importFrom flipU StopForUserError
appendUpdateOption <- function(message.string, options)
{
if (is.null(options) || options == "snapshot")
message.string <- paste0(message.string, " with wakeup and snapshot")
else if (options == "wakeup")
message.string <- paste0(message.string, " with wakeup")
else if (options == "only when open")
{
# don't need to append anything
}
else
StopForUserError("Unrecognized options: ", options)
message.string
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.