export const parseTemplateDate = (value) => { const match = /^(\d+)-(\d{2})-(\d{2})[T ](\d{2}:\d{2}:\d{2}(?:\.\d+)?)( BC)?$/.exec(value || ''); if (!match) return null; return { year: String(match[5] ? 1 - Number(match[1]) : Number(match[1])), month: match[2], day: match[3], time: match[4], }; }; export const serializeTemplateDate = ({ year, month, day, time }) => { const offset = Number(year); const dateYear = String(offset <= 0 ? 1 - offset : offset).padStart(4, '0'); return `${dateYear}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ${time.length === 5 ? `${time}:00` : time}${offset <= 0 ? ' BC' : ''}`; }; export const templateDateNumber = (value) => { if (!value || !/^-?\d+$/.test(value.year) || !Number.isSafeInteger(Number(value.year))) return Number.NaN; const { month, day, time } = value; if (!Number.isInteger(Number(month)) || !Number.isInteger(Number(day)) || Number(month) < 1 || Number(month) > 12 || Number(day) < 1) return Number.NaN; if (!/^\d{2}:\d{2}(?::\d{2}(?:\.\d{1,6})?)?$/.test(time)) return Number.NaN; const [hours, minutes, seconds = 0] = time.split(':').map(Number); const year = 2000 + Number(value.year); const date = new Date(0); date.setUTCFullYear(year, Number(month) - 1, Number(day)); date.setUTCHours(hours, minutes, Math.floor(seconds), 0); if ( date.getUTCFullYear() !== year || date.getUTCMonth() !== Number(month) - 1 || date.getUTCDate() !== Number(day) || hours > 23 || minutes > 59 || seconds >= 60 ) return Number.NaN; return date.getTime() + (seconds % 1) * 1000; }; export const formatTemplateDate = (value) => { const date = parseTemplateDate(value); if (!date) return value || '—'; const offset = Number(date.year); const year = offset === 0 ? 'год бюджета' : `год бюджета ${offset > 0 ? '+' : '−'} ${Math.abs(offset)}`; return `${date.day}.${date.month} (${year})`; }; export const templateKey = (template) => JSON.stringify([template.form_type, template.sheet, template.direction ?? null, template.phase_code]);