Croner
Trigger functions or evaluate cron expressions in JavaScript or TypeScript. No dependencies. All features. Node. Deno. Bun. Browser.

Try it live on jsfiddle.

Croner - Cron for JavaScript and TypeScript

npm version Codacy Badge NPM Downloads No dependencies MIT License

  • Trigger functions in JavaScript using Cron syntax.
  • Find the first date of the next month, the date of the next Tuesday, etc.
  • Pause, resume, or stop execution after a task is scheduled.
  • Works in Node.js >=7.6 (both require and import), Deno >=1.16 and Bun >=0.2.2.
  • Works in browsers as standalone, UMD or ES-module.
  • Schedule using specific target time zones.
  • Over-run protection with callback
  • Built in error handling with callback
  • Includes TypeScript typings.

Quick examples:

// Basic: Run a function at the interval defined by a cron expression
const job = Cron('*/5 * * * * *', () => {
    console.log('This will run every fifth second');
});

// Enumeration: What dates do the next 100 sundays occur at?
const nextSundays = Cron('0 0 0 * * 7').enumerate(100);
console.log(nextSundays);

// Days left to a specific date
const msLeft = Cron('59 59 23 24 DEC *').next() - new Date();
console.log(Math.floor(msLeft/1000/3600/24) + " days left to next christmas eve");

// Run a function at a specific date/time using a non-local timezone (time is ISO 8601 local time)
// This will run 2023-01-23 00:00:00 according to the time in Asia/Kolkata
Cron('2023-01-23T00:00:00', { timezone: 'Asia/Kolkata' }, () => { console.log('Yay!') });

More examples...

Why another JavaScript cron implementation

Because the existing ones are not good enough. They have serious bugs, use bloated dependencies, do not work in all environments, and/or simply do not work as expected.

croner cronosjs node-cron cron node-schedule
Platforms
Node.js (CommonJS)
Browser (ESMCommonJS)
Deno (ESM)
Features
Over-run protection
Error handling
Typescript typings
dom-AND-dow
dom-OR-dow
Next run
Next n runs
Timezone
Minimum interval
Controls (stop/resume)
Range (0-13)
Stepping (*/5)
Last day of month (L)
In depth comparison of various libraries
croner cronosjs node-cron cron node-schedule
Size
Minified size (KB) 15.5 16.3 16.5 - -
Bundlephobia minzip (KB) 3.6 5.1 5.7 23.9 32.4
Dependencies 0 0 1 1 3
Popularity
Downloads/week [^1] 672K 30K 376K 1574K 804K
Quality
Issues [^1] 0 2 118 ⚠️ 119 ⚠️ 135 ⚠️
Code coverage 99% 98% 100% 81% 94%
Performance
Ops/s 1 2 3 4 5 6 99 952 49 308 N/A ❌ Test failed ❌ 2 299 ⚠️
Ops/s 0 0 0 29 2 * 65 392 17 138 N/A ❌ Test failed ❌ 1 450 ⚠️
Tests 8/8 7/8 0/8 [^4] ❓ 1/8 ⚠️ 7/8
Test 0 0 23 * * * 2022-10-09 00:40 2022-10-09 00:40 N/A 2022-10-09 00:40 2022-10-09 00:40
Test 0 0 0 L 2 * [^2] 2023-02-28 00:00 2023-02-28 00:00 N/A N/A 2023-02-28 00:00
Test 0 0 0 29 2 * 2024-02-29 00:00 2024-02-29 00:00 N/A 2023-03-29 00:00 ❌ 2024-02-29 00:00
Test 0 0 0 29 2 6 [^3] 2048-02-09 00:00 N/A N/A N/A N/A
Test 0 0 0 15 2 * 2023-02-16 00:00 2023-02-16 00:00 N/A 2023-03-15 00:00 ❌ 2023-02-16 00:00
Test 0 0 0 * 10 1 2022-10-10 00:00 2022-10-10 00:00 N/A 2022-11-07 00:00 ❌ 2022-10-10 00:00
Test 0 0 23 31 3 * 2023-03-31 23:00 2023-03-31 23:00 N/A 2023-04-01 23:00 ❌ 2023-03-31 23:00
Test 1 2 3 4 5 6 2023-05-04 03:02 2023-05-04 03:02 N/A 2023-06-03 03:02 ❌ 2023-05-04 03:02

