UNPKG

ts-time-utils

Version:

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

100 lines (99 loc) 3.88 kB
/** * Timezone utilities using Intl API with fallbacks */ /** Get offset (minutes) for a zone at a given date */ export function getTimezoneOffset(zone, date = new Date()) { try { const dtf = new Intl.DateTimeFormat('en-US', { timeZone: zone, timeZoneName: 'shortOffset', hour: '2-digit' }); const parts = dtf.formatToParts(date); const tzPart = parts.find(p => p.type === 'timeZoneName'); if (!tzPart) return null; // Examples: "GMT+2", "UTC-05:00" const match = tzPart.value.match(/([+-])(\d{1,2})(?::?(\d{2}))?/); if (!match) return 0; // could be GMT or UTC with no offset const sign = match[1] === '-' ? -1 : 1; const hours = parseInt(match[2], 10); const mins = match[3] ? parseInt(match[3], 10) : 0; return sign * (hours * 60 + mins); } catch { return null; } } /** Format date/time in a zone */ export function formatInTimeZone(date, zone, options = {}) { const fmt = new Intl.DateTimeFormat('en-US', { timeZone: zone, ...options }); return fmt.format(date); } /** Get a lightweight ZonedTime object */ export function getZonedTime(date, zone) { const offset = getTimezoneOffset(zone, date); if (offset == null) return null; return { date: new Date(date), zone, offsetMinutes: offset }; } /** Convert a date (treated as absolute moment) to another zone's clock components */ export function convertDateToZone(date, zone) { try { const fmt = new Intl.DateTimeFormat('en-US', { timeZone: zone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }); const parts = fmt.formatToParts(date); const get = (type) => parseInt(parts.find(p => p.type === type)?.value || '0', 10); return { year: get('year'), month: get('month'), day: get('day'), hour: get('hour'), minute: get('minute'), second: get('second') }; } catch { return null; } } /** Check if provided zone string is a valid IANA zone */ export function isValidTimeZone(zone) { try { new Intl.DateTimeFormat('en-US', { timeZone: zone }); return true; } catch { return false; } } /** List a subset of common timezones (cannot enumerate all via API) */ export const COMMON_TIMEZONES = [ 'UTC', 'Etc/UTC', 'Europe/London', 'Europe/Paris', 'Europe/Berlin', 'Europe/Madrid', 'Europe/Rome', 'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'America/Toronto', 'America/Sao_Paulo', 'Asia/Tehran', 'Asia/Dubai', 'Asia/Tokyo', 'Asia/Shanghai', 'Asia/Singapore', 'Asia/Kolkata', 'Asia/Hong_Kong', 'Australia/Sydney', 'Pacific/Auckland' ]; /** Get current local offset in minutes */ export function getLocalOffset() { return -new Date().getTimezoneOffset(); } /** Compare two timezones offset at given date */ export function compareZoneOffsets(zoneA, zoneB, date = new Date()) { const a = getTimezoneOffset(zoneA, date); const b = getTimezoneOffset(zoneB, date); if (a == null || b == null) return null; return a - b; // positive if A ahead of B } /** Shift a date by target zone offset difference relative to current local zone. * This does not change the absolute moment; instead returns a new Date representing * the same wall clock time in the target zone interpreted as local. * For example useful for naive scheduling. */ export function reinterpretAsZone(date, targetZone) { const target = convertDateToZone(date, targetZone); if (!target) return null; return new Date(Date.UTC(target.year, target.month - 1, target.day, target.hour, target.minute, target.second)); }