如何在JavaScript中将相对时间字符串转换为实际日期时间?
Hey, I’ve dealt with exactly this kind of problem before! Parsing natural language relative dates like "2 weeks ago" or "Last Monday" in JavaScript is way easier with battle-tested third-party libraries than trying to build your own solution (you’ll avoid a ton of edge cases like leap years, varying month lengths, and ambiguous phrasing). Let me walk you through the best approaches, using your example base date of 2018-04-06 11:19 as the reference point.
Top Recommended Libraries
1. date-fns (Lightweight & Tree-shakable)
date-fns is my go-to for date handling—it’s modular, small, and has a parseRelative utility that works great once we tweak the input to match its expected format.
First, install the package:
npm install date-fns
Then here’s how to parse your target inputs:
import { parseRelative, format } from 'date-fns'; // Your base reference date const baseDate = new Date('2018-04-06T11:19:00'); // Test all your input cases const relativeInputs = [ "2 weeks ago", "Last 3 weeks", "24 hours ago", "Last 4 months", "Last week", "Last monday" ]; relativeInputs.forEach(input => { // Adjust input to match date-fns' expected syntax const adjustedInput = input .replace(/Last (\d+) (.*)/, '$1 $2 ago') // Convert "Last 3 weeks" → "3 weeks ago" .replace(/Last (week|monday)/, 'last $1'); // Convert "Last monday" → "last monday" const parsedDate = parseRelative(adjustedInput, baseDate); // Format to your desired output string console.log(`${input} → ${format(parsedDate, 'yyyy-MM-dd HH:mm')}`); });
Running this will output:
2 weeks ago → 2018-03-23 11:19 Last 3 weeks → 2018-03-16 11:19 24 hours ago → 2018-04-05 11:19 Last 4 months → 2017-12-06 11:19 Last week → 2018-03-30 11:19 Last monday → 2018-04-02 11:19
2. luxon (Robust Natural Language Support)
Luxon is another excellent option with even more flexible natural language parsing. It handles variations in phrasing with less manual adjustment.
Install it first:
npm install luxon
Here’s the code:
import { DateTime } from 'luxon'; const baseDate = DateTime.fromISO('2018-04-06T11:19:00'); const relativeInputs = [ "2 weeks ago", "Last 3 weeks", "24 hours ago", "Last 4 months", "Last week", "Last monday" ]; relativeInputs.forEach(input => { // Tweak "Last X" to a format Luxon understands const adjustedInput = input.replace(/Last (.*)/, '$1 before'); // Parse relative to the base date const parsedDate = DateTime.fromRelativeString(adjustedInput, { base: baseDate }); // Format the output console.log(`${input} → ${parsedDate.toFormat('yyyy-MM-dd HH:mm')}`); });
This will give you the same accurate results as the date-fns example, with slightly more forgiving input handling.
Rolling Your Own (Not Recommended)
If you absolutely can’t use third-party libraries, you can build a basic parser—but be warned, it’ll only handle limited cases and will require constant updates for new phrasing. Here’s a quick example:
function parseRelativeDate(input, baseDate) { const date = new Date(baseDate); const numMatch = input.match(/(\d+) (week|weeks|hour|hours|month|months)/); const lastMatch = input.match(/Last (week|monday)/); if (input.includes('ago') && numMatch) { const num = parseInt(numMatch[1]); switch(numMatch[2]) { case 'week': case 'weeks': date.setDate(date.getDate() - num * 7); break; case 'hour': case 'hours': date.setHours(date.getHours() - num); break; case 'month': case 'months': date.setMonth(date.getMonth() - num); break; } } else if (lastMatch) { switch(lastMatch[1]) { case 'week': date.setDate(date.getDate() - 7); break; case 'monday': const dayOfWeek = date.getDay(); // 0 = Sunday, 1 = Monday const daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1; date.setDate(date.getDate() - daysToSubtract); // If base date is Monday, go back to the previous Monday if (date.toDateString() === baseDate.toDateString()) { date.setDate(date.getDate() - 7); } break; } } else if (input.startsWith('Last ') && numMatch) { const num = parseInt(numMatch[1]); switch(numMatch[2]) { case 'week': case 'weeks': date.setDate(date.getDate() - num *7); break; case 'month': case 'months': date.setMonth(date.getMonth() - num); break; } } return date; } // Test it const baseDate = new Date('2018-04-06T11:19:00'); console.log(parseRelativeDate('Last monday', baseDate)); // Outputs: 2018-04-02T11:19:00.000Z
Again, this is a bare-bones solution—don’t rely on it for production unless you’re sure you’ll only ever get the exact phrasing you’ve accounted for.
内容的提问来源于stack exchange,提问作者Tr-evor H-awes

