Сравнение с учетом времени и без

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

Фундаментальные функции сравнения:

  • isBefore(date, dateToCompare)
  • isAfter(date, dateToCompare)
  • isEqual(dateLeft, dateRight)
  • compareAsc(dateLeft, dateRight)
  • compareDesc(dateLeft, dateRight)

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

Абсолютное сравнение с учетом времени

Основой всех операций служит преобразование даты в числовое значение:

const a = new Date(2026, 0, 1, 10, 0);
const b = new Date(2026, 0, 1, 12, 0);

isBefore(a, b); // true
isAfter(a, b);  // false
isEqual(a, b);  // false

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

Функция compareAsc возвращает:

  • -1, если первая дата меньше
  • 1, если больше
  • 0, если равны
compareAsc(a, b); // -1
compareAsc(b, a); // 1

compareDesc инвертирует порядок сортировки.


Сравнение без учета времени

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

Date-fns не скрывает временную составляющую, поэтому для игнорирования времени используется нормализация даты.

Основные подходы:

  • startOfDay(date)
  • endOfDay(date)
  • differenceInCalendarDays(dateLeft, dateRight)

Нормализация к началу дня

Наиболее распространенный способ — приведение даты к началу суток:

import { startOfDay, isEqual } from 'date-fns';

const a = startOfDay(new Date(2026, 0, 1, 10, 30));
const b = startOfDay(new Date(2026, 0, 1, 23, 59));

isEqual(a, b); // true

После нормализации обе даты представляют одно и то же мгновение — 00:00:00.

Нормализация к концу дня

Иногда требуется обратная стратегия — приведение к последнему моменту суток:

import { endOfDay, isEqual } from 'date-fns';

const a = endOfDay(new Date(2026, 0, 1, 1, 0));
const b = endOfDay(new Date(2026, 0, 1, 23, 0));

isEqual(a, b); // true

Такая нормализация используется в фильтрации диапазонов, где важно включить весь день целиком.


Сравнение по календарным единицам

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

Разница в днях без учета времени

import { differenceInCalendarDays } from 'date-fns';

const a = new Date(2026, 0, 1, 23, 59);
const b = new Date(2026, 0, 2, 0, 1);

differenceInCalendarDays(b, a); // 1

Функция игнорирует временную составляющую и работает с календарными границами.

Особенности календарных вычислений

Календарные функции опираются на локальные границы дня. Это означает:

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

Разница между абсолютным и календарным сравнением

Подход Учитывает время Поведение Применение
isBefore / isAfter да точное сравнение по миллисекундам таймеры, события, логи
compareAsc / compareDesc да сортировка по времени списки событий
startOfDay + isEqual нет нормализация к 00:00 сравнение дней
differenceInCalendarDays нет разница по датам календарные расчеты

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

Сравнение без нормализации

const a = new Date(2026, 0, 1, 0, 0);
const b = new Date(2026, 0, 1, 12, 0);

isEqual(a, b); // false

Обе даты относятся к одному дню, но различие во времени делает их неравными.

Использование === для объектов Date

const a = new Date(2026, 0, 1);
const b = new Date(2026, 0, 1);

a === b; // false

Сравнение объектов происходит по ссылке, а не по значению.

Игнорирование часового пояса

Date-fns оперирует локальным временем среды выполнения. При работе с UTC-данными требуется явное приведение:

import { parseISO } from 'date-fns';

const a = parseISO('2026-01-01T00:00:00Z');
const b = new Date(2026, 0, 1);

isEqual(a, b); // зависит от локального часового пояса

Сравнение диапазонов с учетом времени

В задачах фильтрации часто требуется определить принадлежность даты диапазону:

import { isAfter, isBefore } from 'date-fns';

const inRange = (date, start, end) =>
  isAfter(date, start) && isBefore(date, end);

Такой подход учитывает точное время и исключает граничные значения.

Для включающего диапазона используются модификации:

import { isEqual } from 'date-fns';

const inRangeInclusive = (date, start, end) =>
  (isAfter(date, start) || isEqual(date, start)) &&
  (isBefore(date, end) || isEqual(date, end));

Календарное сравнение диапазонов

При работе с датами без времени используется нормализация:

import { startOfDay, endOfDay, isWithinInterval } from 'date-fns';

const rangeStart = startOfDay(start);
const rangeEnd = endOfDay(end);

isWithinInterval(date, { start: rangeStart, end: rangeEnd });

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


Сортировка дат с различной точностью

Сортировка по времени

import { compareAsc } from 'date-fns';

dates.sort(compareAsc);

Результат учитывает миллисекунды, секунды, минуты и часы.

Сортировка по календарным дням

import { startOfDay, compareAsc } from 'date-fns';

dates
  .map(startOfDay)
  .sort(compareAsc);

После приведения к началу дня различия во времени исчезают, и сортировка становится календарной.


Поведение при работе с границами суток

Границы суток являются ключевым источником расхождений при сравнении:

  • 2026-01-01 23:59:59
  • 2026-01-02 00:00:00

С точки зрения абсолютного времени разница минимальна, но с точки зрения календаря это разные дни.

import { differenceInCalendarDays } from 'date-fns';

differenceInCalendarDays(
  new Date(2026, 0, 2, 0, 0),
  new Date(2026, 0, 1, 23, 59)
); // 1

Стратегии выбора подхода сравнения

  • Требуется точное событие во времени — используются isBefore, isAfter, isEqual
  • Требуется сортировка логов или событий — compareAsc
  • Требуется сравнение календарных дней — startOfDay + isEqual или differenceInCalendarDays
  • Требуется работа с диапазонами — isWithinInterval с нормализацией границ

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