function pad2(n: number): string { return n < 10 ? `0${n}` : `${n}`; } /** Сегодня + n дней в формате YYYY-MM-DD (для min/max у input type=date). */ export function isoDatePlusDays(days: number): string { const d = new Date(); d.setDate(d.getDate() + days); return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; } /** * Сегодня + n КАЛЕНДАРНЫХ месяцев в формате YYYY-MM-DD (для min/max у input * type=date) — не приближение через 30 дней: `setMonth` сам разносит месяцы * разной длины (28–31 день) и года на границе декабря/января. * * 31 января + 1 месяц → JS даёт 3 марта (переносит лишние дни на следующий * месяц, а не откатывает до последнего числа) — для месячного уведомления это * не проблема (крайняя ранняя дата и так сдвигается на несколько дней позже, * не раньше), но не считать это «ровно через месяц» в общем случае. */ export function isoDatePlusMonths(months: number): string { const d = new Date(); d.setMonth(d.getMonth() + months); return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; } /** Сегодня по МЕСТНОМУ времени в формате YYYY-MM-DD (toISOString дал бы дату по UTC — до 05:00 вчерашнюю). */ export function todayIsoDate(): string { return isoDatePlusDays(0); } const HALF_DAY_MS = 12 * 60 * 60 * 1000; /** * Значение поля SharePoint «только дата» → YYYY-MM-DD для input type=date. * * REST отдаёт такие поля в UTC: «5 октября» на сайте с поясом UTC+5 приходит * как «2026-10-04T19:00:00Z», и `slice(0, 10)` давал 4-е число (а каждое * пересохранение сдвигало дату ещё на день назад). Округляем до ближайшей * полуночи UTC (+12 ч) — так верно для любого пояса сайта в пределах ±11 ч и * не зависит от пояса браузера. */ export function spDateOnlyToIso(value: unknown): string { if (typeof value !== 'string' || value === '') return ''; if (value.indexOf('T') < 0) return value.slice(0, 10); const ms = Date.parse(value); if (isNaN(ms)) return value.slice(0, 10); return new Date(ms + HALF_DAY_MS).toISOString().slice(0, 10); } /** YYYY-MM-DD → дд.мм.гггг, для текста ошибок валидации. Невалидную строку возвращает как есть. */ export function formatIsoDate(iso: string): string { const [y, m, d] = iso.split('-'); return y && m && d ? `${d}.${m}.${y}` : iso; }