temporal-react-hook
Version:
A React library that provides hooks for handling date and time operations using the Temporal API
58 lines (50 loc) • 2.16 kB
text/typescript
import { useState, useEffect, useCallback } from 'react';
import { Temporal } from '@js-temporal/polyfill';
export interface TimeZoneOffsetOptions {
/**
* If true, the hook returns the offset as a signed number of minutes.
* If false (default), it returns a formatted string such as "UTC+04:00".
*/
asMinutes?: boolean;
/**
* Interval, in milliseconds, at which to re-evaluate the offset.
* Defaults to 60 000 ms (one minute) which is ample to capture DST jumps.
*/
updateOnTick?: number;
}
/**
* React hook that returns the current UTC offset for a given IANA time-zone and
* keeps it up-to-date as Daylight Saving Time transitions occur.
*
* @param zone IANA time-zone identifier. Defaults to the system zone.
* @param opts Behavioural options – see {@link TimeZoneOffsetOptions}.
* @returns Either a formatted offset string (e.g. "UTC+02:00") or a signed
* number of minutes east of UTC, depending on `opts.asMinutes`.
*/
export default function useTimeZoneOffset(
zone: string | Temporal.TimeZoneLike | undefined = Temporal.Now.timeZoneId(),
opts: TimeZoneOffsetOptions = {}
): string | number {
const { asMinutes = false, updateOnTick = 60_000 } = opts;
const calcOffset = useCallback(() => {
const zdt = Temporal.Now.zonedDateTimeISO(zone as any);
const minutes = zdt.offsetNanoseconds / 60_000_000_000;
return asMinutes ? minutes : formatOffset(minutes);
}, [zone, asMinutes]);
const [offset, setOffset] = useState<string | number>(() => calcOffset());
useEffect(() => {
setOffset(calcOffset()); // sync immediately when deps change
const id = window.setInterval(() => setOffset(calcOffset()), updateOnTick);
return () => window.clearInterval(id);
}, [calcOffset, updateOnTick]);
return offset;
}
function formatOffset(totalMinutes: number): string {
const sign = totalMinutes >= 0 ? '+' : '−'; // U+2212 minus sign for aesthetics
const abs = Math.abs(totalMinutes);
const hours = Math.floor(abs / 60)
.toString()
.padStart(2, '0');
const minutes = (abs % 60).toString().padStart(2, '0');
return `UTC${sign}${hours}:${minutes}`;
}