@ratio-hub/time
v1.1.0
Published
Type-safe time library for TypeScript. Branded types prevent mixing up seconds and milliseconds.
Maintainers
Readme
@ratio-hub/time
Type-safe time library for TypeScript. Branded types prevent mixing up seconds and milliseconds.
Install
bun add @ratio-hub/timeQuick Start
import { Time, Duration, dur } from "@ratio-hub/time";
// Create time from JWT expiration (unix seconds)
const exp = Time.seconds(jwt.exp);
// Check if token expired
if (exp.hasExpired()) {
console.log("Token expired");
}
// Check if token expires within 5 minutes (proactive refresh)
if (exp.expiresWithin("5m")) {
console.log("Token expiring soon, refresh it");
}
// Parse duration strings
const oneHour = dur("1h"); // Duration
const mixed = dur("1h30m"); // Duration (1.5 hours)
console.log(mixed.toMillis()); // 5400000
console.log(mixed.toMinutes()); // 90Time
Creating Time Instances
// All factories are explicit about units
const now = Time.now(); // current time
const fromSec = Time.seconds(1704067200); // from unix seconds
const fromMs = Time.millis(1704067200000); // from unix milliseconds
const fromDate = Time.date(new Date()); // from Date object
const fromISO = Time.iso("2024-01-01T00:00:00Z"); // from ISO string
// Shortcuts for relative times
const inOneHour = Time.in("1h"); // Time: 1 hour from now
const thirtyMinsAgo = Time.ago("30m"); // Time: 30 minutes agoArithmetic
All operations return new Time instances (immutable).
const now = Time.now();
const later = now.add("1h"); // Time: 1 hour later
const earlier = now.subtract("30m"); // Time: 30 minutes earlier
// Get difference between two times
const t1 = Time.seconds(2000);
const t2 = Time.seconds(1000);
const diff = t1.diff(t2); // Duration: 1000 seconds
console.log(diff.toSeconds()); // 1000Comparisons
const t1 = Time.seconds(1000);
const t2 = Time.seconds(2000);
t1.isBefore(t2); // true
t1.isAfter(t2); // false
t1.equals(t2); // false
// Relative to current time
const past = Time.ago("1h");
past.isPast(); // true
past.isFuture(); // falseWindow Checks
const lastRequest = Time.ago("30s");
// Is this time within 1 minute of now?
lastRequest.isWithin("1m"); // true (30s < 1m)
// Is this time within 10 seconds of now?
lastRequest.isWithin("10s"); // false (30s > 10s)
// Check against a specific anchor time
const anchor = Time.seconds(1000);
const target = Time.seconds(1050);
target.isWithin("100s", anchor); // true (50s < 100s)Expiration Helpers
const tokenExp = Time.in("10m"); // expires in 10 minutes
tokenExp.hasExpired(); // false (still in future)
tokenExp.expiresWithin("15m"); // true (expires within 15 min window)
tokenExp.expiresWithin("5m"); // false (won't expire in next 5 min)
const oldToken = Time.ago("5m"); // expired 5 minutes ago
oldToken.hasExpired(); // true
oldToken.expiredWithin("10m"); // true (expired within last 10 min)
oldToken.expiredWithin("2m"); // false (expired more than 2 min ago)Output
const time = Time.seconds(1704067200);
time.toSeconds(); // 1704067200 (Seconds type)
time.toMillis(); // 1704067200000 (Milliseconds type)
time.toDate(); // Date object
time.toISO(); // '2024-01-01T00:00:00.000Z'
// Human-readable relative time
Time.in("5m").toRelative(); // 'in 5m'
Time.ago("2h").toRelative(); // '2h ago'
Time.ago("2h").toRelative({ long: true }); // '2 hours ago'Duration
Creating Durations
// From strings using dur()
const d1 = dur("1h"); // 1 hour
const d2 = dur("30m"); // 30 minutes
const d3 = dur("1h30m"); // 1 hour 30 minutes (compound)
const d4 = dur("1w2d"); // 1 week 2 days
const d5 = dur("1 hour"); // with space
const d6 = dur("-5m"); // negative duration
// From numbers using static methods
const d7 = Duration.milliseconds(1000);
const d8 = Duration.seconds(60);
const d9 = Duration.minutes(30);
const d10 = Duration.hours(2);
const d11 = Duration.days(7);
const d12 = Duration.weeks(1);
const d13 = Duration.months(6); // approximate (year/12)
const d14 = Duration.years(1); // approximate (365.25 days)Arithmetic
All operations return new Duration instances (immutable).
const oneHour = dur("1h");
oneHour.add("30m"); // Duration: 1h30m (5400000ms)
oneHour.subtract("15m"); // Duration: 45m (2700000ms)
oneHour.multiply(2); // Duration: 2h (7200000ms)
oneHour.divide(2); // Duration: 30m (1800000ms)
dur("-1h").abs(); // Duration: 1h (positive)
dur("1h").negate(); // Duration: -1h (negative)Comparisons
dur("1h").equals("60m"); // true
dur("2h").greaterThan("1h"); // true
dur("30m").lessThan("1h"); // true
dur("0s").isZero(); // true
dur("-1h").isNegative(); // true
dur("1h").isPositive(); // trueOutput
const d = dur("90m");
d.toMillis(); // 5400000
d.toSeconds(); // 5400
d.toMinutes(); // 90
d.toHours(); // 1.5
d.toDays(); // 0.0625
// Human-readable (rounds to largest sensible unit)
dur("90m").humanize(); // '2h'
dur("90m").humanize({ long: true }); // '2 hours'
dur("45s").humanize(); // '45s'
dur("3d").humanize({ long: true }); // '3 days'Duration Strings
Supported formats:
| Unit | Formats |
| ------------ | ---------------------------------------------------- |
| Years | y, yr, yrs, year, years |
| Months | mo, month, months |
| Weeks | w, week, weeks |
| Days | d, day, days |
| Hours | h, hr, hrs, hour, hours |
| Minutes | m, min, mins, minute, minutes |
| Seconds | s, sec, secs, second, seconds |
| Milliseconds | ms, msec, msecs, millisecond, milliseconds |
Compound: 1h30m, 1w2d, 2h30m15s
Case insensitive: 1H, 1Hour, 1HOUR all work.
Type Safety
The library exports branded Seconds and Milliseconds types. TypeScript will catch if you accidentally mix them:
import type { Seconds, Milliseconds } from "@ratio-hub/time";
const sec: Seconds = time.toSeconds(); // OK
const ms: Milliseconds = time.toMillis(); // OK
// TypeScript error: Type 'Seconds' is not assignable to type 'Milliseconds'
const wrong: Milliseconds = time.toSeconds();This prevents bugs like passing seconds to an API that expects milliseconds.
License
MIT
