Работа с датами и временем в TypeScript: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему работа с датами в TypeScript требует особого внимания

Работа с датами и временем — одна из самых частых и в то же время коварных задач в веб-разработке. В TypeScript, который является строго типизированной надстройкой над JavaScript, объект Date унаследовал все "прелести" своего прародителя: неинтуитивные месяцы (отсчёт с нуля), мутабельность методов и проблемы с часовыми поясами. Однако, используя строгую типизацию и современные библиотеки, вы можете писать безопасный, предсказуемый и читаемый код для работы с временем.

В этой статье мы разберём всё, что нужно знать разработчику: от базового создания дат до продвинутой работы с таймзонами и форматированием. Вы узнаете, как избежать типичных ошибок и какие инструменты (встроенные и сторонние) лучше всего подходят для TypeScript-проектов.

1. Основы: Объект Date и его типизация в TypeScript

Создание и базовые методы

В TypeScript, как и в JavaScript, для работы с датами используется встроенный объект Date. TypeScript предоставляет для него готовые типы, поэтому дополнительных определений не требуется.

// Создание текущей даты
const now: Date = new Date();
console.log(now); // 2024-01-15T10:30:00.000Z

// Создание из строки (ISO 8601)
const specificDate: Date = new Date('2024-12-31T23:59:59');

// Создание из компонентов (год, месяц [0-11], день, часы...)
const birthday: Date = new Date(1990, 0, 15); // 15 января 1990
// Внимание: месяц 0 = Январь!

Проблема с мутабельностью

Методы объекта Date изменяют исходный объект. Это может привести к неожиданным багам. TypeScript не может это предотвратить на уровне типов, но вы можете использовать иммутабельные подходы.

const date = new Date('2024-01-01');
date.setDate(date.getDate() + 5); // мутация! date теперь 6 января
// Лучше создавать новый объект:
const newDate = new Date(date.getTime() + 5 * 24 * 60 * 60 * 1000);

Типизация Unix Timestamp

Часто даты передаются как числа (миллисекунды с 1970 года). Используйте type alias для ясности:

type UnixTimestamp = number;

function formatTimestamp(ts: UnixTimestamp): string {
  return new Date(ts).toISOString();
}

const myTimestamp: UnixTimestamp = 1705315200000;
console.log(formatTimestamp(myTimestamp));

2. Форматирование и парсинг дат

Встроенные методы форматирования

JavaScript предоставляет базовые методы для локализованного вывода. В TypeScript они работают "из коробки":

const date = new Date('2024-06-15T14:30:00');

// Локализованные строки
console.log(date.toLocaleDateString('ru-RU')); // "15.06.2024"
console.log(date.toLocaleTimeString('en-US')); // "2:30:00 PM"
console.log(date.toLocaleString('de-DE'));     // "15.6.2024, 14:30:00"

// ISO-строка (удобно для API)
console.log(date.toISOString()); // "2024-06-15T11:30:00.000Z" (всегда UTC)

Парсинг строк: опасности

Парсинг строк через конструктор new Date(str) может давать неожиданные результаты в разных браузерах. Лучше использовать Date.parse() с явной проверкой или сторонние библиотеки.

// Ненадёжный способ
const parsed = new Date('2024/01/15'); // может работать нестабильно

// Надёжный способ: ISO 8601
const safeParse = (dateStr: string): Date | null => {
  const ts = Date.parse(dateStr);
  return isNaN(ts) ? null : new Date(ts);
};

const result = safeParse('2024-01-15T10:00:00Z');
if (result) {
  console.log(result.toISOString());
}

3. Продвинутые манипуляции и сравнение

Сравнение дат

Даты можно сравнивать напрямую через операторы сравнения, но для точного сравнения (равенства) нужно приводить к числу:

const date1 = new Date('2024-01-01');
const date2 = new Date('2024-01-01');

// Неправильно: сравниваются ссылки
console.log(date1 === date2); // false

// Правильно: сравниваем timestamp
console.log(date1.getTime() === date2.getTime()); // true

// Проверка "раньше/позже"
console.log(date1 < new Date('2025-01-01')); // true

Добавление и вычитание времени

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

function addDays(date: Date, days: number): Date {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

function addMonths(date: Date, months: number): Date {
  const result = new Date(date);
  result.setMonth(result.getMonth() + months);
  return result;
}

const today = new Date();
const nextWeek = addDays(today, 7);
const nextQuarter = addMonths(today, 3);

Расчёт разницы между датами

function daysBetween(date1: Date, date2: Date): number {
  const diffTime = Math.abs(date2.getTime() - date1.getTime());
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  return diffDays;
}

const start = new Date('2024-01-01');
const end = new Date('2024-12-31');
console.log(daysBetween(start, end)); // 365

4. Лучшие практики: библиотеки для TypeScript

Для серьёзных проектов встроенного Date часто недостаточно. Вот две лучшие библиотеки, которые отлично работают с TypeScript:

date-fns (рекомендуется)

Модульная, функциональная, иммутабельная. Идеальна для TypeScript благодаря отличной поддержке типов.

import { format, addDays, differenceInDays, isAfter } from 'date-fns';

const date = new Date('2024-06-15');
console.log(format(date, 'dd.MM.yyyy')); // "15.06.2024"
console.log(addDays(date, 10));          // 25 июня
console.log(differenceIn                

Блоги

Рекомендаций по книгам