Note

  • Table last updated at 2022-10-23
  • node-cron has no interface to predict when the function will run, so tests cannot be carried out.
  • All tests and benchmarks were carried out using https://github.com/Hexagon/cron-comparison

[^1]: As of 2022-10-08 [^2]: Requires support for L-modifier [^3]: In dom-AND-dow mode, only supported by croner at the moment. [^4]: Node-cron has no way of showing next run time.

Installation

If you are migrating from a different library such as cron or node-cron, or upgrading from a older version of croner, see MIGRATION.md.

Node.js

npm install croner --save

JavaScript

// ESM Import ...
import Cron from "croner";

// ... or CommonJS Require
const Cron = require("croner");

TypeScript

Notes for TypeScript:

  • If using strict eslint rules, specifically new-cap combined with no-new, you need to import and use lowercase cron instead of { Cron }.
import { Cron } from "croner";

const job : Cron = new Cron("* * * * * *", () => {
    console.log("This will run every second.");
});

Bun

bun add croner

Note If you encounter problems during installation, try using bun add croner --backend=copyfile.

import Cron from "croner";

Deno

JavaScript

import Cron from "https://deno.land/x/croner@5.6.4/src/croner.js";

Cron("* * * * * *", () => {
    console.log("This will run every second.");
});

TypeScript

import { Cron } from "https://deno.land/x/croner@5.6.4/src/croner.js";

const _scheduler : Cron = new Cron("* * * * * *", () => {
    console.log("This will run every second.");
});

Browser

Manual

  • Download the latest zipball.
  • Unpack the zip file.
  • Grab croner.min.js (UMD and standalone) or croner.min.mjs (ES-module) from the dist/ folder.

CDN

To use as a UMD-module (stand alone, RequireJS etc.)

<script src="https://cdn.jsdelivr.net/npm/croner@5/dist/croner.min.js"></script>

To use as an ES-module

<script type="module">
    import Cron from "https://cdn.jsdelivr.net/npm/croner@5/dist/croner.min.mjs";

    // ... see usage section ...
</script>

Documentation

Full documentation available at hexagon.github.io/croner.

The short version:

Signature

Cron takes three arguments

const job = Cron("* * * * * *" /* Or a date object, or ISO 8601 local time */ , /*optional*/ { maxRuns: 1 } , /*optional*/ () => {} );

// If function is omitted in constructor, it can be scheduled later
job.schedule((/* optional */ job, /* optional */ context) => {});        

// States
const nextRun = job.next( /*optional*/ previousRun );    // Get a Date object representing next run
const nextRuns = job.enumerate(10, /*optional*/ startFrom ); // Get a array of Dates, containing next 10 runs according to pattern
const prevRun = job.previous( );    
const msToNext = job.msToNext( /*optional*/ previousRun ); // Milliseconds left to next execution
const isRunning = job.running();

// Control scheduled execution
job.pause();                
job.resume();
job.stop();

Options

