"был в сети 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' });
Константные переменные можно вынести в общий конфиг решения, но в остальном оно не использует никаких велосипедов и костылей, но предоставляет возможность опираясь на силы браузера реализовать решение простой задачи, не устанавливая лишних зависимостей.