refactor: extract shared formatting utilities (duration, date, age)
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Shared formatting utilities for consistent display across the app.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert minutes to a human-readable duration string.
|
||||
*
|
||||
* Examples:
|
||||
* 45 → "45m"
|
||||
* 60 → "1h"
|
||||
* 90 → "1h 30m"
|
||||
* 120 → "2h"
|
||||
* 150 → "2h 30m"
|
||||
*/
|
||||
export function formatDuration(minutes: number): string {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
if (hours === 0) return `${mins}m`;
|
||||
if (mins === 0) return `${hours}h`;
|
||||
return `${hours}h ${mins}m`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time to "Weekday, Month Day at HH:MM AM/PM".
|
||||
*
|
||||
* Examples:
|
||||
* "2026-05-29T10:00:00Z" → "Friday, May 29 at 10:00 AM"
|
||||
* "2026-06-05T14:30:00Z" → "Friday, Jun 5 at 2:30 PM"
|
||||
*/
|
||||
export function formatDateTime(date: Date | string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
const dateStr = d.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
const timeStr = d.toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
hour12: true
|
||||
});
|
||||
return `${dateStr} at ${timeStr}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date value to "Weekday, Month Day" only (no time).
|
||||
*
|
||||
* Example: "2026-05-29" → "Friday, May 29"
|
||||
*/
|
||||
export function formatDate(date: Date | string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
return d.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a time value to "HH:MM AM/PM".
|
||||
*
|
||||
* Example: new Date("2026-05-29T14:30:00Z") → "2:30 PM"
|
||||
*/
|
||||
export function formatTime(date: Date | string): string {
|
||||
const d = typeof date === 'string' ? new Date(date) : date;
|
||||
return d.toLocaleTimeString('en-US', {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
hour12: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate age from a date-of-birth string.
|
||||
* Returns the number of full years, or null if DOB is invalid.
|
||||
*/
|
||||
export function calculateAge(dateOfBirth: string | undefined | null): number | null {
|
||||
if (!dateOfBirth) return null;
|
||||
const dob = new Date(dateOfBirth);
|
||||
if (isNaN(dob.getTime())) return null;
|
||||
const today = new Date();
|
||||
let age = today.getFullYear() - dob.getFullYear();
|
||||
const monthDiff = today.getMonth() - dob.getMonth();
|
||||
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dob.getDate())) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
Reference in New Issue
Block a user