UNPKG

6.39 kBJavaScriptView Raw
1// Utility function to format time in human-readable "time ago" format.
2function showtimeago(dateParam) {
3 try {
4 const MONTH_NAMES = [
5 'January', 'February', 'March', 'April', 'May', 'June',
6 'July', 'August', 'September', 'October', 'November', 'December'
7 ];
8
9 // Helper function to get the ordinal suffix of a number
10 function getOrdinalNum(n) {
11 return n + (n > 0 ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] : '');
12 }
13
14 // Helper function to format the date
15 function getFormattedDate(date, preformattedDate, hideYear) {
16 const day = date.getDate();
17 const month = MONTH_NAMES[date.getMonth()];
18 const year = date.getFullYear();
19 let hours = date.getHours();
20 let minutes = date.getMinutes();
21 const ampm = hours >= 12 ? 'PM' : 'AM';
22
23 hours = hours % 12 || 12; // Convert hours to 12-hour format
24 minutes = minutes < 10 ? `0${minutes}` : minutes; // Add leading zero to minutes
25
26 if (preformattedDate) {
27 return `${preformattedDate} at ${hours}:${minutes} ${ampm}`;
28 }
29
30 if (hideYear) {
31 return `${month} ${getOrdinalNum(day)}, at ${hours}:${minutes} ${ampm}`;
32 }
33
34 return `${month} ${getOrdinalNum(day)}, ${year} at ${hours}:${minutes} ${ampm}`;
35 }
36
37 // Validate the date parameter
38 function validateDateParam(dateParam) {
39 if (dateParam === undefined || dateParam === null) {
40 throw new Error("Invalid date parameter: dateParam cannot be empty. It must be a valid ISO date string or a Date object.");
41 }
42 if (typeof dateParam === 'string') {
43 const date = new Date(dateParam);
44 if (isNaN(date.getTime())) {
45 throw new Error("Invalid date parameter: dateParam is not a valid ISO date string.");
46 }
47 return date;
48 }
49 if (typeof dateParam === 'object' && dateParam instanceof Date) {
50 return dateParam;
51 }
52 throw new Error("Invalid date parameter: dateParam must be a valid ISO date string or a Date object.");
53 }
54
55 // Main function to calculate the "time ago" string
56 function timeAgo(dateParam) {
57 const date = validateDateParam(dateParam);
58 const now = new Date();
59
60 // Check if the date is in the future
61 if (date > now) {
62 throw new Error("Invalid date: The provided date is in the future.");
63 }
64
65 const DAY_IN_MS = 86400000; // 24 * 60 * 60 * 1000
66 const YEAR_IN_MS = 365.25 * DAY_IN_MS; // Account for leap years
67 const yesterday = new Date(now.getTime() - DAY_IN_MS);
68
69 const seconds = Math.round((now.getTime() - date.getTime()) / 1000);
70 const minutes = Math.round(seconds / 60);
71 const hours = Math.round(minutes / 60);
72 const days = Math.round(hours / 24);
73 const months = Math.round(days / 30.44); // More accurate month calculation
74 const years = Math.floor(days / 365.25); // More accurate year calculation
75
76 const isToday = now.toDateString() === date.toDateString();
77 const isYesterday = yesterday.toDateString() === date.toDateString();
78
79 // Specific check for exactly one year ago
80 const oneYearAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds());
81 if (date.toDateString() === oneYearAgo.toDateString()) {
82 return '1 year ago';
83 }
84
85 // Detailed logging for debugging
86 // console.log({
87 // seconds,
88 // minutes,
89 // hours,
90 // days,
91 // months,
92 // years,
93 // isToday,
94 // isYesterday,
95 // now,
96 // date
97 // });
98
99 switch (true) {
100 case (seconds < 2):
101 return 'now';
102 case (seconds < 60):
103 return `${seconds} seconds ago`;
104 case (seconds < 90):
105 return 'about a minute ago';
106 case (minutes < 60):
107 return `${minutes} minutes ago`;
108 case (hours === 1):
109 return '1 hour ago';
110 case (hours < 24):
111 return `${hours} hours ago`;
112 case (isToday):
113 return getFormattedDate(date, 'Today');
114 case (isYesterday):
115 return getFormattedDate(date, 'Yesterday');
116 case (days < 30):
117 return `${days} days ago`;
118 case (months === 1):
119 return '1 month ago';
120 case (months < 12):
121 return `${months} months ago`;
122 case (years === 1):
123 return '1 year ago';
124 case (years > 1):
125 return `${years} years ago`;
126 default:
127 return getFormattedDate(date);
128 }
129 }
130
131 return timeAgo(dateParam);
132
133 } catch (error) {
134 console.error("Error in showtimeago function:", error);
135 throw new Error(error.message);
136 }
137}
138
139// console.log(showtimeago("2024-07-18T17:12:00.000Z"));
140// Example usage to test with current time
141// const now = new Date();
142// console.log("Current time:", now.toISOString());
143// console.log("Result:", showtimeago(now));
144
145// // Test with 5 seconds ago
146// const fiveSecondsAgo = new Date(now.getTime() - 5000);
147// console.log("5 seconds ago:", fiveSecondsAgo.toISOString());
148// console.log("Result:", showtimeago(fiveSecondsAgo));
149
150// // Test with 1 minute ago
151// const oneMinuteAgo = new Date(now.getTime() - 60000);
152// console.log("1 minute ago:", oneMinuteAgo.toISOString());
153// console.log("Result:", showtimeago(oneMinuteAgo));
154
155module.exports = showtimeago;
\No newline at end of file