UNPKG

ts-time-utils

Version:

A comprehensive TypeScript utility library for time, dates, durations, and calendar operations with full tree-shaking support

708 lines (571 loc) 23.1 kB
# ts-time-utils A lightweight TypeScript utility library for time formatting, calculations, and validation with full tree-shaking support. ## 🚀 Features - **📦 Lightweight** - Import only what you need with tree-shaking support - **⚡ Fast** - Zero dependencies, pure JavaScript functions - **🔧 TypeScript** - Full type safety and IntelliSense support - **🌳 Tree-shakable** - Import individual functions to minimize bundle size - **📚 Comprehensive** - 15 utility categories with 115+ functions ### ⏱️ Duration utilities - Immutable Duration class with arithmetic operations - Create durations from various units and string formats - Add, subtract, multiply, divide durations - Compare durations and check relationships - Format to human-readable strings - Utility functions for arrays of durations ### 💾 Serialization utilities - Safe JSON date serialization and deserialization - Multiple format support (ISO, epoch, object, custom) - Automatic date reviver and replacer functions - Timezone-aware serialization options - Cross-platform date interchange utilities - Validation for ISO strings and epoch timestamps ### 🎨 Format utilities - Format milliseconds to human-readable durations - Get human-friendly "time ago" strings - Parse duration strings back to milliseconds - Format time in 12h/24h/ISO formats ### 🧮 Calculation utilities - Calculate difference between dates in any unit - Add/subtract time from dates - Get start/end of time periods - Business days calculations - Check if date is between two dates ### ✅ Validation utilities - Validate dates and time strings - Check for leap years, weekends, past/future dates - Compare dates (same day, today, yesterday, etc.) ### 🎂 Age utilities - Calculate precise age with years, months, and days - Get life stage classifications (infant, child, adult, etc.) - Birthday calculations and next birthday finder - Check if today is someone's birthday ### 📅 Calendar utilities - ISO week numbers and week-based calculations - Quarter operations and fiscal year support - Holiday calculations (Easter, Thanksgiving, etc.) - Days in month/year calculations ### 🔍 Parse utilities - Advanced date parsing from multiple formats - Relative date parsing ("tomorrow", "next week") - Custom format parsing with flexible patterns - Smart date interpretation ### ⚡ Performance utilities - Async utilities (sleep, timeout, retry) - Performance measurement and benchmarking - Stopwatch for timing operations - Function utilities (debounce, throttle, memoize) ### 📏 Interval utilities - Create and validate intervals - Overlap, intersection, merge, subtraction - Split by day and total coverage - Normalize and compute durations ### 🌐 Timezone utilities - Validate IANA timezones - Get offsets and compare zones - Format in specific timezone - Convert absolute moment to zone components - Reinterpret wall-clock times ### 🕘 Working hours utilities - Define working day patterns and breaks - Check working day/time - Compute working time between dates - Add working hours across days - Find next working time ### 🎯 Range preset utilities - Today / yesterday / tomorrow - Last/next N days windows - This/last/next week, month, quarter, year - Rolling windows and quarter helpers ### 🌍 Locale utilities - Multi-language relative time formatting - Locale-specific date and time formatting - Support for 40+ locales with built-in configurations - Auto-detection of system/browser locale - Custom locale registration - Internationalization (i18n) support - **Locale conversions** - Convert between different locales and detect locale from text ### 🧱 Constants - Milliseconds & seconds per unit - Time unit and formatting option types ## 📦 Installation ```bash npm install ts-time-utils ``` ## 🔧 Usage ### Import everything (not recommended for production) ```ts import { formatDuration, timeAgo, isValidDate } from "ts-time-utils"; ``` ### Import by category (better for tree-shaking) ```ts import { formatDuration, timeAgo } from "ts-time-utils/format"; import { differenceInUnits, addTime } from "ts-time-utils/calculate"; import { isValidDate, isLeapYear } from "ts-time-utils/validate"; import { calculateAge, getNextBirthday } from "ts-time-utils/age"; import { getWeekNumber, getQuarter } from "ts-time-utils/calendar"; import { parseDate, parseRelativeDate } from "ts-time-utils/parse"; import { sleep, benchmark, Stopwatch } from "ts-time-utils/performance"; import { createInterval, mergeIntervals } from "ts-time-utils/interval"; import { formatInTimeZone } from "ts-time-utils/timezone"; import { isWorkingTime, addWorkingHours } from "ts-time-utils/workingHours"; import { today, lastNDays } from "ts-time-utils/rangePresets"; import { Duration, createDuration } from "ts-time-utils/duration"; import { serializeDate, parseJSONWithDates } from "ts-time-utils/serialize"; import { formatRelativeTime, formatDateLocale, detectLocale, } from "ts-time-utils/locale"; ``` ## 📖 Examples ### Duration Utilities ```ts import { Duration, createDuration, formatDurationString, } from "ts-time-utils/duration"; // Create durations const duration1 = Duration.fromHours(2.5); // 2.5 hours const duration2 = new Duration({ hours: 1, minutes: 30 }); // 1.5 hours const duration3 = Duration.fromString("1h 30m 45s"); // Parse from string const duration4 = Duration.between(startDate, endDate); // From date range // Arithmetic operations const sum = duration1.add(duration2); // 4 hours const diff = duration1.subtract(duration2); // 1 hour const doubled = duration1.multiply(2); // 5 hours const half = duration1.divide(2); // 1.25 hours // Comparisons duration1.equals(duration2); // false duration1.greaterThan(duration2); // true duration1.compareTo(duration2); // 1 // Conversions and formatting duration1.hours; // 2.5 duration1.minutes; // 150 duration1.toString(); // "2h 30m" formatDurationString(duration1, { long: true }); // "2 hours, 30 minutes" // Utility functions with arrays const durations = [duration1, duration2, duration3]; const max = maxDuration(...durations); const total = sumDurations(...durations); const average = averageDuration(...durations); ``` ### Serialization Utilities ```ts import { serializeDate, deserializeDate, parseJSONWithDates, stringifyWithDates, toEpochTimestamp, fromEpochTimestamp, toDateObject, fromDateObject, } from "ts-time-utils/serialize"; // Serialize dates in different formats const date = new Date("2025-09-14T12:30:45.123Z"); const isoString = serializeDate(date, { format: "iso" }); // "2025-09-14T12:30:45.123Z" const epochMs = serializeDate(date, { format: "epoch" }); // 1757853045123 const dateObj = serializeDate(date, { format: "object" }); // {year: 2025, month: 9, ...} const custom = serializeDate(date, { format: "custom", customFormat: "YYYY-MM-DD HH:mm:ss", }); // "2025-09-14 12:30:45" // Deserialize from various formats const fromISO = deserializeDate("2025-09-14T12:30:45.123Z"); const fromEpoch = deserializeDate(1757853045123); const fromObj = deserializeDate({ year: 2025, month: 9, day: 14, hour: 12, minute: 30, second: 45, millisecond: 123, }); // Safe JSON handling with automatic date conversion const data = { name: "User", createdAt: new Date(), updatedAt: new Date(), metadata: "other data", }; // Stringify with automatic date serialization const jsonString = stringifyWithDates(data, ["createdAt", "updatedAt"], { format: "epoch", }); // {"name":"User","createdAt":1757853045123,"updatedAt":1757853045123,"metadata":"other data"} // Parse with automatic date restoration const parsed = parseJSONWithDates(jsonString, ["createdAt", "updatedAt"]); // parsed.createdAt and parsed.updatedAt are Date objects // Epoch timestamp utilities const timestamp = toEpochTimestamp(date, "seconds"); // 1757853045 const restoredDate = fromEpochTimestamp(timestamp, "seconds"); // Date object utilities (UTC-based) const dateObject = toDateObject(date, true); // includes timezone const reconstructed = fromDateObject(dateObject); ``` ### Format Utilities ```ts import { formatDuration, timeAgo, parseDuration } from "ts-time-utils/format"; // Format durations formatDuration(65000); // "1 minute, 5 seconds" formatDuration(65000, { short: true }); // "1m 5s" formatDuration(90061000, { maxUnits: 2 }); // "1 day, 1 hour" // Time ago strings timeAgo(new Date(Date.now() - 60000)); // "1 minute ago" timeAgo(new Date(Date.now() + 60000)); // "in 1 minute" // Parse duration strings parseDuration("1h 30m"); // 5400000 (milliseconds) parseDuration("2 days 3 hours"); // 183600000 ``` ### Calculate Utilities ```ts import { differenceInUnits, addTime, startOf } from "ts-time-utils/calculate"; // Date calculations differenceInUnits(new Date("2025-09-01"), new Date("2025-09-11"), "days"); // 10 addTime(new Date(), 5, "hours"); // 5 hours from now startOf(new Date(), "day"); // Start of today (00:00:00) ``` ### Validation Utilities ```ts import { isValidDate, isLeapYear, isWeekend } from "ts-time-utils/validate"; // Validations isValidDate(new Date("2025-13-01")); // false isLeapYear(2024); // true isWeekend(new Date("2025-09-13")); // true (Saturday) ``` ### Age Utilities ```ts import { calculateAge, getLifeStage, getNextBirthday, isBirthday, } from "ts-time-utils/age"; // Age calculations calculateAge(new Date("1990-05-15")); // { years: 34, months: 4, days: 2 } getLifeStage(25); // "adult" getNextBirthday(new Date("1990-05-15")); // Next May 15th isBirthday(new Date("1990-05-15"), new Date("2025-05-15")); // true ``` ### Calendar Utilities ```ts import { getWeekNumber, getQuarter, getEaster, getDaysInMonth, } from "ts-time-utils/calendar"; // Calendar operations getWeekNumber(new Date("2025-01-15")); // 3 getQuarter(new Date("2025-07-15")); // 3 getEaster(2025); // Date object for Easter Sunday 2025 getDaysInMonth(2, 2024); // 29 (leap year) ``` ### Parse Utilities ```ts import { parseDate, parseRelativeDate, parseCustomFormat, } from "ts-time-utils/parse"; // Advanced parsing parseDate("2025-02-30"); // null (invalid date) parseDate("Dec 25, 2025"); // Date object parseRelativeDate("tomorrow"); // Date for tomorrow parseCustomFormat("25/12/2025", "DD/MM/YYYY"); // Date object ``` ### Performance Utilities ```ts import { sleep, timeout, benchmark, Stopwatch, debounce, } from "ts-time-utils/performance"; // Async utilities await sleep(1000); // Wait 1 second await timeout(promise, 5000); // Timeout after 5 seconds // Performance measurement const result = await benchmark(() => heavyOperation(), 10); // Run 10 times const stopwatch = new Stopwatch(); stopwatch.start(); // ... operations console.log(stopwatch.getElapsed()); // Get elapsed time // Function utilities const debouncedFn = debounce(() => console.log("Called!"), 300); ``` ### Interval Utilities ```ts 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 const merged = mergeIntervals([a!, b!]); ``` ### Timezone Utilities ```ts import { formatInTimeZone, getTimezoneOffset } from "ts-time-utils/timezone"; formatInTimeZone(new Date(), "Europe/Paris", { hour: "2-digit", minute: "2-digit", }); getTimezoneOffset("America/New_York"); // e.g. -300 (minutes) ``` ### Working Hours Utilities ```ts import { isWorkingTime, addWorkingHours } from "ts-time-utils/workingHours"; isWorkingTime(new Date()); // depends on config addWorkingHours(new Date(), 10); // adds 10 working hours, skipping off-hours ``` ### Range Preset Utilities ```ts import { lastNDays, thisWeek, quarterRange } from "ts-time-utils/rangePresets"; const last7 = lastNDays(7); const week = thisWeek(); const quarter = quarterRange(); ``` ### Locale Utilities ```ts import { formatRelativeTime, formatDateLocale, formatTimeLocale, formatDateTimeLocale, registerLocale, getLocaleConfig, detectLocale, getSupportedLocales, } from "ts-time-utils/locale"; // Relative time formatting in multiple languages const pastDate = new Date(Date.now() - 2 * 60 * 60 * 1000); // 2 hours ago formatRelativeTime(pastDate, { locale: "en" }); // "2 hours ago" formatRelativeTime(pastDate, { locale: "es" }); // "hace 2 horas" formatRelativeTime(pastDate, { locale: "fr" }); // "il y a 2 heures" formatRelativeTime(pastDate, { locale: "de" }); // "vor 2 Stunden" formatRelativeTime(pastDate, { locale: "nl" }); // "2 uur geleden" formatRelativeTime(pastDate, { locale: "it" }); // "2 ore fa" formatRelativeTime(pastDate, { locale: "zh" }); // "2小时前" formatRelativeTime(pastDate, { locale: "ja" }); // "2時間前" formatRelativeTime(pastDate, { locale: "fa" }); // "2 ساعت پیش" // Future dates const futureDate = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000); formatRelativeTime(futureDate, { locale: "en" }); // "in 3 days" formatRelativeTime(futureDate, { locale: "es" }); // "en 3 días" formatRelativeTime(futureDate, { locale: "nl" }); // "over 3 dagen" formatRelativeTime(futureDate, { locale: "it" }); // "tra 3 giorni" formatRelativeTime(futureDate, { locale: "fa" }); // "3 روز دیگر" // Relative time options formatRelativeTime(pastDate, { locale: "en", maxUnit: "days", // Don't use units larger than days minUnit: "minutes", // Don't use units smaller than minutes precision: 1, // Show 1 decimal place: "2.0 hours ago" short: true, // Use abbreviated format: "2h ago" numeric: "auto", // Use words when appropriate: "yesterday" }); // Date formatting const date = new Date("2024-01-15T14:30:45Z"); formatDateLocale(date, "en", "medium"); // "Jan 15, 2024" formatDateLocale(date, "es", "medium"); // "15 ene 2024" formatDateLocale(date, "fr", "long"); // "15 janvier 2024" formatDateLocale(date, "de", "short"); // "15.1.2024" // Time formatting formatTimeLocale(date, "en", "short"); // "2:30 PM" formatTimeLocale(date, "de", "medium"); // "14:30:45" formatTimeLocale(date, "fr", "long"); // "14:30:45 UTC" // Combined date and time formatDateTimeLocale(date, "en"); // "Jan 15, 2024 2:30:45 PM" // Auto-detect locale from browser/system const userLocale = detectLocale(); // e.g., 'en-US' or 'fr-FR' formatRelativeTime(pastDate, { locale: userLocale }); // Get supported locales const locales = getSupportedLocales(); // ['en', 'es', 'fr', 'de', 'zh', 'ja', ...] // Register custom locale registerLocale("custom", { locale: "custom", dateFormats: { short: "M/d/yyyy", medium: "MMM d, yyyy", long: "MMMM d, yyyy", full: "EEEE, MMMM d, yyyy", }, timeFormats: { short: "h:mm a", medium: "h:mm:ss a", long: "h:mm:ss a z", full: "h:mm:ss a zzzz", }, relativeTime: { future: "in {0}", past: "{0} ago", units: { second: "sec", seconds: "secs", minute: "min", minutes: "mins", hour: "hr", hours: "hrs", day: "day", days: "days", week: "wk", weeks: "wks", month: "mo", months: "mos", year: "yr", years: "yrs", }, }, calendar: { weekStartsOn: 0, // Sunday monthNames: ["Jan", "Feb", "Mar" /* ... */], monthNamesShort: ["J", "F", "M" /* ... */], dayNames: ["Sun", "Mon", "Tue" /* ... */], dayNamesShort: ["S", "M", "T" /* ... */], }, numbers: { decimal: ".", thousands: ",", }, }); // Locale Conversion Utilities import { convertRelativeTime, detectLocaleFromRelativeTime, convertFormatPattern, convertFormattedDate, convertRelativeTimeArray, compareLocaleFormats, } from "ts-time-utils/locale"; // Convert relative time between locales convertRelativeTime("2 hours ago", "en", "es"); // "hace 2 horas" convertRelativeTime("hace 3 días", "es", "fr"); // "il y a 3 jours" convertRelativeTime("2h ago", "en", "de"); // "vor 2h" convertRelativeTime("2 hours ago", "en", "nl"); // "2 uur geleden" convertRelativeTime("2 hours ago", "en", "it"); // "2 ore fa" convertRelativeTime("2 hours ago", "en", "fa"); // "2 ساعت پیش" convertRelativeTime("2 ساعت پیش", "fa", "en"); // "2 hours ago" // Detect locale from formatted text detectLocaleFromRelativeTime("2 hours ago"); // "en" detectLocaleFromRelativeTime("hace 2 horas"); // "es" detectLocaleFromRelativeTime("il y a 2 heures"); // "fr" detectLocaleFromRelativeTime("2 uur geleden"); // "nl" detectLocaleFromRelativeTime("2 ore fa"); // "it" detectLocaleFromRelativeTime("2 ساعت پیش"); // "fa" detectLocaleFromRelativeTime("vor 2 Stunden"); // "de" // Convert date format patterns between locales convertFormatPattern("M/d/yyyy", "en", "de"); // "dd.MM.yyyy" convertFormatPattern("MMM d, yyyy", "en", "fr", "long"); // "d MMMM yyyy" // Convert formatted dates between locales convertFormattedDate("Jan 15, 2024", "en", "es"); // "15 ene 2024" convertFormattedDate("15. Januar 2024", "de", "en"); // "Jan 15, 2024" // Bulk conversion of relative time arrays const englishTimes = ["2 hours ago", "in 3 days", "1 week ago"]; convertRelativeTimeArray(englishTimes, "en", "es"); // ["hace 2 horas", "en 3 días", "hace 1 semana"] // Compare format differences between locales const comparison = compareLocaleFormats("en", "de"); console.log(comparison.dateFormats.short); // { locale1: "M/d/yyyy", locale2: "dd.MM.yyyy" } console.log(comparison.weekStartsOn); // { locale1: 0, locale2: 1 } // Sunday vs Monday ``` ## 📊 API Reference ### Duration Functions - `Duration` class - Immutable duration with full arithmetic support - `createDuration(input)` - Create duration from number, object, or string - `Duration.fromHours/Minutes/Seconds/Days/Weeks(n)` - Create from specific units - `Duration.fromString(str)` - Parse from string like "1h 30m 45s" - `Duration.between(start, end)` - Create from date range - `duration.add/subtract/multiply/divide()` - Arithmetic operations - `duration.equals/greaterThan/lessThan()` - Comparison methods - `formatDurationString(duration, options?)` - Format to readable string - `maxDuration/minDuration(...durations)` - Find extremes - `sumDurations/averageDuration(...durations)` - Aggregate operations ### Serialization Functions - `serializeDate(date, options?)` - Serialize date to various formats (ISO, epoch, object, custom) - `deserializeDate(serialized, options?)` - Deserialize from string, number, or object - `parseJSONWithDates(jsonString, dateKeys?, options?)` - Parse JSON with automatic date conversion - `stringifyWithDates(obj, dateKeys?, options?)` - Stringify JSON with automatic date serialization - `createDateReviver/createDateReplacer(dateKeys?, options?)` - Create JSON reviver/replacer functions - `toEpochTimestamp/fromEpochTimestamp(input, precision?)` - Convert to/from epoch timestamps - `toDateObject/fromDateObject(input)` - Convert to/from safe object representation - `isValidISODateString/isValidEpochTimestamp(input)` - Validation utilities - `cloneDate(date)` - Safe date cloning - `datesEqual(date1, date2, precision?)` - Compare dates with precision control ### Format Functions - `formatDuration(ms, options?)` - Format milliseconds to readable duration - `timeAgo(date, options?)` - Get "time ago" string for past/future dates - `formatTime(date, format?)` - Format time as 12h/24h/ISO - `parseDuration(duration)` - Parse duration string to milliseconds ### Calculate Functions - `differenceInUnits(date1, date2, unit?, precise?)` - Calculate difference between dates - `addTime(date, amount, unit)` - Add time to a date - `subtractTime(date, amount, unit)` - Subtract time from a date - `startOf(date, unit)` - Get start of time period - `endOf(date, unit)` - Get end of time period - `isBetween(date, start, end)` - Check if date is between two dates - `businessDaysBetween(start, end)` - Count business days between dates ### Validation Functions - `isValidDate(date)` - Check if date is valid - `isLeapYear(year)` - Check if year is leap year - `isPast(date)` / `isFuture(date)` - Check if date is past/future - `isToday(date)` / `isYesterday(date)` / `isTomorrow(date)` - Date comparisons - `isSameDay(date1, date2)` - Check if dates are same day - `isWeekend(date)` / `isWeekday(date)` - Check day type - `isValidTimeString(time)` - Validate HH:MM time format - `isValidISOString(dateString)` - Validate ISO 8601 date string ### Locale Functions - `formatRelativeTime(date, options?)` - Format relative time with locale support - Options: `locale`, `maxUnit`, `minUnit`, `precision`, `short`, `numeric`, `style` - Supports 30+ locales: en, es, fr, de, it, pt, nl, sv, da, no, fi, pl, cs, sk, hu, ro, bg, hr, sl, et, lv, lt, ru, uk, tr, ar, he, hi, th, ko, zh, ja - `formatDateLocale(date, locale?, style?)` - Format date in locale-specific format - Styles: 'short', 'medium', 'long', 'full' - `formatTimeLocale(date, locale?, style?)` - Format time in locale-specific format - `formatDateTimeLocale(date, locale?, dateStyle?, timeStyle?)` - Format both date and time - `registerLocale(locale, config)` - Register a custom locale configuration - `getLocaleConfig(locale)` - Get configuration for a specific locale - `detectLocale(fallback?)` - Auto-detect system/browser locale - `getSupportedLocales()` - Get array of all supported locale codes - `getMonthNames(locale?, short?)` - Get localized month names - `getDayNames(locale?, short?)` - Get localized day names - `getBestMatchingLocale(preferences, fallback?)` - Find best matching locale from preferences #### Locale Conversion Functions - `convertRelativeTime(text, fromLocale, toLocale)` - Convert relative time between locales - Example: `convertRelativeTime("2 hours ago", "en", "es")` → `"hace 2 horas"` - Example: `convertRelativeTime("2 hours ago", "en", "nl")` → `"2 uur geleden"` - Example: `convertRelativeTime("2 hours ago", "en", "it")` → `"2 ore fa"` - Example: `convertRelativeTime("2 hours ago", "en", "fa")` → `"2 ساعت پیش"` - `detectLocaleFromRelativeTime(text)` - Detect locale from relative time string - Returns most likely locale or null if detection fails - `convertFormatPattern(pattern, fromLocale, toLocale, style?)` - Convert date format patterns - Maps common patterns between locales or uses target locale's style - `convertFormattedDate(formattedDate, fromLocale, toLocale, targetStyle?)` - Convert formatted dates - Parses date in source locale and reformats in target locale - `convertRelativeTimeArray(array, fromLocale, toLocale)` - Bulk convert relative time arrays - Returns array with same length, null for unparseable strings - `compareLocaleFormats(locale1, locale2)` - Compare format differences between locales - Returns object with dateFormats, timeFormats, and weekStartsOn comparisons ## 🛠️ Development ```bash # Install dependencies npm install # Build (both CommonJS and ES modules) npm run build # Run tests npm test # Run tests in watch mode npm run test:watch # Lint code npm run lint ``` ## 📄 License MIT