PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.11
Yatra – Travel Booking & Tour Operator Software v3.0.11
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / resources / js / lib / dateFormat.ts

dateFormat.ts in Yatra – Travel Booking & Tour Operator Software 3.0.11, at resources/js/lib/dateFormat.ts

390 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 const w = window as any;
28 return (
29 w?.yatraAdmin?.date_format ||
30 w?.yatraAdmin?.dateFormat ||
31 // Customer account pages localize their settings under yatraAccountPage.
32 w?.yatraAccountPage?.date_format ||
33 "Y-m-d"
34 );
35 }
36
37 /**
38 * Get time format from Yatra settings
39 */
40 export function getTimeFormat(): string {
41 const w = window as any;
42 return (
43 w?.yatraAdmin?.time_format ||
44 w?.yatraAdmin?.timeFormat ||
45 w?.yatraAccountPage?.time_format ||
46 "H:i"
47 );
48 }
49
50 /**
51 * Get timezone from Yatra settings
52 */
53 export function getTimezone(): string {
54 const w = window as any;
55 return w?.yatraAdmin?.timezone || w?.yatraAccountPage?.timezone || "UTC";
56 }
57
58 /**
59 * Parse a value into a Date, treating a date-only string ("YYYY-MM-DD") as a
60 * LOCAL calendar date.
61 *
62 * `new Date("2026-08-01")` parses as UTC midnight, but the formatters read it
63 * back with local getters (getDate/getMonth/…), so in any behind-UTC timezone
64 * the day rolls back (Aug 1 → Jul 31) — e.g. a booking's travel_date showing
65 * one day early. Building the Date from its parts pins it to the intended
66 * calendar day regardless of timezone. Datetime strings (with a time part) and
67 * Date objects are parsed/returned as before.
68 */
69 export function toDateValue(value: string | Date): Date {
70 if (typeof value !== "string") return value;
71 const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim());
72 if (dateOnly) {
73 return new Date(
74 Number(dateOnly[1]),
75 Number(dateOnly[2]) - 1,
76 Number(dateOnly[3]),
77 );
78 }
79 return new Date(value);
80 }
81
82 /**
83 * Format a date string according to Yatra settings
84 * @param dateString - Date string in any parseable format (ISO, YYYY-MM-DD, etc.)
85 * @param includeTime - Whether to include time in the output
86 * @returns Formatted date string
87 */
88 export function formatDate(
89 dateString: string | Date | null | undefined,
90 includeTime: boolean = false,
91 ): string {
92 if (!dateString) return "-";
93
94 try {
95 const date = toDateValue(dateString);
96
97 if (isNaN(date.getTime())) {
98 return String(dateString);
99 }
100
101 const phpDateFormat = getDateFormat();
102 const phpTimeFormat = getTimeFormat();
103
104 // Format date part
105 const formattedDate = formatDatePart(date, phpDateFormat);
106
107 // Format time part if requested
108 if (includeTime) {
109 const formattedTime = formatTimePart(date, phpTimeFormat);
110 return `${formattedDate} ${formattedTime}`;
111 }
112
113 return formattedDate;
114 } catch (e) {
115 return String(dateString);
116 }
117 }
118
119 /**
120 * Format only the date part
121 */
122 function formatDatePart(date: Date, phpFormat: string): string {
123 const year = date.getFullYear();
124 const month = date.getMonth();
125 const day = date.getDate();
126
127 const monthNames = [
128 "January",
129 "February",
130 "March",
131 "April",
132 "May",
133 "June",
134 "July",
135 "August",
136 "September",
137 "October",
138 "November",
139 "December",
140 ];
141 const monthShort = [
142 "Jan",
143 "Feb",
144 "Mar",
145 "Apr",
146 "May",
147 "Jun",
148 "Jul",
149 "Aug",
150 "Sep",
151 "Oct",
152 "Nov",
153 "Dec",
154 ];
155
156 const pad = (n: number) => n.toString().padStart(2, "0");
157
158 const dayNames = [
159 "Sunday",
160 "Monday",
161 "Tuesday",
162 "Wednesday",
163 "Thursday",
164 "Friday",
165 "Saturday",
166 ];
167 const dayShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
168 const dayOfWeek = date.getDay();
169
170 switch (phpFormat) {
171 // Numeric formats
172 case "Y-m-d":
173 return `${year}-${pad(month + 1)}-${pad(day)}`;
174 case "Y/m/d":
175 return `${year}/${pad(month + 1)}/${pad(day)}`;
176 case "m/d/Y":
177 return `${pad(month + 1)}/${pad(day)}/${year}`;
178 case "d/m/Y":
179 return `${pad(day)}/${pad(month + 1)}/${year}`;
180 case "d-m-Y":
181 return `${pad(day)}-${pad(month + 1)}-${year}`;
182 case "d.m.Y":
183 return `${pad(day)}.${pad(month + 1)}.${year}`;
184 // Month name formats with padded day
185 case "M d, Y":
186 return `${monthShort[month]} ${pad(day)}, ${year}`;
187 case "F d, Y":
188 return `${monthNames[month]} ${pad(day)}, ${year}`;
189 case "d M Y":
190 return `${pad(day)} ${monthShort[month]} ${year}`;
191 case "d F Y":
192 return `${pad(day)} ${monthNames[month]} ${year}`;
193 // Month name formats with day without leading zero
194 case "M j, Y":
195 return `${monthShort[month]} ${day}, ${year}`;
196 case "F j, Y":
197 return `${monthNames[month]} ${day}, ${year}`;
198 case "j M Y":
199 return `${day} ${monthShort[month]} ${year}`;
200 case "j F Y":
201 return `${day} ${monthNames[month]} ${year}`;
202 // Year first with month name
203 case "Y M j":
204 return `${year} ${monthShort[month]} ${day}`;
205 case "Y F j":
206 return `${year} ${monthNames[month]} ${day}`;
207 // With weekday
208 case "l, F j, Y":
209 return `${dayNames[dayOfWeek]}, ${monthNames[month]} ${day}, ${year}`;
210 case "D, M j, Y":
211 return `${dayShort[dayOfWeek]}, ${monthShort[month]} ${day}, ${year}`;
212 default:
213 // Default to ISO format
214 return `${year}-${pad(month + 1)}-${pad(day)}`;
215 }
216 }
217
218 /**
219 * Format only the time part
220 */
221 function formatTimePart(date: Date, phpFormat: string): string {
222 const hours = date.getHours();
223 const minutes = date.getMinutes();
224 const seconds = date.getSeconds();
225
226 const pad = (n: number) => n.toString().padStart(2, "0");
227
228 const hours12 = hours % 12 || 12;
229 const ampm = hours >= 12 ? "PM" : "AM";
230
231 switch (phpFormat) {
232 case "H:i":
233 return `${pad(hours)}:${pad(minutes)}`;
234 case "h:i A":
235 return `${pad(hours12)}:${pad(minutes)} ${ampm}`;
236 case "h:i a":
237 return `${pad(hours12)}:${pad(minutes)} ${ampm.toLowerCase()}`;
238 case "H:i:s":
239 return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
240 case "h:i:s A":
241 return `${pad(hours12)}:${pad(minutes)}:${pad(seconds)} ${ampm}`;
242 default:
243 return `${pad(hours)}:${pad(minutes)}`;
244 }
245 }
246
247 /**
248 * Format a date for display with time
249 * @param dateString - Date string
250 * @returns Formatted date and time string
251 */
252 export function formatDateTime(
253 dateString: string | Date | null | undefined,
254 ): string {
255 return formatDate(dateString, true);
256 }
257
258 /**
259 * Format time only
260 * @param dateString - Date string or time string
261 * @returns Formatted time string
262 */
263 export function formatTime(
264 dateString: string | Date | null | undefined,
265 ): string {
266 if (!dateString) return "-";
267
268 try {
269 const date = toDateValue(dateString);
270
271 if (isNaN(date.getTime())) {
272 // Try to parse as time only (HH:mm or HH:mm:ss)
273 if (
274 typeof dateString === "string" &&
275 /^\d{1,2}:\d{2}(:\d{2})?$/.test(dateString)
276 ) {
277 const [hours, minutes] = dateString.split(":").map(Number);
278 const tempDate = new Date();
279 tempDate.setHours(hours, minutes, 0, 0);
280 return formatTimePart(tempDate, getTimeFormat());
281 }
282 return String(dateString);
283 }
284
285 return formatTimePart(date, getTimeFormat());
286 } catch (e) {
287 return String(dateString);
288 }
289 }
290
291 /**
292 * Get relative time (e.g., "2 hours ago", "3 days ago")
293 * @param dateString - Date string
294 * @returns Relative time string
295 */
296 export function formatRelativeTime(
297 dateString: string | Date | null | undefined,
298 ): string {
299 if (!dateString) return "-";
300
301 try {
302 const date = toDateValue(dateString);
303
304 if (isNaN(date.getTime())) {
305 return String(dateString);
306 }
307
308 const now = new Date();
309 const diffMs = now.getTime() - date.getTime();
310 const diffSecs = Math.floor(diffMs / 1000);
311 const diffMins = Math.floor(diffSecs / 60);
312 const diffHours = Math.floor(diffMins / 60);
313 const diffDays = Math.floor(diffHours / 24);
314 const diffWeeks = Math.floor(diffDays / 7);
315 const diffMonths = Math.floor(diffDays / 30);
316 const diffYears = Math.floor(diffDays / 365);
317
318 if (diffSecs < 60) return "Just now";
319 if (diffMins < 60)
320 return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
321 if (diffHours < 24)
322 return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
323 if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
324 if (diffWeeks < 4)
325 return `${diffWeeks} week${diffWeeks > 1 ? "s" : ""} ago`;
326 if (diffMonths < 12)
327 return `${diffMonths} month${diffMonths > 1 ? "s" : ""} ago`;
328 return `${diffYears} year${diffYears > 1 ? "s" : ""} ago`;
329 } catch (e) {
330 return String(dateString);
331 }
332 }
333
334 /**
335 * Parse a date string to Date object
336 * @param dateString - Date string in various formats
337 * @returns Date object or null if invalid
338 */
339 export function parseDate(dateString: string | null | undefined): Date | null {
340 if (!dateString) return null;
341
342 try {
343 const date = toDateValue(dateString);
344 return isNaN(date.getTime()) ? null : date;
345 } catch (e) {
346 return null;
347 }
348 }
349
350 /**
351 * Format date for input fields (always YYYY-MM-DD for HTML date inputs)
352 * @param dateString - Date string
353 * @returns Date in YYYY-MM-DD format for input fields
354 */
355 /**
356 * Today's date as a LOCAL "YYYY-MM-DD" string.
357 *
358 * Use this instead of `new Date().toISOString().split("T")[0]` for default/
359 * "today" date values: toISOString() yields the UTC date, which is the wrong
360 * calendar day for a user whose local date differs from UTC at that moment
361 * (e.g. late evening in a behind-UTC zone, or early morning ahead of UTC) —
362 * saving a payment/booking/rule date a day off. This reads the browser's local
363 * calendar day.
364 */
365 export function todayYmd(): string {
366 return formatDateForInput(new Date());
367 }
368
369 export function formatDateForInput(
370 dateString: string | Date | null | undefined,
371 ): string {
372 if (!dateString) return "";
373
374 try {
375 const date = toDateValue(dateString);
376
377 if (isNaN(date.getTime())) {
378 return "";
379 }
380
381 const year = date.getFullYear();
382 const month = (date.getMonth() + 1).toString().padStart(2, "0");
383 const day = date.getDate().toString().padStart(2, "0");
384
385 return `${year}-${month}-${day}`;
386 } catch (e) {
387 return "";
388 }
389 }
390