timezones.ts3.5 KBView on GitHub import { toZonedTime, fromZonedTime, formatInTimeZone } from 'date-fns-tz';
export const getBrowserTimezone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
/** A curated list of common IANA timezones for the calendar timezone picker. */
export const COMMON_TIMEZONES: { id: string; label: string }[] = [
{ id: 'Pacific/Honolulu', label: 'Honolulu' },
{ id: 'America/Anchorage', label: 'Anchorage' },
{ id: 'America/Los_Angeles', label: 'Los Angeles' },
{ id: 'America/Denver', label: 'Denver' },
{ id: 'America/Chicago', label: 'Chicago' },
{ id: 'America/New_York', label: 'New York' },
{ id: 'America/Sao_Paulo', label: 'São Paulo' },
{ id: 'Europe/London', label: 'London' },
{ id: 'Europe/Paris', label: 'Paris' },
{ id: 'Europe/Berlin', label: 'Berlin' },
{ id: 'Europe/Moscow', label: 'Moscow' },
{ id: 'Asia/Dubai', label: 'Dubai' },
{ id: 'Asia/Kolkata', label: 'Mumbai' },
{ id: 'Asia/Singapore', label: 'Singapore' },
{ id: 'Asia/Shanghai', label: 'Shanghai' },
{ id: 'Asia/Tokyo', label: 'Tokyo' },
{ id: 'Australia/Sydney', label: 'Sydney' },
{ id: 'Pacific/Auckland', label: 'Auckland' },
];
/** Short abbreviation for a timezone at a given instant, e.g. "EST", "PST", "GMT+2". */
export function getTimezoneAbbreviation(timezone: string, at: Date = new Date()): string {
return (
at
.toLocaleString('en-US', { timeZoneName: 'short', timeZone: timezone })
.split(' ')
.pop() ?? ''
);
}
/**
* Compact hour label for a multi-timezone calendar gutter. Given `hour` (0–23) as the
* wall-clock hour of the row in `primaryTimezone` on `refDateISO` (a 'yyyy-MM-dd' date in
* that timezone), returns the corresponding wall-clock label in `targetTimezone` — e.g.
* "12AM", "6AM", "12PM". Minutes are shown only when the target has a fractional offset
* (e.g. "12:30AM" for India), so whole-hour zones stay compact.
*/
export function getHourLabelInTimezone(
refDateISO: string,
hour: number,
primaryTimezone: string,
targetTimezone: string,
): string {
const instant = fromZonedTime(
`${refDateISO}T${String(hour).padStart(2, '0')}:00:00`,
primaryTimezone,
);
const minutes = formatInTimeZone(instant, targetTimezone, 'mm');
const pattern = minutes === '00' ? 'ha' : 'h:mma';
return formatInTimeZone(instant, targetTimezone, pattern).toUpperCase();
}
/**
* Convert a date from one timezone to another.
*
* This is useful when parsing dates like "3pm EST" and converting them to the user's timezone.
* The function interprets the input date as being in the source timezone and returns
* the equivalent date in the target timezone.
*
* @param date - The date to convert (interpreted as being in fromTimezone)
* @param fromTimezone - The source IANA timezone identifier (e.g., 'America/New_York')
* @param toTimezone - The target IANA timezone identifier (e.g., 'America/Los_Angeles')
* @returns A new Date object representing the same moment in the target timezone
*
* @example
* // User in PST types "friday 3pm est"
* const date = new Date('2026-01-31T15:00:00'); // 3pm (no timezone)
* const converted = convertTimezone(date, 'America/New_York', 'America/Los_Angeles');
* // Result: 12pm PST (3 hours earlier)
*/
export function convertTimezone(
date: Date,
fromTimezone: string,
toTimezone: string,
): Date {
// Interpret the date as being in the source timezone
const zonedTime = fromZonedTime(date, fromTimezone);
// Convert to the target timezone
return toZonedTime(zonedTime, toTimezone);
}