Работа с датой и временем в JavaScript (Node.js): подробное руководство
Что это такое и зачем? (аналогия из реальной жизни)
Представьте, что вы — организатор школьного лагеря. У вас есть расписание: завтрак в 8:30, обед в 13:00, отбой в 21:00. Вам нужно знать, сколько времени осталось до обеда, через сколько дней закончится смена, или в какой день недели будет родительский день. Всё это — работа с датой и временем.
В программировании дата и время — это не просто цифры на календаре. Это инструмент для:
- Логирования — записи, когда произошло событие (например, пользователь зарегистрировался 15 марта 2025 года в 14:32)
- Планирования — запуска задач по расписанию (отправить письмо через 2 дня)
- Расчётов — сколько дней прошло между двумя событиями
- Форматирования — показать дату в понятном виде: «Сегодня, 10 апреля» или «10.04.2025»
Важно: В JavaScript (и Node.js) работа с датой и временем — одна из самых частых задач. Без неё не обходится ни одно серьёзное приложение: от простого будильника до сложной системы бронирования билетов.
Теория: как это работает изнутри
В основе всего лежит временная метка (timestamp) — это количество миллисекунд, прошедших с 1 января 1970 года 00:00:00 по UTC. Эта дата называется «эпоха Unix» (Unix Epoch).
Почему именно 1970 год? Потому что операционная система Unix была создана в конце 1960-х, и разработчики выбрали эту дату как точку отсчёта. С тех пор все компьютеры в мире «договорились» считать время именно так.
В JavaScript дата и время представлены объектом Date. Внутри него хранится одно число — количество миллисекунд от эпохи Unix. Всё остальное (год, месяц, день, час, минута, секунда) вычисляется из этого числа.
Важно понимать разницу между:
- UTC (Coordinated Universal Time) — всемирное координированное время. Это «базовое» время, от которого считаются все часовые пояса.
- Локальное время — время в вашем часовом поясе. Например, Москва — UTC+3.
Запомните: Внутри компьютера все даты хранятся в UTC. Когда вы видите дату на экране — это уже преобразованное в ваш часовой пояс значение.
Синтаксис в JavaScript (Node.js): все формы и варианты
Создание объекта Date
В JavaScript есть 4 основных способа создать объект даты:
| Способ | Пример | Результат |
|---|---|---|
| Текущая дата и время | new Date() |
Текущий момент времени |
| Из миллисекунд | new Date(1700000000000) |
Дата, соответствующая этим миллисекундам |
| Из строки | new Date("2025-03-15T14:30:00") |
Дата, разобранная из строки |
| Из компонентов | new Date(2025, 2, 15, 14, 30, 0) |
Дата из года, месяца, дня и т.д. |
Внимание: Месяцы в JavaScript нумеруются с 0! Январь — 0, Февраль — 1, Декабрь — 11. Это одна из самых частых ошибок новичков.
Основные методы объекта Date
Все методы делятся на две группы: «получить» (get) и «установить» (set).
| Метод | Что возвращает | Диапазон значений |
|---|---|---|
getFullYear() |
Год (4 цифры) | 1970 — 9999 |
getMonth() |
Месяц (0-11) | 0 (январь) — 11 (декабрь) |
getDate() |
День месяца (1-31) | 1 — 31 |
getDay() |
День недели (0-6) | 0 (воскресенье) — 6 (суббота) |
getHours() |
Часы (0-23) | 0 — 23 |
getMinutes() |
Минуты (0-59) | 0 — 59 |
getSeconds() |
Секунды (0-59) | 0 — 59 |
getMilliseconds() |
Миллисекунды (0-999) | 0 — 999 |
getTime() |
Миллисекунды с эпохи Unix | Очень большое число |
Для UTC-версий методов добавьте «UTC» в название: getUTCFullYear(), getUTCMonth() и т.д.
Методы для установки работают аналогично: setFullYear(), setMonth(), setDate() и т.д.
Форматирование дат
Встроенные методы для преобразования даты в строку:
| Метод | Пример вывода |
|---|---|
toString() |
"Sat Mar 15 2025 14:30:00 GMT+0300" |
toDateString() |
"Sat Mar 15 2025" |
toTimeString() |
"14:30:00 GMT+0300" |
toISOString() |
"2025-03-15T11:30:00.000Z" |
toLocaleDateString() |
"15.03.2025" (зависит от локали) |
toLocaleTimeString() |
"14:30:00" (зависит от локали) |
Примеры кода — от простого к сложному
Пример 1: Получаем текущую дату и время
// Создаём объект с текущей датой и временем
const now = new Date();
// Выводим в консоль
console.log("Текущая дата и время:", now);
// Получаем отдельные компоненты
const year = now.getFullYear(); // 2025
const month = now.getMonth() + 1; // 3 (прибавляем 1, т.к. месяцы с 0)
const day = now.getDate(); // 15
const hours = now.getHours(); // 14
const minutes = now.getMinutes(); // 30
console.log(`Сегодня: ${day}.${month}.${year}`);
console.log(`Сейчас: ${hours}:${minutes}`);
Объяснение: Мы создаём объект Date без аргументов — он автоматически фиксирует текущий момент времени. Затем получаем каждый компонент отдельно. Обратите внимание: к месяцу мы прибавляем 1, потому что JavaScript считает январь нулевым месяцем.
Пример 2: Создаём конкретную дату
// Создаём дату 1 января 2025 года, 12:00
const newYear = new Date(2025, 0, 1, 12, 0, 0);
console.log("Новый год:", newYear);
// Проверяем день недели
const dayOfWeek = newYear.getDay(); // 3 (среда, т.к. 0 - воскресенье)
// Массив с названиями дней недели
const weekDays = ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'];
console.log(`1 января 2025 года — это ${weekDays[dayOfWeek]}`);
Объяснение: Мы передаём в конструктор Date 6 чисел: год, месяц (0 — январь), день, часы, минуты, секунды. Метод getDay() возвращает номер дня недели, где 0 — воскресенье. Используем массив для преобразования числа в название.
Пример 3: Вычисляем разницу между датами
// Дата начала и конца события
const start = new Date(2025, 2, 10); // 10 марта 2025
const end = new Date(2025, 2, 20); // 20 марта 2025
// Разница в миллисекундах
const diffMs = end.getTime() - start.getTime();
// Переводим в дни (1 день = 24 часа * 60 минут * 60 секунд * 1000 мс)
const diffDays = diffMs / (1000 * 60 * 60 * 24);
console.log(`Разница между датами: ${diffDays} дней`); // 10 дней
// Более точный способ с округлением
const diffDaysRounded = Math.round(diffMs / (1000 * 60 * 60 * 24));
console.log(`Округлённая разница: ${diffDaysRounded} дней`);
Объяснение: Мы получаем timestamp каждой даты через getTime(), вычитаем один из другого и делим на количество миллисекунд в одном дне. Math.round() округляет результат до целого числа.
Пример 4: Форматирование даты для пользователя
const date = new Date(2025, 2, 15, 14, 30, 0);
// Стандартное форматирование
console.log("ISO формат:", date.toISOString());
// "2025-03-15T11:30:00.000Z" (в UTC!)
// Локальное форматирование (зависит от системы)
console.log("Локальная дата:", date.toLocaleDateString('ru-RU'));
// "15.03.2025"
console.log("Локальное время:", date.toLocaleTimeString('ru-RU'));
// "14:30:00"
// Полный формат с опциями
const options = {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: '2-digit',
minute: '2-digit'
};
console.log("Красивый формат:", date.toLocaleDateString('ru-RU', options));
// "суббота, 15 марта 2025 г., 14:30"
Объяснение: toLocaleDateString() и toLocaleTimeString() позволяют форматировать дату под конкретную страну. Вторым аргументом можно передать объект с опциями для точной настройки формата.
Пример 5: Работа с часовыми поясами
// Создаём дату в UTC
const utcDate = new Date(Date.UTC(2025, 2, 15, 12, 0, 0));
console.log("UTC время:", utcDate.toISOString());
// "2025-03-15T12:00:00.000Z"
// Получаем компоненты в UTC
console.log("UTC часы:", utcDate.getUTCHours()); // 12
// Получаем компоненты в локальном времени (Москва UTC+3)
console.log("Локальные часы:", utcDate.getHours()); // 15
// Смещение часового пояса в минутах
const timezoneOffset = utcDate.getTimezoneOffset();
console.log(`Смещение от UTC: ${timezoneOffset} минут`);
// Для Москвы: -180 (UTC+3 = -180 минут)
Объяснение: Date.UTC() создаёт дату в UTC, игнорируя локальный часовой пояс. Методы с префиксом getUTC возвращают значения в UTC, а обычные — в локальном времени. getTimezoneOffset() показывает разницу в минутах между локальным временем и UTC.
Пример 6: Таймер обратного отсчёта
// Функция для расчёта времени до указанной даты
function getTimeRemaining(targetDate) {
const now = new Date();
const total = targetDate.getTime() - now.getTime();
// Если дата уже прошла
if (total <= 0) {
return { days: 0, hours: 0, minutes: 0, seconds: 0, total: 0 };
}
// Расчёт компонентов
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
const days = Math.floor(total / (1000 * 60 * 60 * 24));
return { total, days, hours, minutes, seconds };
}
// Целевая дата: 1 июня 2025 года
const target = new Date(2025, 5, 1);
const remaining = getTimeRemaining(target);
console.log(`До 1 июня 2025 осталось:`);
console.log(`${remaining.days} дней`);
console.log(`${remaining.hours} часов`);
console.log(`${remaining.minutes} минут`);
console.log(`${remaining.seconds} секунд`);
Объяснение: Функция getTimeRemaining() вычисляет разницу между текущим моментом и целевой датой. Используем Math.floor() для округления вниз и оператор % (остаток от деления) для получения остатка после выделения дней, часов и минут.
Пример 7: Парсинг даты из строки
// Разные форматы строк с датами
const date1 = new Date("2025-03-15"); // ISO формат
const date2 = new Date("March 15, 2025"); // Американский формат
const date3 = new Date("15/03/2025"); // Европейский формат (может не сработать!)
console.log("ISO:", date1);
console.log("Американский:", date2);
console.log("Европейский:", date3); // Может вернуть Invalid Date!
// Надёжный способ: разобрать строку вручную
function parseDate(dateString) {
// Ожидаем формат "DD.MM.YYYY"
const parts = dateString.split('.');
if (parts.length !== 3) {
return new Date(NaN); // Некорректная дата
}
const day = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1; // Месяцы с 0
const year = parseInt(parts[2], 10);
return new Date(year, month, day);
}
const myDate = parseDate("15.03.2025");
console.log("Разобранная дата:", myDate);
// "Sat Mar 15 2025 00:00:00 GMT+0300"
Объяснение: Встроенный парсинг дат из строк может работать непредсказуемо в разных браузерах и средах. Лучше написать свою функцию, которая разбирает строку по частям и создаёт дату через конструктор с компонентами.
Сравнение с Python: чем похоже и чем отличается
| Характеристика | JavaScript (Node.js) | Python |
|---|---|---|
| Основной модуль/объект | Date (встроенный объект) |
datetime (модуль) |
| Создание текущей даты | new Date() |
datetime.now() |
| Создание конкретной даты | new Date(2025, 2, 15) |
datetime(2025, 3, 15) |
| Нумерация месяцев | С 0 (январь = 0) | С 1 (январь = 1) |
| Форматирование | toLocaleDateString() |
strftime() |
| Работа с часовыми поясами | Сложная (нужны библиотеки) | Встроенная (pytz) |
| Арифметика дат | Ручные расчёты через timestamp | timedelta |
Ключевые отличия:
- В Python месяцы нумеруются с 1, что более логично для человека
- Python имеет встроенный модуль
timedeltaдля удобной работы с интервалами времени - JavaScript требует сторонних библиотек (например,
moment.jsилиdate-fns) для сложных операций с часовыми поясами - В Python форматирование через
strftime()более гибкое и стандартизированное
Совет: Если вы переходите с Python на JavaScript, запомните главное правило: в JS месяцы с 0, а все операции с датами требуют больше ручного кода.
Типичные ошибки и подводные камни
Ошибка 1: Забываем про нумерацию месяцев с 0
// ❌ Неправильно
const wrongDate = new Date(2025, 3, 15); // Это апрель, а не март!
console.log(wrongDate.getMonth()); // 3 (апрель)
// ✅ Правильно
const correctDate = new Date(2025, 2, 15); // Март (месяц 2)
console.log(correctDate.getMonth()); // 2 (март)
Ошибка 2: Сравнение дат через ==
const date1 = new Date(2025, 2, 15);
const date2 = new Date(2025, 2, 15);
// ❌ Неправильно
console.log(date1 == date2); // false! Сравниваются ссылки на объекты
// ✅ Правильно
console.log(date1.getTime() == date2.getTime()); // true
console.log(date1 - date2 === 0); // true (оператор - преобразует в числа)
Ошибка 3: Мутабельность объектов Date
const original = new Date(2025, 2, 15);
const copy = original; // ❌ Это не копия, а ссылка!
copy.setDate(20);
console.log(original.getDate()); // 20 — исходный объект тоже изменился!
// ✅ Правильное копирование
const realCopy = new Date(original.getTime());
realCopy.setDate(25);
console.log(original.getDate()); // 20 — исходный не изменился
Ошибка 4: Игнорирование часовых поясов
// Создаём дату из строки
const date = new Date("2025-03-15"); // Парсится как UTC!
console.log(date.getHours()); // 3 (если вы в Москве, UTC+3)
// ✅ Чтобы получить полночь по локальному времени:
const localDate = new Date(2025, 2, 15);
console.log(localDate.getHours()); // 0
Ошибка 5: Неправильный расчёт разницы в днях
const start = new Date(2025, 2, 10);
const end = new Date(2025, 2, 20);
// ❌ Неправильно: не учитываем переход на летнее время
const diffDays = (end - start) / (1000 * 60 * 60 * 24);
// Может быть 9.95833... из-за перевода часов
// ✅ Правильно: используем UTC для расчётов
const utcStart = Date.UTC(2025, 2, 10);
const utcEnd = Date.UTC(2025, 2, 20);
const safeDiff = (utcEnd - utcStart) / (1000 * 60 * 60 * 24);
console.log(safeDiff); // 10 — всегда точно
Лучшие практики и советы профессионалов
1. Используйте библиотеки для сложных задач
Для серьёзных проектов используйте date-fns или luxon. Они решают проблемы с часовыми поясами, форматированием и локализацией.
2. Храните даты в UTC
В базах данных и API всегда передавайте даты в UTC. Преобразуйте в локальное время только при отображении пользователю.
3. Используйте ISO 8601 для обмена данными
Формат 2025-03-15T14:30:00.000Z — международный стандарт. Он однозначен и легко парсится.
4. Избегайте встроенного парсинга строк
Конструктор new Date(string) работает по-разному в разных браузерах. Всегда разбирайте строки вручную или используйте библиотеки.
5. Округляйте результаты вычислений
При расчёте разницы в днях используйте Math.round() или Math.floor(), чтобы избежать проблем с плавающей точкой.
6. Проверяйте валидность дат
function isValidDate(date) {
return date instanceof Date && !isNaN(date.getTime());
}
const invalid = new Date("не дата");
console.log(isValidDate(invalid)); // false
console.log(isValidDate(new Date())); // true
7. Используйте Intl.DateTimeFormat для форматирования
const formatter = new Intl.DateTimeFormat('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
});
console.log(formatter.format(new Date(2025, 2, 15)));
// "суббота, 15 марта 2025 г."
Вопросы для самопроверки
-
Вопрос: Что такое «эпоха Unix» и почему она важна?
Ответ: Это 1 января 1970 года 00:00:00 UTC. Все даты в JavaScript хранятся как количество миллисекунд, прошедших с этого момента.
-
Вопрос: Почему в JavaScript месяцы нумеруются с 0?
Ответ: Это историческое решение, связанное с языком Java, от которого JavaScript унаследовал много синтаксиса. В массивах индексация тоже начинается с 0.
-
Вопрос: Как правильно сравнить две даты на равенство?
Ответ: Нужно сравнить их timestamp:
date1.getTime() === date2.getTime()илиdate1 - date2 === 0. -
Вопрос: В чём разница между
getDate()иgetDay()?Ответ:
getDate()возвращает день месяца (1-31), аgetDay()— день недели (0-6, где 0 — воскресенье). -
Вопрос: Как создать дату, которая представляет полночь 1 января 2025 года по московскому времени?
Ответ:
new Date(2025, 0, 1)— это создаст дату с учётом локального часового пояса. -
Вопрос: Почему
new Date("2025-03-15")может дать неожиданный результат?Ответ: Строка в формате ISO парсится как UTC, поэтому время будет 00:00 UTC, что в Москве соответствует 03:00 ночи.
-
Вопрос: Как добавить 7 дней к текущей дате?
Ответ:
const future = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);или использоватьsetDate(now.getDate() + 7). -
Вопрос: Что такое
Date.UTC()и чем он отличается отnew Date()?Ответ:
Date.UTC()возвращает timestamp (число) для указанной даты в UTC, не создавая объект Date. Это полезно для расчётов без учёта часового пояса. -
Вопрос: Как проверить, является ли переменная валидной датой?
Ответ: Использовать
date instanceof Date && !isNaN(date.getTime()). -
Вопрос: В чём преимущество библиотеки
date-fnsперед встроеннымDate?Ответ:
date-fnsпредоставляет удобные функции для форматирования, манипуляций с датами, работы с часовыми поясами и локализации, избавляя от рутинного кода.
Итог и что изучить дальше
Мы разобрали основы работы с датой и временем в JavaScript (Node.js). Теперь вы знаете:
- Как создавать объекты Date разными способами
- Как получать и устанавливать компоненты даты
- Как форматировать даты для пользователя
- Как выполнять расчёты с датами
- Какие ошибки чаще всего допускают новички
- Как правильно работать с часовыми поясами
Что изучить дальше:
- Библиотеки для работы с датами:
date-fns— лёгкая библиотека с множеством функцийluxon— современная библиотека от создателей moment.jsdayjs— минималистичная альтернатива
- Работа с календарями: создание календарных сеток, планировщиков задач
- Таймеры и интервалы:
setTimeout(),setInterval()для выполнения кода через определённое время - Сериализация дат: как правильно сохранять даты в JSON, базы данных
- Международная локализация: адаптация форматов дат под разные страны
Главный совет: Не пытайтесь запомнить все методы Date. Запомните основные принципы (timestamp, UTC, нумерация месяцев с 0) и всегда держите под рукой документацию. Практика — лучший способ освоить работу с датами.
Помните: дата и время — это не просто числа. Это инструмент, который делает ваши программы «живыми» и привязанными к реальному миру. Удачи в