当一个cron作业将被再下一次执行计算作业、将被、再下、cron

2023-09-10 23:02:08 作者:宝藏男孩王源

我有一个cron时间的定义

I have a cron "time definition"

1 * * * * (every hour at xx:01)
2 5 * * * (every day at 05:02)
0 4 3 * * (every third day of the month at 04:00)
* 2 * * 5 (every minute between 02:00 and 02:59 on fridays)

和我有一个Unix时间戳。

And I have an unix timestamp.

时有一个明显的方式找到(计算)下一次(即定的时间戳之后)的工作是由于被执行?

Is there an obvious way to find (calculate) the next time (after that given timestamp) the job is due to be executed?

我使用PHP,但问题应该是相当的语言无关。

I'm using PHP, but the problem should be fairly language-agnostic.

[更新]

类 PHP解析器的Cron (雷建议)计算的最后一次cron作业应该被执行,而不是下一个时间

The class "PHP Cron Parser" (suggested by Ray) calculates the LAST time the CRON job was supposed to be executed, not the next time.

为了更方便:在我的情况下的cron时间参数只是绝对的,单一的数字或*。有没有时间范围和没有* / 5的间隔。

To make it easier: In my case the cron time parameters are only absolute, single numbers or "*". There are no time-ranges and no "*/5" intervals.

推荐答案

这基本上是做检查,如果当前时间符合条件的反转。所以是这样的:

This is basically doing the reverse of checking if the current time fits the conditions. so something like:

//Totaly made up language
next = getTimeNow();
next.addMinutes(1) //so that next is never now
done = false;
while (!done) {
  if (cron.minute != '*' && next.minute != cron.minute) {
    if (next.minute > cron.minute) {
      next.addHours(1);
    }
    next.minute = cron.minute;
  }
  if (cron.hour != '*' && next.hour != cron.hour) {
    if (next.hour > cron.hour) {
      next.hour = cron.hour;
      next.addDays(1);
      next.minute = 0;
      continue;
    }
    next.hour = cron.hour;
    next.minute = 0;
    continue;
  }
  if (cron.weekday != '*' && next.weekday != cron.weekday) {
    deltaDays = cron.weekday - next.weekday //assume weekday is 0=sun, 1 ... 6=sat
    if (deltaDays < 0) { deltaDays+=7; }
    next.addDays(deltaDays);
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  if (cron.day != '*' && next.day != cron.day) {
    if (next.day > cron.day || !next.month.hasDay(cron.day)) {
      next.addMonths(1);
      next.day = 1; //assume days 1..31
      next.hour = 0;
      next.minute = 0;
      continue;
    }
    next.day = cron.day
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  if (cron.month != '*' && next.month != cron.month) {
    if (next.month > cron.month) {
      next.addMonths(12-next.month+cron.month)
      next.day = 1; //assume days 1..31
      next.hour = 0;
      next.minute = 0;
      continue;
    }
    next.month = cron.month;
    next.day = 1;
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  done = true;
}

我可能已经写了一个有点倒退。此外,它可以有很多更短,如果在每一个主要的,如果不是这样做的大于检查您只是一个增加当前的时间等级,并设置较小的时候成绩为0,则继续;但是,那么您会循环多了很多。像这样:

I might have written that a bit backwards. Also it can be a lot shorter if in every main if instead of doing the greater than check you merely increment the current time grade by one and set the lesser time grades to 0 then continue; however then you'll be looping a lot more. Like so:

//Shorter more loopy version
next = getTimeNow().addMinutes(1);
while (true) {
  if (cron.month != '*' && next.month != cron.month) {
    next.addMonths(1);
    next.day = 1;
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  if (cron.day != '*' && next.day != cron.day) {
    next.addDays(1);
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  if (cron.weekday != '*' && next.weekday != cron.weekday) {
    next.addDays(1);
    next.hour = 0;
    next.minute = 0;
    continue;
  }
  if (cron.hour != '*' && next.hour != cron.hour) {
    next.addHours(1);
    next.minute = 0;
    continue;
  }
  if (cron.minute != '*' && next.minute != cron.minute) {
    next.addMinutes(1);
    continue;
  }
  break;
}