У JavaScript є вбудований обʼєкт Date, який зберігає дату й час і надає методи для роботи з ними.
Він був заснований на класі java.util.Date з Java, який замінили на початку 2010-х років, але задля зворотної сумісності Date у JavaScript залишається.
Через те, як складно працювати з датами загалом, і через те, що обробка часових поясів або погана, або її зовсім немає, існує чимало бібліотек, як-от moment.js, day.js, date-fns і luxon.
Жодної з них немає на Exercism.
У власних проєктах не використовуйте застарілий чи непідтримуваний пакунок на кшталт moment.js, а покладайтеся на сучасніші альтернативи, як-от luxon, або на ще не поширений Temporal.
Ця вправа зосереджена на Date, який залишатиметься актуальним до самого кінця JavaScript.
Обʼєкт Date - це екземпляр класу Date.
Його можна створити, не передаючи у функцію-конструктор жодних аргументів.
У результаті отримуємо обʼєкт Date, який представляє поточну дату й час:
const now = new Date();
// => Thu Apr 14 2022 11:46:08 GMT+0530 (India Standard Time)
// Shows current day, date and time (in your time zone).
Якщо передати число, його буде інтерпретовано як timestamp.
Мітка часу - це ціле число, яке показує кількість мілісекунд, що минули з 1 січня 1970 UTC+0.
const epoch = new Date(0);
// Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)
const another = new Date(1749508766627);
// Tue Jun 10 2025 00:39:26 GMT+0200 (Central European Summer Time)
Можна було б очікувати, що new Date(0) створить «найраніший» обʼєкт дати, але JavaScript переводить дату в місцевий часовий пояс, тож насправді значення початку відліку Unix отримають лише ті, хто перебуває в часовому поясі GMT / з UTC+0.
У конструктор Date можна передати значення-рядок тексту, яке представляє дату.
Єдиний формат, який однаково працює в усіх реалізаціях, - це спрощена версія міжнародно визнаних і стандартизованих так званих рядків міток часу ISO 8601.
Момент часу за UTC має такий вигляд:
YYYY-MM-DDTHH:mm:ss.mssZ
YYYYMMDDTHHmmss.mssZ
де відбуваються такі підстановки:
| Ключ | Опис | Типове значення |
|---|---|---|
| YYYY | Календарний рік, записаний 4 цифрами | |
| MM | Календарний місяць, записаний 2 цифрами | 01 |
| DD | Календарний день, записаний 2 цифрами | 01 |
| T | Сама літера T, що відокремлює дату від часу | |
| HH | Години за 24-годинним форматом, 2 цифри | 00 |
| mm | Хвилини, 2 цифри | 00 |
| ss | Секунди, 2 цифри | 00 |
| mss | Мілісекунди, 3 цифри | 000 |
| Z | Сама літера Z, або зсув +/-HH:mm
|
Сама літера Z вказує на UTC (без часового поясу, без переходу на літній час).
Оскільки для більшості компонентів є типові значення, частини в кінці можна опускати:
YYYY-MM-DD
Типове значення: час 00:00:00.000
Якщо мітка часу не закінчується на Z і не закінчується на +HH:mm чи -HH:mm (що вказує на зсув часового поясу), то з історичних причин діє таке правило:
Якщо зсув часового поясу відсутній, форми лише з датою інтерпретуються як час UTC, а форми з датою й часом - як місцевий час. Тлумачення як часу UTC спричинене історичною помилкою у специфікації, яка суперечила ISO 8601, але її не можна було виправити через сумісність з вебом. Див. Broken Parser – A Web Reality Issue.
Інші формати, які приймає Date.parse, можуть працювати, а можуть і ні.
Коли ми працюємо з датами в JavaScript, під час перетворення з string у Date завжди використовуймо мітку часу ISO 8601.
Форми лише з датою дозволені, але підтримуються не всі формати ISO 8601. Варто звернутися до сторінки з поясненням спрощеної версії на MDN.
Наявний обʼєкт дати теж можна використати як аргумент конструктора.
Тоді створюється копія наявного обʼєкта Date з тією самою датою й часом.
const t1 = new Date();
const t2 = new Date(t1);
// Values of t1 and t2 will be the same.
Обʼєкт дати, який представляє лише дату, можна створити, передавши три числа. Обʼєкт дати, який представляє дату й час, можна створити, передавши шість чисел.
const date1 = new Date(95, 11, 17);
// Creates Date for Dec 17 1995 00:00 if your local timezone is equivalent to UTC.
const date2 = new Date(2013, 12, 5, 13, 24, 0);
// Creates Date for Jan 5 2014 13:24 if your local timezone is equivalent to UTC.
Друге значення - це month, яке починається з 0 для січня й сягає 11 для грудня.
Date.parse()Можна натрапити на згадки про функцію розбору дат Date.parse або на посилання на неї.
Оскільки для цієї функції існує лише кілька інваріантів (істин), а решта реалізації не специфікована (а отже, не є стандартною), користуватися нею не варто.
Date
В обʼєктів дати є чимало методів, які повертають компоненти дати:
getFullYear(); // Get the year (4 digits)
getMonth(); // Get the month, from 0 to 11.
getDate(); // Get the day of month, from 1 to 31.
getHours(); // Get the hour in a 24 clock, from 0 to 23
getMinutes(); // Get the minutes, from 0 to 59
getSeconds(); // Get the seconds, from 0 to 59
getMilliseconds(); // Get the milliseconds, from 0 and 999
getDay(); // Get the day of week, from 0 (Sunday) to 6 (Saturday).
Для кожного з них є відповідний варіант із set (наприклад, setFullYear), який оновлює значення.
Будь-яке значення, що виходить за межі, переходить до наступного компонента:
const date = new Date('2025-02-28T12:42:00Z');
// => Fri Feb 28 2025 13:42:00 GMT+0100 (Central European Standard Time)
date.setDate(29);
// there was no February 29th in 2025.
date.getDate();
// => 1
date.toString();
// => Sat Mar 01 2025 13:42:00 GMT+0100 (Central European Standard Time)
Для всіх методів є варіанти UTC, які ігнорують місцевий часовий пояс.
В обʼєктів дати є метод getTime(), який повертає мітку часу UNIX у мілісекундах, тобто кількість мілісекунд від півночі 1 січня 1970 року за UTC.
Крім того, є метод toISOString(), який перетворює обʼєкт дати на рядок тексту з міткою часу ISO 8601.
Оператори більше (>) і більше або дорівнює (>=), а також менше (<) і менше або дорівнює (<=) можна застосовувати безпосередньо між двома датами або між датою та числом.
Це працює, тому що JavaScript намагається привести дату до примітивного значення.
Коли виконується порівняння двох дат або дати й числа, JavaScript викликає [Symbol.toPrimitive]("number"), який усередині викликає date.valueOf().
Останній рівнозначний виклику date.getTime().
Якщо ми не хочемо покладатися на цю поведінку, спершу перетворімо дату на число за допомогою getTime().
Дати не можна порівнювати на рівність (== і ===), а ось результат .getTime() - можна.
У цій вправі ми попрацюємо над кількома функціями, щоб керувати зустрічами. Система зберігає все в рядках тексту (англ. string) у форматі ISO 8601, але люди користуються календарем не так. Щоб перетворювати один формат на інший, потрібні різні функції.
Створіть зустріч через n днів від поточного моменту на поточний час.
Функція приймає n днів і повертає час зустрічі через n днів від поточного моменту.
createAppointment(4, now);
// Given now is Sun Oct 05 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)
// => Sun Oct 09 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)
Якщо другий параметр now не використано, слід використати поточний час.
Багато інструментів працюють лише з міжнародним стандартизованим форматом ISO 8601.
Напишіть функцію getAppointmentTimestamp, яка приймає дату й повертає рядок тексту в цьому форматі.
const appointment = new Date(Date.UTC(2010, 6, 16, 12, 42, 0, 0));
getAppointmentTimestamp(appointment);
// => '2010-07-16T12:42:00.000Z'
Мітки часу важко читати, і функція для отримання подробиць зустрічі має з цим допомогти.
Функція getAppointmentDetails приймає мітку часу у форматі ISO 8601 і повертає рік, місяць, число, годину і хвилину.
getAppointmentDetails('2022-04-24T08:15:00.000');
// => { year: 2022, month: 3, date: 24, hour: 8, minute: 15 }
Функція отримає першим аргументом час зустрічі, а другим - обʼєкт із деякими опціями. Потрібно оновити зустріч відповідно до опцій в обʼєкті й повернути нову дату зустрічі. Обʼєкт опцій може містити кілька опцій.
updateAppointment('2022-02-09T09:20:00.000', { month: 6 });
// => { year: 2022, month: 6, date: 9, hour: 10, minute: 20 }
Функція отримає два аргументи - дві зустрічі (мітки часу). Потрібно повернути різницю між цими моментами в секундах.
Оскільки пів секунди майже нічого не значить, округліть число перед тим, як його повернути.
timeBetween('2022-12-12T09:20:00.000', '2022-12-18T08:30:00.000');
// => 515400
Нарешті, коли зустріч призначено, система має перевірити, чи вона дійсна. Іншими словами, зустріч має бути в майбутньому, а не в минулому.
Напишіть функцію isValid, яка приймає два аргументи: мітку часу зустрічі (рядок тексту) і поточний час як мітку часу (рядок тексту), і повертає true, якщо зустріч відбувається в майбутньому відносно поточного часу.
isValid('2022-02-11T23:00:00.000', '2022-02-08T23:00:00.000');
// => true
Зареєструйтеся на Exercism, щоб вивчати й опановувати JavaScript, а також 37 концепцій159 вправ та справжнє наставництво від людей, і все це безкоштовно.