Key Default value Data type Remarks
name undefined String If you specify a name for the job, Croner will keep a reference to the job in exported array scheduledJobs
maxRuns Infinite Number
catch false Boolean|Function Catch unhandled errors in triggered function. Passing true will silently ignore errors. Passing a callback function will trigger this callback on error.
timezone undefined String Timezone in Europe/Stockholm format
startAt undefined String ISO 8601 formatted datetime (2021-10-17T23:43:00)
in local time (according to timezone parameter if passed)
stopAt undefined String ISO 8601 formatted datetime (2021-10-17T23:43:00)
in local time (according to timezone parameter if passed)
interval 0 Number Minimum number of seconds between triggers.
paused false Boolean If the job should be paused from start.
context undefined Any Passed as the second parameter to triggered function
legacyMode true boolean Combine day-of-month and day-of-week using true = OR, false = AND
unref false boolean Setting this to true unrefs the internal timer, which allows the process to exit even if a cron job is running.
utcOffset undefined number Schedule using a specific utc offset in minutes. This does not take care of daylight savings time, you probably want to use option timezone instead.
protect undefined boolean|Function Enabled over-run protection. Will block new triggers as long as an old trigger is in progress. Pass either true or a callback function to enable

Warning Unreferencing timers (option unref) is only supported by Node.js and Deno. Browsers have not yet implemented this feature, and it does not make sense to use it in a browser environment.

Pattern

The expressions used by Croner are very similar to those of Vixie Cron, but with a few additions and changes as outlined below:

// ┌──────────────── (optional) second (0 - 59)
// │ ┌────────────── minute (0 - 59)
// │ │ ┌──────────── hour (0 - 23)
// │ │ │ ┌────────── day of month (1 - 31)
// │ │ │ │ ┌──────── month (1 - 12, JAN-DEC)
// │ │ │ │ │ ┌────── day of week (0 - 6, SUN-Mon) 
// │ │ │ │ │ │       (0 to 6 are Sunday to Saturday; 7 is Sunday, the same as 0)
// │ │ │ │ │ │
// * * * * * *
  • Croner expressions have the following additional modifiers:

    • ? A question mark is substituted with the time of Croner's initialization. For example ? ? * * * * would be substituted with 25 8 * * * * if the time is <any hour>:08:25 at the time of new Cron('? ? * * * *', <...>). The question mark can be used in any field.
    • L L can be used in the day of the month field to specify the last day of the month.
  • Croner allows you to pass a JavaScript Date object or an ISO 8601 formatted string as a pattern. The scheduled function will trigger at the specified date/time and only once. If you use a timezone different from the local timezone, you should pass the ISO 8601 local time in the target location and specify the timezone using the options (2nd parameter).

  • Croner also allows you to change how the day-of-week and day-of-month conditions are combined. By default, Croner (and Vixie cron) will trigger when either the day-of-month OR the day-of-week conditions match. For example, 0 20 1 * MON will trigger on the first of the month as well as each Monday. If you want to use AND (so that it only triggers on Mondays that are also the first of the month), you can pass { legacyMode: false }. For more information, see issue #53.

Field Required Allowed values Allowed special characters Remarks
Seconds Optional 0-59 * , - / ?
Minutes Yes 0-59 * , - / ?
Hours Yes 0-23 * , - / ?
Day of Month Yes 1-31 * , - / ? L
Month Yes 1-12 or JAN-DEC * , - / ?
Day of Week Yes 0-7 or SUN-MON * , - / ? 0 to 6 are Sunday to Saturday
7 is Sunday, the same as 0

Note Weekday and month names are case-insensitive. Both MON and mon work.

It is also possible to use the following "nicknames" as pattern.

Nickname Description
@yearly Run once a year, ie. "0 0 1 1 *".
@annually Run once a year, ie. "0 0 1 1 *".
@monthly Run once a month, ie. "0 0 1 * *".
@weekly Run once a week, ie. "0 0 * * 0".
@daily Run once a day, ie. "0 0 * * *".
@hourly Run once an hour, ie. "0 * * * *".

Contributing

Master branch

Node.js CI Deno CI Bun CI

Dev branch

Node.js CI Deno CI Bun CI

All development happen in the dev branch, you can install latest development version of croner using

npm install croner@dev

See Contribution Guide

... or ...

Buy Me a Coffee at ko-fi.com

License

MIT License