Timezone Helpers#
Timezone utilities for handling dates across different timezones. Uses the Intl API (built-in, zero-deps).
Timezone vs Date Library
These helpers convert instants across zones (parse, format, offset, grouping). For date-fns-style formatting tokens, distances, intervals, and 95 locales, see Date Library.
parseTime#
Parse a time string in a specific timezone:
typescript
import { parseTime } from "@buntok/core";
// Wall-clock string without zone info - interpreted in that timezone
const meeting = parseTime("2024-01-15 14:30", "America/New_York");
// → 2024-01-15T19:30:00.000Z (UTC instant, correct on any server TZ)
// Strings that already carry a zone are used as-is
parseTime("2024-01-15T14:30:00+07:00", "Asia/Jakarta").toISOString();
// "2024-01-15T07:30:00.000Z"
// Must include a date (bare times like "14:30" throw)
parseTime("14:30", "Asia/Jakarta");
// Error: Invalid date string: "14:30"
// Returns a UTC Date instant; print it with formatInTimezone belowformatInTimezone#
Format a Date object in a specific timezone:
typescript
import { formatInTimezone } from "@buntok/core";
const date = new Date("2024-01-15T14:30:00Z");
// 3rd arg is enum: "short" | "default" | "full" (not a custom pattern)
formatInTimezone(date, "Asia/Jakarta", "short");
// "2024-01-15 21:30" - YYYY-MM-DD HH:mm
formatInTimezone(date, "Asia/Jakarta", "default");
// "2024-01-15 21:30:00" - includes seconds
formatInTimezone(date, "Asia/Jakarta", "full");
// "2024-01-15 21:30:00.000" - adds millisecondstoTimezoneParts#
Get individual timezone parts:
typescript
import { toTimezoneParts } from "@buntok/core";
const parts = toTimezoneParts(new Date(), "Asia/Jakarta");
// { year: 2024, month: 1, day: 15, hour: 14, minute: 30, second: 0 }
// (6 fields - no weekday)
nowInTimezone#
Get current time in a specific timezone:
typescript
import { nowInTimezone } from "@buntok/core";
const jakartaTime = nowInTimezone("Asia/Jakarta");
const nyTime = nowInTimezone("America/New_York");getTimezoneOffset#
Get timezone offset in minutes from UTC:
typescript
import { getTimezoneOffset, getTimezoneOffsetString } from "@buntok/core";
getTimezoneOffset("Asia/Jakarta"); // -420 (UTC+7, negative = ahead)
getTimezoneOffset("America/New_York"); // 240 or 300 (DST, positive = behind)
getTimezoneOffset("UTC"); // 0
getTimezoneOffsetString("Asia/Jakarta"); // "+07:00"
getTimezoneOffsetString("America/New_York"); // "-05:00" or "-04:00" (DST)
isValidTimezone#
Check if a timezone string is valid:
typescript
import { isValidTimezone } from "@buntok/core";
isValidTimezone("Asia/Jakarta"); // true
isValidTimezone("America/New_York"); // true
isValidTimezone("Invalid/Zone"); // falseAdditional Helpers#
| Function | Description |
|---|---|
| getTimezoneOffsetString(tz) | Offset as string (+07:00) |
| toISOWithTimezone(date, tz) | ISO string with offset (2024-01-15T17:30:00+07:00) |
| groupByTimezone(items, field, tz, "day") | Group items by hour/day/month/year |
| getGroupLabels(groupMap, groupBy, locale?) | Map of group key → localized label |
| formatGroupLabel(key, groupBy, locale?) | Localize a single key (default en-US) |
typescript
import {
toISOWithTimezone, groupByTimezone, getGroupLabels, formatGroupLabel,
} from "@buntok/core";
// GroupByKey = "hour"|"day"|"month"|"year"; GroupByTimezoneOptions { locale?, labelFormatter? }
toISOWithTimezone(new Date("2024-01-15T10:30:00Z"), "Asia/Jakarta");
// "2024-01-15T17:30:00+07:00"
const grouped = groupByTimezone(orders, "createdAt", "Asia/Jakarta", "day");
// Map<string, Order[]> - e.g. "2024-01-15" → [orders]
const labels = getGroupLabels(grouped, "day");
// Map { "2024-01-15" => "Monday, January 15, 2024" }
formatGroupLabel("2024-01-15", "day", "en-US"); // "Monday, January 15, 2024"Full Example#
typescript
import {
parseTime, formatInTimezone, nowInTimezone,
getTimezoneOffset, getTimezoneOffsetString, isValidTimezone, toTimezoneParts,
} from "@buntok/core";
// API endpoint returning user's local time
app.get("/time/:timezone", (ctx) => {
const { timezone } = ctx.params;
if (!isValidTimezone(timezone)) {
return ctx.error("Invalid timezone", 400);
}
return ctx.json({
timezone,
now: nowInTimezone(timezone),
formatted: formatInTimezone(new Date(), timezone, "default"), // "short"|"default"|"full"
offset: getTimezoneOffset(timezone), // -420 for Jakarta
offsetStr: getTimezoneOffsetString(timezone), // "+07:00"
parts: toTimezoneParts(new Date(), timezone), // { year, month, day, hour, minute, second }
});
});