UNPKG

rsshub

Version:
150 lines (148 loc) 4.69 kB
import dayjs from "dayjs"; import customParseFormat from "dayjs/plugin/customParseFormat.js"; import duration from "dayjs/plugin/duration.js"; import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js"; import weekday from "dayjs/plugin/weekday.js"; //#region lib/utils/parse-date.ts dayjs.extend(customParseFormat); dayjs.extend(duration); dayjs.extend(isSameOrBefore); dayjs.extend(weekday); const words = [ { startAt: dayjs(), regExp: /^(?:今[天日]|to?day?)(.*)/ }, { startAt: dayjs().subtract(1, "days"), regExp: /^(?:昨[天日]|y(?:ester)?day?)(.*)/ }, { startAt: dayjs().subtract(2, "days"), regExp: /^(?:前天|(?:the)?d(?:ay)?b(?:eforeyesterda)?y)(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(1)) ? dayjs().weekday(1).subtract(1, "week") : dayjs().weekday(1), regExp: /^(?:周|星期)一(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(2)) ? dayjs().weekday(2).subtract(1, "week") : dayjs().weekday(2), regExp: /^(?:周|星期)二(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(3)) ? dayjs().weekday(3).subtract(1, "week") : dayjs().weekday(3), regExp: /^(?:周|星期)三(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(4)) ? dayjs().weekday(4).subtract(1, "week") : dayjs().weekday(4), regExp: /^(?:周|星期)四(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(5)) ? dayjs().weekday(5).subtract(1, "week") : dayjs().weekday(5), regExp: /^(?:周|星期)五(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(6)) ? dayjs().weekday(6).subtract(1, "week") : dayjs().weekday(6), regExp: /^(?:周|星期)六(.*)/ }, { startAt: dayjs().isSameOrBefore(dayjs().weekday(7)) ? dayjs().weekday(7).subtract(1, "week") : dayjs().weekday(7), regExp: /^(?:周|星期)[天日](.*)/ }, { startAt: dayjs().add(1, "days"), regExp: /^(?:明[天日]|y(?:ester)?day?)(.*)/ }, { startAt: dayjs().add(2, "days"), regExp: /^(?:[后後][天日]|(?:the)?d(?:ay)?a(?:fter)?t(?:omrrow)?)(.*)/ } ]; const patterns = [ { unit: "years", regExp: /(\d+)(?:年|y(?:ea)?rs?)/ }, { unit: "months", regExp: /(\d+)(?:[个個]?月|months?)/ }, { unit: "weeks", regExp: /(\d+)(?:周|[个個]?星期|weeks?)/ }, { unit: "days", regExp: /(\d+)(?:天|日|d(?:ay)?s?)/ }, { unit: "hours", regExp: /(\d+)(?:[个個]?(?:小?时|時|点|點)|h(?:(?:ou)?r)?s?)/ }, { unit: "minutes", regExp: /(\d+)(?:分[鐘钟]?|m(?:in(?:ute)?)?s?)/ }, { unit: "seconds", regExp: /(\d+)(?:秒[鐘钟]?|s(?:ec(?:ond)?)?s?)/ } ]; const patternSize = Object.keys(patterns).length; /** * 预处理日期字符串 * @param {String} date 原始日期字符串 */ const toDate = (date) => date.toLowerCase().replaceAll(/(^an?\s)|(\san?\s)/g, "1").replaceAll(/几|幾/g, "3").replaceAll(/[\s,]/g, ""); /** * 将 `['\d+时', ..., '\d+秒']` 转换为 `{ hours: \d+, ..., seconds: \d+ }` * 用于描述时间长度 * @param {Array.<String>} matches 所有匹配结果 */ const toDurations = (matches) => { const durations = {}; let p = 0; for (const m of matches) for (; p <= patternSize; p++) { const match = patterns[p].regExp.exec(m); if (match) { durations[patterns[p].unit] = match[1]; break; } } return durations; }; const parseDate = (date, ...options) => dayjs(date, ...options).toDate(); const parseRelativeDate = (date) => { const theDate = toDate(date); const matches = theDate.match(/(?:\D+)?\d+(?!:|-|\/|(a|p)m)\D+/g); if (matches) { const lastMatch = matches.pop(); if (lastMatch) { const beforeMatches = /(.*)(?:[之以]?前|ago)$/.exec(lastMatch); if (beforeMatches) { matches.push(beforeMatches[1]); return dayjs().subtract(dayjs.duration(toDurations(matches))).toDate(); } const afterMatches = /(?:^in(.*)|(.*)[之以]?[后後])$/.exec(lastMatch); if (afterMatches) { matches.push(afterMatches[1] ?? afterMatches[2]); return dayjs().add(dayjs.duration(toDurations(matches))).toDate(); } matches.push(lastMatch); } const firstMatch = matches.shift(); if (firstMatch) for (const w of words) { const wordMatches = w.regExp.exec(firstMatch); if (wordMatches) { matches.unshift(wordMatches[1]); return w.startAt.set("hour", 0).set("minute", 0).set("second", 0).set("millisecond", 0).add(dayjs.duration(toDurations(matches))).toDate(); } } } else for (const w of words) { const wordMatches = w.regExp.exec(theDate); if (wordMatches) return dayjs(`${w.startAt.format("YYYY-MM-DD")} ${/a|pm$/.test(wordMatches[1]) ? wordMatches[1].replace(/a|pm/, " $&") : wordMatches[1]}`).toDate(); } return date; }; //#endregion export { parseRelativeDate as n, parseDate as t };