Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method for comparing date against cron pattern #153

Open
andeersg opened this issue Mar 26, 2019 · 5 comments
Open

Add method for comparing date against cron pattern #153

andeersg opened this issue Mar 26, 2019 · 5 comments

Comments

@andeersg
Copy link

I was trying to find a library that allowed my to check the current time against a cron pattern to see if it matches. So far this library is the one closest to what I want, but I had some problems with milliseconds and rounding errors when I tried to convert it to seconds.

The closest I got was to create this function:

function timeMatches(expression, date) {
  var interval = parser.parseExpression(expression);
  var data = interval._fields;
  
  if (!data.second.includes(date.getSeconds())) {
    return false;
  }
  if (!data.minute.includes(date.getMinutes())) {
    return false;
  }
  if (!data.hour.includes(date.getHours())) {
    return false;
  }
  if (!data.dayOfMonth.includes(date.getDate())) {
    return false;
  }
  if (!data.month.includes(date.getMonth() + 1)) {
    return false;
  }
  if (!data.dayOfWeek.includes(date.getDay())) {
    return false;
  }
  return true;
}

It allows me to do to:

if (timeMatches('* 20 * * * *', new Date()) {
  // This is true when minute is 20.
}

Could it be possible to add a method like this to the library? (Not saying my checks are the best, but something to validate current date against pattern).

@harrisiirak
Copy link
Owner

@andeersg there was some (similar) discussion regards implementing validation interface for such cases in #145.

The idea itself is great, but I'm not completely sure how reasonable it's to add this into core (maybe separate cron-data-validation library or something like that). I must digest this a little bit.

@andeersg
Copy link
Author

Yes I'm not the one to say if this is a feature that belongs here or not. But of all the libraries I found this was the one I thought was the most fitting one, since all the others focus on running functions at cron not parsing the cron string.

But for now I can use my function, so take your time to consider it, and let me know if you need input or something.

@Eric24
Copy link

Eric24 commented Oct 28, 2019

A couple of thoughts:

  1. As mentioned in Expose _fields as public api #145, exposing _fields would make this cleaner that accessing _fields directly. Maybe just as a fields() function?
  2. A simple test() or match() function would serve this purpose--pass in an object that contains one or more props that match the array names in _fields (only those passed in are tested, which gives the caller the ability to set the level of granularity they are interested in); each can be a single number or an array of numbers; the function returns true if all of the props' values match what's in _fields. This serves the OP's use-case, and I think it's also generic enough to be a reasonable addition to the library. As the OP mentions, there is no library (that I could find, either) that has the functionality of being able to parse a cron string and compare it to a specific moment in time.

PS - For 2, an alternative might be to pass in a date and a "resolution" prop (a string value of second|minute|hour|day|month|weekday). The concept is the same, it's just a different way to specifying the "test" date and the level of granularity.

@Eric24
Copy link

Eric24 commented Feb 23, 2020

Here's what I ended up doing. Since you already have a dependency on moment-timezone, it's a pretty lightweight function:

function match(expression, date, scope = 'second') {
  scope = ['second', 'minute', 'hour', 'day', 'month', 'weekday'].indexOf(scope.toLowerCase());
  try {
    let data = cron.parseExpression(expression)._fields;

    if (scope <= 0 && !data.second.includes(date.second())) return false;
    if (scope <= 1 && !data.minute.includes(date.minute())) return false;
    if (scope <= 2 && !data.hour.includes(date.hour())) return false;
    if (scope <= 3 && !data.dayOfMonth.includes(date.date())) return false;
    if (scope <= 4 && !data.month.includes(date.month() + 1)) return false;
    if (scope <= 5 && !data.dayOfWeek.includes(date.day())) return false;

    return true;
  } catch (e) {
    return false;
  }
}

@chengB12
Copy link

chengB12 commented Oct 27, 2022

This is what I do

export function isTimeMatches(cronExpression: string, date: Date): boolean {
    const currentDate = date.valueOf()
    const parsed = cronParser.parseExpression(cronExpression, {
        // this is bug of cron-parser, if date is exact match current cronExpression,
        // current date will be missing from parsed, neither prev() nor next() would have current date
        // thus we need to push currentDate back a little
        currentDate: new Date(date).setSeconds(-1),
        tz: 'UTC',
    })
    return parsed.next().toDate().valueOf() === currentDate
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants