| 286 | * @returns A parsed JavaScript Date object. |
| 287 | */ |
| 288 | export const parseRelativeDate = (date: string, ...options: OptionType[]): Date => { |
| 289 | if (!date) { |
| 290 | return new Date(); |
| 291 | } |
| 292 | |
| 293 | const normalized = normalize(date); |
| 294 | |
| 295 | // Strategy 1: Immediate Time |
| 296 | if (normalized === 'just now') { |
| 297 | return dayjs().subtract(3, 'seconds').toDate(); |
| 298 | } |
| 299 | |
| 300 | // Strategy 2: Relative Duration |
| 301 | const agoMatch = REGEX_AGO.exec(normalized); |
| 302 | if (agoMatch) { |
| 303 | const duration = parseDuration(agoMatch[1]); |
| 304 | if (duration.asMilliseconds() > 0) { |
| 305 | return dayjs().subtract(duration).toDate(); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | const inMatch = REGEX_IN.exec(normalized); |
| 310 | if (inMatch) { |
| 311 | const duration = parseDuration(inMatch[1] || inMatch[2]); |
| 312 | if (duration.asMilliseconds() > 0) { |
| 313 | return dayjs().add(duration).toDate(); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | // Strategy 3: Semantic Keywords extraction and processing |
| 318 | const cleanStr = normalized.replaceAll(/\s+/g, ''); |
| 319 | for (const word of KEYWORDS) { |
| 320 | const match = word.regExp.exec(cleanStr); |
| 321 | if (match) { |
| 322 | const baseTime = word.calc(); |
| 323 | const timePart = cleanStr.replace(word.regExp, ''); |
| 324 | return processSemanticKeyword(baseTime, timePart, normalized); |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | // Strategy 4: Fallback to standard Day.js parsing |
| 329 | return parseDate(date, ...options); |
| 330 | }; |