ts-time-utils
v4.4.1
Published
A comprehensive TypeScript utility library for time, dates, durations, and calendar operations with full tree-shaking support
Downloads
280
Maintainers
Readme
ts-time-utils
A comprehensive TypeScript utility library for time, dates, durations, and calendar operations. Zero dependencies, full tree-shaking support, 430+ functions across 32 public modules.
Live Playground & Docs | GitHub
Features
- Lightweight — Import only what you need with tree-shaking support
- Zero dependencies — Pure TypeScript, no external packages
- Type-safe — Full TypeScript support with IntelliSense
- Comprehensive — 430+ functions across 32 public modules
- Fluent API — Chain operations with the
chain()API - Extensible — Plugin system for custom functionality
When Not To Use This Library
- You only need a single built-in
Datehelper or oneIntlformatter. - You want the standardized Temporal API rather than a utility library.
- You need a mutable Moment-style wrapper with implicit global locale state.
Installation
npm install ts-time-utilsQuick Start
import { formatDuration, timeAgo, Duration } from 'ts-time-utils';
// Format milliseconds to readable duration
formatDuration(3661000); // "1 hour, 1 minute, 1 second"
// Get "time ago" strings
timeAgo(new Date(Date.now() - 3600000)); // "1 hour ago"
// Duration arithmetic
const meeting = Duration.fromMinutes(45);
const buffer = Duration.fromMinutes(15);
meeting.add(buffer).toString(); // "1h"Tree-shaking (recommended)
import { formatDuration } from 'ts-time-utils/format';
import { differenceInUnits } from 'ts-time-utils/calculate';
import { isValidDate } from 'ts-time-utils/validate';Every public module is also available as a subpath import such as
ts-time-utils/timezone, ts-time-utils/workingHours, or
ts-time-utils/naturalLanguage.
Module Selection
- Use
ts-time-utilswhen you need a few core utilities from different areas. - Use
ts-time-utils/formatorts-time-utils/calculatewhen one module is enough. - Use dedicated subpaths like
ts-time-utils/chain,ts-time-utils/plugins,ts-time-utils/locale, orts-time-utils/workingHoursfor those feature areas.
Utility Categories
Format
Format durations, time ago strings, and custom date formats.
import { formatDuration, timeAgo, parseDuration } from 'ts-time-utils/format';
formatDuration(65000); // "1 minute, 5 seconds"
formatDuration(65000, { short: true }); // "1m 5s"
timeAgo(new Date(Date.now() - 60000)); // "1 minute ago"
parseDuration('1h 30m'); // 5400000 (ms)Calculate
Date arithmetic, differences, and business day calculations.
import { differenceInUnits, differenceInCalendarDays, addTime, startOf, endOf } from 'ts-time-utils/calculate';
differenceInUnits(date1, date2, 'days'); // 10
differenceInCalendarDays(date1, date2); // Calendar date boundary count
addTime(new Date(), 5, 'hours'); // 5 hours from now
startOf(new Date(), 'day'); // 00:00:00 today
endOf(new Date(), 'month'); // Last moment of monthValidate
Date validation, checks, and comparisons.
import { isValidDate, isLeapYear, isWeekend, isSameDay } from 'ts-time-utils/validate';
isValidDate(new Date('2025-13-01')); // false
isLeapYear(2024); // true
isWeekend(new Date('2025-09-13')); // true (Saturday)
isSameDay(date1, date2); // booleanDuration
Immutable Duration class with arithmetic operations.
import { Duration } from 'ts-time-utils/duration';
const d1 = Duration.fromHours(2.5);
const d2 = Duration.fromString('1h 30m 45s');
const d3 = Duration.between(startDate, endDate);
d1.add(d2).toString(); // "4h 0m 45s"
d1.greaterThan(d2); // true
d1.multiply(2).hours; // 5Chain API
Fluent chainable API for date operations.
import { chain } from 'ts-time-utils/chain';
chain(new Date())
.startOf('day')
.add(9, 'hours')
.add(30, 'minutes')
.toDate(); // Today at 9:30am
chain(new Date())
.add(1, 'week')
.startOf('week')
.format('YYYY-MM-DD'); // Next week MondayPlugin extensions are imported from ts-time-utils/plugins, and that module now loads the chain class directly. You can import plugins before or after chain without any hidden global setup.
Timezone
Timezone conversions, DST handling, and zone comparisons.
import { formatInTimeZone, isDST, convertBetweenZones } from 'ts-time-utils/timezone';
formatInTimeZone(new Date(), 'America/New_York');
isDST(new Date('2025-07-14'), 'America/New_York'); // true
convertBetweenZones(new Date(), 'UTC', 'Asia/Tokyo');isDST() uses a yearly-offset heuristic rather than authoritative transition metadata.
Calendar
ISO weeks, quarters, holidays, and calendar grids.
import { getWeekNumber, getQuarter, getEaster, getUSHolidays } from 'ts-time-utils/calendar';
getWeekNumber(new Date('2025-09-14')); // 37
getQuarter(new Date('2025-07-15')); // 3
getEaster(2025); // Easter Sunday 2025
getUSHolidays(2025); // Array of US federal holidaysDate Range
Date range operations: overlap, gaps, merge, split.
import { mergeDateRanges, findGaps, dateRangeOverlap } from 'ts-time-utils/dateRange';
const ranges = [
{ start: new Date('2024-01-01'), end: new Date('2024-01-10') },
{ start: new Date('2024-01-05'), end: new Date('2024-01-15') },
];
mergeDateRanges(ranges); // Merged into single range
findGaps(busyTimes, workday); // Available time slots
dateRangeOverlap(range1, range2); // true/falseRecurrence
RRULE-inspired recurring event patterns.
import { createRecurrence, recurrenceToString } from 'ts-time-utils/recurrence';
const weekly = createRecurrence({
frequency: 'weekly',
interval: 1,
startDate: new Date('2025-01-01'),
byWeekday: [1, 3, 5], // Mon, Wed, Fri
});
weekly.getNextOccurrence(new Date());
weekly.getAllOccurrences();
recurrenceToString(weekly.rule); // "Every week on Monday, Wednesday, Friday"Cron
Parse and match cron expressions.
import { parseCronExpression, matchesCron, getNextCronDate, describeCron } from 'ts-time-utils/cron';
const date = new Date();
parseCronExpression('0 9 * * 1-5'); // minute/hour/day/month/day-of-week parts
matchesCron(date, '0 9 * * 1-5'); // true if weekday 9am
getNextCronDate('0 9 * * *'); // Next 9am
describeCron('0 9 * * 1-5'); // "At 09:00 on Monday through Friday"Fiscal Year
Fiscal year utilities with configurable start month.
import { getFiscalYear, getFiscalQuarter } from 'ts-time-utils/fiscal';
const date = new Date();
getFiscalYear(date, { startMonth: 4 }); // April start
getFiscalYear(date, { startMonth: 7 }); // July start
getFiscalYear(date, { startMonth: 10 }); // October start
getFiscalQuarter(date, { startMonth: 4 }); // Q2 for UK fiscalCompare & Sort
Sort, group, and analyze date arrays.
import { sortDates, closestDate, groupDatesByMonth, snapDate } from 'ts-time-utils/compare';
sortDates(dates, 'desc');
closestDate(target, candidates);
groupDatesByMonth(dates); // Map by YYYY-MM
snapDate(date, 15, 'minutes'); // Snap to 15-min gridIterate
Iterate through date sequences and count dates.
import { eachDay, eachWeekday, countWeekdays, filterDays } from 'ts-time-utils/iterate';
eachDay(start, end); // Array of each day
eachWeekday(start, end); // Weekdays only (Mon-Fri)
countWeekdays(start, end); // Number of weekdays
filterDays(start, end, d => d.getDate() === 15); // 15th of each monthNatural Language
Parse human-friendly date strings.
import { parseNaturalDate, extractDatesFromText } from 'ts-time-utils/naturalLanguage';
parseNaturalDate('tomorrow');
parseNaturalDate('next Friday');
parseNaturalDate('in 2 weeks');
parseNaturalDate('end of month');
extractDatesFromText('Meeting tomorrow at 3pm');
// [{ date: Date, text: 'tomorrow at 3pm', confidence: 0.9 }]parseNaturalDate accepts referenceDate, defaultTime, and strict. When strict is true, the parser only returns the library's recognized patterns and skips the permissive Date fallback.
International Holidays
Public holidays for 20 countries.
import { getHolidays, isHoliday, getNextHoliday } from 'ts-time-utils/holidays';
const today = new Date();
getHolidays(2025, 'UK'); // UK bank holidays
getHolidays(2025, 'DE'); // German holidays
isHoliday(today, 'CA'); // Is Canadian holiday?
getNextHoliday(today, 'AU'); // Next Australian holiday
// Supported: UK, NL, DE, CA, AU, IT, ES, CN, IN, US,
// JP, FR, BR, MX, KR, SG, PL, SE, BE, CHLocale
Multi-language formatting with 40+ locales.
import { formatRelativeTime, formatDateLocale, detectLocale } from 'ts-time-utils/locale';
const pastDate = new Date(Date.now() - 2 * 60 * 60 * 1000);
const date = new Date();
formatRelativeTime(pastDate, { locale: 'es' }); // "hace 2 horas"
formatRelativeTime(pastDate, { locale: 'de' }); // "vor 2 Stunden"
formatDateLocale(date, 'fr', 'long'); // "15 janvier 2024"
detectLocale(); // Auto-detect system localeWorking Hours
Business hours calculations with break support. These helpers use the
Date values you pass in directly; if you need a different timezone's wall
clock, adapt the instant first with a timezone helper such as
convertDateToZone() or reinterpretAsZone().
import { isWorkingTime, addWorkingDays, workingDaysBetween } from 'ts-time-utils/workingHours';
const config = {
workingDays: [1, 2, 3, 4, 5],
hours: { start: 9, end: 17 },
breaks: [{ start: 12, end: 13 }]
};
const now = new Date();
isWorkingTime(now, config);
addWorkingDays(now, 5, config);
workingDaysBetween(now, new Date('2025-12-31'), config);Serialization
Safe JSON date serialization and deserialization.
import { serializeDate, parseJSONWithDates, stringifyWithDates } from 'ts-time-utils/serialize';
serializeDate(date, { format: 'iso' }); // "2025-09-14T12:30:45.123Z"
serializeDate(date, { format: 'epoch' }); // 1757853045123
const json = stringifyWithDates(data, ['createdAt']);
const parsed = parseJSONWithDates(json, ['createdAt']);Performance
Async utilities, benchmarking, and timing.
import { sleep, benchmark, Stopwatch, debounce } from 'ts-time-utils/performance';
await sleep(1000);
await benchmark(() => heavyOperation(), 10);
const stopwatch = new Stopwatch();
stopwatch.start();
// ... operations
stopwatch.getElapsed();
const debouncedFn = debounce(fn, 300);Age
Age calculations and birthday utilities.
import { calculateAge, getLifeStage, getNextBirthday } from 'ts-time-utils/age';
calculateAge(new Date('1990-05-15')); // { years: 34, months: 4, days: 2 }
getLifeStage(25); // "adult"
getNextBirthday(birthDate); // Next birthday dateCountdown
Timer and countdown utilities.
import { createCountdown, getRemainingTime, formatCountdown } from 'ts-time-utils/countdown';
const countdown = createCountdown(targetDate, {
onTick: (remaining) => console.log(remaining.days, 'd'),
onComplete: () => console.log('Done!'),
});
countdown.start();
getRemainingTime(targetDate); // { days, hours, minutes, seconds }
formatCountdown(targetDate, { units: ['days', 'hours'] }); // "45d 12h"Interval
Time interval operations.
import { createInterval, intervalsOverlap, mergeIntervals } from 'ts-time-utils/interval';
const a = createInterval('2025-01-01', '2025-01-05');
const b = createInterval('2025-01-04', '2025-01-10');
intervalsOverlap(a, b); // true
mergeIntervals([a, b]); // Single merged intervalRange Presets
Common date range presets.
import { today, lastNDays, thisWeek, thisMonth } from 'ts-time-utils/rangePresets';
today(); // { start, end } for today
lastNDays(7); // Last 7 days
thisWeek(); // Current week
thisMonth(); // Current monthNon-Gregorian Calendars
Convert dates between calendar systems using Intl.DateTimeFormat.
import { toHebrewDate, toIslamicDate, toJapaneseDate, getChineseZodiac } from 'ts-time-utils/calendars';
toHebrewDate(new Date()); // { year: 5785, month: 4, day: 23, calendar: 'hebrew' }
toIslamicDate(new Date()); // { year: 1446, month: 7, day: 1, calendar: 'islamic-umalqura' }
toJapaneseDate(new Date()); // { year: 6, era: 'Reiwa', calendar: 'japanese' }
getChineseZodiac(2024); // 'Dragon'
// Supported: Hebrew, Islamic, Buddhist, Japanese, Persian, ChineseTemporal API Compatibility
Future-proof with Temporal-like objects that work with native Date.
import { toPlainDate, toPlainDateTime, toZonedDateTime, toInstant } from 'ts-time-utils/temporal';
const date = toPlainDate(2024, 3, 25);
date.add({ days: 7 }); // PlainDate
date.until(otherDate); // Duration
date.dayOfWeek; // 1 (Monday, ISO)
const zdt = toZonedDateTime(new Date(), 'America/New_York');
zdt.hour; // Hour in that timezone
zdt.toInstant(); // Epoch-based Instant
const instant = toInstant(Date.now());
instant.toZonedDateTime('UTC'); // Convert to any timezoneHigh-Precision Utilities
Nanosecond timestamps, BigInt support, DST handling, and leap seconds.
import {
createNanosecondTimestamp, nowNanoseconds,
toBigIntMs, ValidDate, isInDSTGap, leapSecondsBetween
} from 'ts-time-utils/precision';
// Nanosecond precision
const ts = createNanosecondTimestamp(Date.now(), 500000);
ts.totalNanoseconds; // BigInt
// BigInt timestamps for large date ranges
toBigIntMs(new Date()); // BigInt milliseconds
// DST transition detection
isInDSTGap(new Date('2024-03-10T02:30:00'));
// Validated dates (never invalid)
const valid = ValidDate.from(date); // Throws if invalid
const maybe = ValidDate.tryFrom(date); // Returns null if invalid
// Leap second awareness
leapSecondsBetween(date1, date2); // Number of leap secondsParse
Date parsing from various formats.
import { parseDate, parseTime, guessDateFormat } from 'ts-time-utils/parse';
parseDate('Dec 25, 2025');
parseDate('25/12/2025', 'DD/MM/YYYY');
parseTime('2:30 PM'); // { hour: 14, minute: 30 }
guessDateFormat('2025-09-14'); // 'YYYY-MM-DD'Scheduling
Appointment slots, availability, and booking conflict detection.
import {
generateSlots, getAvailableSlots, findNextAvailable,
hasConflict, findConflicts, mergeBookings
} from 'ts-time-utils/scheduling';
// Generate 30-min slots for a day
const slots = generateSlots(new Date(), {
slotDuration: 30,
workingHours: {
workingDays: [1, 2, 3, 4, 5],
hours: { start: 9, end: 17 }
}
});
// Find available slots (excluding existing bookings)
const available = getAvailableSlots(new Date(), existingBookings, config);
// Find next available slot of specific duration
findNextAvailable(new Date(), bookings, 60, config); // 60-min slot
// Check for conflicts
hasConflict(bookings, proposedSlot); // true/false
findConflicts(bookings, proposedSlot); // Array of conflicting bookings
// Merge adjacent bookings
mergeBookings(bookings);Finance
Market hours, trading days, and settlement date calculations.
import {
isMarketOpen, isTradingDay, getMarketHours,
getNextMarketOpen, addTradingDays, getSettlementDate,
eachTradingDay, getOptionsExpiration
} from 'ts-time-utils/finance';
// Check market status
isMarketOpen(new Date(), 'NYSE'); // Is NYSE open right now?
isTradingDay(new Date(), 'NASDAQ'); // Is today a trading day?
getMarketHours('NYSE'); // { open: {hour:9,minute:30}, close: {hour:16,minute:0} }
// Market timing
getNextMarketOpen(new Date()); // Next market open time
addTradingDays(new Date(), 5); // 5 trading days from now
// Settlement (T+2, etc.)
getSettlementDate(tradeDate, 2); // T+2 settlement date
// Iterate trading days
eachTradingDay(start, end); // Array of trading days
// Options expiration (3rd Friday)
getOptionsExpiration(2025, 3); // March 2025 expirationHealthcare
Medication scheduling, shift patterns, and compliance windows.
import {
getMedicationTimes, getNextMedicationTime, parseMedicationFrequency,
generateShiftSchedule, getShiftForTime, isOnShift,
createOnCallRotation, getOnCallStaff,
getComplianceDeadline, timeUntilDeadline
} from 'ts-time-utils/healthcare';
// Medication times (BID = twice daily, TID = 3x daily, etc.)
getMedicationTimes(new Date(), 'BID'); // [8am, 8pm] (default wake/sleep times)
getMedicationTimes(new Date(), 'q6h'); // Every 6 hours
getNextMedicationTime(now, 'TID'); // Next scheduled dose
parseMedicationFrequency('twice daily'); // 'BID'
// Shift scheduling
generateShiftSchedule(start, end, { pattern: '12hr', startTime: { hour: 7, minute: 0 } });
getShiftForTime(now, shiftConfig); // Current shift
isOnShift(now, shiftStart, config); // Is within shift?
// On-call rotations
const rotation = createOnCallRotation(start, end, ['Dr. Smith', 'Dr. Jones'], 24);
getOnCallStaff(now, rotation); // Who's on call?
// Compliance windows
getComplianceDeadline(eventDate, 72); // 72-hour window
timeUntilDeadline(eventDate, deadline); // Duration remainingPlugin System
Extend ChainedDate with custom functionality.
import { chain, ChainedDate } from 'ts-time-utils/chain';
import { extend } from 'ts-time-utils/plugins';
extend('business', {
addBusinessDays(this: ChainedDate, days: number) {
// Implementation
return this;
},
isBusinessDay(this: ChainedDate) {
const day = this.toDate().getDay();
return day !== 0 && day !== 6;
}
});
chain(new Date())
.addBusinessDays(5)
.isBusinessDay(); // true/falseAPI Reference
For complete API documentation, see the Playground & Docs.
All Modules
| Module | Description |
|--------|-------------|
| format | Duration formatting, time ago, date patterns |
| calculate | Date arithmetic, differences, rounding |
| validate | Date validation, comparisons, type checks |
| duration | Immutable Duration class with arithmetic |
| chain | Fluent chainable API |
| timezone | Timezone conversions, DST handling |
| calendar | ISO weeks, quarters, holidays, grids |
| calendars | Non-Gregorian calendars (Hebrew, Islamic, etc.) |
| temporal | Temporal API compatibility layer |
| precision | Nanoseconds, BigInt, DST, leap seconds |
| dateRange | Range operations: overlap, gaps, merge |
| recurrence | RRULE-inspired recurring patterns |
| cron | Cron expression parsing and matching |
| fiscal | Fiscal year utilities |
| compare | Date sorting, grouping, statistics |
| iterate | Date iteration and counting |
| naturalLanguage | Natural language date parsing |
| holidays | International holidays (20 countries) |
| locale | Multi-language formatting (40+ locales) |
| workingHours | Business hours calculations |
| serialize | JSON date serialization |
| performance | Async utilities, benchmarking |
| age | Age calculations, birthdays |
| countdown | Timer and countdown utilities |
| interval | Time interval operations |
| rangePresets | Common date range presets |
| parse | Date parsing from various formats |
| scheduling | Appointment slots, availability, booking |
| finance | Market hours, trading days, settlement |
| healthcare | Medication schedules, shifts, on-call |
| plugins | Plugin system for extensions |
| constants | Time constants and types |
Development
npm install # Install dependencies
npm run build # Build both CJS and ESM
npm test # Run tests
npm run test:package # Verify built package exports after build
npm run lint # Lint codeReleasing
Releases are automated via GitHub Actions with npm trusted publishing (OIDC).
To release a new version:
git tag vX.Y.Z # Create a semantic version tag for the release
git push --tags # Push tag -> triggers publish workflowThe workflow automatically:
- Sets
package.jsonversion from tag - Runs
npm run release:verify - Publishes to npm with provenance
Version format: Tags must match v* pattern (e.g., v1.2.3, v1.2.3-beta.1)
Before tagging, run:
npm run release:verifyLicense
MIT
