export function formatRussianDate(dateStr: string): string { // 1. Вытаскиваем только саму дату (2026-03-24) с помощью регулярного выражения // Это защитит нас от багов с часовыми поясами при парсинге const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!match) { throw new Error("Неверный формат входной строки"); } // 2. Преобразуем строки в числа const year = parseInt(match[1], 10); const month = parseInt(match[2], 10); const day = parseInt(match[3], 10); // 3. Создаем объект даты (обратите внимание: в JS месяцы начинаются с 0, поэтому month - 1) const dateObj = new Date(year, month - 1, day); // 4. Словари для точного форматирования (родительный падеж для месяцев) const monthsRu = [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ]; // В JS 0 - это воскресенье, 1 - понедельник и т.д. const weekdaysRu = [ "воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота" ]; // 5. Получаем нужные значения const monthName = monthsRu[dateObj.getMonth()]; const weekdayName = weekdaysRu[dateObj.getDay()]; // 6. Собираем итоговую строку return `${weekdayName} ${day} ${monthName}`; } export function getRelativeDayName(dateStr: string): string { // 1. Вытаскиваем только дату (например, 2026-03-24) const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})/); if (!match) { throw new Error("Неверный формат входной строки"); } const year = parseInt(match[1], 10); const month = parseInt(match[2], 10) - 1; // Месяцы в JS начинаются с 0 const day = parseInt(match[3], 10); // 2. Создаем объект целевой даты и сбрасываем время в 00:00:00 const targetDate = new Date(year, month, day, 0, 0, 0, 0); // 3. Создаем объект СЕГОДНЯШНЕЙ даты и тоже сбрасываем время в 00:00:00 const today = new Date(); today.setHours(0, 0, 0, 0); // 4. Вычисляем разницу в миллисекундах и переводим в дни // Используем Math.round, чтобы избежать багов при переходе на летнее/зимнее время const diffInMs = targetDate.getTime() - today.getTime(); const diffInDays = Math.round(diffInMs / (1000 * 60 * 60 * 24)); // 5. Возвращаем результат в зависимости от разницы в днях switch (diffInDays) { case 0: return "сегодня"; case 1: return "завтра"; case 2: return "послезавтра"; // бонус :) case -1: return "вчера"; // бонус :) default: // Если это не сегодня и не завтра, можно вернуть пустую строку, // либо просто количество дней, либо отформатированную дату (как в прошлом ответе) return ""; } } /** * Функция для склонения слов (1 минута, 2 минуты, 5 минут) */ function getDeclension(number: number, titles: [string, string, string]): string { const cases = [2, 0, 1, 1, 1, 2]; return titles[ (number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5] ]; } /** * Основная функция форматирования времени */ export function timeAgo(goDateStr: string): string { // 1. Парсим строку регуляркой, чтобы вытащить дату, время и смещение пояса. // Игнорируем "m=+..." и доли секунд, так как для "5 минут назад" они не нужны. // Группы: 1-Дата, 2-Время, 3-Часовой пояс (например +0700) const regex = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})(?:\.\d+)? ([+-]\d{4})/; const match = goDateStr.match(regex); if (!match) { console.error("Неверный формат даты:", goDateStr); return goDateStr; // Возвращаем как есть в случае ошибки } const datePart = match[1]; const timePart = match[2]; const timezone = match[3]; // 2. Приводим к формату ISO 8601, который понимает любой браузер: // "2026-03-26T12:11:18+0700" const isoString = `${datePart}T${timePart}${timezone}`; const date = new Date(isoString); const now = new Date(); // 3. Считаем разницу в секундах const seconds = Math.floor((now.getTime() - date.getTime()) / 1000); // Если дата в будущем (например, как в вашем примере 2026 год) if (seconds < 0) { return "в будущем"; } // 4. Логика интервалов const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (seconds < 60) { return "только что"; } if (minutes < 60) { return `${minutes} ${getDeclension(minutes, ['минуту', 'минуты', 'минут'])} назад`; } if (hours < 24) { return `${hours} ${getDeclension(hours, ['час', 'часа', 'часов'])} назад`; } if (days < 7) { return `${days} ${getDeclension(days, ['день', 'дня', 'дней'])} назад`; } // Если прошло больше недели, возвращаем просто дату // Можно использовать Intl.DateTimeFormat для красоты return date.toLocaleDateString("ru-RU", { day: "numeric", month: "long", year: "numeric" }); } export function formatTime(timeStr: string): string { if (!timeStr) { return ""; } return timeStr // 1. Убираем абсолютно все пробелы (включая табы и неразрывные пробелы) .replace(/\s+/g, "") // 2. Заменяем все точки на двоеточия .replace(/\./g, ":"); } export function formatTimeRange(text: string): string { if (!text) { return ""; } return text // 1. Меняем точку на двоеточие ТОЛЬКО в форматах времени (например, 16.00 -> 16:00) // (^|[^\d]) - проверяем, что перед цифрой нет других цифр // ([0-2]?\d) - часы (от 0 до 29) // \. - сама точка // ([0-5]\d) - минуты (от 00 до 59) // (?!\d) - после минут не должно быть других цифр .replace(/(^|[^\d])([0-2]?\d)\.([0-5]\d)(?!\d)/g, "$1$2:$3") // 2. Находим любые дефисы или тире и делаем красивые пробелы вокруг них ("-" -> " - ") .replace(/\s*([-–—])\s*/g, " - ") // 3. На всякий случай сжимаем двойные пробелы в один (если они случайно появились) .replace(/\s{2,}/g, " ") // 4. Убираем пробелы в самом начале и в самом конце строки .trim(); }