Библиотека date-fns предоставляет набор чистых функций
для работы с датами: они атомарны, предсказуемы и не изменяют входные
данные. Однако в реальных проектах часто требуется не просто вызвать
функцию, а адаптировать её поведение под конкретные доменные сценарии,
стандарты данных, временные зоны или требования к устойчивости. В таких
случаях формируются обертки — функции более высокого уровня,
инкапсулирующие повторяющуюся логику.
Функции date-fns проектируются как чистые
преобразования:
Обертка сохраняет эту модель, добавляя слой логики:
null и undefinedВ прикладных системах дата может приходить в разных форматах: строка
ISO, timestamp, объект Date, значение из базы данных.
Типовая обертка нормализации:
import { parseISO, isValid } from 'date-fns';
function toDate(input) {
if (!input) return null;
const date =
input instanceof Date ? input :
typeof input === 'string' ? parseISO(input) :
typeof input === 'number' ? new Date(input) :
null;
if (!date || !isValid(date)) return null;
return date;
}
Такая функция становится базовым строительным блоком для всех дальнейших операций.
Чистые функции date-fns не обрабатывают ошибки входных
данных. В прикладной логике это часто приводит к каскадным сбоям.
Безопасная обертка для форматирования:
import { format } from 'date-fns';
function safeFormat(dateInput, formatString) {
const date = toDate(dateInput);
if (!date) return null;
try {
return format(date, formatString);
} catch {
return null;
}
}
Такая конструкция применяется в UI-слое, где важно избегать исключений при отображении.
Часто используется фиксированный формат даты или повторяющиеся настройки.
import { format } from 'date-fns';
const DEFAULT_FORMAT = 'yyyy-MM-dd';
function formatDate(dateInput, formatString = DEFAULT_FORMAT) {
const date = toDate(dateInput);
if (!date) return null;
return format(date, formatString);
}
Подобный подход снижает дублирование и фиксирует стандарты отображения дат в проекте.
Одна из сильных сторон date-fns — возможность композиции
функций. Обертки позволяют создавать цепочки преобразований.
Пример: вычисление даты истечения срока с форматированием:
import { addDays } from 'date-fns';
import { format } from 'date-fns';
function addDaysAndFormat(dateInput, days, formatString) {
const date = toDate(dateInput);
if (!date) return null;
const result = addDays(date, days);
return format(result, formatString);
}
Такие функции объединяют несколько шагов в единый доменный оператор.
Для повторяющихся сценариев удобно фиксировать часть параметров.
import { format } from 'date-fns';
function createFormatter(formatString) {
return function(dateInput) {
const date = toDate(dateInput);
if (!date) return null;
return format(date, formatString);
};
}
const formatISODate = createFormatter('yyyy-MM-dd');
const formatDateTime = createFormatter('yyyy-MM-dd HH:mm:ss');
Это снижает когнитивную нагрузку в бизнес-логике и стандартизирует форматирование.
date-fns в базовой поставке не управляет временными
зонами напрямую. Поэтому часто создаются обертки вокруг
date-fns-tz.
import { formatInTimeZone } from 'date-fns-tz';
function formatUTC(dateInput, formatString) {
const date = toDate(dateInput);
if (!date) return null;
return formatInTimeZone(date, 'UTC', formatString);
}
Подобная абстракция фиксирует зону времени и предотвращает ошибки смещения.
В прикладных системах даты часто имеют семантику: дедлайны, периоды подписки, окна доступности.
import { isAfter, isBefore } from 'date-fns';
function isActivePeriod(dateInput, start, end) {
const date = toDate(dateInput);
const startDate = toDate(start);
const endDate = toDate(end);
if (!date || !startDate || !endDate) return false;
return isAfter(date, startDate) && isBefore(date, endDate);
}
Такая обертка превращает низкоуровневые операции в доменные проверки.
Работа с датами часто требует контроля допустимых границ.
import { min, max } from 'date-fns';
function clampDate(dateInput, minDate, maxDate) {
const date = toDate(dateInput);
const minD = toDate(minDate);
const maxD = toDate(maxDate);
if (!date || !minD || !maxD) return null;
return min([max([date, minD]), maxD]);
}
Такие конструкции предотвращают выход значений за допустимые пределы.
Часто требуется массовая обработка списков дат.
import { format } from 'date-fns';
function formatDateList(dates, formatString) {
if (!Array.isArray(dates)) return [];
return dates
.map(toDate)
.filter(Boolean)
.map(date => format(date, formatString));
}
Подобная обертка стандартизирует обработку коллекций и снижает вероятность ошибок в итерациях.
Обертки могут использоваться для наблюдения за поведением функций
date-fns.
import { format } from 'date-fns';
function withLogging(fn) {
return function(...args) {
const start = Date.now();
const result = fn(...args);
const end = Date.now();
console.log('Execution time:', end - start);
return result;
};
}
const loggedFormat = withLogging(format);
Такой подход применяется при оптимизации производительности и отладке.
Локализация требует единых точек настройки:
import { format } from 'date-fns';
import { ru } from 'date-fns/locale';
function formatRu(dateInput, formatString) {
const date = toDate(dateInput);
if (!date) return null;
return format(date, formatString, { locale: ru });
}
В больших системах локаль часто фиксируется на уровне обертки, исключая необходимость повторного указания.
В высоконагруженных системах форматирование может оптимизироваться через мемоизацию.
import { format } from 'date-fns';
const cache = new Map();
function cachedFormat(dateInput, formatString) {
const date = toDate(dateInput);
if (!date) return null;
const key = `${date.getTime()}_${formatString}`;
if (cache.has(key)) return cache.get(key);
const result = format(date, formatString);
cache.set(key, result);
return result;
}
Такой подход полезен при массовом рендеринге списков.
Масштабируемость достигается через фабрики, создающие специализированные функции:
import { addDays, format } from 'date-fns';
function createDatePipeline({ daysToAdd = 0, formatString }) {
return function(dateInput) {
const date = toDate(dateInput);
if (!date) return null;
const shifted = addDays(date, daysToAdd);
return format(shifted, formatString);
};
}
const formatNextWeek = createDatePipeline({
daysToAdd: 7,
formatString: 'yyyy-MM-dd'
});
Фабрики позволяют собирать доменные операции как конфигурации, а не как разрозненные функции.
В архитектурном разрезе обертки над date-fns выполняют
роль промежуточного слоя:
Именно через обертки формируется стабильный контракт работы с датами внутри приложения.