Appearance
useTemporalNow
Reactive Temporal API with timezone conversion and calendar system support.
Uses the modern Temporal API instead of the legacy Date object, providing better timezone handling, calendar systems, and date/time operations.
Demo
Requirements
This function relies on the Temporal API. It does not bundle or depend on any Temporal implementation — by default it reads the global Temporal object, but you can also pass your own implementation via the temporal option.
Modern JS engines (recent Node.js, Deno, and browsers) already expose
Temporalnatively, or will soon.For environments without native support, install a polyfill yourself, for example
temporal-polyfill:bashnpm i temporal-polyfilland either load it once as a global, before this function is used (e.g. in your app's entry point):
tsimport 'temporal-polyfill/global'If you need calendar systems beyond
iso8601/gregory(e.g.islamic,hebrew,chinese,japaneseas used in the examples below), use the/full/entry point instead:tsimport 'temporal-polyfill/full/global'...or pass it explicitly via the
temporaloption instead of touching the global scope:tsximport { useTemporalNow } from '@reause/core' import { Temporal } from 'temporal-polyfill' const temporal = useTemporalNow({ temporal: Temporal })@js-temporal/polyfillis another common alternative. It does not install a globalTemporalobject by itself, so thetemporaloption is the natural way to use it. Its type declarations are authored independently from TypeScript's own ambientTemporaltypes (unliketemporal-polyfill, which derives its types from the same source), so a cast is needed to satisfy thetemporaloption at compile time — the runtime objects are spec-compliant and interoperate fine:tsximport type { TemporalImplementation } from '@reause/core' import { Temporal } from '@js-temporal/polyfill' import { useTemporalNow } from '@reause/core' const temporal = useTemporalNow({ temporal: Temporal as unknown as TemporalImplementation })
If no Temporal implementation can be found (neither passed via the temporal option nor available globally), calling useTemporalNow will throw an error.
Usage
Basic Usage
tsx
import { useTemporalNow } from '@reause/core'
const { now, timezone, calendar, format } = useTemporalNow()
// Display current time
console.log(format()) // "12/25/2023, 3:30:00 PM"Timezone Conversion
tsx
const temporal = useTemporalNow({ timezone: 'America/New_York' })
// Convert to different timezones
const tokyoTime = temporal.toTimezone('Asia/Tokyo')
const londonTime = temporal.toTimezone('Europe/London')
const utcTime = temporal.toTimezone('UTC')
// Change timezone reactively
temporal.setTimezone('Europe/Berlin')Calendar Systems
tsx
const temporal = useTemporalNow({ calendar: 'gregory' })
// Convert to different calendar systems
const islamicDate = temporal.toCalendar('islamic-umalqura')
const hebrewDate = temporal.toCalendar('hebrew')
const chineseDate = temporal.toCalendar('chinese')
// Change calendar reactively
temporal.setCalendar('islamic-umalqura')Date/Time Manipulation
tsx
const { add, subtract, compare } = useTemporalNow()
// Add/subtract durations
const nextWeek = add('P7D') // add 7 days
const lastMonth = subtract('P1M') // subtract 1 month
const inTwoHours = add('PT2H') // add 2 hours
// Compare dates
const futureDate = add('P1Y') // add 1 year
const comparison = compare(futureDate) // -1 (now is before futureDate)Format Options
tsx
const { format } = useTemporalNow()
// Different formatting options
const short = format({ dateStyle: 'short' }) // "12/25/23"
const long = format({ dateStyle: 'long' }) // "December 25, 2023"
const time = format({ timeStyle: 'medium' }) // "3:30:00 PM"
const custom = format({
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}) // "Monday, December 25, 2023"Control Auto-Update
By default useTemporalNow updates on every requestAnimationFrame. Pass a custom scheduler to control how updates are driven — for example, tick on a fixed interval, or start paused:
tsx
import { useTemporalNow } from '@reause/core'
import { useIntervalFn } from '@reause/shared'
const { pause, resume, isActive } = useTemporalNow({
// Update every 500ms instead of on every animation frame,
// and don't start immediately.
scheduler: cb => useIntervalFn(cb, 500, { immediate: false }),
})
// Manually control updates
resume() // Start auto-update
pause() // Stop auto-update
console.log(isActive) // true/falseType Declarations
Toggle
ts
export interface TemporalDurationLike {
days?: number;
hours?: number;
microseconds?: number;
milliseconds?: number;
minutes?: number;
months?: number;
nanoseconds?: number;
seconds?: number;
weeks?: number;
years?: number;
}
export interface TemporalPlainDate {
toString: () => string;
}
export interface TemporalPlainTime {
toString: () => string;
}
export interface TemporalPlainDateTime {
toString: () => string;
}
export interface TemporalZonedDateTime {
readonly epochNanoseconds: bigint;
readonly timeZoneId: string;
readonly calendarId: string;
withTimeZone: (timezone: string) => TemporalZonedDateTime;
withCalendar: (calendar: string) => TemporalZonedDateTime;
toPlainDate: () => TemporalPlainDate;
toPlainTime: () => TemporalPlainTime;
toPlainDateTime: () => TemporalPlainDateTime;
toLocaleString: (locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions) => string;
add: (duration: TemporalDurationLike | string) => TemporalZonedDateTime;
subtract: (duration: TemporalDurationLike | string) => TemporalZonedDateTime;
}
export interface TemporalImplementation {
Now: {
zonedDateTimeISO: (timezone?: string) => TemporalZonedDateTime;
};
ZonedDateTime: {
compare: (a: TemporalZonedDateTime, b: TemporalZonedDateTime | string) => number;
};
}
export interface UseTemporalNowOptions {
timezone?: string;
calendar?: string;
temporal?: TemporalImplementation;
scheduler?: UseTemporalNowScheduler;
}
export interface UseTemporalNowControls {
isActive: boolean;
pause: () => void;
resume: () => void;
}
export type UseTemporalNowScheduler = (updateNow: () => void) => UseTemporalNowControls
export interface UseTemporalNowReturn extends UseTemporalNowControls {
now: TemporalZonedDateTime;
timezone: string;
calendar: string;
setTimezone: Dispatch<SetStateAction<string>>;
setCalendar: Dispatch<SetStateAction<string>>;
toTimezone: (timezone: string) => TemporalZonedDateTime;
toCalendar: (calendar: string) => TemporalZonedDateTime;
toPlainDate: () => TemporalPlainDate;
toPlainTime: () => TemporalPlainTime;
toPlainDateTime: () => TemporalPlainDateTime;
format: (options?: Intl.DateTimeFormatOptions) => string;
add: (duration: TemporalDurationLike | string) => TemporalZonedDateTime;
subtract: (duration: TemporalDurationLike | string) => TemporalZonedDateTime;
compare: (other: TemporalZonedDateTime | string) => number;
}
export function useTemporalNow(options?: UseTemporalNowOptions): UseTemporalNowReturn