feat: refactor date formatting and timezone utilities for improved consistency and functionality
This commit is contained in:
115
src/utils/format-date.ts
Normal file
115
src/utils/format-date.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Parse and optionally convert a date string to a Date object with timezone handling
|
||||
* @param dateString - The date string to parse
|
||||
* @param isUTC - Whether to convert from UTC to local timezone (default: true)
|
||||
* @returns Processed Date object or null if invalid
|
||||
*/
|
||||
function parseAndConvertDate(dateString: string, isUTC: boolean = true): Date | null {
|
||||
try {
|
||||
// If isUTC is true and the date string doesn't have timezone info, treat it as UTC
|
||||
let dateToProcess = dateString;
|
||||
if (isUTC && !dateString.endsWith('Z') && !dateString.includes('+') && !dateString.includes('-', 10)) {
|
||||
dateToProcess = `${dateString}Z`;
|
||||
}
|
||||
|
||||
const date = new Date(dateToProcess);
|
||||
|
||||
if (isNaN(date.getTime())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isUTC) {
|
||||
return date;
|
||||
}
|
||||
|
||||
// Get timezone from localStorage, default to Europe/Paris
|
||||
const timezone = localStorage.getItem('timezone') || 'Europe/Paris';
|
||||
|
||||
// Format the date in the target timezone
|
||||
const formatter = new Intl.DateTimeFormat('fr-FR', {
|
||||
timeZone: timezone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
|
||||
const parts = formatter.formatToParts(date);
|
||||
const partsObj = parts.reduce((acc, part) => {
|
||||
acc[part.type] = part.value;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
|
||||
// Create new date object in the target timezone
|
||||
return new Date(
|
||||
parseInt(partsObj.year),
|
||||
parseInt(partsObj.month) - 1, // Month is 0-indexed
|
||||
parseInt(partsObj.day),
|
||||
parseInt(partsObj.hour),
|
||||
parseInt(partsObj.minute),
|
||||
parseInt(partsObj.second)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error parsing date:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date string to DD/MM/YYYY HH:MM:SS or DD/MM/YYYY
|
||||
* @param dateString - The date string to format
|
||||
* @param withTime - Whether to include time in the output (default: true)
|
||||
* @param isUTC - Whether to convert from UTC to local timezone (default: true)
|
||||
* @returns Formatted date string
|
||||
*/
|
||||
export function formatDate(
|
||||
dateString: string,
|
||||
withTime: boolean = true,
|
||||
isUTC: boolean = true
|
||||
): string {
|
||||
const date = parseAndConvertDate(dateString, isUTC);
|
||||
|
||||
if (!date) {
|
||||
return 'Invalid Date';
|
||||
}
|
||||
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = date.getFullYear().toString();
|
||||
|
||||
const dateFormatted = `${day}/${month}/${year}`;
|
||||
|
||||
if (!withTime) {
|
||||
return dateFormatted;
|
||||
}
|
||||
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = date.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
return `${dateFormatted} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date string to show distance to now (e.g., "2 hours ago", "3 days ago")
|
||||
* @param dateString - The date string to format
|
||||
* @param isUTC - Whether to convert from UTC to local timezone (default: true)
|
||||
* @returns Formatted distance string (e.g., "2 hours ago")
|
||||
*/
|
||||
export function formatDateDistanceToNow(
|
||||
dateString: string,
|
||||
isUTC: boolean = true
|
||||
): string {
|
||||
const date = parseAndConvertDate(dateString, isUTC);
|
||||
|
||||
if (!date) {
|
||||
return 'Invalid Date';
|
||||
}
|
||||
|
||||
return formatDistanceToNow(date, { addSuffix: true });
|
||||
}
|
||||
Reference in New Issue
Block a user