const MONTHS_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] const MONTHS_LONG = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] const WEEKDAYS_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] const WEEKDAYS_LONG = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] export function formatDate(date: Date, format: string): string { if (!format) return '' const year = date.getFullYear() const month = date.getMonth() const day = date.getDate() const weekday = date.getDay() const ordinalSuffix = day >= 11 && day <= 13 ? 'th' : ({ 1: 'st', 2: 'nd', 3: 'rd' } as Record)[day % 10] ?? 'th' const replacements: [RegExp, string][] = [ [/YYYY/g, String(year)], [/YY/g, String(year).slice(-2)], [/MMMM/g, MONTHS_LONG[month]], [/MMM/g, MONTHS_SHORT[month]], [/MM/g, String(month + 1).padStart(2, '0')], [/M/g, String(month + 1)], [/dddd/g, WEEKDAYS_LONG[weekday]], [/ddd/g, WEEKDAYS_SHORT[weekday]], [/Do/g, `${day}${ordinalSuffix}`], [/DD/g, String(day).padStart(2, '0')], [/D/g, String(day)], ] let result = format const placeholders: string[] = [] for (let i = 0; i < replacements.length; i++) { const [pattern, value] = replacements[i] const placeholder = `\x00${i}\x00` result = result.replace(pattern, () => { placeholders[i] = value return placeholder }) } for (let i = 0; i < replacements.length; i++) { const placeholder = `\x00${i}\x00` if (placeholders[i] !== undefined) { result = result.split(placeholder).join(placeholders[i]) } } return result } export function formatTime(date: Date, format: string): string { if (!format) return '' const hours24 = date.getHours() const hours12 = hours24 % 12 || 12 const minutes = date.getMinutes() const seconds = date.getSeconds() const isPM = hours24 >= 12 const replacements: [RegExp, string][] = [ [/HH/g, String(hours24).padStart(2, '0')], [/H/g, String(hours24)], [/hh/g, String(hours12).padStart(2, '0')], [/h/g, String(hours12)], [/mm/g, String(minutes).padStart(2, '0')], [/m/g, String(minutes)], [/ss/g, String(seconds).padStart(2, '0')], [/s/g, String(seconds)], [/A/g, isPM ? 'PM' : 'AM'], [/a/g, isPM ? 'pm' : 'am'], ] let result = format const placeholders: string[] = [] for (let i = 0; i < replacements.length; i++) { const [pattern, value] = replacements[i] const placeholder = `\x00${i}\x00` result = result.replace(pattern, () => { placeholders[i] = value return placeholder }) } for (let i = 0; i < replacements.length; i++) { const placeholder = `\x00${i}\x00` if (placeholders[i] !== undefined) { result = result.split(placeholder).join(placeholders[i]) } } return result }