Search code examples
javascriptcron

The difference in the format for cron is not entirely clear


It confuses me a little that 6 ranges are shown here: https://www.npmjs.com/package/cron?activeTab=readme, and for example here https://crontab.guru/ or here https://cronitor.io/guides/cron-jobs?utm_source=crontabguru&utm_campaign=cron_reference => 5(!)

from minutes and from seconds... If I understand correctly, this is not related to the cron version.

my package.json => "cron": "^1.7.0",

I want to build a task that runs every first day of the month =>
const myJob = new CronJob('0 0 0 1 * *', async () => {});
is correct? and why 5 or 6 symbols used in different examples?

Thanks for any help!


Solution

  • The Cron tool accepts 6 fields, 1 more than the standard cron expressions allow. This is similar to the cron expressions used by Spring

     # ┌────────────── second (optional)
     # │ ┌──────────── minute
     # │ │ ┌────────── hour
     # │ │ │ ┌──────── day of month
     # │ │ │ │ ┌────── month
     # │ │ │ │ │ ┌──── day of week
     # │ │ │ │ │ │
     # │ │ │ │ │ │
     # * * * * * *
    

    It will accept standard, 5 field cron expressions as well, you simply can omit the seconds field.

    Standard Cron expression:

    1 2 3 4 5 Index
    - - - - -
    * * * * * command to be executed
    - - - - -
    | | | | |
    | | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
    | | | ------- Month (1 - 12)
    | | --------- Day of month (1 - 31)
    | ----------- Hour (0 - 23)
    ------------- Minute (0 - 59)
    

    This just allows a little more flexibility. For example, you can run a job every 10 seconds:

    */10 * * * * *
    

    You can set seconds to 0 if you don't need to use this field.

    For example, to run every 5 minutes:

    0 */5 * * * *
    

    Or, you can simply omit the seconds parameter

    */5 * * * *
    

    In your case, you wish to run a job on the first day of each month, so the expression you've used above is correct. You can get the next N dates from the API to verify when the job will run. Like so:

    const CronJob = require('cron').CronJob;
    const job = new CronJob(
        '0 0 0 1 * *',
        function() {
            console.log(new Date().toTimeString(), 'Job running');
        },
        null,
        true
    );
    
    console.log('Next dates:', job.nextDates(10).map(dt => dt.toFormat('yyyy-MM-dd HH:mm:ss')));
    

    This will look like:

    [
      '2023-07-01 00:00:00',
      '2023-08-01 00:00:00',
      '2023-09-01 00:00:00',
      '2023-10-01 00:00:00',
      '2023-11-01 00:00:00',
      '2023-12-01 00:00:00',
      '2024-01-01 00:00:00',
      '2024-02-01 00:00:00',
      '2024-03-01 00:00:00',
      '2024-04-01 00:00:00'
    ]
    

    So your job will run at midnight local time on the first of each month. You could also set an IANA timezone if you wish the job to run at the specified time in that timezone.

    I find it useful to log periodically the next runtime of each cronjob, for example:

    setInterval(() => console.log('Cron job will next run at ' + job.nextDate().toFormat('yyyy-MM-dd HH:mm:ss')), 60000);
    

    See also: https://en.wikipedia.org/wiki/Cron#Cron_expression