Типичные проблемы и решения

Одной из наиболее частых проблем при использовании date-fns становится ожидание полноценной поддержки временных зон. Библиотека оперирует объектом Date из JavaScript, который хранит момент времени в UTC, но отображает его в локальной зоне окружения.

Типичная ошибка

import { format } from 'date-fns';

const date = new Date('2026-01-01T00:00:00Z');

console.log(format(date, 'yyyy-MM-dd HH:mm'));

Результат зависит от локальной зоны выполнения кода, что часто приводит к расхождению между сервером и клиентом.

Решение

Для работы с временными зонами требуется использование дополнительных инструментов, например date-fns-tz:

import { format } from 'date-fns-tz';

const date = new Date('2026-01-01T00:00:00Z');

console.log(format(date, 'yyyy-MM-dd HH:mm', {
  timeZone: 'Europe/Moscow'
}));

Ключевой момент: date-fns сама по себе не управляет часовыми поясами, она лишь форматирует переданный момент времени.


Ошибки при парсинге строк дат

Функция parse в date-fns требует строгого соответствия шаблону. Любое несоответствие формату приводит к некорректным результатам или Invalid Date.

Проблема

import { parse } from 'date-fns';

const date = parse('2026/01/01', 'yyyy-MM-dd', new Date());
console.log(date);

Несоответствие разделителей (/ вместо -) приводит к неверному разбору.

Корректный подход

const date = parse('2026/01/01', 'yyyy/MM/dd', new Date());

Рекомендация

Всегда фиксировать формат входной строки и не полагаться на автоматическое определение структуры даты.


Ошибки сравнения дат

JavaScript позволяет сравнивать даты напрямую, но это приводит к логическим ошибкам из-за сравнения объектов, а не значений времени.

Ошибочный подход

const a = new Date('2026-01-01');
const b = new Date('2026-01-01');

console.log(a === b); // false

Правильное решение с date-fns

import { isEqual } from 'date-fns';

console.log(isEqual(a, b)); // true

Альтернатива через timestamp

a.getTime() === b.getTime();

Проблемы с мутирующими функциями

Некоторые функции date-fns возвращают новый объект даты, но разработчики часто предполагают мутацию исходного значения.

Пример ошибки

import { addDays } from 'date-fns';

const date = new Date('2026-01-01');
addDays(date, 5);

console.log(date); // исходная дата не изменилась

Правильное использование

const newDate = addDays(date, 5);

Важно: все функции date-fns являются чистыми и не изменяют входные данные.


Ошибки работы с таймстампами

date-fns ожидает объекты Date, а не числа, представляющие UNIX timestamp.

Проблема

import { format } from 'date-fns';

const ts = 1767225600000;

console.log(format(ts, 'yyyy-MM-dd'));

Результат может быть некорректным или зависеть от неявного преобразования.

Решение

const date = new Date(ts);

console.log(format(date, 'yyyy-MM-dd'));

Некорректное использование локализации

Форматирование с локалями требует явного подключения нужного языка.

Проблема

import { format } from 'date-fns';

format(new Date(), 'PPPP');

Результат всегда будет на английском языке.

Решение

import { format } from 'date-fns';
import { ru } from 'date-fns/locale';

format(new Date(), 'PPPP', { locale: ru });

Частая ошибка

Подключение локали без передачи её в функцию не даёт эффекта.


Ошибки работы с началом и концом интервалов

Функции startOfDay, endOfDay, startOfMonth часто используются для фильтрации данных, но приводят к логическим ошибкам при смешении зон и форматов.

Проблема

import { endOfDay } from 'date-fns';

const end = endOfDay(new Date('2026-01-01'));

Ожидается конец дня в UTC, но возвращается локальное время.

Решение

Для серверной логики необходимо явно нормализовать данные:

const end = endOfDay(new Date(Date.UTC(2026, 0, 1)));

Ошибки при работе с интервалами

Функции вроде isWithinInterval чувствительны к порядку границ.

Проблема

import { isWithinInterval } from 'date-fns';

isWithinInterval(new Date('2026-01-10'), {
  start: new Date('2026-01-20'),
  end: new Date('2026-01-01')
});

Результат всегда false, даже если логика предполагает обратное.

Решение

Перед использованием интервал должен быть нормализован:

const start = new Date('2026-01-01');
const end = new Date('2026-01-20');

isWithinInterval(date, { start, end });

Потеря точности при работе с миллисекундами

При многократных преобразованиях дат часто теряется точность из-за приведения типов и округлений.

Проблема

const date = new Date(Math.round(Date.now() / 1000) * 1000);

Решение

Использовать единый формат хранения времени — миллисекунды:

const timestamp = Date.now();
const date = new Date(timestamp);

Ошибки при цепочках функций

date-fns часто используется в функциональных цепочках, где легко потерять промежуточный результат.

Проблема

import { addDays, format } from 'date-fns';

format(addDays(new Date(), 3), 'yyyy-MM-dd');

При усложнении логики это приводит к ухудшению читаемости и ошибкам при изменении порядка операций.

Более надёжный подход

const base = new Date();
const shifted = addDays(base, 3);
const result = format(shifted, 'yyyy-MM-dd');

Несовместимость форматов между библиотеками

При интеграции с другими библиотеками даты часто приходят в разных форматах: ISO, timestamp, строки.

Проблема

parseISO('01-01-2026'); // неверный формат

Решение

Разделение входных типов:

import { parseISO, fromUnixTime } from 'date-fns';

const a = parseISO('2026-01-01');
const b = fromUnixTime(1767225600);

Ошибки при кэшировании дат

Объекты Date изменяемы по внутреннему состоянию при операциях форматирования и преобразования в сторонних слоях приложения.

Проблема

Повторное использование одного объекта даты в разных частях системы приводит к рассинхронизации логики отображения и расчётов.

Решение

Всегда создавать копии:

const copy = new Date(original.getTime());