feat(web): add formatDmTimestamp utility with smart date formatting

This commit is contained in:
Jannis Braun
2026-04-02 17:47:18 +02:00
parent 416636530a
commit 03667947aa
2 changed files with 90 additions and 0 deletions
@@ -0,0 +1,60 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { formatDmTimestamp } from './dmFormatters';
/** Build a local-time Date: new Date(year, month-1, day, hour, minute) as a timestamp. */
function localTs(year: number, month: number, day: number, hour = 12, minute = 0): number {
return new Date(year, month - 1, day, hour, minute).getTime();
}
describe('formatDmTimestamp', () => {
afterEach(() => {
vi.useRealTimers();
});
it('shows time for today', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 3, 2, 16, 0)); // Apr 2 2026, 4:00 PM local
const twoHoursAgo = localTs(2026, 4, 2, 14, 0); // Apr 2 2026, 2:00 PM local
const result = formatDmTimestamp(twoHoursAgo);
// Should be a time string like "2:00 PM" — not "Yesterday" or a date
expect(result).not.toBe('Yesterday');
expect(result).not.toMatch(/\d{4}/); // no year
expect(result).toMatch(/\d{1,2}/); // has a number (hour)
});
it('shows "Yesterday" for yesterday', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 3, 2, 16, 0)); // Apr 2 2026
const yesterday = localTs(2026, 4, 1, 12, 0); // Apr 1 2026
expect(formatDmTimestamp(yesterday)).toBe('Yesterday');
});
it('shows month and day for this year', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 3, 2, 16, 0)); // Apr 2 2026
const marchDate = localTs(2026, 3, 15, 12, 0); // Mar 15 2026
const result = formatDmTimestamp(marchDate);
expect(result).toMatch(/Mar\s+15/);
});
it('shows month, day and year for previous years', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 3, 2, 16, 0)); // Apr 2 2026
const lastYear = localTs(2025, 12, 14, 12, 0); // Dec 14 2025
const result = formatDmTimestamp(lastYear);
expect(result).toMatch(/Dec\s+14/);
expect(result).toMatch(/2025/);
});
it('handles midnight boundary correctly', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 3, 2, 0, 5)); // Apr 2 2026, 00:05 local
const lastNight = localTs(2026, 4, 1, 23, 55); // Apr 1 2026, 23:55 local
expect(formatDmTimestamp(lastNight)).toBe('Yesterday');
});
});
+30
View File
@@ -0,0 +1,30 @@
/**
* Smart timestamp for DM sidebar items.
* Today → time ("4:32 PM"), Yesterday → "Yesterday",
* This year → "Mar 31", Older → "Dec 14, 2025"
*/
export function formatDmTimestamp(createdAt: number): string {
const now = new Date();
const date = new Date(createdAt);
// Build "start of today" and "start of yesterday" in local time
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const startOfYesterday = new Date(startOfToday.getTime() - 86400000);
if (date >= startOfToday) {
// Today — show time
return date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
}
if (date >= startOfYesterday) {
return 'Yesterday';
}
if (date.getFullYear() === now.getFullYear()) {
// This year — "Mar 31"
return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
}
// Previous year — "Dec 14, 2025"
return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
}