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

@pvorona/duration

v0.2.3

Published

An immutable ESM-only duration type with unit conversions, comparisons, and basic arithmetic.

Readme

@pvorona/duration

An immutable ESM-only duration type with unit conversions, comparisons, and basic arithmetic.

Install

npm i @pvorona/duration

This package is ESM-only. Import it from ESM modules instead of require(...).

Usage

Create and convert

import { duration, TimeUnit } from '@pvorona/duration';

const d = duration(2, TimeUnit.Minute);
d.toSeconds(); // 120
d.toMilliseconds(); // 120_000
duration(250, TimeUnit.Millisecond).toSeconds(); // 0.25

Compose from multiple units

import { duration } from '@pvorona/duration';

const total = duration({ minutes: 1, seconds: 30 });
total.toSeconds(); // 90

const negative = duration({ hours: -1, minutes: -30 });
negative.toMilliseconds(); // -5_400_000

duration(parts) accepts only the exact plural keys milliseconds, seconds, minutes, hours, days, weeks, months, and years.

All non-zero parts must share the same sign. For example, duration({ hours: 1, minutes: -30 }) throws TypeError.

Compare

import { milliseconds, seconds } from '@pvorona/duration';

const a = seconds(1);
const b = milliseconds(900);

a.greaterThan(b); // true
a.compare(b); // 1

Arithmetic

import { add, milliseconds, seconds } from '@pvorona/duration';

const total = add(seconds(1), milliseconds(500));
total.toMilliseconds(); // 1500

Between dates

import { since } from '@pvorona/duration';

const startedAt = new Date(Date.now() - 2_000);
const elapsed = since(startedAt);
elapsed.toSeconds(); // ~2

Apply a duration to a date

import { addTo, seconds, subtractFrom } from '@pvorona/duration';

const start = new Date(1_000);

addTo(start, seconds(2)).getTime(); // 3_000
subtractFrom(start, seconds(2)).getTime(); // -1_000

Important semantics

  • ESM-only package: use import, not require(...).
  • Duration values are frozen branded objects created by this package. Use isDuration(...) for unknown inputs instead of duck typing.
  • Compare durations by value with d.equals(other) or isEqual(a, b), not ===.
  • Do not spread, JSON-serialize, or structured-clone Duration values as a transport format. Serialize your own explicit shape and reconstruct with milliseconds(...) for finite values or infinite for the sentinel.
  • DurationParts is constructor input only. It is not a serialized Duration format and should not be treated as one.
  • instant is the exported zero-duration constant, but any zero-valued duration has isInstant === true.
  • The public millisecond APIs are TimeUnit.Millisecond, milliseconds(...), and toMilliseconds().
  • Month is treated as 30 days and Year as 365.25 days. These are approximations, not calendar-aware durations.
  • Negative finite durations are valid. between(...), since(...), arithmetic, and comparisons can produce or operate on negative values.
  • Constructors accept only finite numeric inputs. infinite is the only supported non-finite duration.
  • duration(parts) requires at least one supported plural key, rejects unknown keys, rejects non-finite part values, and rejects mixed-sign non-zero parts.
  • add(infinite, x), subtract(infinite, finite), multiply(infinite, positive finite), and divide(infinite, positive finite) return infinite.
  • addTo(date, duration) and subtractFrom(date, duration) do exact timestamp arithmetic equivalent to new Date(date.getTime() +/- duration.toMilliseconds()).
  • addTo(...) and subtractFrom(...) reject invalid dates, reject infinite, and reject result timestamps outside the JavaScript Date range.
  • addTo(...) and subtractFrom(...) are timestamp-based, not calendar-aware. Local clock time may shift across DST or timezone offset transitions.
  • Date values only have millisecond precision, so the date helpers follow native JavaScript Date semantics for fractional-millisecond timestamps.
  • Invalid units, invalid dates, non-finite scalar inputs, divide-by-zero, subtract(infinite, infinite), subtract(finite, infinite), multiply(infinite, 0), multiply(infinite, negative), and divide(infinite, negative) throw TypeError.

API

TimeUnit

The package exports both:

  • type TimeUnit: the union of the supported runtime unit values

  • const TimeUnit: the runtime constants accepted by duration(value, unit) and d.to(unit)

  • TimeUnit.Millisecond

  • TimeUnit.Second

  • TimeUnit.Minute

  • TimeUnit.Hour

  • TimeUnit.Day

  • TimeUnit.Week

  • TimeUnit.Month

  • TimeUnit.Year

type Duration

An opaque, immutable duration value. Duration instances are branded by the package, so use isDuration(...) for unknown inputs and compare values with equals(...) / isEqual(...) rather than ===.

Properties

  • isFinite: boolean: true for finite durations
  • isInfinite: boolean: true only for infinite
  • isInstant: boolean: true for any zero duration (including instant)

Conversions

  • to(unit: TimeUnit): number: convert to an arbitrary unit
  • toMilliseconds(): number
  • toSeconds(): number
  • toMinutes(): number
  • toHours(): number
  • toDays(): number
  • toWeeks(): number
  • toMonths(): number (30-day months)
  • toYears(): number (365.25-day years)

Comparisons

  • equals(other: Duration): boolean
  • lessThan(other: Duration): boolean
  • lessThanOrEqual(other: Duration): boolean
  • greaterThan(other: Duration): boolean
  • greaterThanOrEqual(other: Duration): boolean
  • compare(other: Duration): -1 | 0 | 1

Example:

import { milliseconds, seconds, type Duration } from '@pvorona/duration';

function isShort(d: Duration) {
  return d.isFinite && d.toSeconds() < 5;
}

const a = seconds(1);
const b = milliseconds(900);

isShort(a); // true
a.greaterThan(b); // true

type DurationParts

Strict constructor input for duration(parts). Supported keys:

  • milliseconds?: number
  • seconds?: number
  • minutes?: number
  • hours?: number
  • days?: number
  • weeks?: number
  • months?: number
  • years?: number

At least one key is required. All non-zero keys must share the same sign.

Function API

Constructors

  • duration(value: number, unit: TimeUnit): Duration
  • duration(parts: DurationParts): Duration
  • milliseconds(value: number): Duration
  • seconds(value: number): Duration
  • minutes(value: number): Duration
  • hours(value: number): Duration
  • days(value: number): Duration
  • weeks(value: number): Duration
  • months(value: number): Duration
  • years(value: number): Duration

Date helpers

  • between(start: Date, end: Date): Duration
  • since(start: Date): Duration
  • addTo(date: Date, duration: Duration): Date
  • subtractFrom(date: Date, duration: Duration): Date

Arithmetic helpers

  • add(a: Duration, b: Duration): Duration
  • subtract(a: Duration, b: Duration): Duration
  • multiply(a: Duration, b: number): Duration
  • divide(a: Duration, b: number): Duration

Constants

  • instant: Duration
  • infinite: Duration

Guards / equality

  • isDuration(value: unknown): value is Duration
  • isEqual(a: Duration, b: Duration): boolean

Example:

import { isDuration, seconds } from '@pvorona/duration';

const maybe: unknown = seconds(1);
if (isDuration(maybe)) {
  maybe.toMilliseconds(); // ok, narrowed
}