harrisiirak / cron-parser

Node.js library for parsing crontab instructions
MIT License
1.32k stars 156 forks source link

Unexpected behavior when the step size plus the starting value is higher than the maximal expected value #331

Closed davilavillalobosa closed 1 year ago

davilavillalobosa commented 1 year ago

When the step size plus the starting point is greater than the maximal expected value, then the next or prev function will return unexpected values.

Regardless of the starting point, I would expect the following cron expressions to be equal given the same current date.

In the example, the maximal month is 12. The first cron expression '0 0 0 1 2/6 ?' returns the expected prev and next dates. But the second cron expression '0 0 0 1 8/6 ?' exceeds the maximal value (8 + 6 > 12) and therefore returns an unexpected value.

Steps to Reproduce

import cronParser from 'cron-parser';

const cronExpressions = ['0 0 0 1 2/6 ?', '0 0 0 1 8/6 ?'];
const startingDate = '2023-05-01T00:00:00.000Z';

for (const cronExpression of cronExpressions) {
  console.log('-----');
  console.log(`Given cron expression [${cronExpression}]`);
  console.log('-----');
  console.log(`Given date ${new Date(startingDate).toISOString()}`);
  console.log('-----');

  console.log('Using next()');
  console.log('-----');

  const cronNext = cronParser.parseExpression(cronExpression, {
    currentDate: startingDate,
    utc: true,
  });
  console.log('current \t', cronNext.next().toISOString());
  console.log('next 1 \t', cronNext.next().toISOString());
  console.log('next 2 \t', cronNext.next().toISOString());
  console.log('next 3 \t', cronNext.next().toISOString());

  console.log('-----');
  console.log('Using prev()');
  console.log('-----');
  const cronPrev = cronParser.parseExpression(cronExpression, {
    currentDate: startingDate,
    utc: true,
  });
  console.log('current \t', cronPrev.prev().toISOString());
  console.log('prev 1 \t', cronPrev.prev().toISOString());
  console.log('prev 2 \t', cronPrev.prev().toISOString());
  console.log('prev 3 \t', cronPrev.prev().toISOString());
}

Result

Given cron expression [0 0 0 1 2/6 ?]

Given date 2023-05-01T00:00:00.000Z

Using next()

current 2023-08-01T00:00:00.000Z next 1 2024-02-01T00:00:00.000Z next 2 2024-08-01T00:00:00.000Z next 3 2025-02-01T00:00:00.000Z

Using prev()

current 2023-02-01T00:00:00.000Z prev 1 2022-08-01T00:00:00.000Z prev 2 2022-02-01T00:00:00.000Z prev 3 2021-08-01T00:00:00.000Z

Given cron expression [0 0 0 1 8/6 ?]

Given date 2023-05-01T00:00:00.000Z

Using next()

current 2023-08-01T00:00:00.000Z next 1 2024-08-01T00:00:00.000Z next 2 2025-08-01T00:00:00.000Z next 3 2026-08-01T00:00:00.000Z

Using prev()

current 2022-08-01T00:00:00.000Z prev 1 2021-08-01T00:00:00.000Z prev 2 2020-08-01T00:00:00.000Z prev 3 2019-08-01T00:00:00.000Z

The same issue can also be reproduced with the following cron expressions '0 10/20 ?', '0 50/20 ?'

I'm currently reducing the month size with the following function:

const month = 1;
const stepSize = 6;
const newMonth =
  month <= stepSize
  ? month
  : month % stepSize !== 0
  ? month % stepSize
  : stepSize;

Is this a bug?

harrisiirak commented 1 year ago

Hi @davilavillalobosa!

But the second cron expression '0 0 0 1 8/6 ?' exceeds the maximal value (8 + 6 > 12) and therefore returns an unexpected value.

Currently it's expected behaviour. 8/6 will be expanded to 8 - 12 (and 2/6 will be expanded to 2 - 12 and matches 2,8) and matches 8 only as this is in the range. It's also non-standard way to use repeats, but if you check it against some other implementation (https://crontab.guru for example), it behaves the same.

Relates to this: https://github.com/harrisiirak/cron-parser/issues/156