Data displayui
Relative time
"3 min ago" that stays current, with the absolute time in a tooltip.
- Deployed
- Deployed
- Deployed
- Deployed
- Deployed
Installation
npx shadcn@latest add @particular/relative-timenpm dependencies
- cn@^0.4.0
Installs these registry items
Source
"use client"
import * as React from "react"
import { cn } from "cn"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
const units: Array<[Intl.RelativeTimeFormatUnit, number]> = [
["year", 365 * 24 * 60 * 60],
["month", 30 * 24 * 60 * 60],
["week", 7 * 24 * 60 * 60],
["day", 24 * 60 * 60],
["hour", 60 * 60],
["minute", 60],
]
function formatRelativeTime(date: Date, now: Date, locale = "en-US"): string {
const seconds = Math.round((date.getTime() - now.getTime()) / 1000)
if (Math.abs(seconds) < 45) return "just now"
const format = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "short" })
for (const [unit, size] of units) {
if (Math.abs(seconds) >= size) return format.format(Math.round(seconds / size), unit)
}
return format.format(Math.round(seconds / 60), "minute")
}
function useNow(intervalMs: number) {
const [now, setNow] = React.useState(() => new Date())
React.useEffect(() => {
const id = setInterval(() => setNow(new Date()), intervalMs)
return () => clearInterval(id)
}, [intervalMs])
return now
}
function RelativeTime({
date,
locale = "en-US",
updateInterval = 30_000,
className,
...props
}: Omit<React.ComponentProps<"time">, "dateTime" | "children"> & {
date: Date | string | number
locale?: string
updateInterval?: number
}) {
const value = new Date(date)
const now = useNow(updateInterval)
const absolute = new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "long" }).format(value)
return (
<Tooltip>
<TooltipTrigger
render={
<time
dateTime={value.toISOString()}
suppressHydrationWarning
className={cn("whitespace-nowrap tabular-nums underline-offset-2 hover:underline hover:decoration-dotted", className)}
{...props}
/>
}
>
{formatRelativeTime(value, now, locale)}
</TooltipTrigger>
<TooltipContent>
<span suppressHydrationWarning>{absolute}</span>
</TooltipContent>
</Tooltip>
)
}
export { RelativeTime, formatRelativeTime }