port-nimara-client-portal/utils/dateUtils.ts

192 lines
5.8 KiB
TypeScript

/**
* Unified date formatting utilities for consistent date display across the application
*/
/**
* Format date string to display format (DD/MM/YYYY HH:mm or DD/MM/YYYY)
* Handles multiple input formats: ISO, DD-MM-YYYY, YYYY-MM-DD, DD/MM/YYYY
*/
export const formatDate = (dateString: string | null | undefined): string => {
if (!dateString) return "-";
try {
let date: Date;
// Check if it's an ISO date string (e.g., "2025-06-09T22:58:47.731Z")
if (dateString.includes('T') || dateString.includes('Z')) {
date = new Date(dateString);
}
// Handle DD-MM-YYYY format
else if (dateString.match(/^\d{1,2}-\d{1,2}-\d{4}$/)) {
const [day, month, year] = dateString.split("-");
date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
}
// Handle DD/MM/YYYY format
else if (dateString.match(/^\d{1,2}\/\d{1,2}\/\d{4}$/)) {
const [day, month, year] = dateString.split("/");
date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
}
// Handle YYYY-MM-DD format
else if (dateString.match(/^\d{4}-\d{1,2}-\d{1,2}$/)) {
date = new Date(dateString);
}
// Fallback to direct parsing
else {
date = new Date(dateString);
}
// Check if date is valid
if (isNaN(date.getTime())) {
console.warn("Invalid date format:", dateString);
return dateString;
}
// Format date in DD/MM/YYYY HH:mm format
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
// Include time if it's not midnight
if (hours !== '00' || minutes !== '00') {
return `${day}/${month}/${year} ${hours}:${minutes}`;
}
return `${day}/${month}/${year}`;
} catch (error) {
console.error('Date formatting error:', error, dateString);
return dateString;
}
};
/**
* Get relative time description (e.g., "2 days ago", "Yesterday", "Today")
*/
export const getRelativeTime = (dateString: string | null | undefined): string => {
if (!dateString) return '';
try {
let date: Date;
// Handle DD-MM-YYYY format
if (dateString.includes('-') && dateString.match(/^\d{1,2}-\d{1,2}-\d{4}$/)) {
const parts = dateString.split('-');
if (parts.length === 3) {
const [day, month, year] = parts;
date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
} else {
date = new Date(dateString);
}
} else {
date = new Date(dateString);
}
if (isNaN(date.getTime())) return '';
const now = new Date();
const diffTime = Math.abs(now.getTime() - date.getTime());
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
if (diffDays === 0) return 'Today';
if (diffDays === 1) return 'Yesterday';
if (diffDays < 7) return `${diffDays} days ago`;
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
return `${Math.floor(diffDays / 365)} years ago`;
} catch (error) {
console.error('Relative time calculation error:', error, dateString);
return '';
}
};
/**
* Format date for display in US locale (Month DD, YYYY)
*/
export const formatDateUS = (dateString: string | null | undefined): string => {
if (!dateString) return "-";
try {
let date: Date;
// Handle DD-MM-YYYY format
if (dateString.includes('-') && dateString.match(/^\d{1,2}-\d{1,2}-\d{4}$/)) {
const parts = dateString.split('-');
if (parts.length === 3) {
const [day, month, year] = parts;
date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
} else {
date = new Date(dateString);
}
} else {
date = new Date(dateString);
}
if (isNaN(date.getTime())) {
console.warn("Invalid date format:", dateString);
return "-";
}
return date.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
} catch (error) {
console.error("Error formatting date:", dateString, error);
return "-";
}
};
/**
* Format time only (HH:mm)
*/
export const formatTime = (dateString: string | Date | null | undefined): string => {
if (!dateString) return "-";
try {
const date = dateString instanceof Date ? dateString : new Date(dateString);
if (isNaN(date.getTime())) {
console.warn("Invalid date format:", dateString);
return "-";
}
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
} catch (error) {
console.error("Error formatting time:", dateString, error);
return "-";
}
};
/**
* Format full date and time (DD/MM/YYYY HH:mm:ss)
*/
export const formatDateTime = (dateString: string | Date | null | undefined): string => {
if (!dateString) return "-";
try {
const date = dateString instanceof Date ? dateString : new Date(dateString);
if (isNaN(date.getTime())) {
console.warn("Invalid date format:", dateString);
return "-";
}
const day = date.getDate().toString().padStart(2, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const year = date.getFullYear();
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 `${day}/${month}/${year} ${hours}:${minutes}:${seconds}`;
} catch (error) {
console.error("Error formatting datetime:", dateString, error);
return "-";
}
};