convert cron to timestamps in R

1k Views Asked by At

I am looking for a way to convert cron information into a list of timestamps, using R. is there an easy way to do do?

Given the crontab and a start date and an end date, I would like to obtain the list of trigger timestamps during these 2 dates.

I have not found any package that specifically deals with CRON info, but maybe somebody has already had this problem?

Thanks

1

There are 1 best solutions below

0
On BEST ANSWER

I assume you mean the crontab(5) format. I know of no library parsing this information, but the following snippet should get you started:

splitre <- function(p, s) {
  s <- as.character(s)
  stopifnot(length(s) == 1)
  m <- gregexpr(p, s)[[1]]
  if (m[1] == -1) return(s);
  return(substring(s, c(1, m + attr(m, "match.length")), c(m - 1, nchar(s))))
}

ranges <- function(desc, lo, hi, name) {
  res <- integer(0)
  for (range in splitre(",", desc)) {
    m <- regexec("^(?:\\*|(?:(\\d+)(?:-(\\d+))?))(?:/(\\d+))?$", range)
    m <- regmatches(range, m)[[1]]
    m[m == ""] <- NA
    m[1] <- NA
    m <- as.integer(m)
    if (is.na(m[2])) r <- lo:hi
    else if (is.na(m[3])) r <- m[2]
    else r <- m[2]:m[3]
    if (!is.na(m[4])) {
      stopifnot(m[4] > 0)
      r <- r[rep(c(TRUE, rep(FALSE, m[4] - 1)), length.out = length(r))]
    }
    res <- c(res, r)
  }
  res <- data.frame(res)
  names(res) <- name
  return(res)
}

ct2df <- function(lines) {
  res <- data.frame()
  for (line in lines) {
    if (regexpr("^ *(#|$)", line) == 1) continue
    parts <- splitre(" +", line)
    stopifnot(length(parts) > 5)
    j <- ranges(parts[1], 0, 59, "minute")
    j <- merge(j, ranges(parts[2], 0, 23, "hour"))
    j <- merge(j, ranges(parts[3], 1, 31, "day.of.month"))
    j <- merge(j, ranges(parts[4], 1, 12, "month"))
    j <- merge(j, ranges(parts[5], 0, 6, "day.of.week"))
    res <- rbind(res, j)
  }
  return(res)
}

print(ct2df("* 1-2,5 1-10/2 */3 1 command"))

This is not perfect, as it won't handle names for months or day of week, and it won't handle the special case about day of month vs. day of week, which requires treatment of * as more than a simple range.

Note: The day of a command's execution can be specified by two fields - day of month, and day of week. If both fields are restricted (ie, aren't *), the command will be run when either field matches the current time. For example, 30 4 1,15 * 5 would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.

The resulting data frame can be turned into a list of timestamps, but I haven't written code for that. Perhaps someone else will, building on this post. The simple but slow method would be iterating over possible timestamps minute by minute, ans for every timestamp see whether a row from the computed data frame matches that value. Faster solutions would iterate on a day-by-day basis, use that to work out day of week and day of month, and then take times from all rows matching that day.