🌳 Tree-shakable |
📦 Zero runtime dependencies |
🧪 No global monkey-patching |
🛡️ Type-safe |
⏱️ Deterministic timers |
🕓 Four clock strategies |
🌍 Real timezone support (when applicable) |
🔌 Bring your own date library |
🧩 Modular & Extensible
Disclaimer
Time-Provider is currently under active development. While the project follows Semantic Versioning and may release versions beyond 1.0 before the API is considered stable, the API should be considered unstable for the time being and may change between releases.
Note: As the new API (timers: once/every/recurring/wait with abort/dispose interfaces) is released, a compat addon that still exposes the previous low-level-like methods (setTimeout/clearTimeout) is also available here. It will expose your previous method calls through the compat prefix and may help transitioning to the new API.
This disclaimer will be removed once the API has stabilized.
Time is a dependency
Code coupled to the native Date object, Temporal objects, any specific date library, or the
environment's timers has an implicit dependency on the system clock. That's what pushes teams toward global
fake-timer libraries for testing - patching Date/timers process-wide,
which affects unrelated code and makes tests harder to reason about.
vs. jest.useFakeTimers() / sinon.useFakeTimers(): scoped per call site, no global patch, no restore/cleanup step.
time-provider makes time an explicit, injectable dependency instead: a
single object exposing a clock, a converter, a scheduler, and a performance API swappable per
call site.
Note: The animation-frame API is available as an addon.
Features
Four clock strategies: system (real time), fixed, manual (advance time explicitly), sequential (predefined instants) - same API for production and tests.
Deterministic timers: driven by the clock strategy, not the real event loop, so manual/sequential/fixed runs are synchronous and don't depend on wall-clock time.
Real timezone support where the underlying library allows it (native Date, plain Moment.js are UTC-only - see ARCHITECTURE.md) - withTimezone(...) plus localNow()/utcNow().
Tree-shakable: no deterministic runtimes bundled when not imported.
scheduler is where everything that schedules a callback to run later sits, so the
scheduling addons extend that facet rather than the root. Animation-Frame comes with
its addon that
extends ITimeProvider with:
Manual and sequential clocks run synchronously. A due timer callback fires in-line, as a direct side effect of the call that made it due (advance() (or localNow(), utcNow() on sequential clocks)) - not on a real event-loop tick. This is what makes them deterministic without await, but it means call ordering can differ subtly from a real async run. Use timestampNow() instead when you only need a value to compute with - it never triggers any timer on sequential clocks or advances time.
Addons vs. Plugins
Within the scope of this library, these two terms refer to different concepts.
A plugin, is essentially an adapter. It allows you to connect your preferred date library (e.g. Luxon, Temporal, etc.) to the Time Provider core library without adding any new functionality. Its sole purpose is to bridge the two libraries (e.g. the dayjs plugin).
An addon, as the name suggests, extends the library by introducing new functionality or enhancing existing facades (e.g. the animation-frame API addon)
The npm package @time-provider/core receives a total of 0 weekly downloads. As such, @time-provider/core popularity was classified as not popular.
We found that @time-provider/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 1 open source maintainer collaborating on the project.