date-fns предоставляет набор функций для работы с датами, где операции округления реализуются не как единая универсальная функция, а через комбинацию базовых примитивов: усечение, добавление единиц времени и вычисление разницы между датами. Такой подход обеспечивает предсказуемость поведения и минимизирует скрытую сложность при работе с временными зонами и переходами на летнее/зимнее время.
Округление даты в контексте date-fns обычно сводится к трём стратегиям:
В отличие от числовых типов, даты имеют сложную структуру: часы зависят от дней, дни от месяцев, а месяцы от календарных правил. Поэтому округление реализуется через специализированные функции.
Для работы с часовыми границами используются функции усечения и границ интервала.
Основные инструменты:
startOfHourendOfHourstartOfHour приводит дату к началу текущего часа,
обнуляя минуты, секунды и миллисекунды.
import { startOfHour } from 'date-fns';
startOfHour(new Date('2026-05-22T14:37:45'));
// 2026-05-22T14:00:00.000
endOfHour устанавливает дату на последний момент
текущего часа:
import { endOfHour } from 'date-fns';
endOfHour(new Date('2026-05-22T14:37:45'));
// 2026-05-22T14:59:59.999
Эти функции фактически реализуют два крайних варианта округления: вниз и вверх относительно часа.
В date-fns нет универсальной встроенной функции «round to nearest hour», поэтому применяется комбинация вычислений.
Алгоритм:
import { startOfHour, addHours } from 'date-fns';
function roundToNearestHour(date) {
const minutes = date.getMinutes();
const base = startOfHour(date);
return minutes >= 30
? addHours(base, 1)
: base;
}
Поведение такого округления предсказуемо и не зависит от локали или временной зоны, так как используется локальное представление даты.
Иногда применяется более точная модель через миллисекунды:
function roundToNearestHour(date) {
const msInHour = 3600000;
return new Date(Math.round(date.getTime() / msInHour) * msInHour);
}
Такой подход быстрее, но может давать неожиданные эффекты при переходах DST.
Работа с днями проще концептуально, но сложнее из-за календарных особенностей.
Основные функции:
startOfDayendOfDayimport { startOfDay, endOfDay } from 'date-fns';
startOfDay(new Date('2026-05-22T14:37:45'));
// 2026-05-22T00:00:00.000
endOfDay(new Date('2026-05-22T14:37:45'));
// 2026-05-22T23:59:59.999
Эти операции часто используются как базовые элементы округления дат в бизнес-логике: отчёты, фильтры, агрегации.
Поскольку встроенного «roundToNearestDay» нет, используется сравнение с серединой суток.
import { startOfDay, addDays } from 'date-fns';
function roundToNearestDay(date) {
const start = startOfDay(date);
const diff = date - start;
const halfDay = 12 * 60 * 60 * 1000;
return diff >= halfDay
? addDays(start, 1)
: start;
}
Логика опирается на середину суток как порог округления.
Другой подход использует вычисление разницы и последующее добавление:
import { differenceInDays, addDays, startOfDay } from 'date-fns';
function roundByDays(base, target) {
const start = startOfDay(base);
const diff = differenceInDays(target, start);
return addDays(start, diff);
}
Такой метод используется при нормализации дат относительно базовой точки.
Округление времени осложняется особенностями временных зон:
Функции startOfHour и startOfDay учитывают
эти особенности через встроенный механизм JavaScript Date,
что снижает риск некорректных вычислений.
Однако ручное округление через getTime() требует
осторожности:
В date-fns округление часто комбинируется с фильтрацией и агрегацией данных.
import { startOfHour } from 'date-fns';
const normalized = dates.map(startOfHour);
import { startOfDay } from 'date-fns';
function groupByDay(dates) {
return dates.reduce((acc, date) => {
const key = startOfDay(date).toISOString();
acc[key] = acc[key] || [];
acc[key].push(date);
return acc;
}, {});
}
В реальных системах используются три устойчивые модели:
Используется при сохранении логов и событий:
startOfHour(date)
startOfDay(date)
Используется в UI и отчетах:
startOfDay(date) → endOfDay(date)
Такой подход позволяет строить запросы диапазонов без потери точности.
Функции startOfHour и startOfDay всегда
сбрасывают:
Это важно при сравнении дат:
startOfDay(a).getTime() === startOfDay(b).getTime()
Такое сравнение часто используется вместо прямого
Date-сравнения.
Выбор метода зависит от задачи:
date-fns предоставляет базовые строительные блоки, а логика округления формируется на уровне приложения.