npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@time-provider/addon-cron

v0.4.0

Published

Time-Provider : Cron addon ~ Your single time interface for all your JavaScript / TypeScript projects.

Downloads

336

Readme

NPM types Node.js ^18.18 || >=20.4 module ESM + CJS CodeQL check codecov npm downloads dependencies unpacked-size minified size openssf best practices license

Time-Provider ~ Cron Addon

Description

This is the cron scheduling addon for Time-Provider.
Extends the library with a scheduler.cron facade that runs a callback on a schedule described by a standard 5-field cron expression (minute hour day-of-month month day-of-week), evaluated in the runtime's own local timezone.

The expression parser and next-occurrence calculator are hand-rolled, with zero runtime dependencies. It supports *, single values, a-b ranges, .../n steps and comma-separated lists on every field, the usual 3-letter month/day names (JAN-DEC, SUN-SAT, case-insensitive), the 7 Sunday alias, and the POSIX quirk where a match on either day-of-month or day-of-week counts when both are restricted. It does not support seconds, or the L/W/# special characters some cron implementations add.

Just like the plugin packages, this addon is tree-shakable.
It is split into a default (system/real-time) entry point and a deterministic one, so each import pulls in only the code it needs:

  • @time-provider/addon-cron - for a system (real time) Time-Provider created via @time-provider/core. Schedules run on real native timers.
  • @time-provider/addon-cron/deterministic - for a deterministic Time-Provider (fixed/manual/sequential) created via @time-provider/core/deterministic. Schedules run against that runtime's own simulated clock.

Usage

import { createTimeProvider } from "@time-provider/core";
import { createTimeProvider as createDeterministicTimeProvider } from "@time-provider/core/deterministic";
import { plugin } from "@time-provider/plugin-native";
import { plugin as deterministicPlugin } from "@time-provider/plugin-native/deterministic";
import { addon } from "@time-provider/addon-cron";
import { addon as deterministicAddon } from "@time-provider/addon-cron/deterministic";

// System: runs on real native timers, in the runtime's local timezone.
const timeProvider = createTimeProvider
  .for(plugin)
  .use(addon)
  .withTimezone("Europe/Paris")
  .create();
const handle = timeProvider.scheduler.cron.schedule("0 9 * * MON-FRI", () =>
  console.log("Good morning!"),
);
// ...
handle.dispose();

// Deterministic: runs against the runtime's own simulated clock.
using manual = createDeterministicTimeProvider
  .for(deterministicPlugin)
  .use(deterministicAddon)
  .asManual()
  .withInitialTime("2024-01-01T00:00:00.000Z")
  .create();
using handle = manual.scheduler.cron.schedule("*/15 * * * *", () =>
  console.log("Every 15 minutes"),
);
manual.clock.advance({ minutes: 15 });

JSON schedules

schedule also accepts a JSON ICronSpec instead of a cron expression string, for callers who'd rather avoid the positional/symbolic syntax. Each field (minute, hour, dayOfMonth, month, dayOfWeek) defaults to every value when omitted, and otherwise accepts a number, a numeric string (e.g. "9"), a name (e.g. "JAN", "MON"), a { from, to, step? } range, or an array mixing any of those. month and dayOfWeek only accept their own names - giving a day-of-week name to hour, or a month name to dayOfWeek, is a compile-time type error, not just a runtime one:

timeProvider.scheduler.cron.schedule({ hour: 9, dayOfWeek: ["MON", "WED", "FRI"] }, () =>
  console.log("Good morning!"),
);

timeProvider.scheduler.cron.schedule({ minute: { from: 0, to: 45, step: 15 } }, () =>
  console.log("Every 15 minutes"),
);

Timezones and callbacks that throw

Schedules are read in the runtime's own local timezone, captured when schedule() is called - so a schedule created after clock.withTimezone(...) uses the new timezone, while one already running keeps the timezone it started with. Wall-clock times that a DST transition skips resolve to the first instant past the gap, and ones it repeats resolve to the earlier of the two.

A cron callback is an ordinary timer callback, so one that throws follows the runtime's usual rule (see ITimers): the exception propagates in a Node-like environment, and is logged in a browser-like one. Either way that schedule stops, exactly as a recurring timer callback that throws does - catch inside your own callback if a failing run shouldn't end the job.

License

MIT