All files / utils date.ts

0% Statements 0/38
0% Branches 0/38
0% Functions 0/3
0% Lines 0/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                                                                                                                                                           
const ISO_DATE_ONLY_REGEX = /^\d{4}-\d{2}-\d{2}$/;
 
const DATE_WITH_YEAR_FORMATTER = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  year: "numeric",
  timeZone: "UTC",
});
 
const MONTH_DAY_FORMATTER = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  timeZone: "UTC",
});
 
export function parseIsoDateUtc(value: string): Date | null {
  if (!ISO_DATE_ONLY_REGEX.test(value)) return null;
 
  const [yearText, monthText, dayText] = value.split("-");
  const year = Number(yearText);
  const month = Number(monthText);
  const day = Number(dayText);
 
  if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
    return null;
  }
 
  const parsed = new Date(Date.UTC(year, month - 1, day));
 
  if (
    parsed.getUTCFullYear() !== year ||
    parsed.getUTCMonth() !== month - 1 ||
    parsed.getUTCDate() !== day
  ) {
    return null;
  }
 
  return parsed;
}
 
export function formatDateWithYear(date: Date): string {
  return DATE_WITH_YEAR_FORMATTER.format(date);
}
 
export function formatHumanDateRange(startDate: string, endDate: string): string {
  if (!startDate && !endDate) return "—";
 
  if (!startDate || !endDate) {
    const single = startDate || endDate;
    const parsed = parseIsoDateUtc(single);
    return parsed ? DATE_WITH_YEAR_FORMATTER.format(parsed) : single;
  }
 
  const parsedStart = parseIsoDateUtc(startDate);
  const parsedEnd = parseIsoDateUtc(endDate);
 
  if (!parsedStart || !parsedEnd) {
    return startDate === endDate ? startDate : `${startDate} → ${endDate}`;
  }
 
  if (startDate === endDate) {
    return DATE_WITH_YEAR_FORMATTER.format(parsedStart);
  }
 
  const sameYear = parsedStart.getUTCFullYear() === parsedEnd.getUTCFullYear();
  const sameMonth = sameYear && parsedStart.getUTCMonth() === parsedEnd.getUTCMonth();
 
  if (sameMonth) {
    return `${MONTH_DAY_FORMATTER.format(parsedStart)}–${parsedEnd.getUTCDate()}, ${parsedStart.getUTCFullYear()}`;
  }
 
  if (sameYear) {
    return `${MONTH_DAY_FORMATTER.format(parsedStart)} – ${MONTH_DAY_FORMATTER.format(parsedEnd)}, ${parsedStart.getUTCFullYear()}`;
  }
 
  return `${DATE_WITH_YEAR_FORMATTER.format(parsedStart)} – ${DATE_WITH_YEAR_FORMATTER.format(parsedEnd)}`;
}