在Javascript/Node.js中解析不规则日期格式的方案咨询
在JavaScript/Node.js中解析多种不规则日期格式的最佳方案
你需要解析一组格式各异的日期字符串(如["December 15th", "31 of October", "22.10.2022"]等)并转换为MM/DD/YYYY或标准可处理格式,自行尝试的字符清理+Date.parse()方法通用性不足,以下是几种可行的解决方案:
一、使用第三方日期解析库(首推方案)
手动覆盖所有不规则格式成本极高,成熟的日期库已经封装了大量解析逻辑,能处理绝大多数场景:
1. date-fns(轻量模块化)
date-fns支持多格式尝试解析,配合序数词清理即可覆盖你的需求:
import { parse, format } from 'date-fns'; const dateStrings = ["December 15th", "October 31st", "31 of October", "November 25th 2022", "22.10.2022", "15 November 2022", "9th of April 2023", "Friday 25 November 2022"]; // 定义所有待匹配的格式模板(date-fns格式令牌) const formats = [ 'MMMM do', // December 15th 'MMMM do yyyy', // November 25th 2022 'do of MMMM', // 31 of October 'do of MMMM yyyy',// 9th of April 2023 'dd.MM.yyyy', // 22.10.2022 'dd MMMM yyyy', // 15 November 2022 'EEEE dd MMMM yyyy' // Friday 25 November 2022 ]; const parseDate = (str) => { // 先移除序数词(st/nd/rd/th) const cleanedStr = str.replace(/(st|nd|rd|th)/gi, ''); // 遍历所有格式尝试解析 for (const fmt of formats) { try { const date = parse(cleanedStr, fmt, new Date()); if (date.toString() !== 'Invalid Date') { return format(date, 'MM/dd/yyyy'); } } catch (e) { continue; } } return '无法解析的日期'; }; // 测试解析 dateStrings.forEach(str => { console.log(`${str} -> ${parseDate(str)}`); });
2. Luxon(强类型+时区友好)
Luxon的fromString方法支持多格式配置,错误处理更严谨:
import { DateTime } from 'luxon'; const dateStrings = ["December 15th", "October 31st", "31 of October", "November 25th 2022", "22.10.2022", "15 November 2022", "9th of April 2023", "Friday 25 November 2022"]; const parseDate = (str) => { const cleanedStr = str.replace(/(st|nd|rd|th)/gi, ''); const date = DateTime.fromString(cleanedStr, { formats: [ 'MMMM d', 'MMMM d yyyy', 'd of MMMM', 'd of MMMM yyyy', 'dd.MM.yyyy', 'd MMMM yyyy', 'EEEE d MMMM yyyy' ], zone: 'utc' }); return date.isValid ? date.toFormat('MM/dd/yyyy') : '无法解析的日期'; }; // 测试解析 dateStrings.forEach(str => { console.log(`${str} -> ${parseDate(str)}`); });
二、自定义正则解析(无依赖场景)
如果不想引入第三方库,可以针对已知格式编写正则匹配逻辑:
const dateStrings = ["December 15th", "October 31st", "31 of October", "November 25th 2022", "22.10.2022", "15 November 2022", "9th of April 2023", "Friday 25 November 2022"]; // 月份名称转数字映射(0-11对应1-12月) const monthMap = { january: 0, february: 1, march: 2, april: 3, may: 4, june: 5, july: 6, august: 7, september: 8, october: 9, november: 10, december: 11 }; const parseDate = (str) => { const cleaned = str.toLowerCase().replace(/(st|nd|rd|th|,|\.)/gi, '').trim(); let year = new Date().getFullYear(); // 默认当年 let month, day; // 匹配 "December 15" / "December 15 2022" const mdYMatch = cleaned.match(/^(\w+) (\d+)(?: (\d{4}))?$/); if (mdYMatch) { month = monthMap[mdYMatch[1]]; day = parseInt(mdYMatch[2], 10); year = mdYMatch[3] ? parseInt(mdYMatch[3], 10) : year; } // 匹配 "31 of October" / "9 of April 2023" else if (cleaned.match(/^\d+ of \w+(?: \d{4})?$/)) { const [dayPart, rest] = cleaned.split(' of '); day = parseInt(dayPart, 10); const [monthName, yearStr] = rest.split(' '); month = monthMap[monthName]; year = yearStr ? parseInt(yearStr, 10) : year; } // 匹配 "22.10.2022"(日.月.年) else if (cleaned.match(/^\d{2}\s*\d{2}\s*\d{4}$/)) { const [dayStr, monthStr, yearStr] = cleaned.split(/\s+/); day = parseInt(dayStr, 10); month = parseInt(monthStr, 10) - 1; year = parseInt(yearStr, 10); } // 匹配 "Friday 25 November 2022" else if (cleaned.match(/^\w+ \d+ \w+ \d{4}$/)) { const [_, dayStr, monthName, yearStr] = cleaned.split(' '); day = parseInt(dayStr, 10); month = monthMap[monthName]; year = parseInt(yearStr, 10); } // 验证日期有效性并格式化 if (month !== undefined && day !== undefined) { const date = new Date(year, month, day); if (date.getFullYear() === year && date.getMonth() === month && date.getDate() === day) { return `${(month + 1).toString().padStart(2, '0')}/${day.toString().padStart(2, '0')}/${year}`; } } return '无法解析的日期'; }; // 测试解析 dateStrings.forEach(str => { console.log(`${str} -> ${parseDate(str)}`); });
注意:这种方法仅适用于格式固定的场景,新增格式需要手动更新正则。
三、极端场景方案(机器学习/第三方API)
如果日期格式极度多样且无法枚举:
- 机器学习模型:用TensorFlow.js训练一个实体提取模型,输入日期字符串输出年、月、日,但需要大量标注数据,开发成本高。
- 第三方NLP API:借助自然语言处理API提取日期实体(如Google Cloud NLP、AWS Comprehend),再转换为标准格式,但需要付费且依赖网络。
内容的提问来源于stack exchange,提问作者Camille Feghali
相关产品推荐
相关产品推荐

