Обработка null и undefined

Обработка значений null и undefined в date-fns напрямую связана с тем, как JavaScript представляет отсутствие данных и как библиотека интерпретирует некорректные или неполные даты. В отличие от более «толерантных» утилит, date-fns придерживается строгой модели: большинство функций ожидают валидный объект Date, timestamp или строку, которую можно однозначно преобразовать в дату.

При передаче null или undefined в функции date-fns поведение зависит от конкретной функции, но общая логика сводится к нескольким сценариям:

  • возвращение Invalid Date
  • возврат NaN (для арифметических операций)
  • выброс ошибки RangeError
  • некорректный результат без явного исключения

Пример:

import { format } from 'date-fns';

format(null, 'yyyy-MM-dd'); 
// Invalid Date или RangeError (в зависимости от версии и окружения)
format(undefined, 'yyyy-MM-dd');
// аналогичное поведение: ошибка или Invalid Date

Главная причина такого поведения заключается в том, что внутри date-fns происходит приведение входного значения к объекту Date:

new Date(value)

Для null это превращается в new Date(null) → валидная дата эпохи (1970-01-01), тогда как new Date(undefined)Invalid Date. Однако date-fns дополнительно валидирует результат, и итоговое поведение становится более строгим.


Различие между null и undefined в контексте дат

В JavaScript эти значения имеют разную семантику:

  • null — явное отсутствие значения
  • undefined — неопределённость или неинициализированность

В date-fns это приводит к разным результатам на уровне преобразования:

new Date(null);      // Thu Jan 01 1970
new Date(undefined); // Invalid Date

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


Invalid Date как основной индикатор ошибки

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

const d = new Date('invalid');

Number(d); // NaN

Функции, выполняющие вычисления, начинают «распространять» NaN:

import { differenceInDays } from 'date-fns';

differenceInDays(null, new Date());
// NaN

Это поведение критично: ошибка не всегда проявляется сразу, а проявляется в цепочке вычислений.


Арифметические функции и null/undefined

Функции типа differenceIn*, add*, sub* используют внутреннее преобразование даты. При получении null или undefined результат почти всегда становится NaN.

differenceInDays(undefined, undefined);
// NaN
addDays(null, 5);
// Invalid Date или NaN в дальнейших операциях

Причина заключается в том, что вычисления базируются на timestamp:

getTime(date)

Если date невалидна, getTime() возвращает NaN, что «ломает» всю цепочку.


Форматирование и строгая проверка входных данных

Функция format наиболее чувствительна к некорректным значениям.

import { format } from 'date-fns';

format(undefined, 'dd.MM.yyyy');
format(null, 'dd.MM.yyyy');

Обе ситуации приводят к ошибкам, так как форматирование требует валидной даты.

Внутри происходит цепочка:

  1. Преобразование входного значения в Date
  2. Проверка валидности
  3. Извлечение компонентов даты

Если на этапе (2) обнаруживается Invalid Date, выполнение прерывается.


Проверка валидности через isValid

Ключевой механизм защиты от null и undefined — функция isValid:

import { isValid } from 'date-fns';

isValid(null);       // false
isValid(undefined);  // false
isValid(new Date()); // true

isValid проверяет числовое представление даты:

Number(date) !== NaN

или более точно:

!isNaN(date.getTime())

parseISO и поведение при пустых значениях

Функция parseISO ожидает строку ISO-формата. При передаче null или undefined происходит преобразование к строке:

parseISO(null);      // Invalid Date
parseISO(undefined); // Invalid Date

Это связано с тем, что:

String(null)      // "null"
String(undefined) // "undefined"

Обе строки не являются корректными ISO-датами.


Защитные стратегии при работе с внешними данными

Данные из API часто содержат null в полях дат:

{
  "createdAt": null
}

При прямой передаче в date-fns возникает каскадная ошибка. Поэтому обычно применяется нормализация:

const safeDate = value ? new Date(value) : null;

или:

const safeDate = value ?? undefined;

Но даже после этого требуется проверка:

if (!safeDate || !isValid(safeDate)) {
  // обработка отсутствующей даты
}

Значение default-параметров и нормализация входа

Часто используется паттерн с дефолтами:

function formatSafe(date) {
  if (!date) return '';
  if (!isValid(date)) return '';

  return format(date, 'dd.MM.yyyy');
}

или через раннюю нормализацию:

const toDateOrNull = (value) => {
  if (value === null || value === undefined) return null;

  const d = new Date(value);
  return isNaN(d.getTime()) ? null : d;
};

Каскадные ошибки при цепочках функций

date-fns часто используется в композиции:

format(addDays(parseISO(value), 2), 'dd.MM.yyyy');

При value = null происходит цепочка:

  1. parseISO(null) → Invalid Date
  2. addDays(Invalid Date, 2) → Invalid Date
  3. format(Invalid Date) → ошибка или Invalid Date

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


Поведение при сравнении дат

Функции сравнения также чувствительны:

import { isBefore } from 'date-fns';

isBefore(null, new Date()); // false или ошибка

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


Обработка edge-case сценариев

Наиболее проблемные ситуации:

  • пустые строки ''
  • null из API
  • undefined из необязательных полей
  • некорректные строки даты
  • частично заполненные структуры { year: null, month: undefined }

Все они приводят к одному базовому состоянию — Invalid Date.


Стратегия устойчивой работы с date-fns

Основной подход заключается в том, чтобы никогда не передавать необработанные значения:

  • нормализация входных данных до вызова функций
  • явная проверка через isValid
  • отказ от цепочек без промежуточной валидации
  • использование null как маркера отсутствия даты вместо Invalid Date

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