In many NestJS applications, time handling is critical - whether it's timestamps, expiration checks, scheduling, domain logic, or logging.
Calling new Date() directly throughout your code makes unit testing difficult and tightly couples your business logic to system time.
@nestjstools/clock is a lightweight NestJS time abstraction library that provides a clean IClock interface for injecting time providers via dependency injection.
It enables:
- Deterministic testing with a fixed clock
- Clean separation of infrastructure concerns
- Better testability and maintainability
This library is ideal for clean architecture, hexagonal architecture, and time-dependent domain logic in NestJS applications.
- Abstraction of time handling via the
IClockinterface - Swappable implementations:
SystemClock(real time) andFixedClock(test time) - Perfect for mocking time in NestJS unit tests
- Seamless integration with NestJS dependency injection
- Clean separation between domain logic and system time
- Includes
CalendarDatevalue object for date-only domain modeling - Lightweight and dependency-free
npm install @nestjstools/clock
#or
yarn add @nestjstools/clockReturns the actual current system time.
import { SystemClock } from '@nestjstools/clock';
const clock = new SystemClock();
console.log(clock.now()); // → current system date/timeReturns a fixed date/time—ideal for deterministic tests.
import { FixedClock } from '@nestjstools/clock';
const fixedDate = new Date('2023-01-01T00:00:00Z');
const clock = new FixedClock(fixedDate);
console.log(clock.now()); // → always returns 2023-01-01T00:00:00Z - helpful in testsYou can easily register the clock as a provider in your modules:
import { Module } from '@nestjs/common';
import { ClockModule } from '@nestjstools/clock';
@Module({
imports: [
ClockModule.forRoot(), //By default global - .forFeature() also available
]
})
export class AppModule {}Inject the clock into your services (example):
import { Injectable } from '@nestjs/common';
import { IClock, Clock } from '@nestjstools/clock';
@Injectable()
export class SubscriptionService {
constructor(@Clock() private readonly clock: IClock) {}
isSubscriptionActive(startDate: Date, durationDays: number): boolean {
const now = this.clock.now();
const endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + durationDays);
return now < endDate;
}
}Swap out the system clock with a fixed one in your test setup:
import { Test } from '@nestjs/testing';
import { SubscriptionService } from './subscription.service';
import { FixedClock, Service } from '@nestjstools/clock';
describe('SubscriptionService', () => {
let service: SubscriptionService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
SubscriptionService,
],
})
.overrideProvider(Service.CLOCK_SERVICE)
.useValue(new FixedClock(new Date('2020-10-10T00:00:00Z')))
.compile();
service = moduleRef.get(SubscriptionService);
});
it('returns true when subscription is still active', () => {
const start = new Date('2020-10-01T00:00:00Z');
const active = service.isSubscriptionActive(start, 20); // expires 2020-10-21
expect(active).toBe(true);
});
it('returns false when subscription has expired', () => {
const start = new Date('2020-09-01T00:00:00Z');
const active = service.isSubscriptionActive(start, 20); // expires 2020-09-21
expect(active).toBe(false);
});
});CalendarDate is a simple and immutable value object representing a calendar date without time or timezone information, storing only the year, month, and day. It ensures valid date creation and provides convenient methods for manipulation and comparison.
- Immutable representation of a date in
YYYY-MM-DDformat. - Creation from string (
YYYY-MM-DD) or nativeDateobjects. - Validation to prevent invalid dates.
- Comparison methods (
equals,isBefore,isAfter, etc.). - Methods to add or subtract days safely.
- Conversion back to native
Dateobjects (with time zeroed). - Useful for date-only domain logic where time is irrelevant.
import { CalendarDate } from '../value-object/calendar-date';
// Create from string
const date1 = CalendarDate.fromString('2025-06-14');
// Create from native Date
const date2 = CalendarDate.fromDate(new Date());
// Get today's date as CalendarDate
const today = CalendarDate.today();
// Manipulate dates
const nextWeek = today.addDays(7);
const yesterday = today.subtractDays(1);
// Compare dates
if (date1.isBefore(nextWeek)) {
console.log(`${date1.toString()} is before ${nextWeek.toString()}`);
}
// Convert back to native Date
const nativeDate = date1.toDate();import { Injectable } from '@nestjs/common';
import { IClock, Clock } from '@nestjstools/clock';
@Injectable()
export class ReturnToday {
constructor(@Clock() private readonly clock: IClock) {}
todayIs(): string {
const today = this.clock.today();
return today.toString(); // output in format YYYY-MM-DD
}
}- Avoid scattered use of
new Date()in your business logic - Lightweight and dependency-free
- Improve the testability and maintainability of your time-dependent logic
- Fits well in clean architecture and DDD practices
nestjs clock, nestjs time provider, nestjs mock date, nestjs test time, nestjs calendar date, typescript date value object, clean architecture time abstraction
