@jsxx/ms
v1.0.1
Published
A lightweight, type-safe utility for converting between time durations and human-readable strings.
Downloads
16
Maintainers
Readme
@jsxx/ms
A lightweight, type-safe utility library for converting between time durations and human-readable strings.
Features
- Zero dependencies - Minimal footprint
- Type-safe - Full TypeScript support with template literal types
- Dual API - Single function for both formatting and parsing
- Flexible units - Supports ms, s, m, h, d, w, mo, y with multiple aliases
- Long format - Optional verbose output (e.g., "1 second" vs "1s")
- Fast - Optimized with precompiled regex and Map-based lookups
- Well-tested - Comprehensive test coverage with 43+ tests
Installation
npm add @jsxx/ms
# or
pnpm add @jsxx/ms
# or
yarn add @jsxx/ms
# or
bun add @jsxx/msQuick Start
import ms from '@jsxx/ms';
// Parse time strings to milliseconds
ms('1s'); // 1000
ms('5m'); // 300000
ms('2h'); // 7200000
ms('1d'); // 86400000
// Format milliseconds to time strings
ms(1000); // "1s"
ms(60000); // "1m"
ms(3600000); // "1h"
ms(1000, {long: true}); // "1 second"API Reference
ms(value, options?)
Main function with overloaded signatures for bidirectional conversion.
Signature 1: Parse time string to milliseconds
function ms(value: StringValue, options?: Options): number;Converts a human-readable time string into milliseconds.
Parameters:
value(StringValue): A time string (e.g.,"1s","5m","2h")options(Options): Not used for parsing (reserved for future use)
Returns: number - The number of milliseconds
Examples:
ms('1s'); // 1000
ms('5m'); // 300000
ms('2h'); // 7200000
ms('3d'); // 259200000
ms('1w'); // 604800000
ms('6mo'); // 15778800000
ms('1y'); // 31557600000
// With spaces
ms('1 s'); // 1000
ms('5 m'); // 300000
// Decimal values
ms('1.5s'); // 1500
ms('2.5m'); // 150000
ms('0.5h'); // 1800000
// Negative values
ms('-1s'); // -1000
ms('-5m'); // -300000
// Default to milliseconds
ms('100'); // 100
ms('500'); // 500Supported Units:
| Unit | Aliases | Example |
| ---- | ------------------------------------------ | --------- |
| ms | milliseconds, millisecond, msecs, msec, ms | "100ms" |
| s | seconds, second, secs, sec, s | "1s" |
| m | minutes, minute, mins, min, m | "5m" |
| h | hours, hour, hrs, hr, h | "2h" |
| d | days, day, d | "3d" |
| w | weeks, week, w | "1w" |
| mo | months, month, mo | "6mo" |
| y | years, year, yrs, yr, y | "1y" |
Edge Cases:
- Returns
NaNfor invalid input (e.g.,"invalid","1xyz") - Case-insensitive:
"1S","1s","1Second"all work - Throws for empty string, non-string input, or strings > 100 characters
Signature 2: Format milliseconds to time string
function ms(value: number, options?: Options): string;Converts milliseconds into a human-readable time string.
Parameters:
value(number): The number of millisecondsoptions(Options): Optional formatting options
Returns: string - Formatted string like "1s" or "1 second"
Examples:
// Short format (default)
ms(1000); // "1s"
ms(60000); // "1m"
ms(3600000); // "1h"
ms(86400000); // "1d"
ms(604800000); // "1w"
ms(2629800000); // "1mo"
ms(31557600000); // "1y"
// Long format
ms(1000, {long: true}); // "1 second"
ms(2000, {long: true}); // "2 seconds"
ms(60000, {long: true}); // "1 minute"
ms(120000, {long: true}); // "2 minutes"
ms(3600000, {long: true}); // "1 hour"
ms(7200000, {long: true}); // "2 hours"
// Negative values
ms(-1000); // "-1s"
ms(-60000); // "-1m"
ms(-1000, {long: true}); // "-1 second"
// Rounding
ms(1500); // "2s" (rounds to nearest)
ms(90000); // "2m"
ms(5400000); // "2h"Throws:
- Non-number input
Infinityor-InfinityNaN
parse(str)
Explicit function to parse a time string into milliseconds.
function parse(str: string): number;Parameters:
str(string): A time string such as"1s","5m","2h"
Returns: number - The number of milliseconds, or NaN if invalid
Throws: If the string is empty, not a string, or longer than 100 characters
Example:
import {parse} from '@jsxx/ms';
parse('1s'); // 1000
parse('5m'); // 300000
parse('2h'); // 7200000
parse('invalid'); // NaNformat(msValue, options?)
Explicit function to format milliseconds into a time string.
function format(msValue: number, options?: Options): string;Parameters:
msValue(number): The number of millisecondsoptions(Options): Optional formatting options
Returns: string - Formatted string
Throws: If the value is not a finite number
Example:
import {format} from '@jsxx/ms';
format(1000); // "1s"
format(60000); // "1m"
format(3600000); // "1h"
format(1000, {long: true}); // "1 second"
format(120000, {long: true}); // "2 minutes"Types
StringValue
type StringValue =
| `${number}`
| `${number}${UnitAnyCase}`
| `${number} ${UnitAnyCase}`;Template literal type for type-safe time strings. Supports any case variation of units.
Valid formats:
"1s","5m","2h"(lowercase)"1S","5M","2H"(uppercase)"1Second","5Minutes"(capitalized)"1 s","5 m"(with space)"100"(number only, defaults to ms)
Options
type Options = {
/**
* Use verbose formatting (e.g., "1 second" instead of "1s").
* @default false
*/
long?: boolean;
};Options for customizing time formatting.
Supported Units
All units are based on standard time conversions:
| Unit | Name | Milliseconds | Calculation | | ---- | ----------- | -------------- | --------------------------------- | | ms | Millisecond | 1 | 1 | | s | Second | 1,000 | 1000 | | m | Minute | 60,000 | 60 × 1000 | | h | Hour | 3,600,000 | 60 × 60 × 1000 | | d | Day | 86,400,000 | 24 × 60 × 60 × 1000 | | w | Week | 604,800,000 | 7 × 24 × 60 × 60 × 1000 | | mo | Month | 2,629,800,000 | 365.25 ÷ 12 × 24 × 60 × 60 × 1000 | | y | Year | 31,557,600,000 | 365.25 × 24 × 60 × 60 × 1000 |
Note: Months and years use average values (365.25 days/year, 30.4375 days/month) for consistency.
Usage Examples
Basic Parsing
import ms from '@jsxx/ms';
console.log(ms('1s')); // 1000
console.log(ms('5m')); // 300000
console.log(ms('2h')); // 7200000
console.log(ms('3d')); // 259200000
console.log(ms('1w')); // 604800000
console.log(ms('1y')); // 31557600000Basic Formatting
import ms from '@jsxx/ms';
console.log(ms(1000)); // "1s"
console.log(ms(60000)); // "1m"
console.log(ms(3600000)); // "1h"
console.log(ms(86400000)); // "1d"Long Format
import ms from '@jsxx/ms';
console.log(ms(1000, {long: true})); // "1 second"
console.log(ms(2000, {long: true})); // "2 seconds"
console.log(ms(60000, {long: true})); // "1 minute"
console.log(ms(120000, {long: true})); // "2 minutes"
console.log(ms(3600000, {long: true})); // "1 hour"
console.log(ms(7200000, {long: true})); // "2 hours"Timeout Configuration
import ms from '@jsxx/ms';
function setTimeout(callback: () => void, delay: string) {
const ms = parse(delay);
return globalThis.setTimeout(callback, ms);
}
setTimeout(() => console.log('Done!'), '5s');
setTimeout(() => console.log('Later!'), '2m');API Rate Limiting
import ms from '@jsxx/ms';
interface RateLimitConfig {
window: string;
maxRequests: number;
}
const config: RateLimitConfig = {
window: '1m',
maxRequests: 100,
};
const windowMs = ms(config.window); // 60000Cache TTL
import ms from '@jsxx/ms';
class Cache {
constructor(private ttl: string) {}
getTTLMs(): number {
return ms(this.ttl);
}
}
const cache = new Cache('5m');
console.log(cache.getTTLMs()); // 300000Duration Display
import ms from '@jsxx/ms';
function formatDuration(milliseconds: number, verbose = false): string {
return ms(milliseconds, {long: verbose});
}
const duration = 125000;
console.log(formatDuration(duration)); // "2m"
console.log(formatDuration(duration, true)); // "2 minutes"Uptime Display
import ms from '@jsxx/ms';
function showUptime(startTime: number): string {
const uptime = Date.now() - startTime;
return `Uptime: ${ms(uptime, {long: true})}`;
}
const serverStart = Date.now() - 3600000;
console.log(showUptime(serverStart)); // "Uptime: 1 hour"Countdown Timer
import ms from '@jsxx/ms';
function countdown(duration: string) {
let remaining = ms(duration);
const interval = setInterval(() => {
console.log(`Time remaining: ${ms(remaining)}`);
remaining -= 1000;
if (remaining <= 0) {
clearInterval(interval);
console.log('Done!');
}
}, 1000);
}
countdown('10s');Configuration Parsing
import ms from '@jsxx/ms';
interface ServerConfig {
requestTimeout: string;
sessionExpiry: string;
cacheExpiry: string;
}
const config: ServerConfig = {
requestTimeout: '30s',
sessionExpiry: '1d',
cacheExpiry: '1h',
};
const timeouts = {
request: ms(config.requestTimeout), // 30000
session: ms(config.sessionExpiry), // 86400000
cache: ms(config.cacheExpiry), // 3600000
};Retry Logic
import ms from '@jsxx/ms';
async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = '1s',
): Promise<T> {
let lastError: Error;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
const delay = ms(baseDelay) * Math.pow(2, i);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError!;
}Performance Monitoring
import ms from '@jsxx/ms';
function measurePerformance<T>(fn: () => T, label: string): T {
const start = performance.now();
const result = fn();
const duration = performance.now() - start;
console.log(`${label}: ${ms(duration)}`);
return result;
}
measurePerformance(() => {
// Some operation
}, 'Operation completed in');Edge Cases & Behavior
Zero and Special Values
ms(0); // "0ms"
ms('0'); // 0
ms('0ms'); // 0Negative Numbers
ms(-1000); // "-1s"
ms(-60000); // "-1m"
ms('-1s'); // -1000
ms('-5m'); // -300000Rounding Behavior
Format rounds to the nearest unit:
ms(1500); // "2s" (1.5s rounds to 2s)
ms(1400); // "1s" (1.4s rounds to 1s)
ms(90000); // "2m" (1.5m rounds to 2m)
ms(45000); // "45s" (doesn't round up to 1m)Invalid Input
// Parsing returns NaN
parse('invalid'); // NaN
parse('1xyz'); // NaN
parse('abc123'); // NaN
// Parsing throws for bad input
parse(''); // Error: must be string with length 1-99
parse(123 as any); // Error: must be string with length 1-99
parse('x'.repeat(101)); // Error: must be string with length 1-99
// Formatting throws for bad input
format('1000' as any); // Error: must be of type number
format(Infinity); // Error: must be of type number
format(NaN); // Error: must be of type numberCase Insensitivity
ms('1s'); // 1000
ms('1S'); // 1000
ms('1Second'); // 1000
ms('1SECOND'); // 1000Whitespace Handling
ms('1 s'); // 1000
ms('5 m'); // 300000
ms('2 h'); // 7200000Decimal Precision
ms('1.5s'); // 1500
ms('2.5m'); // 150000
ms('0.5h'); // 1800000
ms('0.001s'); // 1
ms('0.1s'); // 100TypeScript Usage
Type Safety
import {ms, StringValue} from '@jsxx/ms';
// Valid at compile-time
const duration: StringValue = '1s';
ms(duration); // ✓
// Type inference
const milliseconds = ms('1s'); // type: number
const formatted = ms(1000); // type: stringFunction Overloads
TypeScript correctly infers return types:
const num = ms('1s'); // type: number
const str = ms(1000); // type: string
const longStr = ms(1000, {long: true}); // type: stringGeneric Usage
function convertTime<T extends number | StringValue>(
value: T,
): T extends number ? string : number {
return ms(value as any);
}
convertTime(1000); // Returns string
convertTime('1s'); // Returns numberPerformance
- Lightweight: ~1KB minified + gzipped
- Fast parsing: O(1) Map-based unit lookup with precompiled regex
- Fast formatting: O(1) direct if-else chain (no iteration)
- Optimized: Precompiled regex and efficient data structures
Browser Support
Works in all modern browsers and Node.js environments that support:
- ES2015+ features
MapandSetNumber.isFinite()Math.abs(),Math.round()- Regular expressions
Why @jsxx/ms?
- Lightweight - ~1KB minified + gzipped
- Type-safe - Template literal types for compile-time safety
- Fast - Optimized with Map-based lookups and precompiled regex
- Modern - Written with modern JavaScript, ESM-first
- Well-tested - 43+ tests covering all features and edge cases
- Tree-shakeable - Import only what you need
- Part of @jsxx ecosystem - Consistent API across @jsxx packages
Contributing
Contributions are welcome! Please ensure:
- All tests pass:
pnpm test - Code follows existing style:
pnpm lint - Types are correct:
pnpm check-types - Add tests for new features
- Update documentation
License
MIT
