Продвинутая работа с датами и временем в TypeScript
Работа с датами и временем — одна из самых частых и одновременно сложных задач в веб-разработке. В TypeScript, благодаря строгой типизации, мы можем избежать многих ошибок, связанных с манипуляциями датами, но стандартный объект Date имеет ряд ограничений. В этой статье мы рассмотрим продвинутые подходы к работе с датами и временем, включая использование современных библиотек, типизацию, работу с часовыми поясами и парсинг сложных форматов.
1. Проблемы нативного Date и их решение с помощью TypeScript
Стандартный Date в JavaScript крайне неудобен для сложных операций:
- Мутабельность: методы вроде
setDate()изменяют исходный объект. - Отсутствие форматирования: нет встроенного способа вывести дату в формате "DD.MM.YYYY".
- Слабая работа с часовыми поясами:
Dateхранит время в UTC, а методыgetHours()возвращают локальное время. - Проблемы с парсингом:
new Date("2023-01-01")может интерпретироваться по-разному в разных браузерах.
TypeScript помогает, позволяя нам создавать обертки и утилиты. Например, можно определить строгие типы для форматирования:
type DateFormat = 'DD.MM.YYYY' | 'YYYY-MM-DD' | 'HH:mm:ss';
function formatDate(date: Date, format: DateFormat): string {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
switch (format) {
case 'DD.MM.YYYY':
return `${day}.${month}.${year}`;
case 'YYYY-MM-DD':
return `${year}-${month}-${day}`;
case 'HH:mm:ss':
return `${hours}:${minutes}:${seconds}`;
default:
return '';
}
}
// Использование
const now = new Date();
console.log(formatDate(now, 'DD.MM.YYYY')); // "15.10.2023"
Такой подход гарантирует, что мы не передадим неверный формат в функцию, так как TypeScript проверит тип на этапе компиляции.
2. Использование библиотеки date-fns: чистота и функциональность
date-fns — это современная библиотека для работы с датами, которая идеально подходит для TypeScript. Её главные преимущества:
- Иммутабельность: все функции возвращают новые объекты, не изменяя исходные.
- Модульность: вы импортируете только нужные функции, что уменьшает размер бандла.
- Типизация: библиотека имеет встроенную поддержку TypeScript.
Установка:
npm install date-fns
Примеры продвинутого использования:
import { format, addDays, differenceInDays, isWeekend, parseISO } from 'date-fns';
// Форматирование
const date = new Date(2023, 9, 15); // 15 октября 2023
console.log(format(date, 'dd.MM.yyyy')); // "15.10.2023"
console.log(format(date, 'EEEE, MMMM do yyyy')); // "Sunday, October 15th 2023"
// Арифметика
const nextWeek = addDays(date, 7);
console.log(format(nextWeek, 'dd.MM.yyyy')); // "22.10.2023"
// Разница между датами
const startDate = new Date(2023, 0, 1);
const endDate = new Date(2023, 11, 31);
const diff = differenceInDays(endDate, startDate);
console.log(diff); // 364
// Проверка выходного дня
console.log(isWeekend(date)); // true (воскресенье)
// Парсинг ISO строки
const parsed = parseISO("2023-10-15T10:30:00Z");
console.log(format(parsed, 'HH:mm')); // "13:30" (с учетом часового пояса)
Важно: date-fns работает с объектами Date, поэтому вы можете легко комбинировать её с нативным кодом. Для сложных проектов это лучший выбор, так как она не расширяет прототипы (в отличие от Moment.js).
3. Работа с часовыми поясами и библиотека date-fns-tz
Одна из самых сложных задач — корректная работа с разными часовыми поясами. Нативный Date не хранит информацию о часовом поясе, а только преобразует время в UTC. Библиотека date-fns-tz решает эту проблему.
Установка:
npm install date-fns-tz
Примеры:
import { format, utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz';
// Конвертация UTC времени в заданный часовой пояс
const utcDate = new Date('2023-10-15T12:00:00Z'); // 12:00 UTC
const timeZone = 'Europe/Moscow'; // UTC+3
const moscowTime = utcToZonedTime(utcDate, timeZone);
console.log(format(moscowTime, 'HH:mm')); // "15:00"
// Создание даты в конкретном часовом поясе
const nyTime = 'America/New_York';
const nyDate = zonedTimeToUtc('2023-10-15 10:00:00', nyTime);
console.log(nyDate.toISOString()); // "2023-10-15T14:00:00.000Z"
Почему это важно? Представьте, что вы работаете с международным приложением. Пользователь из Нью-Йорка создает событие на 10:00 утра. Сервер должен сохранить это время в UTC, чтобы пользователь из Москвы увидел корректное локальное время. date-fns-tz делает эту логику прозрачной и типобезопасной.
Также можно определить строгие типы для часовых поясов:
type TimeZone = 'Europe/Moscow' | 'America/New_York' | 'Asia/Tokyo';
function getLocalTime(date: Date, tz: TimeZone): string {
const zonedDate = utcToZonedTime(date, tz);