Пошук уроків, статей та іншого контенту
Навчитеся змінювати компоненти Date, додавати тривалість і враховувати переповнення місяців та днів.
DateОб’єкт Date зберігає момент часу, але дозволяє окремо читати й змінювати його компоненти:
рік;
місяць;
день місяця;
години, хвилини, секунди;
мілісекунди.
Методи без суфікса UTC працюють у локальному часовому поясі середовища виконання:
const date = new Date(2025, 5, 15, 10, 30, 0);
console.log(date.getFullYear()); // 2025
console.log(date.getMonth()); // 5, червень
console.log(date.getDate()); // 15
console.log(date.getHours()); // 10Місяці в JavaScript нумеруються від нуля:
0 — січень;
1 — лютий;
5 — червень;
11 — грудень.
Для зміни компонентів використовують методи set...:
const date = new Date(2025, 5, 15, 10, 30, 0);
date.setFullYear(2026);
date.setMonth(0);
date.setDate(20);
date.setHours(8);
date.setMinutes(45);
console.log(date.toString());Після виклику set... змінюється сам об’єкт Date. Це важливо: Date є змінюваним об’єктом.
const original = new Date(2025, 5, 15);
const changed = original;
changed.setDate(20);
console.log(original.getDate()); // 20Якщо потрібно зберегти початкову дату, створіть копію:
const original = new Date(2025, 5, 15);
const changed = new Date(original);
changed.setDate(20);
console.log(original.getDate()); // 15
console.log(changed.getDate()); // 20Методи set... автоматично обробляють значення за межами звичайного діапазону. Ця поведінка називається нормалізацією дати.
Наприклад, якщо встановити 32-й день січня, JavaScript перенесе дату на лютий:
const date = new Date(2025, 0, 31);
date.setDate(32);
console.log(date.toDateString()); // Sat Feb 01 2025Так само можна перейти до попереднього місяця, передавши нульовий або від’ємний день:
const date = new Date(2025, 2, 1);
date.setDate(0);
console.log(date.toDateString()); // Fri Feb 28 2025Нульовий день означає останній день попереднього місяця.
Переповнення працює і для місяців:
const date = new Date(2025, 0, 15);
date.setMonth(12);
console.log(date.toDateString()); // Thu Jan 15 2026Місяць 12 означає січень наступного року, оскільки нумерація починається з нуля.
Від’ємні значення також нормалізуються:
const date = new Date(2025, 0, 15);
date.setMonth(-1);
console.log(date.toDateString()); // Sun Dec 15 2024Для календарної арифметики найчастіше використовують поточний день і setDate():
function addDays(date, amount) {
const result = new Date(date);
result.setDate(result.getDate() + amount);
return result;
}
const start = new Date(2025, 0, 31);
const nextDay = addDays(start, 1);
const previousDay = addDays(start, -1);
console.log(start.toDateString()); // Fri Jan 31 2025
console.log(nextDay.toDateString()); // Sat Feb 01 2025
console.log(previousDay.toDateString()); // Thu Jan 30 2025Функція повертає новий об’єкт і не змінює вхідну дату.
Цей підхід правильно працює з різною кількістю днів у місяцях та високосними роками:
const beforeLeapDay = new Date(2024, 1, 28);
const leapDay = addDays(beforeLeapDay, 1);
console.log(leapDay.toDateString()); // Thu Feb 29 2024Для віднімання днів достатньо передати від’ємне число:
const date = new Date(2025, 2, 1);
console.log(addDays(date, -1).toDateString()); // Fri Feb 28 2025Для додавання місяців використовують setMonth():
function addMonths(date, amount) {
const result = new Date(date);
result.setMonth(result.getMonth() + amount);
return result;
}
const date = new Date(2025, 0, 15);
console.log(addMonths(date, 2).toDateString()); // Sat Mar 15 2025Проте з кінцевими днями місяця потрібно бути уважним.
const date = new Date(2025, 0, 31);
date.setMonth(date.getMonth() + 1);
console.log(date.toDateString()); // Mon Mar 03 2025Чому результат — 3 березня, а не 28 лютого?
Початкова дата — 31 січня.
Після збільшення місяця JavaScript намагається створити 31 лютого.
У лютому немає 31 дня.
Надлишкові дні переносяться на березень.
Отже, простий виклик setMonth() не означає «перейти до такого самого порядкового дня або до останнього доступного дня». Він зберігає номер дня, а потім нормалізує результат.
Якщо бізнес-правило вимагає перейти до останнього доступного дня цільового місяця, спочатку можна встановити день 1, змінити місяць, а потім вибрати мінімум між початковим днем і кількістю днів у цільовому місяці.
function daysInMonth(year, month) {
// Нульовий день наступного місяця — останній день поточного
return new Date(year, month + 1, 0).getDate();
}
function addMonthsClamped(date, amount) {
const result = new Date(date);
const originalDay = result.getDate();
result.setDate(1);
result.setMonth(result.getMonth() + amount);
const lastDay = daysInMonth(
result.getFullYear(),
result.getMonth()
);
result.setDate(Math.min(originalDay, lastDay));
return result;
}
const january31 = new Date(2025, 0, 31);
console.log(
addMonthsClamped(january31, 1).toDateString()
); // Fri Feb 28 2025
console.log(
addMonthsClamped(january31, 2).toDateString()
); // Mon Mar 31 2025Такий варіант корисний для підписок, платежів і нагадувань, які мають відбуватися в останній доступний день місяця.
Роки змінюють за допомогою setFullYear():
const date = new Date(2025, 5, 15);
date.setFullYear(date.getFullYear() + 1);
console.log(date.toDateString()); // Mon Jun 15 2026З високосним днем виникає така сама проблема, як і з кінцевими днями місяця:
const date = new Date(2024, 1, 29);
date.setFullYear(2025);
console.log(date.toDateString()); // Sat Mar 01 2025JavaScript нормалізує 29 лютого невисокосного року до 1 березня.
Якщо потрібно зберігати дату 29 лютого як останній день лютого, використовуйте обмеження:
function addYearsClamped(date, amount) {
const result = new Date(date);
const originalDay = result.getDate();
const originalMonth = result.getMonth();
result.setDate(1);
result.setFullYear(result.getFullYear() + amount);
result.setMonth(originalMonth);
const lastDay = daysInMonth(
result.getFullYear(),
result.getMonth()
);
result.setDate(Math.min(originalDay, lastDay));
return result;
}
const leapDay = new Date(2024, 1, 29);
console.log(
addYearsClamped(leapDay, 1).toDateString()
); // Fri Feb 28 2025Години, хвилини, секунди та мілісекунди змінюють аналогічно:
const date = new Date(2025, 5, 15, 23, 50, 30, 500);
date.setHours(date.getHours() + 2);
console.log(date.toString());Результат перейде на наступний день, оскільки 23:50 плюс 2 години — це 01:50 наступної доби.
Можна передавати значення, що виходять за межі діапазону:
const date = new Date(2025, 5, 15, 10, 0);
date.setMinutes(-30);
console.log(date.toString()); // 09:30 того самого дняА якщо відняти більше:
const date = new Date(2025, 5, 15, 0, 15);
date.setMinutes(-30);
console.log(date.toString()); // 23:45 попереднього дняЄ дві різні операції, які часто називають «додати час».
Date всередині представляє момент часу як кількість мілісекунд від початку Unix-епохи. Метод getTime() повертає це число.
const date = new Date("2025-06-15T10:00:00Z");
const oneHour = 60 * 60 * 1000;
const result = new Date(date.getTime() + oneHour);
console.log(result.toISOString()); // 2025-06-15T11:00:00.000ZТакий підхід додає саме фіксовану тривалість. Він зручний для:
тайм-аутів;
терміну дії токена;
вимірювання інтервалів;
операцій, де важливі точні 60 хвилин або 24 години.
setDate() змінює календарний день і враховує локальний часовий пояс:
function addCalendarDays(date, amount) {
const result = new Date(date);
result.setDate(result.getDate() + amount);
return result;
}
const start = new Date(2025, 5, 15, 12, 0);
const result = addCalendarDays(start, 1);
console.log(result.toString());Календарний день і 24 години не завжди є одним і тим самим. У часових поясах, де застосовується перехід на літній або зимовий час, доба може тривати 23 або 25 годин.
Тому потрібно обирати операцію за змістом:
«через 24 години» — додавання мілісекунд;
«завтра в цей самий локальний час» — setDate();
«наступного місяця в цей самий день» — setMonth();
«через 30 днів» — додавання днів, а не місяця.
Для кожного основного локального методу існує UTC-версія:
| Локальний метод | UTC-метод | | --- | --- | | getFullYear() | getUTCFullYear() | | getMonth() | getUTCMonth() | | getDate() | getUTCDate() | | getHours() | getUTCHours() | | setFullYear() | setUTCFullYear() | | setMonth() | setUTCMonth() | | setDate() | setUTCDate() | | setHours() | setUTCHours() |
Наприклад:
const date = new Date("2025-06-15T23:00:00.000Z");
console.log(date.getUTCDate()); // 15
console.log(date.getUTCHours()); // 23
console.log(date.getDate()); // Локальний день може відрізнятися
console.log(date.getHours()); // Локальна година може відрізнятисяОдин і той самий момент часу може мати різну календарну дату в UTC та локальному часовому поясі.
Якщо дані зберігаються й обробляються як UTC, не змішуйте локальні та UTC-методи в одній операції:
const date = new Date("2025-06-15T23:00:00.000Z");
date.setUTCDate(date.getUTCDate() + 1);
console.log(date.toISOString()); // 2025-06-16T23:00:00.000ZДля UTC-арифметики краще послідовно використовувати getUTC... і setUTC....
Уявімо, що замовлення дійсне протягом семи календарних днів від дати створення. Функція має повернути новий об’єкт і не змінювати початкову дату:
function getExpirationDate(createdAt, validDays) {
const expiration = new Date(createdAt);
expiration.setDate(expiration.getDate() + validDays);
return expiration;
}
const createdAt = new Date(2025, 0, 31, 14, 30);
const expiresAt = getExpirationDate(createdAt, 7);
console.log(createdAt.toString());
console.log(expiresAt.toString());Якщо ж термін визначено як точні 168 годин, треба використовувати мілісекунди:
function getExpirationAfterHours(createdAt, hours) {
const milliseconds = hours * 60 * 60 * 1000;
return new Date(createdAt.getTime() + milliseconds);
}
const createdAt = new Date("2025-01-31T14:30:00Z");
const expiresAt = getExpirationAfterHours(createdAt, 168);
console.log(expiresAt.toISOString());Формулювання вимоги визначає правильний алгоритм. «Сім днів» і «168 годин» можуть відрізнятися під час переходу між часовими режимами.
Після обчислень можна порівнювати дати за їхнім числовим значенням:
const first = new Date(2025, 5, 15);
const second = new Date(2025, 5, 16);
console.log(first < second); // true
console.log(first.getTime() < second.getTime()); // trueДля отримання різниці в мілісекундах:
const start = new Date("2025-06-15T10:00:00Z");
const end = new Date("2025-06-16T13:30:00Z");
const difference = end.getTime() - start.getTime();
const hours = difference / (60 * 60 * 1000);
console.log(hours); // 27.5Під час перетворення мілісекунд у дні пам’ятайте: це різниця фіксованих інтервалів, а не обов’язково кількість календарних дат.
const date = new Date(2025, 6, 1);
console.log(date.getMonth()); // 6, липеньДля липня потрібно передавати 6, а не 7.
function addDaysIncorrect(date, amount) {
date.setDate(date.getDate() + amount);
return date;
}Ця функція змінює аргумент. Якщо це небажано, створіть копію:
function addDaysCorrect(date, amount) {
const result = new Date(date);
result.setDate(result.getDate() + amount);
return result;
}const date = new Date(2025, 0, 31);
date.setMonth(date.getMonth() + 1);
console.log(date.toDateString()); // Березень, а не очікуваний лютийДля таких випадків заздалегідь визначте правило: потрібна нормалізація JavaScript чи перехід до останнього дня місяця.
setDate() для додавання мілісекундsetDate() призначений для календарних днів. Якщо потрібно додати точний інтервал, використовуйте getTime():
const result = new Date(
date.getTime() + 30 * 60 * 1000
);Виклики getDate() і setUTCDate() в одній операції можуть дати неочікуваний результат. Виберіть одну модель:
локальні get... разом із локальними set...;
UTC-методи разом із UTC-методами.
Рядки на кшталт "06/15/2025" залежать від формату та середовища. Для передбачуваного результату використовуйте ISO-формат:
const date = new Date("2025-06-15T10:00:00Z");
console.log(date.toISOString());Date можна змінювати методами set....
Місяці в JavaScript нумеруються від 0 до 11.
Значення за межами діапазону автоматично переносяться в сусідні компоненти.
setDate() зручно використовувати для додавання календарних днів.
setMonth() і setFullYear() можуть змінити очікуваний день для 31-го числа або 29 лютого.
Для збереження початкової дати створюйте копію через new Date(date).
Додавання мілісекунд означає фіксований інтервал, а зміна календарного дня — календарну операцію.
UTC-методи потрібно використовувати послідовно, не змішуючи їх із локальними методами.
Для кінцевих днів місяця та високосних дат заздалегідь визначайте потрібне бізнес-правило.