feat: implement relative date formatting, real-time clock display

This commit is contained in:
ramvignesh-b
2026-04-14 21:00:08 +05:30
parent 8f9c0b5430
commit 9e5db3b99c
3 changed files with 92 additions and 4 deletions
+21 -4
View File
@@ -1,3 +1,5 @@
import { useEffect, useState } from "react";
interface DateDisplayProps {
date?: Date;
className?: string;
@@ -13,15 +15,30 @@ export default function DateDisplay({
year: "numeric",
});
const [now, setNow] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setNow(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
return (
<div
className={`text-right flex flex-col gap-2 min-w-[140px] ${className}`}
>
<div className={`text-right flex flex-col gap-2 min-w-35 ${className}`}>
<span className="text-[10px] uppercase tracking-[0.4em] text-accent font-bold">
Date
</span>
<span className="text-sm font-serif text-secondary-content italic whitespace-nowrap">
{formattedDate}
{formattedDate} <br />
<span className="text-secondary-content/50 font-sans not-italic">
{hours}:{minutes}:{seconds}
</span>
</span>
</div>
);
+37
View File
@@ -0,0 +1,37 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { formatRelativeDate } from "./dateFormat";
describe("formatRelativeDate", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-04-14T15:30:00Z"));
});
afterEach(() => {
vi.useRealTimers();
});
it("should format a same-day timestamp as Today, <time>", () => {
const result = formatRelativeDate("2026-04-14T10:15:00Z");
expect(result).toBe("Today, 3:45 PM");
});
it("should format a previous-day timestamp as Yesterday, <time>", () => {
const result = formatRelativeDate("2026-04-13T09:10:00Z");
expect(result).toBe("Yesterday, 2:40 PM");
});
it("should format dates within the last week as relative day + time", () => {
const result = formatRelativeDate("2026-04-12T08:00:00Z");
expect(result).toBe("2 days ago, 1:30 PM");
});
it("should format dates older than a week as a full date+time", () => {
const result = formatRelativeDate("2026-04-01T13:15:00Z");
expect(result).toBe("Apr 1, 2026, 6:45 PM");
});
});
+34
View File
@@ -0,0 +1,34 @@
const timeFormatter = new Intl.DateTimeFormat(undefined, {
timeStyle: "short",
});
const dateTimeFormatter = new Intl.DateTimeFormat(undefined, {
dateStyle: "medium",
timeStyle: "short",
});
const rtf = new Intl.RelativeTimeFormat(undefined, {
numeric: "auto",
});
function startOfDay(d: Date) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
export function formatRelativeDate(input: Date | string | number) {
const date = new Date(input);
const now = new Date();
const dayMs = 24 * 60 * 60 * 1000;
const diffDays = Math.round(
(startOfDay(date).getTime() - startOfDay(now).getTime()) / dayMs,
);
const time = timeFormatter.format(date);
if (diffDays === 0) return `Today, ${time}`;
if (diffDays === -1) return `Yesterday, ${time}`;
if (diffDays > -7) return `${rtf.format(diffDays, "day")}, ${time}`;
return dateTimeFormatter.format(date);
}