Работа с датами в JavaScript сопровождается большим количеством
потенциальных ошибок. Форматы отличаются между странами, входящие
значения могут быть неполными, а встроенный объект Date
ведёт себя непредсказуемо при невалидных строках. Библиотека date-fns
предоставляет инструменты для безопасного парсинга и проверки дат,
однако неправильное использование функций также способно привести к
ошибкам.
Наиболее распространённые проблемы:
undefined или null;После парсинга дата должна проходить обязательную проверку. В
date-fns для этого используется функция
isValid.
import { parse, isValid } from 'date-fns'
const result = parse('31.02.2024', 'dd.MM.yyyy', new Date())
console.log(isValid(result)) // false
Функция parse не выбрасывает исключение при ошибке.
Вместо этого создаётся объект Invalid Date.
Это важная особенность библиотеки:
const invalid = new Date('wrong')
console.log(invalid)
Результат:
Invalid Date
Поэтому после любого парсинга рекомендуется выполнять проверку:
if (!isValid(result)) {
console.error('Некорректная дата')
}
Функция parse требует точного соответствия между строкой
и шаблоном.
Пример ошибки:
parse('2024/10/15', 'dd.MM.yyyy', new Date())
Строка содержит:
2024/10/15
А шаблон ожидает:
15.10.2024
Результат:
Invalid Date
Правильный вариант:
parse('2024/10/15', 'yyyy/MM/dd', new Date())
В date-fns используются собственные токены
форматирования, отличающиеся от других библиотек.
Частая ошибка — использование:
YYYY
вместо:
yyyy
Неправильно:
parse('2024-05-10', 'YYYY-MM-dd', new Date())
Правильно:
parse('2024-05-10', 'yyyy-MM-dd', new Date())
| Ошибка | Правильный токен | Описание |
|---|---|---|
YYYY |
yyyy |
Год |
DD |
dd |
День месяца |
YY |
yy |
Короткий год |
A |
a |
AM/PM |
Третий аргумент parse — базовая дата
(referenceDate).
parse(dateString, formatString, referenceDate)
Ошибка:
parse('15:30', 'HH:mm')
Будет выброшено исключение:
3 arguments required
Правильно:
parse('15:30', 'HH:mm', new Date())
Некоторые функции date-fns действительно выбрасывают
ошибки. Например, при неправильном количестве аргументов.
import { format } from 'date-fns'
format()
Ошибка:
TypeError: 2 arguments required
Безопасная обработка:
try {
const result = format()
} catch (error) {
console.error(error.message)
}
Данные от пользователя никогда нельзя считать корректными.
Небезопасный код:
const result = parse(userInput, 'dd.MM.yyyy', new Date())
Без проверки возможно появление:
Invalid Date;Безопасный вариант:
import { parse, isValid } from 'date-fns'
function parseUserDate(input) {
const parsed = parse(input, 'dd.MM.yyyy', new Date())
if (!isValid(parsed)) {
return null
}
return parsed
}
Использование:
const date = parseUserDate('99.99.9999')
if (!date) {
console.log('Дата введена неверно')
}
Иногда дата формально валидна, но не подходит бизнес-логике.
Пример:
parse('01.01.1800', 'dd.MM.yyyy', new Date())
Дата существует, но может быть недопустимой для приложения.
Проверка диапазона:
import { isBefore, isAfter } from 'date-fns'
function isAllowedDate(date) {
const min = new Date(2000, 0, 1)
const max = new Date(2100, 11, 31)
return !isBefore(date, min) && !isAfter(date, max)
}
Для ISO-строк используется parseISO.
import { parseISO } from 'date-fns'
const date = parseISO('2024-05-20')
Некорректная строка:
parseISO('20-05-2024')
Результат:
Invalid Date
Проверка:
const parsed = parseISO(input)
if (!isValid(parsed)) {
throw new Error('Некорректный ISO формат')
}
Дата может быть валидной, но отображаться неверно из-за часового пояса.
Пример:
parseISO('2024-05-10T00:00:00Z')
В некоторых часовых поясах локальная дата станет предыдущим днём.
Проверка:
console.log(date.toISOString())
console.log(date.toString())
Типичная ошибка:
const date = parseISO('2024-05-10')
Строка без времени интерпретируется как локальное время, а не UTC.
Некоторые функции используют локализацию.
Пример:
import { parse } from 'date-fns'
import { ru } from 'date-fns/locale'
parse('10 мая 2024', 'dd MMMM yyyy', new Date(), {
locale: ru
})
Без локали:
parse('10 мая 2024', 'dd MMMM yyyy', new Date())
Результат:
Invalid Date
JavaScript автоматически корректирует некоторые значения.
Пример:
new Date(2024, 1, 31)
Результат:
Sat Mar 02 2024
Это опасное поведение.
date-fns позволяет обнаружить подобные проблемы через
isValid.
const parsed = parse('31.02.2024', 'dd.MM.yyyy', new Date())
console.log(isValid(parsed))
Практика крупных приложений — создание собственного слоя валидации.
Пример универсального парсера:
import { parse, isValid } from 'date-fns'
function safeParseDate(input, formatString) {
if (typeof input !== 'string') {
return {
success: false,
error: 'Дата должна быть строкой'
}
}
const parsed = parse(input, formatString, new Date())
if (!isValid(parsed)) {
return {
success: false,
error: 'Некорректный формат даты'
}
}
return {
success: true,
value: parsed
}
}
Использование:
const result = safeParseDate(
'15.10.2024',
'dd.MM.yyyy'
)
if (!result.success) {
console.error(result.error)
} else {
console.log(result.value)
}
Иногда дата приходит в разных форматах.
Пример:
[
'dd.MM.yyyy',
'yyyy-MM-dd',
'MM/dd/yyyy'
]
Реализация:
import { parse, isValid } from 'date-fns'
function parseMultipleFormats(input, formats) {
for (const formatString of formats) {
const parsed = parse(
input,
formatString,
new Date()
)
if (isValid(parsed)) {
return parsed
}
}
return null
}
Использование:
const result = parseMultipleFormats(
'2024-10-15',
[
'dd.MM.yyyy',
'yyyy-MM-dd',
'MM/dd/yyyy'
]
)
console.log(result)
Unix timestamp часто путают с миллисекундами.
Ошибка:
new Date(1715000000)
JavaScript ожидает миллисекунды.
Правильно:
new Date(1715000000 * 1000)
В date-fns используется fromUnixTime.
import { fromUnixTime } from 'date-fns'
const date = fromUnixTime(1715000000)
Некорректная дата ломает JSON-сериализацию.
Пример:
const invalid = new Date('wrong')
JSON.stringify({
date: invalid
})
Результат:
{
"date": null
}
Без проверки возможна потеря данных.
Безопасный вариант:
if (!isValid(date)) {
throw new Error('Дата повреждена')
}
Сравнение невалидных дат приводит к непредсказуемому поведению.
Ошибка:
const date = new Date('wrong')
console.log(date > new Date())
Результат:
false
Без явной ошибки.
Безопасное сравнение:
if (!isValid(date)) {
throw new Error('Некорректная дата')
}
Проверка сразу после парсинга:
const parsed = parse(input, format, new Date())
if (!isValid(parsed)) {
return
}
Создание единой функции:
function validateDate(date) {
return isValid(date)
}
Плохой вариант:
throw new Error('Ошибка')
Хороший вариант:
throw new Error(
'Дата должна соответствовать формату dd.MM.yyyy'
)
Неверно:
if (!date) {
throw new Error('Ошибка даты')
}
Лучше:
if (!isValid(date)) {
throw new Error('Некорректный формат')
}
if (isBefore(date, minDate)) {
throw new Error('Дата слишком ранняя')
}
Иногда parse способен интерпретировать строку
неожиданным образом.
Для строгой проверки используется повторное форматирование.
import {
parse,
format,
isValid
} from 'date-fns'
function strictParse(input, formatString) {
const parsed = parse(
input,
formatString,
new Date()
)
if (!isValid(parsed)) {
return null
}
const formatted = format(parsed, formatString)
if (formatted !== input) {
return null
}
return parsed
}
Проверка:
strictParse(
'1.1.2024',
'dd.MM.yyyy'
)
Результат:
null
Потому что ожидается:
01.01.2024
Для диагностики полезно сохранять:
Пример:
function logDateError(input, format, error) {
console.error({
input,
format,
error: error.message,
timestamp: new Date().toISOString()
})
}
При обработке HTTP-запросов дата должна проверяться до бизнес-логики.
Пример:
app.post('/events', (req, res) => {
const parsed = parse(
req.body.date,
'yyyy-MM-dd',
new Date()
)
if (!isValid(parsed)) {
return res.status(400).json({
error: 'Некорректная дата'
})
}
res.sendStatus(200)
})
Частая ошибка:
parse('', 'dd.MM.yyyy', new Date())
Результат:
Invalid Date
Безопасная проверка:
if (!input?.trim()) {
throw new Error('Дата не указана')
}
Ошибка:
parse(undefined, 'dd.MM.yyyy', new Date())
Безопасный вариант:
function ensureString(value) {
if (typeof value !== 'string') {
throw new TypeError(
'Ожидается строка'
)
}
return value
}
Типизация уменьшает количество проблем.
function parseDate(
input: string
): Date | null {
const parsed = parse(
input,
'dd.MM.yyyy',
new Date()
)
return isValid(parsed)
? parsed
: null
}
Строгие типы позволяют обнаруживать ошибки ещё до выполнения приложения.
Надёжная работа с датами строится на нескольких принципах:
Date;