"был в сети 15 минут назад" — учимся форматировать даты на фронтенде
Идея этого поста пришла ко мне во время кодревью, в процессе которого я вспомнил про такую штуку, как dayjs. Библиотека, которая на мой взгляд, в принципе не нужна, потому что существует Intl API (которым, к сожалению, мало кто пользуется). Причём про это даже в саркастичном ключе написал автор канала ExtremeCode. И ещё тогда я пересылал друзьям и писал, что смешно, что такое решение существует. Но пошутили и забыли, а тут я увидел его в MR и сразу забраковал. И дело вовсе не в саркастичных постах.
Если говорить кратко, dayjs это более современная замена moment.js. Только весит moment в распакованном виде 4.35 Мб, а dayjs всего 664 Кб. Впрочем, это не значит, что это решение в чём-то действительно лучше, поскольку, ни то, ни другое не использует браузерные API, а предоставляет вам свой собственный велосипед. И он действительно может быть неплох в каких-то моментах, но вряд ли вы будете спорить с тем, что решение, интегрированное в браузер будет менее оптимальным выбором.
В нашем случае, dayjs был втянут в проект только чтобы отрисовывать текст типа: "30 минут назад", вместо конкретной даты и времени. Именно это мне и не понравилось, что ради одного красивого вывода мы тянем целую отдельную библиотеку. В качестве альтернативы, я накидал небольшой пример для решения задачи, которую мой сотрудник пытался решить с помощью dayjs:
function countTimedeltaFromToday(date: Date) {
const currDate = new Date();
const delta = currDate.getTime() - date.getTime();
const ONE_MILLISECOND = 1000;
const HOUR_IN_SECONDS = 60 * 60;
const DAY_IN_HOURS = 24;
const MONTH_IN_DAYS = 30;
const YEAR_IN_MONTH = 12;
const daysDelta = delta / ONE_MILLISECOND / HOUR_IN_SECONDS / DAY_IN_HOURS;
const monthsDelta = daysDelta / MONTH_IN_DAYS;
const yearsDelta = monthsDelta / YEAR_IN_MONTH;
return {
delta,
daysDelta,
monthsDelta,
yearsDelta,
};
}
function formatDate(intl: Intl.RelativeTimeFormat, date: Date) {
const MAX_DAYS_DELTA = 15;
const MAX_MONTHS_DELTA = 11;
const delta = countTimedeltaFromToday(date);
const { daysDelta, monthsDelta, yearsDelta } = delta;
if (daysDelta < MAX_DAYS_DELTA) {
return intl.format(Math.floor(-daysDelta), 'day');
}
if (monthsDelta < MAX_MONTHS_DELTA) {
return intl.format(Math.floor(-monthsDelta), 'month');
}
return intl.format(Math.floor(-yearsDelta), 'year');
}
const intl = new Intl.RelativeTimeFormat('ru', { style: 'long', numeric: 'auto' });Константные переменные можно вынести в общий конфиг решения, но в остальном оно не использует никаких велосипедов и костылей, но предоставляет возможность опираясь на силы браузера реализовать решение простой задачи, не устанавливая лишних зависимостей.