Работа с датами в JavaScript: практическое руководство и решения
Для кого эта статья:
- Разработчики на начальном и среднем уровне, стремящиеся улучшить навыки работы с датами в JavaScript
- Студенты и обучающиеся веб-разработке, интересующиеся практическими аспектами программирования
Полный стек разработчики, ищущие решения для сложных задач, связанных с датами и временем в приложениях
Работа с датами в JavaScript — это настоящее минное поле для разработчиков всех уровней. Один неверный шаг, и ваше приложение будет отображать пользователям в Токио вчерашнюю дату, а клиентам в Нью-Йорке — время, которое наступит только через три часа! Я прошёл через все эти баги, потерял десятки часов отладки и готов поделиться картой, которая проведёт вас через это датовое болото с минимальными потерями. 🗓️
Хотите не просто понять, как работать с датами в JavaScript, а стать экспертом во всех аспектах веб-разработки? Обучение веб-разработке от Skypro — это не просто курс, а полноценная программа, где вы освоите не только нюансы работы с временем, но и научитесь создавать полнофункциональные веб-приложения с использованием современных технологий. Наши студенты не просто знают теорию — они умеют применять её на практике с первого дня обучения.
Основы объекта Date в JavaScript: создание и форматирование
Объект Date в JavaScript — это встроенный инструмент для работы с датами и временем. На первый взгляд он кажется простым, но имеет множество нюансов, которые важно понимать для корректной разработки.
Начнём с создания объектов Date. Существует четыре способа инициализации:
- Без аргументов (текущая дата и время):
new Date() - С временной меткой (миллисекунды с 1 января 1970):
new Date(1627824000000) - Строкой с датой:
new Date('2021-08-01') - С отдельными компонентами (год, месяц, день...):
new Date(2021, 7, 1)
Обратите внимание на особенность при создании даты с компонентами: месяцы в JavaScript индексируются с нуля! То есть январь — это 0, а декабрь — 11. Этот момент становится источником множества ошибок.
// Создаём дату "1 августа 2021"
const date = new Date(2021, 7, 1); // Обратите внимание: 7 = август!
Для форматирования даты JavaScript предлагает несколько встроенных методов:
| Метод | Описание | Пример вывода |
|---|---|---|
| toString() | Полное представление даты и времени | Sun Aug 01 2021 00:00:00 GMT+0300 |
| toDateString() | Только дата без времени | Sun Aug 01 2021 |
| toTimeString() | Только время без даты | 00:00:00 GMT+0300 |
| toISOString() | Формат ISO 8601 | 2021-08-01T00:00:00.000Z |
| toLocaleString() | Локализованный формат | 01.08.2021, 00:00:00 |
Метод toLocaleString() особенно полезен, так как позволяет настраивать формат вывода с учётом локальных правил:
// Форматируем дату по-русски
date.toLocaleString('ru-RU', {
day: '2-digit',
month: 'long',
year: 'numeric'
}); // "01 августа 2021 г."
Для извлечения отдельных компонентов даты используйте специальные методы:
getFullYear()— получить год (например, 2021)getMonth()— получить месяц (0-11)getDate()— получить день месяца (1-31)getHours(),getMinutes(),getSeconds()— для времениgetDay()— день недели (0-6, где 0 — воскресенье)
Максим, senior frontend-разработчик
Однажды я разрабатывал систему бронирования для международной сети отелей. Пользователи жаловались, что бронирования иногда создавались на неправильные даты. После долгого расследования я обнаружил, что проблема была в некорректной работе с датами в JavaScript.
Мы использовали код вида
new Date(year, month, day), где month получали напрямую из номера месяца, выбранного пользователем (1-12). Поскольку в JavaScript месяцы индексируются с 0, все даты смещались на месяц вперед! Февраль становился мартом, и так далее.
Исправление было простым:
new Date(year, month-1, day), но этот опыт научил меня всегда быть предельно внимательным при работе с датами в JavaScript.

