New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@time-provider/core

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@time-provider/core

Time-Provider : Core library ~ TypeScript library for injecting time and timers with adapters for multiple date libraries.

Source
npmnpm
Version
1.2.0
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

Time-Provider

npm types CodeQL check codecov npm downloads dependencies unpacked-size minzipped size openssf best practices license

Time-Provider

🌳 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

Time is a dependency

Code coupled to the native Date object, Temporal objects, any specific date library, or the environment's scheduler (setTimeout, setInterval) 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 parser, and a scheduler, swappable per call site.

Features

  • Four clock strategies: system (real time), fixed, manual (advance time explicitly), sequential (predefined instants) - same API for production and tests.
  • Deterministic timers: setTimeout/setInterval 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.
  • Bring your own date library: adapters for Temporal, Day.js, Luxon, Moment.js, Moment.js + moment-timezone, and native Date. Your code keeps working with the date type it already uses.
  • Real timezone support where the underlying library allows it (native Date, plain Moment.js are UTC-only - see ARCHITECTURE.md) - withLocalTimezone(...) plus localNow()/utcNow().
  • Tree-shakable: no deterministic runtimes bundled when not imported.
  • Zero runtime dependencies in @time-provider/core.

Install

npm install @time-provider/core @time-provider/plugin-native

Swap plugin-native for plugin-dayjs, plugin-luxon, plugin-moment, plugin-moment-timezone, or plugin-temporal depending on the date library you use.

Usage

// production: import the default production runtime
import { createTimeProvider } from "@time-provider/core";
import { plugin } from "@time-provider/plugin-native";

// create a production runtime
const timeProvider = createTimeProvider.for(plugin).create();

class UserService {
  constructor(private readonly timeProvider: ITimeProvider<Date>) {}

  createUser() {
    return { createdAt: this.timeProvider.clock.utcNow() };
  }
}
// test: import the deterministic runtime
import { createTimeProvider } from "@time-provider/core/deterministic";
import { plugin } from "@time-provider/plugin-native/deterministic";

// create a deterministic runtime
const timeProvider = createTimeProvider
  .for(plugin)
  .asManual()
  .withInitialTime("2026-01-01T00:00:00.000Z")
  .create();

let retries = 0;
timeProvider.scheduler.setInterval(() => retries++, 1000);
timeProvider.clock.advance({ seconds: 3 });

expect(retries).toBe(3);

Every time provider exposes the same three-part surface:

interface ITimeProvider<TDate> {
  clock: IClock<TDate>; // localNow(), utcNow(), withLocalTimezone()
  parser: IParser<TDate>; // parseToUtc(), parseToLocal()
  scheduler: IScheduler; // setTimeout/clearTimeout/setInterval/clearInterval
}

Clock strategies

StrategyBehaviorTypical use
SystemReal time, real timersProduction
FixedAlways the same instantDeterministic single-instant tests
ManualAdvances only when told toSimulations, timer/retry logic tests
SequentialReturns a predefined instant sequenceTests asserting on changing timestamps
createTimeProvider.for(plugin).asFixed().withFixedTime("2026-01-01T00:00Z").create();
createTimeProvider.for(plugin).asManual().withInitialTime("2026-01-01T00:00Z").create();
createTimeProvider
  .for(plugin)
  .asSequential()
  .withSequentialTime("2026-01-01T00:01Z")
  .withSequentialTime("2026-01-01T00:02Z")
  .create();

Manual and sequential clocks run synchronously. A due setTimeout/setInterval callback fires in-line, as a direct side effect of the call that made it due (advance(), localNow(), utcNow()) - 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.

Learn more

  • ARCHITECTURE.md - how the packages fit together, the plugin/adapter model, why native Date and plain Moment.js are UTC-only.
  • CONTRIBUTING.md - development setup, workflow, reporting bugs/features.
  • BENCHMARK.md - faster than jest/sinon fake timers.
  • Per-package README (packages/<name>/README.md) for adapter-specific notes.
  • CHANGELOG.md - changes log from the core library and all plugins.

License

MIT

Keywords

clock

FAQs

Package last updated on 25 Jul 2026

Related posts