Типичные ошибки при работе с датами

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

Основная проблема возникает из-за различий между локальным временем и UTC. Встроенный Date интерпретирует строки неоднозначно: одна и та же дата может быть распознана по-разному в зависимости от окружения.

Наиболее частая ошибка — смешивание локального времени и UTC без явного контроля.

new Date("2026-01-01") // интерпретация зависит от окружения

В date-fns большинство функций работают с объектом Date, не изменяя его временную зону, поэтому ошибка переносится на уровень входных данных.

Типичный дефект проявляется при вычислениях:

  • добавление дней к локальной дате с последующим сравнением в UTC
  • сериализация в JSON и обратное чтение в другом часовом поясе

Корректный подход требует явного выбора стратегии: либо полностью UTC, либо полностью локальное время в пределах одного контекста.


Нестабильный парсинг строк дат

Парсинг строк — один из самых проблемных участков. Встроенный Date.parse не гарантирует единообразного поведения для всех форматов.

new Date("01/02/2026") // неоднозначно: 1 февраля или 2 января

Функции date-fns, такие как parse и parseISO, уменьшают риск ошибок, но требуют строгого формата входных данных.

Типичные ошибки:

  • использование нестандартизированных строк
  • попытка парсинга локализованных форматов
  • отсутствие проверки валидности результата

Особо опасна ситуация, когда некорректная дата превращается в Invalid Date, но не обрабатывается явно:

import { parseISO, isValid } from "date-fns";

const d = parseISO("2026-13-40");

isValid(d); // false

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

Сравнение объектов Date через оператор равенства приводит к неожиданным результатам, поскольку сравниваются ссылки, а не значения.

new Date("2026-01-01") === new Date("2026-01-01") // false

Корректное сравнение требует преобразования в числовое представление:

  • timestamp (getTime())
  • функции сравнения из date-fns

Пример:

import { isEqual } from "date-fns";

isEqual(new Date(2026, 0, 1), new Date(2026, 0, 1)); // true

Распространённая ошибка — сравнение только части даты (день, месяц), что приводит к логическим сбоям при разных временных зонах.


Мутации и непредсказуемое изменение состояния

Хотя функции date-fns возвращают новые объекты и не изменяют входные данные, сам Date в JavaScript является изменяемым.

const d = new Date();
d.setDate(d.getDate() + 1);

Типичная ошибка — повторное использование одного и того же объекта даты в нескольких вычислениях.

Последствия:

  • накопление смещения
  • трудно воспроизводимые баги
  • нарушение чистоты функций

Правильный подход — избегать мутаций и использовать функции вроде:

  • addDays
  • subMonths
  • set

Летнее время и «прыгающие» сутки

Переход на летнее и зимнее время создаёт ситуации, когда сутки содержат не 24 часа.

import { addDays } from "date-fns";

addDays(new Date("2026-03-29T00:00:00"), 1);

Результат может сместиться не на ровно 24 часа, а на 23 или 25.

Частые ошибки:

  • предположение, что день всегда равен 86400000 миллисекунд
  • ручная арифметика через getTime() + 86400000

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


Начало и конец периода: ошибки округления

Работа с диапазонами дат часто приводит к ошибкам включения/исключения границ.

import { startOfDay, endOfDay } from "date-fns";

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

  • использование endOfDay для SQL-запросов без учёта миллисекунд
  • пересечение диапазонов из-за разной точности
  • несоответствие UTC и локального времени

Особенно часто возникает ошибка «пропущенного дня», когда сравнение выполняется с невыравненными временными метками.


Форматы ISO и локализованные строки

ISO-формат считается наиболее надёжным:

2026-01-01T00:00:00.000Z

Ошибки возникают при переходе между форматами:

  • ISO → локальная строка → ISO
  • потеря временной зоны
  • неявное округление

Функции форматирования date-fns решают задачу представления, но не хранят информацию о временной зоне.

import { format } from "date-fns";

format(new Date(), "yyyy-MM-dd");

Ошибка возникает, когда отформатированная строка используется обратно как источник истины.


Некорректная проверка валидности даты

Invalid Date не всегда приводит к немедленной ошибке выполнения.

const d = new Date("invalid");
console.log(d); // Invalid Date

Распространённая проблема — отсутствие проверки перед использованием.

В date-fns предусмотрена функция isValid, однако она часто игнорируется.

Ошибки проявляются:

  • в цепочках вычислений
  • при форматировании
  • при сериализации

Арифметика дат и накопление погрешностей

Ручное изменение даты через миллисекунды приводит к накоплению ошибок.

date.setTime(date.getTime() + 30 * 24 * 60 * 60 * 1000);

Проблемы:

  • игнорирование високосных лет
  • нарушение календарной логики
  • ошибки при переходах времени

Функции date-fns addDays, addMonths, addYears учитывают календарные особенности, но не компенсируют неверную исходную модель данных.


Форматирование и локали

Ошибки форматирования возникают при смешивании бизнес-логики и представления.

import { format } from "date-fns";

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

  • использование одного формата для разных регионов
  • хранение форматированной строки вместо даты
  • отсутствие единого слоя локализации

Форматированная дата не должна использоваться для вычислений, но часто именно так и происходит, особенно в UI-слоях.


Производительность при повторных вычислениях

Частая ошибка — многократное создание объектов Date и повторный парсинг одних и тех же значений.

format(parseISO(dateString), "yyyy-MM-dd");
format(parseISO(dateString), "dd.MM.yyyy");

В date-fns каждая функция чистая, но не кеширует результат.

Проблемы:

  • избыточные вычисления
  • деградация производительности в циклах
  • лишние преобразования строк → Date → строка

Оптимизация требует явного кеширования промежуточного результата.


Смешивание native Date и функций библиотеки

Наиболее распространённая архитектурная ошибка — одновременное использование методов Date и функций date-fns.

addDays(new Date().setHours(0,0,0,0), 1);

Проблемы:

  • потеря читаемости
  • скрытые преобразования типов
  • ошибки при цепочках операций

Рекомендуется единый стиль:

  • либо только функции библиотеки
  • либо только методы Date (в редких случаях)

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

Интервалы часто представляются как два Date, но логика проверки пересечений часто реализуется неправильно.

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

  • использование строгих неравенств без учёта включительности границ
  • игнорирование миллисекундной точности

Это приводит к ситуациям, когда интервалы «визуально пересекаются», но логически считаются раздельными.


Потеря контекста временной зоны при сериализации

JSON не хранит информацию о временной зоне:

JSON.stringify(new Date())

После восстановления:

new Date(jsonValue)

В результате:

  • возможное смещение времени
  • различие между серверами и клиентами
  • несогласованность данных

date-fns не решает проблему хранения, так как работает на уровне преобразований, а не сериализации.