166 lines
4.6 KiB
TypeScript
166 lines
4.6 KiB
TypeScript
import {
|
|
format as dateFnsFormat,
|
|
isToday as dateFnsIsToday,
|
|
isYesterday as dateFnsIsYesterday,
|
|
} from 'date-fns';
|
|
import { es } from 'date-fns/locale';
|
|
import { __ } from '@/utils/i18n';
|
|
|
|
/**
|
|
* Get the date-fns locale object based on locale code
|
|
*/
|
|
function getDateFnsLocale(locale: string) {
|
|
switch (locale) {
|
|
case 'es':
|
|
return es;
|
|
default:
|
|
return undefined; // Uses English by default
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format a date using the user's locale
|
|
*/
|
|
export function formatDate(
|
|
date: Date | string | number,
|
|
formatStr: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const dateObj =
|
|
typeof date === 'string' || typeof date === 'number'
|
|
? new Date(date)
|
|
: date;
|
|
|
|
const dateFnsLocale = getDateFnsLocale(locale);
|
|
|
|
return dateFnsFormat(dateObj, formatStr, {
|
|
locale: dateFnsLocale,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Format a month from YYYY-MM string
|
|
* Shows abbreviated month for current year, or "MMM 'YY" for other years
|
|
*/
|
|
export function formatMonthFromYearMonth(
|
|
yearMonth: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const [year, month] = yearMonth.split('-');
|
|
const date = new Date(parseInt(year), parseInt(month) - 1);
|
|
const isCurrentYear = date.getFullYear() === new Date().getFullYear();
|
|
|
|
const formatStr = isCurrentYear ? 'MMM' : "MMM ''yy";
|
|
|
|
return formatDate(date, formatStr, locale);
|
|
}
|
|
|
|
/**
|
|
* Format a date to show month and year (e.g., "January 2026" or "Enero 2026")
|
|
* Capitalizes the first letter
|
|
*/
|
|
export function formatMonthYear(date: Date, locale: string = 'en-US'): string {
|
|
const formatted = formatDate(date, 'MMMM yyyy', locale);
|
|
|
|
// Capitalize first letter (important for Spanish months)
|
|
return formatted.charAt(0).toUpperCase() + formatted.slice(1);
|
|
}
|
|
|
|
/**
|
|
* Format a compact number (for charts, etc.)
|
|
*/
|
|
export function formatCompactNumber(
|
|
value: number,
|
|
locale: string = 'en-US',
|
|
currency?: string,
|
|
): string {
|
|
const options: Intl.NumberFormatOptions = {
|
|
notation: 'compact',
|
|
compactDisplay: 'short',
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 0,
|
|
};
|
|
|
|
if (currency) {
|
|
options.style = 'currency';
|
|
options.currency = currency;
|
|
}
|
|
|
|
return new Intl.NumberFormat(locale, options).format(value);
|
|
}
|
|
|
|
/**
|
|
* Format a date with day, month, and year (e.g., "Jan 23, 2025" or "23 ene 2025")
|
|
* Capitalizes the first letter
|
|
*/
|
|
export function formatDateMedium(
|
|
dateStr: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const date = new Date(dateStr);
|
|
const formatted = formatDate(date, 'MMM d, yyyy', locale);
|
|
|
|
// Capitalize first letter (important for Spanish dates)
|
|
return formatted.charAt(0).toUpperCase() + formatted.slice(1);
|
|
}
|
|
|
|
/**
|
|
* Format a date from YYYY-MM-DD string using relative wording when close to
|
|
* the current date. Returns "Today" or "Yesterday" when appropriate, otherwise
|
|
* a long weekday-based label like "Monday, 3 of Jun".
|
|
*/
|
|
export function formatRelativeDate(
|
|
dateStr: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const date = new Date(dateStr + 'T00:00:00');
|
|
|
|
if (dateFnsIsToday(date)) {
|
|
return __('Today');
|
|
}
|
|
|
|
if (dateFnsIsYesterday(date)) {
|
|
return __('Yesterday');
|
|
}
|
|
|
|
const weekday = formatDate(date, 'EEEE', locale);
|
|
const day = formatDate(date, 'd', locale);
|
|
const month = formatDate(date, 'MMM', locale);
|
|
const capitalizedWeekday =
|
|
weekday.charAt(0).toUpperCase() + weekday.slice(1);
|
|
const capitalizedMonth = month.charAt(0).toUpperCase() + month.slice(1);
|
|
|
|
return `${capitalizedWeekday}, ${day} ${__('of')} ${capitalizedMonth}`;
|
|
}
|
|
|
|
/**
|
|
* Format a date from YYYY-MM-DD string for daily chart X-axis labels
|
|
* Shows "MMM d" (e.g., "Feb 14") for current year, or "MMM d 'YY" for other years
|
|
*/
|
|
export function formatDayFromDate(
|
|
dateStr: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const date = new Date(dateStr + 'T00:00:00');
|
|
const isCurrentYear = date.getFullYear() === new Date().getFullYear();
|
|
|
|
const formatStr = isCurrentYear ? 'MMM d' : "MMM d ''yy";
|
|
|
|
return formatDate(date, formatStr, locale);
|
|
}
|
|
|
|
/**
|
|
* Format a date with weekday, day, month, and year (e.g., "Thu, Jan 23, 2025" or "Jue, 23 ene 2025")
|
|
* Capitalizes the first letter
|
|
*/
|
|
export function formatDateLong(
|
|
dateStr: string,
|
|
locale: string = 'en-US',
|
|
): string {
|
|
const date = new Date(dateStr);
|
|
const formatted = formatDate(date, 'EEE, MMM d, yyyy', locale);
|
|
|
|
// Capitalize first letter (important for Spanish dates)
|
|
return formatted.charAt(0).toUpperCase() + formatted.slice(1);
|
|
}
|