formatTimeAgo
Formats a date into a relative time string like "5 minutes ago".
1/**
2 * Formats a date into a relative time string like "5 minutes ago".
3 *
4 * @param date - The date to format.
5 * @param now - Optional reference date (defaults to current time).
6 * @returns A human-readable relative time string.
7 */
8export function formatTimeAgo(date: Date, now: Date = new Date()): string {
9 const diffMs = now.getTime() - date.getTime();
10 const diffSec = Math.floor(diffMs / 1000);
11
12 const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
13
14 if (diffSec < 60) return rtf.format(-diffSec, 'second');
15
16 const diffMin = Math.floor(diffSec / 60);
17 if (diffMin < 60) return rtf.format(-diffMin, 'minute');
18
19 const diffHr = Math.floor(diffMin / 60);
20 if (diffHr < 24) return rtf.format(-diffHr, 'hour');
21
22 const diffDay = Math.floor(diffHr / 24);
23 if (diffDay < 30) return rtf.format(-diffDay, 'day');
24
25 const diffMonth = Math.floor(diffDay / 30);
26 if (diffMonth < 12) return rtf.format(-diffMonth, 'month');
27
28 const diffYear = Math.floor(diffMonth / 12);
29 return rtf.format(-diffYear, 'year');
30}
Human-Friendly Output
Generates natural language strings like “2 hours ago” or “last month” using
Intl.RelativeTimeFormat
, enhancing user experience.Locale-Safe and Future-Proof
Leverages the built-in internationalization API, making it robust and adaptable to multilingual needs if expanded.
Granular Time Resolution
Covers multiple levels of time granularity — from seconds to years — without extra dependencies.
Optional Reference Date
Allows comparison against a custom reference (
now
), enabling testing or simulation scenarios.Clean Fallbacks
Uses
numeric: 'auto'
to allow friendly strings like "yesterday" instead of rigid numerical formats.
Tests | Examples
1const now = new Date('2024-06-27T12:00:00Z');
2
3test('formats seconds ago', () => {
4 const date = new Date('2024-06-27T11:59:45Z');
5 expect(formatTimeAgo(date, now)).toBe('15 seconds ago');
6});
7
8test('formats minutes ago', () => {
9 const date = new Date('2024-06-27T11:57:00Z');
10 expect(formatTimeAgo(date, now)).toBe('3 minutes ago');
11});
12
13test('formats hours ago', () => {
14 const date = new Date('2024-06-27T09:00:00Z');
15 expect(formatTimeAgo(date, now)).toBe('3 hours ago');
16});
17
18test('formats days ago', () => {
19 const date = new Date('2024-06-25T12:00:00Z');
20 expect(formatTimeAgo(date, now)).toBe('2 days ago');
21});
22
23test('formats months ago', () => {
24 const date = new Date('2024-03-27T12:00:00Z');
25 expect(formatTimeAgo(date, now)).toBe('3 months ago');
26});
27
28test('formats years ago', () => {
29 const date = new Date('2022-06-27T12:00:00Z');
30 expect(formatTimeAgo(date, now)).toBe('2 years ago');
31});
Common Use Cases
Social Media Timestamps
Show when a post, comment, or message was created in a natural, compact way.
Notification Logs
Display how recently a user received alerts, warnings, or updates.
Activity Feeds
Communicate recency of user activity (e.g. "signed in 2 days ago").
Data Versioning or Sync Info
Indicate how stale or fresh certain cached or synced data is.
UI Enhancements in Time-Based Apps
Improve UX in calendars, schedules, or time trackers by showing relative dates.