Пользовательский ввод — один из самых проблемных источников данных при работе с датами. Пользователи могут вводить значения в разных форматах:
12.05.20262026-05-1212/05/2026May 12, 202612 мая 2026сегоднязавтра в 18:00Нативный объект Date в JavaScript плохо подходит для
безопасного разбора подобных значений:
new Date('12.05.2026')
Результат зависит от браузера, локали и движка JavaScript.
Библиотека date-fns решает эту проблему через строгие функции парсинга, валидации и форматирования.
npm install date-fns
Импорт отдельных функций:
import { parse, format, isValid } from 'date-fns'
Главный инструмент обработки пользовательского ввода —
parse.
Сигнатура:
parse(dateString, formatString, referenceDate)
Параметры:
| Параметр | Описание |
|---|---|
dateString |
Строка от пользователя |
formatString |
Ожидаемый формат |
referenceDate |
Базовая дата |
dd.MM.yyyyimport { parse } from 'date-fns'
const input = '25.12.2026'
const result = parse(input, 'dd.MM.yyyy', new Date())
console.log(result)
Результат:
2026-12-25T00:00:00.000Z
yyyy-MM-ddconst result = parse(
'2026-12-25',
'yyyy-MM-dd',
new Date()
)
const result = parse(
'25.12.2026 18:30',
'dd.MM.yyyy HH:mm',
new Date()
)
| Токен | Описание |
|---|---|
d |
День |
dd |
День с нулём |
Пример:
parse('05.12.2026', 'dd.MM.yyyy', new Date())
| Токен | Описание |
|---|---|
M |
Месяц |
MM |
Месяц с нулём |
MMM |
Короткое название |
MMMM |
Полное название |
Пример:
parse('05 December 2026', 'dd MMMM yyyy', new Date())
| Токен | Описание |
|---|---|
yy |
Две цифры |
yyyy |
Полный год |
| Токен | Описание |
|---|---|
HH |
Часы 00–23 |
mm |
Минуты |
ss |
Секунды |
После парсинга обязательно выполняется валидация.
import { parse, isValid } from 'date-fns'
const date = parse(
'31.02.2026',
'dd.MM.yyyy',
new Date()
)
console.log(isValid(date))
Результат:
false
function parseUserDate(input) {
const date = parse(
input,
'dd.MM.yyyy',
new Date()
)
if (!isValid(date)) {
return null
}
return date
}
Использование:
const result = parseUserDate('15.08.2026')
if (!result) {
console.log('Некорректная дата')
}
Проблема:
parse('32.01.2026', 'dd.MM.yyyy', new Date())
Иногда JavaScript автоматически корректирует дату.
Для строгой проверки используется повторное форматирование.
import { parse, format, isValid } from 'date-fns'
function strictParse(input) {
const parsed = parse(
input,
'dd.MM.yyyy',
new Date()
)
if (!isValid(parsed)) {
return null
}
const normalized = format(parsed, 'dd.MM.yyyy')
if (normalized !== input) {
return null
}
return parsed
}
Пользователи редко придерживаются одного шаблона.
Часто требуется поддержка:
dd.MM.yyyyyyyy-MM-dddd/MM/yyyyimport { parse, isValid, format } from 'date-fns'
const formats = [
'dd.MM.yyyy',
'yyyy-MM-dd',
'dd/MM/yyyy'
]
function parseDate(input) {
for (const pattern of formats) {
const date = parse(
input,
pattern,
new Date()
)
if (!isValid(date)) {
continue
}
if (format(date, pattern) !== input) {
continue
}
return date
}
return null
}
function validateInput(input) {
if (!input.trim()) {
return 'Дата обязательна'
}
return null
}
function validateDate(input) {
if (!input.trim()) {
return 'Введите дату'
}
const date = parse(
input,
'dd.MM.yyyy',
new Date()
)
if (!isValid(date)) {
return 'Неверная дата'
}
return null
}
Date-fns поддерживает локализованный ввод.
import { parse } from 'date-fns'
import { ru } from 'date-fns/locale'
const result = parse(
'25 декабря 2026',
'd MMMM yyyy',
new Date(),
{
locale: ru
}
)
import { enUS } from 'date-fns/locale'
const result = parse(
'December 25, 2026',
'MMMM dd, yyyy',
new Date(),
{
locale: enUS
}
)
const time = parse(
'18:45',
'HH:mm',
new Date()
)
const dateTime = parse(
'25.12.2026 18:45',
'dd.MM.yyyy HH:mm',
new Date()
)
После парсинга часто требуется проверить ограничения.
import { isBefore } from 'date-fns'
if (isBefore(userDate, new Date())) {
console.log('Дата не может быть в прошлом')
}
import { isAfter } from 'date-fns'
const maxDate = new Date(2030, 0, 1)
if (isAfter(userDate, maxDate)) {
console.log('Дата слишком большая')
}
import {
parse,
differenceInYears
} from 'date-fns'
const birthDate = parse(
'15.05.2008',
'dd.MM.yyyy',
new Date()
)
const age = differenceInYears(
new Date(),
birthDate
)
if (age < 18) {
console.log('Доступ запрещён')
}
Пользователи часто вводят:
1.1.202601.01.2026Можно автоматически привести значение к единому формату.
import { parse, format } from 'date-fns'
const parsed = parse(
'1.1.2026',
'd.M.yyyy',
new Date()
)
const normalized = format(
parsed,
'dd.MM.yyyy'
)
console.log(normalized)
Результат:
01.01.2026
<input id="dateInput" />
import { parse, isValid } from 'date-fns'
const input = document.getElementById('dateInput')
input.addEventListener('change', () => {
const date = parse(
input.value,
'dd.MM.yyyy',
new Date()
)
if (!isValid(date)) {
console.log('Ошибка')
}
})
import { useState } from 'react'
import { parse, isValid } from 'date-fns'
export default function App() {
const [error, setError] = useState('')
function handleChange(event) {
const value = event.target.value
const date = parse(
value,
'dd.MM.yyyy',
new Date()
)
if (!isValid(date)) {
setError('Неверная дата')
return
}
setError('')
}
return (
<div>
<input onCha nge={handleChange} />
{error && <p>{error}</p>}
</div>
)
}
Для ISO-строк существует специальная функция.
import { parseISO } from 'date-fns'
const date = parseISO(
'2026-12-25T18:30:00'
)
import {
parseISO,
isValid
} from 'date-fns'
const parsed = parseISO(input)
if (!isValid(parsed)) {
console.log('Некорректный ISO')
}
Частая задача:
Пользователь вводит: 25.12.2026
Сервер ожидает: 2026-12-25
import {
parse,
format
} from 'date-fns'
const parsed = parse(
'25.12.2026',
'dd.MM.yyyy',
new Date()
)
const apiDate = format(
parsed,
'yyyy-MM-dd'
)
console.log(apiDate)
Date-fns работает с локальным временем браузера.
Это важно учитывать при:
new Date('2026-12-25')
Может интерпретироваться как UTC.
parse(
'25.12.2026',
'dd.MM.yyyy',
new Date()
)
MM вместо
mmНеправильно:
'HH:MM'
Правильно:
'HH:mm'
MM — месяц, mm — минуты.
YYYYВ date-fns используется:
yyyy
А не:
YYYY
Нельзя:
const date = parse(...)
console.log(date)
Нужно:
if (isValid(date)) {
// работа с датой
}
import {
parse,
format,
isValid
} from 'date-fns'
export function validateDate(input) {
if (!input.trim()) {
return {
valid: false,
error: 'Введите дату'
}
}
const pattern = 'dd.MM.yyyy'
const parsed = parse(
input,
pattern,
new Date()
)
if (!isValid(parsed)) {
return {
valid: false,
error: 'Некорректная дата'
}
}
const normalized = format(
parsed,
pattern
)
if (normalized !== input) {
return {
valid: false,
error: 'Неверный формат'
}
}
return {
valid: true,
value: parsed
}
}
Date-fns не умеет напрямую разбирать:
сегоднязавтрачерез 3 дняПодобные конструкции обрабатываются вручную.
import {
addDays,
startOfDay
} from 'date-fns'
function parseRelative(input) {
const value = input.toLowerCase()
if (value === 'сегодня') {
return startOfDay(new Date())
}
if (value === 'завтра') {
return addDays(
startOfDay(new Date()),
1
)
}
return null
}
Date-fns не занимается масками ввода.
Обычно библиотека используется вместе с:
Пример логики:
12.__.____
После завершения ввода строка передаётся в parse.
Типичная схема:
Пользовательский ввод
↓
Очистка строки
↓
Проверка пустоты
↓
parse()
↓
isValid()
↓
Строгая сверка format()
↓
Нормализация
↓
Отправка на сервер
import {
parse,
format,
isValid,
isBefore
} from 'date-fns'
function processBookingDate(input) {
const parsed = parse(
input,
'dd.MM.yyyy',
new Date()
)
if (!isValid(parsed)) {
return {
ok: false,
error: 'Некорректная дата'
}
}
if (
format(parsed, 'dd.MM.yyyy') !== input
) {
return {
ok: false,
error: 'Неверный формат'
}
}
if (isBefore(parsed, new Date())) {
return {
ok: false,
error: 'Дата уже прошла'
}
}
return {
ok: true,
apiValue: format(
parsed,
'yyyy-MM-dd'
)
}
}