// Helpers for Persian (Shamsi) dates and relative time labels used across the site. const PERSIAN_DIGITS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; /** Convert any latin digits in a string (or a number) to Persian digits. */ export const toPersianDigits = (value: string | number): string => String(value).replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)] ?? digit); type DatedPost = { publishedAt?: string; slug: string; time: string }; /** * Resolve the publish timestamp of a post. * * Posts created by the TASS agent embed `Date.now()` at the end of their slug, * so we can recover a real timestamp even for older posts that only stored the * placeholder string "هم‌اکنون". */ export const getPublishedAt = (post: DatedPost): Date | null => { if (post.publishedAt) { const date = new Date(post.publishedAt); return Number.isNaN(date.getTime()) ? null : date; } const match = post.slug.match(/(\d{13})$/); if (match) { const date = new Date(Number(match[1])); return Number.isNaN(date.getTime()) ? null : date; } return null; }; /** Derive an ISO timestamp for a post, or null when none can be inferred. */ export const derivePublishedAt = (post: DatedPost): string | undefined => { const date = getPublishedAt(post); return date ? date.toISOString() : undefined; }; /** Exact Shamsi date + time, e.g. "۱۴ تیر ۱۴۰۵، ۱۴:۳۰". */ export const formatShamsiDate = (date: Date): string => { const formatter = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }); return toPersianDigits(formatter.format(date)); }; /** Short Shamsi date without time, e.g. "۱۴ تیر ۱۴۰۵". */ export const formatShamsiDay = (date: Date): string => { const formatter = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: 'long', day: 'numeric', }); return toPersianDigits(formatter.format(date)); }; /** * Relative Persian time label: "هم‌اکنون", "۲ دقیقه پیش", "۱۰ دقیقه پیش", * "۳ ساعت پیش", "۵ روز پیش" — and falls back to an exact Shamsi date for * anything older than a month. */ export const formatRelativeTime = (date: Date): string => { const now = Date.now(); const diffSeconds = Math.max(0, Math.round((now - date.getTime()) / 1000)); if (diffSeconds < 60) { return 'هم‌اکنون'; } const diffMinutes = Math.floor(diffSeconds / 60); if (diffMinutes < 60) { return `${toPersianDigits(diffMinutes)} دقیقه پیش`; } const diffHours = Math.floor(diffMinutes / 60); if (diffHours < 24) { return `${toPersianDigits(diffHours)} ساعت پیش`; } const diffDays = Math.floor(diffHours / 24); if (diffDays < 30) { return `${toPersianDigits(diffDays)} روز پیش`; } return formatShamsiDay(date); }; /** Relative label for a post, falling back to its stored `time` string. */ export const formatPostRelativeTime = (post: DatedPost): string => { const date = getPublishedAt(post); return date ? formatRelativeTime(date) : post.time; }; /** Exact Shamsi label for a post, falling back to its stored `time` string. */ export const formatPostShamsiDate = (post: DatedPost): string => { const date = getPublishedAt(post); return date ? formatShamsiDate(date) : post.time; };