38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
/**
|
|
* RelativeTimeDisplay
|
|
*
|
|
* Deterministic relative time formatting.
|
|
*/
|
|
|
|
export class RelativeTimeFormatter {
|
|
/**
|
|
* Formats a date relative to "now".
|
|
* "now" must be passed as an argument for determinism.
|
|
*/
|
|
static format(date: string | Date, now: Date): string {
|
|
const d = typeof date === 'string' ? new Date(date) : date;
|
|
const diffMs = d.getTime() - now.getTime();
|
|
const diffHours = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60));
|
|
const diffDays = Math.floor(Math.abs(diffMs) / (1000 * 60 * 60 * 24));
|
|
|
|
if (diffMs < 0) {
|
|
if (diffHours < 1) return 'Just now';
|
|
if (diffHours < 24) return `${diffHours}h ago`;
|
|
if (diffDays === 1) return 'Yesterday';
|
|
if (diffDays < 7) return `${diffDays}d ago`;
|
|
return this.formatAbsolute(d);
|
|
} else {
|
|
if (diffHours < 1) return 'Starting soon';
|
|
if (diffHours < 24) return `In ${diffHours}h`;
|
|
if (diffDays === 1) return 'Tomorrow';
|
|
if (diffDays < 7) return `In ${diffDays} days`;
|
|
return this.formatAbsolute(d);
|
|
}
|
|
}
|
|
|
|
private static formatAbsolute(date: Date): string {
|
|
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
return `${months[date.getUTCMonth()]} ${date.getUTCDate()}`;
|
|
}
|
|
}
|