Плагинная система в Day.js строится вокруг принципа минимального ядра. Базовый пакет содержит только основные операции с датами, а дополнительная функциональность подключается через расширения. При проектировании приложений это приводит к важной задаче: замена или исключение плагинов в пользу нативных возможностей, пользовательских функций или альтернативных подходов, уменьшающих связанность кода.
Переход от плагинов к альтернативным реализациям обычно мотивирован тремя факторами: уменьшение размера бандла, упрощение зависимости, повышение предсказуемости поведения даты без внешних расширений.
Плагин в Day.js — это функция, расширяющая прототип Day.js дополнительными методами или изменяющая поведение парсинга и форматирования.
Типичный механизм подключения:
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)
После подключения появляются дополнительные методы:
dayjs().fromNow()
dayjs().to(dayjs('2025-01-01'))
Проблема подхода заключается в том, что каждый плагин увеличивает поверхность API и усложняет контроль над зависимостями, особенно в крупных приложениях.
Плагин relativeTime часто используется для отображения
разницы между датами. Его можно заменить вычислением разницы через
стандартные методы Day.js без расширений.
import dayjs from 'dayjs'
function diffFromNow(date) {
const now = dayjs()
const target = dayjs(date)
const seconds = now.diff(target, 'second')
const minutes = now.diff(target, 'minute')
const hours = now.diff(target, 'hour')
const days = now.diff(target, 'day')
if (seconds < 60) return `${seconds} секунд назад`
if (minutes < 60) return `${minutes} минут назад`
if (hours < 24) return `${hours} часов назад`
return `${days} дней назад`
}
Такой подход устраняет зависимость от плагина и фиксирует логику отображения в одном месте.
Плагин customParseFormat используется для парсинга строк
нестандартных форматов. Его можно заменить явной нормализацией входных
данных до передачи в Day.js.
import dayjs from 'dayjs'
function parseCustom(dateString) {
const [day, month, year] = dateString.split('.')
return dayjs(`${year}-${month}-${day}`)
}
В более сложных сценариях применяется слой адаптеров, преобразующий любые входные форматы в ISO-совместимый вид.
Плагины utc и timezone добавляют поддержку
временных зон. Их замена возможна через работу с нативным
Date и ISO-строками.
import dayjs from 'dayjs'
function toUTC(date) {
return dayjs(date).toISOString()
}
import dayjs from 'dayjs'
function shiftTimezone(date, offsetHours) {
return dayjs(date).add(offsetHours, 'hour')
}
Хотя такой подход не покрывает полноценную IANA-логику, он достаточен для прикладных задач, где требуется фиксированное смещение.
Плагин duration предоставляет объект длительности. Его
можно заменить структурой на основе разницы и простого
объекта-агрегатора.
import dayjs from 'dayjs'
function createDuration(start, end) {
const d = dayjs(end).diff(dayjs(start), 'millisecond')
return {
milliseconds: d,
seconds: Math.floor(d / 1000),
minutes: Math.floor(d / 60000),
hours: Math.floor(d / 3600000),
days: Math.floor(d / 86400000)
}
}
Такой подход сохраняет вычислительную модель без необходимости подключения расширения.
Плагин advancedFormat добавляет расширенные токены
форматирования. Его функциональность может быть заменена композиционным
форматированием и предобработкой строк.
import dayjs from 'dayjs'
function formatAdvanced(date) {
const d = dayjs(date)
return {
isoWeekYear: d.format('GGGG'),
quarter: Math.ceil((d.month() + 1) / 3),
dayOfYear: d.dayOfYear ? d.dayOfYear() : null
}
}
В случае отсутствия метода dayOfYear он вычисляется
вручную:
function getDayOfYear(date) {
const start = dayjs(date).startOf('year')
return dayjs(date).diff(start, 'day') + 1
}
Наиболее устойчивый способ отказа от плагинов заключается в создании промежуточного слоя функций поверх Day.js. Такой слой инкапсулирует всю дополнительную логику.
import dayjs from 'dayjs'
export const DateUtils = {
format(date, fmt) {
return dayjs(date).format(fmt)
},
diffInHours(a, b) {
return dayjs(a).diff(dayjs(b), 'hour')
},
isExpired(date) {
return dayjs(date).isBefore(dayjs())
}
}
Этот подход устраняет необходимость расширять прототип Day.js и снижает риск конфликтов между плагинами.
Функциональность проверки високосного года часто предоставляется плагином, но может быть реализована математически.
function isLeapYear(date) {
const year = dayjs(date).year()
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
}
Логика полностью независима от Day.js API.
При масштабировании приложения плагины часто становятся источником неявных зависимостей. Замена строится на трёх уровнях:
Перенос логики в утилиты Все расширения прототипа заменяются чистыми функциями.
Использование композиции вместо расширений Day.js используется только как базовый парсер и форматтер.
Фиксация контрактов данных Все операции с датами приводятся к единому формату (ISO 8601), что устраняет необходимость в специализированных плагинах.
Некоторые плагины добавляют цепочные методы. Их можно заменить функциями высшего порядка.
import dayjs from 'dayjs'
const pipeDate = (date, ...fns) =>
fns.reduce((acc, fn) => fn(acc), dayjs(date))
const addDays = (n) => (d) => d.add(n, 'day')
const format = (fmt) => (d) => d.format(fmt)
const result = pipeDate('2026-01-01', addDays(5), format('YYYY-MM-DD'))
Такой подход заменяет расширения прототипа функциональной композицией.
Механизм extend в Day.js может быть полностью исключён
при переходе на модульную архитектуру утилит. В этом случае Day.js
остаётся неизменяемым ядром, а вся логика переносится в слой доменных
функций, что делает систему предсказуемой и облегчает тестирование.