При работе с пользовательским вводом нельзя полагаться на встроенный
конструктор Date. Многие строки интерпретируются по-разному
в разных браузерах, а часть значений автоматически «исправляется»,
создавая ложное ощущение корректности.
Библиотека date-fns предоставляет набор функций для строгой и предсказуемой валидации.
Установка библиотеки:
npm install date-fns
Проверка валидности объекта даты выполняется через
isValid.
import { isValid } from "date-fns";
const date = new Date("2025-10-15");
console.log(isValid(date)); // true
Некорректная дата:
const invalidDate = new Date("invalid");
console.log(isValid(invalidDate)); // false
Важно понимать, что isValid проверяет именно объект
Date, а не пользовательскую строку. Поэтому перед проверкой
обычно используется парсинг.
Для безопасного преобразования строк применяется функция
parse.
import { parse, isValid } from "date-fns";
const value = "25.12.2025";
const parsedDate = parse(
value,
"dd.MM.yyyy",
new Date()
);
console.log(isValid(parsedDate)); // true
Аргументы функции:
parse безопаснее конструктора DateПроблема стандартного Jav * aScript:
new Date("10/11/2025");
Невозможно однозначно определить:
В разных окружениях результат может отличаться.
С date-fns формат задаётся явно:
parse("10/11/2025", "dd/MM/yyyy", new Date());
Функция parse сама по себе не гарантирует абсолютную
корректность строки. Некоторые значения могут быть автоматически
преобразованы.
Пример:
parse("32.01.2025", "dd.MM.yyyy", new Date());
JavaScript попытается преобразовать дату в февраль.
Для строгой проверки применяется комбинация parse и
format.
import {
parse,
format,
isValid
} from "date-fns";
function isDateValid(value) {
const parsed = parse(
value,
"dd.MM.yyyy",
new Date()
);
if (!isValid(parsed)) {
return false;
}
return format(parsed, "dd.MM.yyyy") === value;
}
console.log(isDateValid("25.12.2025")); // true
console.log(isDateValid("32.01.2025")); // false
Такая схема считается одной из самых надёжных.
Типичная задача — убедиться, что пользователь вообще ввёл дату.
function validateRequiredDate(value) {
if (!value.trim()) {
return "Дата обязательна";
}
return null;
}
Комбинированная проверка:
function validateDate(value) {
if (!value.trim()) {
return "Введите дату";
}
const parsed = parse(
value,
"dd.MM.yyyy",
new Date()
);
if (!isValid(parsed)) {
return "Некорректная дата";
}
if (format(parsed, "dd.MM.yyyy") !== value) {
return "Неверный формат";
}
return null;
}
Часто необходимо ограничивать допустимый интервал.
Например:
Для проверки диапазона используются:
isBeforeisAfterisWithinIntervalimport {
parse,
isAfter
} from "date-fns";
const date = parse(
"25.12.2030",
"dd.MM.yyyy",
new Date()
);
const result = isAfter(date, new Date());
console.log(result); // true
import {
parse,
isBefore
} from "date-fns";
const date = parse(
"01.01.2020",
"dd.MM.yyyy",
new Date()
);
console.log(
isBefore(date, new Date())
);
import {
parse,
isWithinInterval
} from "date-fns";
const date = parse(
"15.06.2025",
"dd.MM.yyyy",
new Date()
);
const result = isWithinInterval(date, {
start: new Date(2025, 0, 1),
end: new Date(2025, 11, 31)
});
console.log(result); // true
Распространённый сценарий — ограничение минимального возраста.
Функция differenceInYears вычисляет разницу между
датами.
import {
parse,
differenceInYears
} from "date-fns";
function isAdult(value) {
const birthDate = parse(
value,
"dd.MM.yyyy",
new Date()
);
const age = differenceInYears(
new Date(),
birthDate
);
return age >= 18;
}
import {
parse,
isBefore,
isAfter
} from "date-fns";
function validateDateRange(value) {
const date = parse(
value,
"dd.MM.yyyy",
new Date()
);
const minDate = new Date(2020, 0, 1);
const maxDate = new Date(2030, 11, 31);
if (isBefore(date, minDate)) {
return "Дата слишком ранняя";
}
if (isAfter(date, maxDate)) {
return "Дата слишком поздняя";
}
return null;
}
Пользовательский ввод времени также требует строгой валидации.
import {
parse,
format,
isValid
} from "date-fns";
function validateTime(value) {
const parsed = parse(
value,
"HH:mm",
new Date()
);
if (!isValid(parsed)) {
return false;
}
return format(parsed, "HH:mm") === value;
}
console.log(validateTime("18:30")); // true
console.log(validateTime("25:90")); // false
import {
parse,
format,
isValid
} from "date-fns";
function validateDateTime(value) {
const parsed = parse(
value,
"dd.MM.yyyy HH:mm",
new Date()
);
if (!isValid(parsed)) {
return false;
}
return (
format(
parsed,
"dd.MM.yyyy HH:mm"
) === value
);
}
API часто работают с ISO-форматом.
Пример:
2025-12-25T18:30:00Z
Для разбора используется parseISO.
import {
parseISO,
isValid
} from "date-fns";
const date = parseISO(
"2025-12-25T18:30:00Z"
);
console.log(isValid(date));
import { isLeapYear } from "date-fns";
console.log(
isLeapYear(new Date(2024, 0, 1))
); // true
Практическое применение:
Иногда дата выглядит корректной, но фактически не существует.
Например:
31.02.2025
Строгая проверка:
function existsDate(value) {
const parsed = parse(
value,
"dd.MM.yyyy",
new Date()
);
return (
isValid(parsed) &&
format(parsed, "dd.MM.yyyy") === value
);
}
Часто требуется проверить две даты одновременно.
Например:
import {
parse,
isAfter
} from "date-fns";
function validatePeriod(start, end) {
const startDate = parse(
start,
"dd.MM.yyyy",
new Date()
);
const endDate = parse(
end,
"dd.MM.yyyy",
new Date()
);
if (isAfter(startDate, endDate)) {
return "Начальная дата больше конечной";
}
return null;
}
Типичная интеграция с <input>:
<input id="date" />
<button id="send">
Отправить
</button>
import {
parse,
format,
isValid
} from "date-fns";
const input =
document.getElementById("date");
const button =
document.getElementById("send");
button.addEventListener("click", () => {
const value = input.value;
const parsed = parse(
value,
"dd.MM.yyyy",
new Date()
);
const isCorrect =
isValid(parsed) &&
format(parsed, "dd.MM.yyyy") === value;
if (!isCorrect) {
alert("Ошибка даты");
return;
}
console.log(parsed);
});
Пример проверки поля формы:
import { useState } from "react";
import {
parse,
format,
isValid
} from "date-fns";
export default function App() {
const [value, setValue] =
useState("");
const [error, setError] =
useState("");
function validate(dateString) {
const parsed = parse(
dateString,
"dd.MM.yyyy",
new Date()
);
const correct =
isValid(parsed) &&
format(
parsed,
"dd.MM.yyyy"
) === dateString;
if (!correct) {
setError("Неверная дата");
return;
}
setError("");
}
return (
<div>
<input
value={value}
onCha nge={(e) => {
setValue(e.target.value);
validate(e.target.value);
}}
/>
{error && <p>{error}</p>}
</div>
);
}
Серверные приложения также должны валидировать даты независимо от клиентской части.
Пример для Node.js:
import {
parseISO,
isValid
} from "date-fns";
function validatePayload(body) {
const date = parseISO(body.createdAt);
if (!isValid(date)) {
throw new Error(
"Некорректная дата"
);
}
}
new Date(userInput)new Date("01.02.2025");
Проблемы:
Неправильно:
isValid(parse(value, "dd.MM.yyyy", new Date()));
Правильно:
const parsed = parse(
value,
"dd.MM.yyyy",
new Date()
);
const valid =
isValid(parsed) &&
format(parsed, "dd.MM.yyyy") === value;
ISO-даты могут содержать timezone:
2025-10-15T12:00:00+05:00
При сравнении дат необходимо учитывать локальное время и UTC.
import {
parse,
format,
isValid,
isBefore,
isAfter
} from "date-fns";
export function validateDate(
value,
options = {}
) {
const {
formatPattern = "dd.MM.yyyy",
minDate,
maxDate
} = options;
if (!value.trim()) {
return {
valid: false,
error: "Пустое значение"
};
}
const parsed = parse(
value,
formatPattern,
new Date()
);
if (!isValid(parsed)) {
return {
valid: false,
error: "Некорректная дата"
};
}
if (
format(parsed, formatPattern) !==
value
) {
return {
valid: false,
error: "Неверный формат"
};
}
if (
minDate &&
isBefore(parsed, minDate)
) {
return {
valid: false,
error: "Дата меньше допустимой"
};
}
if (
maxDate &&
isAfter(parsed, maxDate)
) {
return {
valid: false,
error: "Дата больше допустимой"
};
}
return {
valid: true,
value: parsed
};
}
Пример использования:
const result = validateDate(
"25.12.2025",
{
minDate: new Date(2020, 0, 1),
maxDate: new Date(2030, 11, 31)
}
);
console.log(result);