Обработка пользовательского ввода

Пользовательский ввод — один из самых проблемных источников данных при работе с датами. Пользователи могут вводить значения в разных форматах:

  • 12.05.2026
  • 2026-05-12
  • 12/05/2026
  • May 12, 2026
  • 12 мая 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.

Сигнатура:

parse(dateString, formatString, referenceDate)

Параметры:

Параметр Описание
dateString Строка от пользователя
formatString Ожидаемый формат
referenceDate Базовая дата

Разбор даты по шаблону

Формат dd.MM.yyyy

import { 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-dd

const 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 Секунды

Проверка корректности даты

После парсинга обязательно выполняется валидация.

isValid

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.yyyy
  • yyyy-MM-dd
  • dd/MM/yyyy

Универсальный парсер

import { 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
}

Объединение с parse

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.2026
  • 01.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

Работа с HTML-формами

Обработка input

<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('Ошибка')
  }
})

Интеграция с React

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-форматов

parseISO

Для ISO-строк существует специальная функция.

import { parseISO } from 'date-fns'

const date = parseISO(
  '2026-12-25T18:30:00'
)

Проверка ISO-ввода

import {
  parseISO,
  isValid
} from 'date-fns'

const parsed = parseISO(input)

if (!isValid(parsed)) {
  console.log('Некорректный ISO')
}

Преобразование пользовательской даты в API-формат

Частая задача:

  1. Пользователь вводит: 25.12.2026

  2. Сервер ожидает: 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 работает с локальным временем браузера.

Это важно учитывать при:

  • отправке данных на сервер;
  • работе с UTC;
  • международных приложениях.

Пример проблемы

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

Игнорирование isValid

Нельзя:

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 не занимается масками ввода.

Обычно библиотека используется вместе с:

  • Inputmask
  • IMask
  • react-input-mask

Пример логики:

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'
    )
  }
}