77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
/** Formatting helpers for dates, sizes and durations. */
|
|
|
|
const MONTHS = [
|
|
'January', 'February', 'March', 'April', 'May', 'June',
|
|
'July', 'August', 'September', 'October', 'November', 'December',
|
|
];
|
|
|
|
export function formatBytes(bytes?: number): string {
|
|
if (!bytes || bytes <= 0) return '—';
|
|
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.min(units.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
const value = bytes / Math.pow(1024, i);
|
|
return `${value.toFixed(value >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
|
|
}
|
|
|
|
export function formatDuration(seconds?: number): string {
|
|
if (!seconds || seconds < 0) return '';
|
|
const s = Math.floor(seconds % 60);
|
|
const m = Math.floor((seconds / 60) % 60);
|
|
const h = Math.floor(seconds / 3600);
|
|
const pad = (n: number) => n.toString().padStart(2, '0');
|
|
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
|
|
}
|
|
|
|
export function formatDate(ms: number): string {
|
|
const d = new Date(ms);
|
|
return `${MONTHS[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
|
|
}
|
|
|
|
export function formatDay(ms: number): string {
|
|
const d = new Date(ms);
|
|
const today = new Date();
|
|
const yesterday = new Date(today);
|
|
yesterday.setDate(today.getDate() - 1);
|
|
const sameDay = (a: Date, b: Date) =>
|
|
a.getFullYear() === b.getFullYear() &&
|
|
a.getMonth() === b.getMonth() &&
|
|
a.getDate() === b.getDate();
|
|
if (sameDay(d, today)) return 'Today';
|
|
if (sameDay(d, yesterday)) return 'Yesterday';
|
|
const weekday = d.toLocaleDateString(undefined, { weekday: 'long' });
|
|
return `${weekday}, ${MONTHS[d.getMonth()]} ${d.getDate()}`;
|
|
}
|
|
|
|
export function formatMonth(ms: number): string {
|
|
const d = new Date(ms);
|
|
return `${MONTHS[d.getMonth()]} ${d.getFullYear()}`;
|
|
}
|
|
|
|
export function formatYear(ms: number): string {
|
|
return new Date(ms).getFullYear().toString();
|
|
}
|
|
|
|
export function formatTime(ms: number): string {
|
|
return new Date(ms).toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
|
|
}
|
|
|
|
export function relativeTime(ms: number): string {
|
|
const diff = Date.now() - ms;
|
|
const day = 24 * 60 * 60 * 1000;
|
|
if (diff < 0) return 'in the future';
|
|
if (diff < day) return 'today';
|
|
const days = Math.floor(diff / day);
|
|
if (days === 1) return 'yesterday';
|
|
if (days < 30) return `${days} days ago`;
|
|
const months = Math.floor(days / 30);
|
|
if (months < 12) return `${months} month${months > 1 ? 's' : ''} ago`;
|
|
const years = Math.floor(days / 365);
|
|
return `${years} year${years > 1 ? 's' : ''} ago`;
|
|
}
|
|
|
|
/** Days remaining before a trashed item is permanently removed. */
|
|
export function daysUntilPermanentDelete(deletedAt: number, retentionMs: number): number {
|
|
const remaining = deletedAt + retentionMs - Date.now();
|
|
return Math.max(0, Math.ceil(remaining / (24 * 60 * 60 * 1000)));
|
|
}
|