SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
2.4 KB · 65 lines typescript
Raw Blame History
1const MONTHS: Record<string, number> = {2  jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5, jul: 6, aug: 7, sep: 8, sept: 8, oct: 9, nov: 10, dec: 11,3};45/**6 * Parse common marketplace/auction date formats into a UTC Date (midnight when no time).7 * Returns null instead of guessing. Crawl time is never substituted for a sale date here.8 */9export function parseSourceDate(raw: string | null | undefined, opts: { dayFirst?: boolean } = {}): Date | null {10  if (!raw) return null;11  const s = raw.trim().replace(/ /g, ' ');12  if (!s) return null;1314  // ISO-ish15  if (/^\d{4}-\d{2}-\d{2}/.test(s)) {16    const d = new Date(s.length === 10 ? `${s}T00:00:00Z` : s);17    return Number.isNaN(d.getTime()) ? null : d;18  }19  // "Jan 5, 2024", "5 Jan 2024", "January 05 2024", "Sept 12, 2023 10:31 AM"20  const m1 = s.match(/\b([A-Za-z]{3,9})\.?\s+(\d{1,2})(?:st|nd|rd|th)?,?\s+(\d{4})/);21  if (m1) {22    const mo = MONTHS[m1[1]!.slice(0, 3).toLowerCase()];23    if (mo !== undefined) return new Date(Date.UTC(Number(m1[3]), mo, Number(m1[2])));24  }25  const m2 = s.match(/\b(\d{1,2})(?:st|nd|rd|th)?\s+([A-Za-z]{3,9})\.?,?\s+(\d{4})/);26  if (m2) {27    const mo = MONTHS[m2[2]!.slice(0, 3).toLowerCase()];28    if (mo !== undefined) return new Date(Date.UTC(Number(m2[3]), mo, Number(m2[1])));29  }30  // numeric 01/05/2024 or 05.01.2024 or 2024/01/0531  const m3 = s.match(/\b(\d{1,4})[./-](\d{1,2})[./-](\d{1,4})\b/);32  if (m3) {33    const a = Number(m3[1]);34    const b = Number(m3[2]);35    const c = Number(m3[3]);36    if (m3[1]!.length === 4) return new Date(Date.UTC(a, b - 1, c));37    let year = c;38    if (m3[3]!.length === 2) year = 2000 + c;39    const dayFirst = opts.dayFirst ?? a > 12;40    const [day, month] = dayFirst ? [a, b] : [b, a];41    if (month < 1 || month > 12 || day < 1 || day > 31) return null;42    return new Date(Date.UTC(year, month - 1, day));43  }44  // "Mar 2024" (month precision)45  const m4 = s.match(/\b([A-Za-z]{3,9})\.?\s+(\d{4})\b/);46  if (m4) {47    const mo = MONTHS[m4[1]!.slice(0, 3).toLowerCase()];48    if (mo !== undefined) return new Date(Date.UTC(Number(m4[2]), mo, 1));49  }50  const d = new Date(s);51  return Number.isNaN(d.getTime()) ? null : d;52}5354export function toDateOnly(d: Date): string {55  return d.toISOString().slice(0, 10);56}5758export function daysBetween(a: Date, b: Date): number {59  return Math.abs(a.getTime() - b.getTime()) / 86_400_000;60}6162export function addDays(d: Date, days: number): Date {63  return new Date(d.getTime() + days * 86_400_000);64}65