Манипуляции с датами: расчёт разницы и преобразования
Одна из самых частых операций с датами — это модификация значений и расчёт временных интервалов. JavaScript предоставляет набор инструментов для решения этих задач. 🔄
Для изменения компонентов даты можно использовать соответствующие сеттеры:
const date = new Date();
date.setFullYear(2022); // Устанавливаем год
date.setMonth(0); // Устанавливаем январь (не забываем про индексацию с 0)
date.setDate(15); // Устанавливаем 15-й день месяца
Важная особенность этих методов — они автоматически корректируют дату при выходе за допустимые пределы:
const date = new Date(2022, 0, 31); // 31 января 2022
date.setMonth(1); // Устанавливаем февраль
console.log(date); // 28 февраля 2022 (февраль 2022 имеет 28 дней)
date.setDate(32); // Устанавливаем 32-й день
console.log(date); // 4 апреля 2022 (31 день марта + 1 день)
Эта особенность чрезвычайно полезна для добавления интервалов:
// Добавляем 45 дней к текущей дате
const date = new Date();
date.setDate(date.getDate() + 45);
Для вычисления разницы между датами в JavaScript есть несколько подходов:
- Вычитание объектов Date (даёт разницу в миллисекундах)
- Ручной расчёт разницы по компонентам
- Использование сторонних библиотек
Давайте рассмотрим первый подход подробнее:
const date1 = new Date('2022-01-01');
const date2 = new Date('2022-02-15');
const diffInMs = date2 – date1; // 3888000000 миллисекунд
const diffInDays = diffInMs / (1000 * 60 * 60 * 24); // 45 дней
При работе с датами часто требуется преобразование между различными форматами. Вот таблица с основными преобразованиями:
| Из формата | В формат | Метод/подход |
|---|---|---|
| Date объект | Timestamp (мс) | date.getTime() или +date |
| Timestamp (мс) | Date объект | new Date(timestamp) |
| Date объект | ISO строка | date.toISOString() |
| ISO строка | Date объект | new Date(isoString) |
| Date объект | Компоненты (год, месяц, ...) | date.getFullYear(), date.getMonth(), ... |
Один из самых мощных приёмов — использование временных меток (timestamp). Это позволяет выполнять арифметические операции с датами:
// Получаем дату через 7 дней от текущей
const now = new Date();
const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
// Или то же самое более кратко
const nextWeek = new Date(+now + 7 * 24 * 60 * 60 * 1000);
При работе с разницей дат необходимо быть осторожным с переходом на летнее/зимнее время и високосными годами. В сложных случаях лучше использовать специализированные библиотеки, о которых мы поговорим позже.
Работа с часовыми поясами и локализация времени
Часовые пояса — одна из самых сложных частей работы с датами в JavaScript. Объект Date всегда хранит время в UTC (Coordinated Universal Time), но методы отображения и получения компонентов времени работают в локальном часовом поясе пользователя, что часто вызывает путаницу. ⏰
Существует два типа методов для работы с датой:
- Локальные методы:
getHours(),getDate(),getMonth(), и т.д. - UTC методы:
getUTCHours(),getUTCDate(),getUTCMonth(), и т.д.
Локальные методы возвращают значения в часовом поясе пользователя, а UTC методы — в универсальном времени:
const date = new Date('2022-01-15T12:00:00Z'); // 'Z' означает UTC
console.log(date.getHours()); // Может быть 15 (если вы в UTC+3)
console.log(date.getUTCHours()); // Всегда 12
Для работы с часовыми поясами в JavaScript есть несколько подходов:
- Хранить все даты в UTC и преобразовывать их в локальное время только для отображения
- Использовать метод
toLocaleString()с опцией timeZone - Применять специализированные библиотеки (Luxon, date-fns-tz)
Метод toLocaleString() позволяет форматировать дату с учетом определенного часового пояса:
const date = new Date('2022-01-15T12:00:00Z');
// Отображение в разных часовых поясах
console.log(date.toLocaleString('ru-RU', { timeZone: 'Europe/Moscow' }));
console.log(date.toLocaleString('en-US', { timeZone: 'America/New_York' }));
console.log(date.toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }));
Для локализации дат важно учитывать культурные особенности форматирования. Разные страны используют разные порядки компонентов даты, разделители и форматы времени:
const date = new Date('2022-01-15T12:30:45Z');
// Локализация для разных стран
console.log(date.toLocaleString('ru-RU')); // 15.01.2022, 15:30:45
console.log(date.toLocaleString('en-US')); // 1/15/2022, 12:30:45 PM
console.log(date.toLocaleString('de-DE')); // 15.1.2022, 13:30:45
Метод toLocaleString() принимает дополнительные параметры для тонкой настройки форматирования:
const options = {
weekday: 'long', // 'long', 'short', 'narrow'
year: 'numeric', // 'numeric', '2-digit'
month: 'long', // 'numeric', '2-digit', 'long', 'short', 'narrow'
day: 'numeric', // 'numeric', '2-digit'
hour: '2-digit', // 'numeric', '2-digit'
minute: '2-digit', // 'numeric', '2-digit'
second: '2-digit', // 'numeric', '2-digit'
timeZoneName: 'long' // 'long', 'short'
};
console.log(date.toLocaleString('ru-RU', options));
// "суббота, 15 января 2022 г., 15:30:45 Москва, стандартное время"
Когда дело касается работы с разницей во времени между часовыми поясами, чистый JavaScript предлагает ограниченные возможности. Для сложных сценариев стоит обратить внимание на специализированные библиотеки, о которых мы поговорим в следующем разделе.
Анна, full-stack разработчик
Наша команда столкнулась с серьезной проблемой при разработке системы онлайн-конференций. Пользователи из разных стран видели разное время начала мероприятий, что приводило к путанице и пропускам важных сессий.
Ошибка крылась в том, что мы хранили время мероприятий в базе данных без привязки к часовому поясу, а при отображении интерпретировали его как локальное время пользователя. В результате одно и то же мероприятие отображалось с разницей в несколько часов для участников из разных регионов.
Решение оказалось многоэтапным:
- Мы перешли на хранение всех времен в UTC
- Добавили в профиль пользователя выбор часового пояса
- Внедрили библиотеку Luxon для правильного преобразования времени при отображении
Теперь каждый пользователь видит корректное локальное время начала мероприятий, независимо от его географического положения.
Современные библиотеки для работы с датами в JavaScript
Нативный API для работы с датами в JavaScript имеет множество ограничений и непоследовательностей. Именно поэтому сообщество разработало несколько библиотек, значительно упрощающих работу с датами и временем. 📚
Рассмотрим три самые популярные библиотеки и их особенности:
| Библиотека | Преимущества | Недостатки | Размер (min+gzip) |
|---|---|---|---|
| date-fns | – Модульная структура<br>- Неизменяемый API<br>- Поддержка функционального программирования<br>- Хорошая производительность | – Требует импорта множества функций<br>- Отдельный пакет для работы с часовыми поясами | ~4 KB (импорт отдельных функций) |
| Luxon | – Современный API<br>- Хорошая работа с часовыми поясами<br>- Расширенная локализация<br>- Создан автором moment.js | – Меньше дополнительных функций по сравнению с moment.js<br>- Не такая обширная экосистема | ~13 KB |
| Day.js | – Очень маленький размер<br>- API, совместимый с moment.js<br>- Плагинная архитектура<br>- Проще мигрировать с moment.js | – Меньше функций в базовой версии<br>- Требует загрузки плагинов для расширенного функционала | ~2 KB (базовый) + плагины |
Выбор библиотеки зависит от ваших конкретных задач:
- Если размер бандла критичен — Day.js
- Если важна модульность и функциональный подход — date-fns
- Если нужна мощная работа с часовыми поясами — Luxon
Давайте посмотрим на примеры использования каждой из этих библиотек для решения одной и той же задачи — добавление 1 месяца и форматирование даты:
date-fns:
import { format, addMonths } from 'date-fns';
import { ru } from 'date-fns/locale';
const date = new Date();
const newDate = addMonths(date, 1);
const formatted = format(newDate, 'dd MMMM yyyy', { locale: ru });
console.log(formatted); // например, "15 февраля 2022"
Luxon:
import { DateTime } from 'luxon';
const date = DateTime.now();
const newDate = date.plus({ months: 1 });
const formatted = newDate.setLocale('ru').toFormat('dd MMMM yyyy');
console.log(formatted); // например, "15 февраля 2022"
Day.js:
import dayjs from 'dayjs';
import 'dayjs/locale/ru';
import localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(localizedFormat);
dayjs.locale('ru');
const date = dayjs();
const newDate = date.add(1, 'month');
const formatted = newDate.format('DD MMMM YYYY');
console.log(formatted); // например, "15 февраля 2022"
Большинство современных проектов предпочитают date-fns из-за модульности и удобства использования с современными подходами к импорту. Day.js выбирают, когда важен размер, а Luxon — для сложных сценариев с часовыми поясами.
Важно отметить, что популярная ранее библиотека moment.js с 2020 года находится в режиме поддержки и не рекомендуется для новых проектов из-за своего размера и мутабельного API.
Практические решения типичных задач с датами и временем
В этом разделе мы рассмотрим конкретные решения для распространённых задач при работе с датами в JavaScript. Эти примеры помогут вам справиться с большинством сценариев, возникающих в реальных проектах. 💡
1. Проверка корректности даты
JavaScript не имеет встроенного способа проверки корректности строки даты, но можно использовать следующий подход:
function isValidDate(dateString) {
const date = new Date(dateString);
return !isNaN(date) && date.toString() !== 'Invalid Date';
}
console.log(isValidDate('2022-02-31')); // false (31 февраля не существует)
console.log(isValidDate('2022-02-28')); // true
2. Вычисление возраста по дате рождения
function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() – birth.getFullYear();
const monthDiff = today.getMonth() – birth.getMonth();
// Уменьшаем возраст, если день рождения в этом году ещё не наступил
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
}
console.log(calculateAge('1990-05-15')); // Выведет возраст в годах
3. Получение первого и последнего дня месяца
function getFirstDayOfMonth(year, month) {
return new Date(year, month, 1);
}
function getLastDayOfMonth(year, month) {
return new Date(year, month + 1, 0);
}
console.log(getFirstDayOfMonth(2022, 1)); // 1 февраля 2022
console.log(getLastDayOfMonth(2022, 1)); // 28 февраля 2022
4. Добавление рабочих дней (без выходных)
function addBusinessDays(date, days) {
const result = new Date(date);
let addedDays = 0;
while (addedDays < days) {
result.setDate(result.getDate() + 1);
const dayOfWeek = result.getDay();
// Пропускаем выходные (0 – воскресенье, 6 – суббота)
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
addedDays++;
}
}
return result;
}
const nextBusinessDay = addBusinessDays(new Date('2022-02-18'), 3);
// Если 18 февраля – пятница, то результат будет 23 февраля (среда)
5. Форматирование относительного времени
Для отображения времени в формате "5 минут назад", "вчера" и т.д.:
function formatRelativeTime(date) {
const now = new Date();
const diff = now – date; // разница в миллисекундах
// Преобразуем в секунды
const seconds = Math.floor(diff / 1000);
if (seconds < 60) return 'только что';
// Преобразуем в минуты
const minutes = Math.floor(seconds / 60);
if (minutes < 60) return `${minutes} ${declOfNum(minutes, ['минуту', 'минуты', 'минут'])} назад`;
// Преобразуем в часы
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours} ${declOfNum(hours, ['час', 'часа', 'часов'])} назад`;
// Для более старых дат используем обычное форматирование
return date.toLocaleDateString();
}
// Вспомогательная функция для склонения существительных
function declOfNum(n, titles) {
return titles[
n % 10 === 1 && n % 100 !== 11
? 0
: n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)
? 1
: 2
];
}
console.log(formatRelativeTime(new Date(Date.now() – 5 * 60 * 1000))); // "5 минут назад"
6. Работа с датами в UTC
Если ваше приложение должно работать с единым временем независимо от часового пояса пользователя:
function getUTCDate() {
const now = new Date();
return new Date(Date.UTC(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate(),
now.getUTCHours(),
now.getUTCMinutes(),
now.getUTCSeconds()
));
}
// Текущая дата в UTC
console.log(getUTCDate().toISOString());
При работе со сложными сценариями, такими как повторяющиеся события, учёт праздников или специфические бизнес-правила для дат, рекомендую использовать специализированные библиотеки, которые мы обсудили в предыдущем разделе. Они предоставляют готовые решения для большинства подобных задач и позволяют избежать множества ошибок.
Работа с датами и временем в JavaScript может быть запутанной, но, освоив основные принципы и инструменты, вы сможете уверенно решать даже сложные задачи. Помните главные правила: всегда учитывайте часовые пояса, используйте современные библиотеки для сложных случаев и тестируйте ваш код на разных локалях и часовых поясах. Эти знания значительно упростят вашу работу и помогут создавать более надёжные и интернациональные приложения. Следуя рекомендациям из этого руководства, вы избежите большинства распространенных ошибок и сэкономите множество часов отладки.