2026-03-26 14:41:25 +07:00

188 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}