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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 11x 11x 45x 45x 45x 45x 11x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 11x 11x 23x 172x 172x 172x 172x 172x 172x 172x 172x 172x 80x 80x 78x 7x 7x 7x 71x 71x 71x 71x 58x 13x 13x 13x 13x | import { THREAD_TIMESTAMP_FORMAT, THREAD_TIMESTAMP_LOCALE } from "@/constants/date-time";
const ISO_DATE_ONLY_REGEX = /^\d{4}-\d{2}-\d{2}$/;
export function formatTimestamp(value: string): string {
Iif (!value) return "";
try {
return new Intl.DateTimeFormat(THREAD_TIMESTAMP_LOCALE, THREAD_TIMESTAMP_FORMAT).format(new Date(value));
} catch {
return value;
}
}
const DATE_GROUP_LABELS = ["Today", "Yesterday", "Previous 7 Days", "Previous 30 Days"];
export function getThreadDateGroup(updatedAt: string): string {
const date = new Date(updatedAt);
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const dateStart = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const diffDays = Math.round((todayStart.getTime() - dateStart.getTime()) / (1000 * 60 * 60 * 24));
Iif (diffDays === 0) return "Today";
Iif (diffDays === 1) return "Yesterday";
Iif (diffDays <= 7) return "Previous 7 Days";
Eif (diffDays <= 30) return "Previous 30 Days";
return date.toLocaleString("default", { month: "long", year: "numeric" });
}
export function getThreadDateGroupOrder(label: string): number {
const idx = DATE_GROUP_LABELS.indexOf(label);
return idx === -1 ? DATE_GROUP_LABELS.length : idx;
}
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 {
Iif (!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);
Iif (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
return null;
}
const parsed = new Date(Date.UTC(year, month - 1, day));
Iif (
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);
Iif (!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();
Eif (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)}`;
}
|