| 1 |
/** |
| 2 |
* Date and Time Formatting Utilities |
| 3 |
* Uses global Yatra settings for consistent date/time formatting across all pages |
| 4 |
*/ |
| 5 |
|
| 6 |
// Supported PHP date formats: |
| 7 |
// 'Y-m-d' -> 2025-12-15 |
| 8 |
// 'm/d/Y' -> 12/15/2025 |
| 9 |
// 'd/m/Y' -> 15/12/2025 |
| 10 |
// 'd-m-Y' -> 15-12-2025 |
| 11 |
// 'M d, Y' -> Dec 15, 2025 |
| 12 |
// 'F d, Y' -> December 15, 2025 |
| 13 |
// 'd M Y' -> 15 Dec 2025 |
| 14 |
// 'd F Y' -> 15 December 2025 |
| 15 |
|
| 16 |
// Supported PHP time formats: |
| 17 |
// 'H:i' -> 14:30 (24-hour) |
| 18 |
// 'h:i A' -> 02:30 PM (12-hour) |
| 19 |
// 'h:i a' -> 02:30 pm (12-hour lowercase) |
| 20 |
// 'H:i:s' -> 14:30:00 (24-hour with seconds) |
| 21 |
// 'h:i:s A' -> 02:30:00 PM (12-hour with seconds) |
| 22 |
|
| 23 |
/** |
| 24 |
* Get date format from Yatra settings |
| 25 |
*/ |
| 26 |
export function getDateFormat(): string { |
| 27 |
return ( |
| 28 |
(window as any)?.yatraAdmin?.date_format || |
| 29 |
(window as any)?.yatraAdmin?.dateFormat || |
| 30 |
"Y-m-d" |
| 31 |
); |
| 32 |
} |
| 33 |
|
| 34 |
/** |
| 35 |
* Get time format from Yatra settings |
| 36 |
*/ |
| 37 |
export function getTimeFormat(): string { |
| 38 |
return ( |
| 39 |
(window as any)?.yatraAdmin?.time_format || |
| 40 |
(window as any)?.yatraAdmin?.timeFormat || |
| 41 |
"H:i" |
| 42 |
); |
| 43 |
} |
| 44 |
|
| 45 |
/** |
| 46 |
* Get timezone from Yatra settings |
| 47 |
*/ |
| 48 |
export function getTimezone(): string { |
| 49 |
return (window as any)?.yatraAdmin?.timezone || "UTC"; |
| 50 |
} |
| 51 |
|
| 52 |
/** |
| 53 |
* Format a date string according to Yatra settings |
| 54 |
* @param dateString - Date string in any parseable format (ISO, YYYY-MM-DD, etc.) |
| 55 |
* @param includeTime - Whether to include time in the output |
| 56 |
* @returns Formatted date string |
| 57 |
*/ |
| 58 |
export function formatDate( |
| 59 |
dateString: string | Date | null | undefined, |
| 60 |
includeTime: boolean = false, |
| 61 |
): string { |
| 62 |
if (!dateString) return "-"; |
| 63 |
|
| 64 |
try { |
| 65 |
const date = |
| 66 |
typeof dateString === "string" ? new Date(dateString) : dateString; |
| 67 |
|
| 68 |
if (isNaN(date.getTime())) { |
| 69 |
return String(dateString); |
| 70 |
} |
| 71 |
|
| 72 |
const phpDateFormat = getDateFormat(); |
| 73 |
const phpTimeFormat = getTimeFormat(); |
| 74 |
|
| 75 |
// Format date part |
| 76 |
const formattedDate = formatDatePart(date, phpDateFormat); |
| 77 |
|
| 78 |
// Format time part if requested |
| 79 |
if (includeTime) { |
| 80 |
const formattedTime = formatTimePart(date, phpTimeFormat); |
| 81 |
return `${formattedDate} ${formattedTime}`; |
| 82 |
} |
| 83 |
|
| 84 |
return formattedDate; |
| 85 |
} catch (e) { |
| 86 |
return String(dateString); |
| 87 |
} |
| 88 |
} |
| 89 |
|
| 90 |
/** |
| 91 |
* Format only the date part |
| 92 |
*/ |
| 93 |
function formatDatePart(date: Date, phpFormat: string): string { |
| 94 |
const year = date.getFullYear(); |
| 95 |
const month = date.getMonth(); |
| 96 |
const day = date.getDate(); |
| 97 |
|
| 98 |
const monthNames = [ |
| 99 |
"January", |
| 100 |
"February", |
| 101 |
"March", |
| 102 |
"April", |
| 103 |
"May", |
| 104 |
"June", |
| 105 |
"July", |
| 106 |
"August", |
| 107 |
"September", |
| 108 |
"October", |
| 109 |
"November", |
| 110 |
"December", |
| 111 |
]; |
| 112 |
const monthShort = [ |
| 113 |
"Jan", |
| 114 |
"Feb", |
| 115 |
"Mar", |
| 116 |
"Apr", |
| 117 |
"May", |
| 118 |
"Jun", |
| 119 |
"Jul", |
| 120 |
"Aug", |
| 121 |
"Sep", |
| 122 |
"Oct", |
| 123 |
"Nov", |
| 124 |
"Dec", |
| 125 |
]; |
| 126 |
|
| 127 |
const pad = (n: number) => n.toString().padStart(2, "0"); |
| 128 |
|
| 129 |
const dayNames = [ |
| 130 |
"Sunday", |
| 131 |
"Monday", |
| 132 |
"Tuesday", |
| 133 |
"Wednesday", |
| 134 |
"Thursday", |
| 135 |
"Friday", |
| 136 |
"Saturday", |
| 137 |
]; |
| 138 |
const dayShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; |
| 139 |
const dayOfWeek = date.getDay(); |
| 140 |
|
| 141 |
switch (phpFormat) { |
| 142 |
// Numeric formats |
| 143 |
case "Y-m-d": |
| 144 |
return `${year}-${pad(month + 1)}-${pad(day)}`; |
| 145 |
case "Y/m/d": |
| 146 |
return `${year}/${pad(month + 1)}/${pad(day)}`; |
| 147 |
case "m/d/Y": |
| 148 |
return `${pad(month + 1)}/${pad(day)}/${year}`; |
| 149 |
case "d/m/Y": |
| 150 |
return `${pad(day)}/${pad(month + 1)}/${year}`; |
| 151 |
case "d-m-Y": |
| 152 |
return `${pad(day)}-${pad(month + 1)}-${year}`; |
| 153 |
case "d.m.Y": |
| 154 |
return `${pad(day)}.${pad(month + 1)}.${year}`; |
| 155 |
// Month name formats with padded day |
| 156 |
case "M d, Y": |
| 157 |
return `${monthShort[month]} ${pad(day)}, ${year}`; |
| 158 |
case "F d, Y": |
| 159 |
return `${monthNames[month]} ${pad(day)}, ${year}`; |
| 160 |
case "d M Y": |
| 161 |
return `${pad(day)} ${monthShort[month]} ${year}`; |
| 162 |
case "d F Y": |
| 163 |
return `${pad(day)} ${monthNames[month]} ${year}`; |
| 164 |
// Month name formats with day without leading zero |
| 165 |
case "M j, Y": |
| 166 |
return `${monthShort[month]} ${day}, ${year}`; |
| 167 |
case "F j, Y": |
| 168 |
return `${monthNames[month]} ${day}, ${year}`; |
| 169 |
case "j M Y": |
| 170 |
return `${day} ${monthShort[month]} ${year}`; |
| 171 |
case "j F Y": |
| 172 |
return `${day} ${monthNames[month]} ${year}`; |
| 173 |
// Year first with month name |
| 174 |
case "Y M j": |
| 175 |
return `${year} ${monthShort[month]} ${day}`; |
| 176 |
case "Y F j": |
| 177 |
return `${year} ${monthNames[month]} ${day}`; |
| 178 |
// With weekday |
| 179 |
case "l, F j, Y": |
| 180 |
return `${dayNames[dayOfWeek]}, ${monthNames[month]} ${day}, ${year}`; |
| 181 |
case "D, M j, Y": |
| 182 |
return `${dayShort[dayOfWeek]}, ${monthShort[month]} ${day}, ${year}`; |
| 183 |
default: |
| 184 |
// Default to ISO format |
| 185 |
return `${year}-${pad(month + 1)}-${pad(day)}`; |
| 186 |
} |
| 187 |
} |
| 188 |
|
| 189 |
/** |
| 190 |
* Format only the time part |
| 191 |
*/ |
| 192 |
function formatTimePart(date: Date, phpFormat: string): string { |
| 193 |
const hours = date.getHours(); |
| 194 |
const minutes = date.getMinutes(); |
| 195 |
const seconds = date.getSeconds(); |
| 196 |
|
| 197 |
const pad = (n: number) => n.toString().padStart(2, "0"); |
| 198 |
|
| 199 |
const hours12 = hours % 12 || 12; |
| 200 |
const ampm = hours >= 12 ? "PM" : "AM"; |
| 201 |
|
| 202 |
switch (phpFormat) { |
| 203 |
case "H:i": |
| 204 |
return `${pad(hours)}:${pad(minutes)}`; |
| 205 |
case "h:i A": |
| 206 |
return `${pad(hours12)}:${pad(minutes)} ${ampm}`; |
| 207 |
case "h:i a": |
| 208 |
return `${pad(hours12)}:${pad(minutes)} ${ampm.toLowerCase()}`; |
| 209 |
case "H:i:s": |
| 210 |
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`; |
| 211 |
case "h:i:s A": |
| 212 |
return `${pad(hours12)}:${pad(minutes)}:${pad(seconds)} ${ampm}`; |
| 213 |
default: |
| 214 |
return `${pad(hours)}:${pad(minutes)}`; |
| 215 |
} |
| 216 |
} |
| 217 |
|
| 218 |
/** |
| 219 |
* Format a date for display with time |
| 220 |
* @param dateString - Date string |
| 221 |
* @returns Formatted date and time string |
| 222 |
*/ |
| 223 |
export function formatDateTime( |
| 224 |
dateString: string | Date | null | undefined, |
| 225 |
): string { |
| 226 |
return formatDate(dateString, true); |
| 227 |
} |
| 228 |
|
| 229 |
/** |
| 230 |
* Format time only |
| 231 |
* @param dateString - Date string or time string |
| 232 |
* @returns Formatted time string |
| 233 |
*/ |
| 234 |
export function formatTime( |
| 235 |
dateString: string | Date | null | undefined, |
| 236 |
): string { |
| 237 |
if (!dateString) return "-"; |
| 238 |
|
| 239 |
try { |
| 240 |
const date = |
| 241 |
typeof dateString === "string" ? new Date(dateString) : dateString; |
| 242 |
|
| 243 |
if (isNaN(date.getTime())) { |
| 244 |
// Try to parse as time only (HH:mm or HH:mm:ss) |
| 245 |
if ( |
| 246 |
typeof dateString === "string" && |
| 247 |
/^\d{1,2}:\d{2}(:\d{2})?$/.test(dateString) |
| 248 |
) { |
| 249 |
const [hours, minutes] = dateString.split(":").map(Number); |
| 250 |
const tempDate = new Date(); |
| 251 |
tempDate.setHours(hours, minutes, 0, 0); |
| 252 |
return formatTimePart(tempDate, getTimeFormat()); |
| 253 |
} |
| 254 |
return String(dateString); |
| 255 |
} |
| 256 |
|
| 257 |
return formatTimePart(date, getTimeFormat()); |
| 258 |
} catch (e) { |
| 259 |
return String(dateString); |
| 260 |
} |
| 261 |
} |
| 262 |
|
| 263 |
/** |
| 264 |
* Get relative time (e.g., "2 hours ago", "3 days ago") |
| 265 |
* @param dateString - Date string |
| 266 |
* @returns Relative time string |
| 267 |
*/ |
| 268 |
export function formatRelativeTime( |
| 269 |
dateString: string | Date | null | undefined, |
| 270 |
): string { |
| 271 |
if (!dateString) return "-"; |
| 272 |
|
| 273 |
try { |
| 274 |
const date = |
| 275 |
typeof dateString === "string" ? new Date(dateString) : dateString; |
| 276 |
|
| 277 |
if (isNaN(date.getTime())) { |
| 278 |
return String(dateString); |
| 279 |
} |
| 280 |
|
| 281 |
const now = new Date(); |
| 282 |
const diffMs = now.getTime() - date.getTime(); |
| 283 |
const diffSecs = Math.floor(diffMs / 1000); |
| 284 |
const diffMins = Math.floor(diffSecs / 60); |
| 285 |
const diffHours = Math.floor(diffMins / 60); |
| 286 |
const diffDays = Math.floor(diffHours / 24); |
| 287 |
const diffWeeks = Math.floor(diffDays / 7); |
| 288 |
const diffMonths = Math.floor(diffDays / 30); |
| 289 |
const diffYears = Math.floor(diffDays / 365); |
| 290 |
|
| 291 |
if (diffSecs < 60) return "Just now"; |
| 292 |
if (diffMins < 60) |
| 293 |
return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`; |
| 294 |
if (diffHours < 24) |
| 295 |
return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`; |
| 296 |
if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`; |
| 297 |
if (diffWeeks < 4) |
| 298 |
return `${diffWeeks} week${diffWeeks > 1 ? "s" : ""} ago`; |
| 299 |
if (diffMonths < 12) |
| 300 |
return `${diffMonths} month${diffMonths > 1 ? "s" : ""} ago`; |
| 301 |
return `${diffYears} year${diffYears > 1 ? "s" : ""} ago`; |
| 302 |
} catch (e) { |
| 303 |
return String(dateString); |
| 304 |
} |
| 305 |
} |
| 306 |
|
| 307 |
/** |
| 308 |
* Parse a date string to Date object |
| 309 |
* @param dateString - Date string in various formats |
| 310 |
* @returns Date object or null if invalid |
| 311 |
*/ |
| 312 |
export function parseDate(dateString: string | null | undefined): Date | null { |
| 313 |
if (!dateString) return null; |
| 314 |
|
| 315 |
try { |
| 316 |
const date = new Date(dateString); |
| 317 |
return isNaN(date.getTime()) ? null : date; |
| 318 |
} catch (e) { |
| 319 |
return null; |
| 320 |
} |
| 321 |
} |
| 322 |
|
| 323 |
/** |
| 324 |
* Format date for input fields (always YYYY-MM-DD for HTML date inputs) |
| 325 |
* @param dateString - Date string |
| 326 |
* @returns Date in YYYY-MM-DD format for input fields |
| 327 |
*/ |
| 328 |
export function formatDateForInput( |
| 329 |
dateString: string | Date | null | undefined, |
| 330 |
): string { |
| 331 |
if (!dateString) return ""; |
| 332 |
|
| 333 |
try { |
| 334 |
const date = |
| 335 |
typeof dateString === "string" ? new Date(dateString) : dateString; |
| 336 |
|
| 337 |
if (isNaN(date.getTime())) { |
| 338 |
return ""; |
| 339 |
} |
| 340 |
|
| 341 |
const year = date.getFullYear(); |
| 342 |
const month = (date.getMonth() + 1).toString().padStart(2, "0"); |
| 343 |
const day = date.getDate().toString().padStart(2, "0"); |
| 344 |
|
| 345 |
return `${year}-${month}-${day}`; |
| 346 |
} catch (e) { |
| 347 |
return ""; |
| 348 |
} |
| 349 |
} |
| 350 |
|